blob: bb560b0652411b747921687d10412ee17ac6b14e [file] [log] [blame]
[email protected]cb370a0632010-01-30 08:24:121// Copyright (c) 2010 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit586acc5fe2008-07-26 22:42:524
[email protected]175adac2008-07-30 17:28:045#include "net/url_request/url_request_http_job.h"
initial.commit586acc5fe2008-07-26 22:42:526
[email protected]4ed2755f2008-12-15 09:01:337#include "base/base_switches.h"
8#include "base/command_line.h"
[email protected]39ce5c02008-08-22 04:03:449#include "base/compiler_specific.h"
[email protected]60889422008-09-23 01:18:1610#include "base/file_util.h"
11#include "base/file_version_info.h"
initial.commit586acc5fe2008-07-26 22:42:5212#include "base/message_loop.h"
[email protected]5b90b5d2009-04-30 23:06:0113#include "base/rand_util.h"
initial.commit586acc5fe2008-07-26 22:42:5214#include "base/string_util.h"
[email protected]a9cea7542009-05-20 04:30:2315#include "net/base/cert_status_flags.h"
[email protected]cb370a0632010-01-30 08:24:1216#include "net/base/cookie_policy.h"
[email protected]9349cfb2010-08-31 18:00:5317#include "net/base/cookie_store.h"
[email protected]423041b2008-10-27 17:39:2818#include "net/base/filter.h"
[email protected]326e6792009-12-11 21:04:4219#include "net/base/transport_security_state.h"
[email protected]b8430722008-09-17 20:05:4420#include "net/base/load_flags.h"
initial.commit586acc5fe2008-07-26 22:42:5221#include "net/base/net_errors.h"
22#include "net/base/net_util.h"
[email protected]60889422008-09-23 01:18:1623#include "net/base/sdch_manager.h"
[email protected]0b45559b2009-06-12 21:45:1124#include "net/base/ssl_cert_request_info.h"
[email protected]8c76ae22010-04-20 22:15:4325#include "net/http/http_request_headers.h"
[email protected]319d9e6f2009-02-18 19:47:2126#include "net/http/http_response_headers.h"
initial.commit586acc5fe2008-07-26 22:42:5227#include "net/http/http_response_info.h"
28#include "net/http/http_transaction.h"
29#include "net/http/http_transaction_factory.h"
[email protected]0757e7702009-03-27 04:00:2230#include "net/http/http_util.h"
[email protected]be4d55fe2010-06-01 13:40:0231#include "net/url_request/https_prober.h"
initial.commit586acc5fe2008-07-26 22:42:5232#include "net/url_request/url_request.h"
[email protected]319d9e6f2009-02-18 19:47:2133#include "net/url_request/url_request_context.h"
initial.commit586acc5fe2008-07-26 22:42:5234#include "net/url_request/url_request_error_job.h"
[email protected]06965e02009-09-04 21:36:4235#include "net/url_request/url_request_redirect_job.h"
[email protected]6b3f9642010-11-25 02:29:0636#include "net/url_request/url_request_throttler_header_adapter.h"
37#include "net/url_request/url_request_throttler_manager.h"
initial.commit586acc5fe2008-07-26 22:42:5238
[email protected]8c76ae22010-04-20 22:15:4339static const char kAvailDictionaryHeader[] = "Avail-Dictionary";
40
[email protected]4f5656c62010-12-13 10:47:0941namespace net {
42
43namespace {
44
45class HTTPSProberDelegateImpl : public HTTPSProberDelegate {
46 public:
47 HTTPSProberDelegateImpl(const std::string& host, int max_age,
48 bool include_subdomains,
49 TransportSecurityState* sts)
50 : host_(host),
51 max_age_(max_age),
52 include_subdomains_(include_subdomains),
53 sts_(sts) { }
54
55 virtual void ProbeComplete(bool result) {
56 if (result) {
57 base::Time current_time(base::Time::Now());
58 base::TimeDelta max_age_delta = base::TimeDelta::FromSeconds(max_age_);
59
60 TransportSecurityState::DomainState domain_state;
61 domain_state.expiry = current_time + max_age_delta;
62 domain_state.mode =
63 TransportSecurityState::DomainState::MODE_OPPORTUNISTIC;
64 domain_state.include_subdomains = include_subdomains_;
65
66 sts_->EnableHost(host_, domain_state);
67 }
68
69 delete this;
70 }
71
72 private:
73 const std::string host_;
74 const int max_age_;
75 const bool include_subdomains_;
76 scoped_refptr<TransportSecurityState> sts_;
77};
78
79} // namespace
80
initial.commit586acc5fe2008-07-26 22:42:5281// TODO(darin): make sure the port blocking code is not lost
initial.commit586acc5fe2008-07-26 22:42:5282// static
[email protected]4f5656c62010-12-13 10:47:0983URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request,
84 const std::string& scheme) {
initial.commit586acc5fe2008-07-26 22:42:5285 DCHECK(scheme == "http" || scheme == "https");
86
[email protected]bcb84f8b2009-08-31 16:20:1487 int port = request->url().IntPort();
[email protected]4f5656c62010-12-13 10:47:0988 if (!IsPortAllowedByDefault(port) && !IsPortAllowedByOverride(port))
89 return new URLRequestErrorJob(request, ERR_UNSAFE_PORT);
initial.commit586acc5fe2008-07-26 22:42:5290
91 if (!request->context() ||
92 !request->context()->http_transaction_factory()) {
93 NOTREACHED() << "requires a valid context";
[email protected]4f5656c62010-12-13 10:47:0994 return new URLRequestErrorJob(request, ERR_INVALID_ARGUMENT);
initial.commit586acc5fe2008-07-26 22:42:5295 }
96
[email protected]4f5656c62010-12-13 10:47:0997 TransportSecurityState::DomainState domain_state;
[email protected]90b153012009-09-10 18:35:1698 if (scheme == "http" &&
[email protected]326e6792009-12-11 21:04:4299 (request->url().port().empty() || port == 80) &&
100 request->context()->transport_security_state() &&
101 request->context()->transport_security_state()->IsEnabledForHost(
102 &domain_state, request->url().host())) {
103 if (domain_state.mode ==
[email protected]4f5656c62010-12-13 10:47:09104 TransportSecurityState::DomainState::MODE_STRICT) {
[email protected]326e6792009-12-11 21:04:42105 DCHECK_EQ(request->url().scheme(), "http");
106 url_canon::Replacements<char> replacements;
107 static const char kNewScheme[] = "https";
108 replacements.SetScheme(kNewScheme,
109 url_parse::Component(0, strlen(kNewScheme)));
110 GURL new_location = request->url().ReplaceComponents(replacements);
111 return new URLRequestRedirectJob(request, new_location);
112 } else {
113 // TODO(agl): implement opportunistic HTTPS upgrade.
114 }
[email protected]06965e02009-09-04 21:36:42115 }
[email protected]4ed2755f2008-12-15 09:01:33116
[email protected]175adac2008-07-30 17:28:04117 return new URLRequestHttpJob(request);
initial.commit586acc5fe2008-07-26 22:42:52118}
119
[email protected]4f5656c62010-12-13 10:47:09120URLRequestHttpJob::URLRequestHttpJob(URLRequest* request)
121 : URLRequestJob(request),
initial.commit586acc5fe2008-07-26 22:42:52122 response_info_(NULL),
[email protected]34602282010-02-03 22:14:15123 response_cookies_save_index_(0),
[email protected]4f5656c62010-12-13 10:47:09124 proxy_auth_state_(AUTH_STATE_DONT_NEED_AUTH),
125 server_auth_state_(AUTH_STATE_DONT_NEED_AUTH),
[email protected]34602282010-02-03 22:14:15126 ALLOW_THIS_IN_INITIALIZER_LIST(can_get_cookies_callback_(
127 this, &URLRequestHttpJob::OnCanGetCookiesCompleted)),
128 ALLOW_THIS_IN_INITIALIZER_LIST(can_set_cookie_callback_(
129 this, &URLRequestHttpJob::OnCanSetCookieCompleted)),
130 ALLOW_THIS_IN_INITIALIZER_LIST(start_callback_(
131 this, &URLRequestHttpJob::OnStartCompleted)),
132 ALLOW_THIS_IN_INITIALIZER_LIST(read_callback_(
133 this, &URLRequestHttpJob::OnReadCompleted)),
[email protected]3589e552008-08-20 23:11:34134 read_in_progress_(false),
[email protected]2aecf7382009-06-17 04:14:27135 transaction_(NULL),
[email protected]4f5656c62010-12-13 10:47:09136 throttling_entry_(URLRequestThrottlerManager::GetInstance()->
[email protected]6b3f9642010-11-25 02:29:06137 RegisterRequestUrl(request->url())),
[email protected]5b90b5d2009-04-30 23:06:01138 sdch_dictionary_advertised_(false),
139 sdch_test_activated_(false),
[email protected]d8fd5132009-05-15 01:06:53140 sdch_test_control_(false),
[email protected]00e48bf2010-12-03 06:15:42141 is_cached_content_(false),
142 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
initial.commit586acc5fe2008-07-26 22:42:52143}
144
[email protected]175adac2008-07-30 17:28:04145URLRequestHttpJob::~URLRequestHttpJob() {
[email protected]5b90b5d2009-04-30 23:06:01146 DCHECK(!sdch_test_control_ || !sdch_test_activated_);
[email protected]d8fd5132009-05-15 01:06:53147 if (!IsCachedContent()) {
148 if (sdch_test_control_)
149 RecordPacketStats(SDCH_EXPERIMENT_HOLDBACK);
150 if (sdch_test_activated_)
151 RecordPacketStats(SDCH_EXPERIMENT_DECODE);
152 }
[email protected]284c373d42009-05-19 23:39:03153 // Make sure SDCH filters are told to emit histogram data while this class
154 // can still service the IsCachedContent() call.
155 DestroyFilters();
[email protected]5b90b5d2009-04-30 23:06:01156
[email protected]7234e6c2009-02-11 21:37:04157 if (sdch_dictionary_url_.is_valid()) {
[email protected]d55ad15d2009-02-17 19:40:50158 // Prior to reaching the destructor, request_ has been set to a NULL
159 // pointer, so request_->url() is no longer valid in the destructor, and we
160 // use an alternate copy |request_info_.url|.
[email protected]a41fae82009-02-21 06:11:45161 SdchManager* manager = SdchManager::Global();
162 // To be extra safe, since this is a "different time" from when we decided
163 // to get the dictionary, we'll validate that an SdchManager is available.
164 // At shutdown time, care is taken to be sure that we don't delete this
165 // globally useful instance "too soon," so this check is just defensive
166 // coding to assure that IF the system is shutting down, we don't have any
167 // problem if the manager was deleted ahead of time.
168 if (manager) // Defensive programming.
169 manager->FetchDictionary(request_info_.url, sdch_dictionary_url_);
[email protected]7234e6c2009-02-11 21:37:04170 }
initial.commit586acc5fe2008-07-26 22:42:52171}
172
[email protected]4f5656c62010-12-13 10:47:09173void URLRequestHttpJob::SetUpload(UploadData* upload) {
[email protected]af4876d2008-10-21 23:10:57174 DCHECK(!transaction_.get()) << "cannot change once started";
initial.commit586acc5fe2008-07-26 22:42:52175 request_info_.upload_data = upload;
176}
177
[email protected]175adac2008-07-30 17:28:04178void URLRequestHttpJob::SetExtraRequestHeaders(
[email protected]4f5656c62010-12-13 10:47:09179 const HttpRequestHeaders& headers) {
[email protected]af4876d2008-10-21 23:10:57180 DCHECK(!transaction_.get()) << "cannot change once started";
[email protected]ee1a29b02010-05-06 20:42:12181 request_info_.extra_headers.CopyFrom(headers);
initial.commit586acc5fe2008-07-26 22:42:52182}
183
[email protected]175adac2008-07-30 17:28:04184void URLRequestHttpJob::Start() {
[email protected]af4876d2008-10-21 23:10:57185 DCHECK(!transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52186
initial.commit586acc5fe2008-07-26 22:42:52187 // Ensure that we do not send username and password fields in the referrer.
[email protected]e600c822009-08-31 16:57:08188 GURL referrer(request_->GetSanitizedReferrer());
initial.commit586acc5fe2008-07-26 22:42:52189
190 request_info_.url = request_->url();
191 request_info_.referrer = referrer;
192 request_info_.method = request_->method();
193 request_info_.load_flags = request_->load_flags();
[email protected]725355a2009-03-25 20:42:55194 request_info_.priority = request_->priority();
initial.commit586acc5fe2008-07-26 22:42:52195
[email protected]6f681a42009-01-27 22:28:54196 if (request_->context()) {
[email protected]8c76ae22010-04-20 22:15:43197 request_info_.extra_headers.SetHeader(
[email protected]4f5656c62010-12-13 10:47:09198 HttpRequestHeaders::kUserAgent,
[email protected]8c76ae22010-04-20 22:15:43199 request_->context()->GetUserAgent(request_->url()));
[email protected]6f681a42009-01-27 22:28:54200 }
initial.commit586acc5fe2008-07-26 22:42:52201
202 AddExtraHeaders();
[email protected]34602282010-02-03 22:14:15203 AddCookieHeaderAndStart();
initial.commit586acc5fe2008-07-26 22:42:52204}
205
[email protected]175adac2008-07-30 17:28:04206void URLRequestHttpJob::Kill() {
[email protected]af4876d2008-10-21 23:10:57207 if (!transaction_.get())
initial.commit586acc5fe2008-07-26 22:42:52208 return;
209
210 DestroyTransaction();
[email protected]4f5656c62010-12-13 10:47:09211 URLRequestJob::Kill();
initial.commit586acc5fe2008-07-26 22:42:52212}
213
[email protected]4f5656c62010-12-13 10:47:09214LoadState URLRequestHttpJob::GetLoadState() const {
[email protected]af4876d2008-10-21 23:10:57215 return transaction_.get() ?
[email protected]4f5656c62010-12-13 10:47:09216 transaction_->GetLoadState() : LOAD_STATE_IDLE;
initial.commit586acc5fe2008-07-26 22:42:52217}
218
[email protected]175adac2008-07-30 17:28:04219uint64 URLRequestHttpJob::GetUploadProgress() const {
[email protected]af4876d2008-10-21 23:10:57220 return transaction_.get() ? transaction_->GetUploadProgress() : 0;
initial.commit586acc5fe2008-07-26 22:42:52221}
222
[email protected]60c413c92009-03-09 16:53:31223bool URLRequestHttpJob::GetMimeType(std::string* mime_type) const {
[email protected]af4876d2008-10-21 23:10:57224 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52225
226 if (!response_info_)
227 return false;
228
229 return response_info_->headers->GetMimeType(mime_type);
230}
231
[email protected]175adac2008-07-30 17:28:04232bool URLRequestHttpJob::GetCharset(std::string* charset) {
[email protected]af4876d2008-10-21 23:10:57233 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52234
235 if (!response_info_)
236 return false;
237
238 return response_info_->headers->GetCharset(charset);
239}
240
[email protected]4f5656c62010-12-13 10:47:09241void URLRequestHttpJob::GetResponseInfo(HttpResponseInfo* info) {
initial.commit586acc5fe2008-07-26 22:42:52242 DCHECK(request_);
[email protected]af4876d2008-10-21 23:10:57243 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52244
245 if (response_info_)
246 *info = *response_info_;
247}
248
[email protected]175adac2008-07-30 17:28:04249bool URLRequestHttpJob::GetResponseCookies(
initial.commit586acc5fe2008-07-26 22:42:52250 std::vector<std::string>* cookies) {
[email protected]af4876d2008-10-21 23:10:57251 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52252
253 if (!response_info_)
254 return false;
255
[email protected]34602282010-02-03 22:14:15256 // TODO(darin): Why are we extracting response cookies again? Perhaps we
257 // should just leverage response_cookies_.
initial.commit586acc5fe2008-07-26 22:42:52258
259 cookies->clear();
[email protected]34602282010-02-03 22:14:15260 FetchResponseCookies(response_info_, cookies);
initial.commit586acc5fe2008-07-26 22:42:52261 return true;
262}
263
[email protected]84973ad2009-03-30 18:05:43264int URLRequestHttpJob::GetResponseCode() const {
[email protected]af4876d2008-10-21 23:10:57265 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52266
267 if (!response_info_)
268 return -1;
269
270 return response_info_->headers->response_code();
271}
272
[email protected]60889422008-09-23 01:18:16273bool URLRequestHttpJob::GetContentEncodings(
[email protected]423041b2008-10-27 17:39:28274 std::vector<Filter::FilterType>* encoding_types) {
[email protected]af4876d2008-10-21 23:10:57275 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52276 if (!response_info_)
277 return false;
[email protected]423041b2008-10-27 17:39:28278 DCHECK(encoding_types->empty());
initial.commit586acc5fe2008-07-26 22:42:52279
[email protected]60889422008-09-23 01:18:16280 std::string encoding_type;
281 void* iter = NULL;
282 while (response_info_->headers->EnumerateHeader(&iter, "Content-Encoding",
283 &encoding_type)) {
[email protected]423041b2008-10-27 17:39:28284 encoding_types->push_back(Filter::ConvertEncodingToType(encoding_type));
[email protected]60889422008-09-23 01:18:16285 }
[email protected]c631b6aa2008-10-15 21:21:37286
[email protected]77e9fcf2009-03-28 01:45:58287 // Even if encoding types are empty, there is a chance that we need to add
288 // some decoding, as some proxies strip encoding completely. In such cases,
289 // we may need to add (for example) SDCH filtering (when the context suggests
290 // it is appropriate).
291 Filter::FixupEncodingTypes(*this, encoding_types);
292
[email protected]60889422008-09-23 01:18:16293 return !encoding_types->empty();
initial.commit586acc5fe2008-07-26 22:42:52294}
295
[email protected]c631b6aa2008-10-15 21:21:37296bool URLRequestHttpJob::IsSdchResponse() const {
[email protected]5b90b5d2009-04-30 23:06:01297 return sdch_dictionary_advertised_;
[email protected]c631b6aa2008-10-15 21:21:37298}
299
[email protected]175adac2008-07-30 17:28:04300bool URLRequestHttpJob::IsSafeRedirect(const GURL& location) {
initial.commit586acc5fe2008-07-26 22:42:52301 // We only allow redirects to certain "safe" protocols. This does not
302 // restrict redirects to externally handled protocols. Our consumer would
303 // need to take care of those.
304
[email protected]4f5656c62010-12-13 10:47:09305 if (!URLRequest::IsHandledURL(location))
initial.commit586acc5fe2008-07-26 22:42:52306 return true;
307
308 static const char* kSafeSchemes[] = {
309 "http",
310 "https",
311 "ftp"
312 };
313
314 for (size_t i = 0; i < arraysize(kSafeSchemes); ++i) {
315 if (location.SchemeIs(kSafeSchemes[i]))
316 return true;
317 }
318
319 return false;
320}
321
[email protected]175adac2008-07-30 17:28:04322bool URLRequestHttpJob::NeedsAuth() {
initial.commit586acc5fe2008-07-26 22:42:52323 int code = GetResponseCode();
324 if (code == -1)
325 return false;
326
327 // Check if we need either Proxy or WWW Authentication. This could happen
328 // because we either provided no auth info, or provided incorrect info.
329 switch (code) {
330 case 407:
[email protected]4f5656c62010-12-13 10:47:09331 if (proxy_auth_state_ == AUTH_STATE_CANCELED)
initial.commit586acc5fe2008-07-26 22:42:52332 return false;
[email protected]4f5656c62010-12-13 10:47:09333 proxy_auth_state_ = AUTH_STATE_NEED_AUTH;
initial.commit586acc5fe2008-07-26 22:42:52334 return true;
335 case 401:
[email protected]4f5656c62010-12-13 10:47:09336 if (server_auth_state_ == AUTH_STATE_CANCELED)
initial.commit586acc5fe2008-07-26 22:42:52337 return false;
[email protected]4f5656c62010-12-13 10:47:09338 server_auth_state_ = AUTH_STATE_NEED_AUTH;
initial.commit586acc5fe2008-07-26 22:42:52339 return true;
340 }
341 return false;
342}
343
[email protected]175adac2008-07-30 17:28:04344void URLRequestHttpJob::GetAuthChallengeInfo(
[email protected]4f5656c62010-12-13 10:47:09345 scoped_refptr<AuthChallengeInfo>* result) {
[email protected]af4876d2008-10-21 23:10:57346 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52347 DCHECK(response_info_);
348
349 // sanity checks:
[email protected]4f5656c62010-12-13 10:47:09350 DCHECK(proxy_auth_state_ == AUTH_STATE_NEED_AUTH ||
351 server_auth_state_ == AUTH_STATE_NEED_AUTH);
initial.commit586acc5fe2008-07-26 22:42:52352 DCHECK(response_info_->headers->response_code() == 401 ||
353 response_info_->headers->response_code() == 407);
354
355 *result = response_info_->auth_challenge;
356}
357
[email protected]13c8a092010-07-29 06:15:44358void URLRequestHttpJob::SetAuth(const string16& username,
359 const string16& password) {
[email protected]af4876d2008-10-21 23:10:57360 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52361
362 // Proxy gets set first, then WWW.
[email protected]4f5656c62010-12-13 10:47:09363 if (proxy_auth_state_ == AUTH_STATE_NEED_AUTH) {
364 proxy_auth_state_ = AUTH_STATE_HAVE_AUTH;
initial.commit586acc5fe2008-07-26 22:42:52365 } else {
[email protected]4f5656c62010-12-13 10:47:09366 DCHECK(server_auth_state_ == AUTH_STATE_NEED_AUTH);
367 server_auth_state_ = AUTH_STATE_HAVE_AUTH;
initial.commit586acc5fe2008-07-26 22:42:52368 }
369
[email protected]0757e7702009-03-27 04:00:22370 RestartTransactionWithAuth(username, password);
371}
372
373void URLRequestHttpJob::RestartTransactionWithAuth(
[email protected]13c8a092010-07-29 06:15:44374 const string16& username,
375 const string16& password) {
[email protected]34602282010-02-03 22:14:15376 username_ = username;
377 password_ = password;
[email protected]0757e7702009-03-27 04:00:22378
initial.commit586acc5fe2008-07-26 22:42:52379 // These will be reset in OnStartCompleted.
380 response_info_ = NULL;
381 response_cookies_.clear();
382
[email protected]0757e7702009-03-27 04:00:22383 // Update the cookies, since the cookie store may have been updated from the
384 // headers in the 401/407. Since cookies were already appended to
[email protected]34602282010-02-03 22:14:15385 // extra_headers, we need to strip them out before adding them again.
[email protected]8c76ae22010-04-20 22:15:43386 request_info_.extra_headers.RemoveHeader(
[email protected]4f5656c62010-12-13 10:47:09387 HttpRequestHeaders::kCookie);
[email protected]0757e7702009-03-27 04:00:22388
[email protected]34602282010-02-03 22:14:15389 AddCookieHeaderAndStart();
initial.commit586acc5fe2008-07-26 22:42:52390}
391
[email protected]175adac2008-07-30 17:28:04392void URLRequestHttpJob::CancelAuth() {
initial.commit586acc5fe2008-07-26 22:42:52393 // Proxy gets set first, then WWW.
[email protected]4f5656c62010-12-13 10:47:09394 if (proxy_auth_state_ == AUTH_STATE_NEED_AUTH) {
395 proxy_auth_state_ = AUTH_STATE_CANCELED;
initial.commit586acc5fe2008-07-26 22:42:52396 } else {
[email protected]4f5656c62010-12-13 10:47:09397 DCHECK(server_auth_state_ == AUTH_STATE_NEED_AUTH);
398 server_auth_state_ = AUTH_STATE_CANCELED;
initial.commit586acc5fe2008-07-26 22:42:52399 }
400
401 // These will be reset in OnStartCompleted.
402 response_info_ = NULL;
403 response_cookies_.clear();
404
405 // OK, let the consumer read the error page...
406 //
407 // Because we set the AUTH_STATE_CANCELED flag, NeedsAuth will return false,
408 // which will cause the consumer to receive OnResponseStarted instead of
409 // OnAuthRequired.
410 //
411 // We have to do this via InvokeLater to avoid "recursing" the consumer.
412 //
[email protected]00e48bf2010-12-03 06:15:42413 MessageLoop::current()->PostTask(
414 FROM_HERE,
415 method_factory_.NewRunnableMethod(
[email protected]4f5656c62010-12-13 10:47:09416 &URLRequestHttpJob::OnStartCompleted, OK));
initial.commit586acc5fe2008-07-26 22:42:52417}
418
[email protected]0b45559b2009-06-12 21:45:11419void URLRequestHttpJob::ContinueWithCertificate(
[email protected]4f5656c62010-12-13 10:47:09420 X509Certificate* client_cert) {
[email protected]0b45559b2009-06-12 21:45:11421 DCHECK(transaction_.get());
422
423 DCHECK(!response_info_) << "should not have a response yet";
424
425 // No matter what, we want to report our status as IO pending since we will
426 // be notifying our consumer asynchronously via OnStartCompleted.
427 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
428
429 int rv = transaction_->RestartWithCertificate(client_cert, &start_callback_);
[email protected]4f5656c62010-12-13 10:47:09430 if (rv == ERR_IO_PENDING)
[email protected]0b45559b2009-06-12 21:45:11431 return;
432
433 // The transaction started synchronously, but we need to notify the
[email protected]4f5656c62010-12-13 10:47:09434 // URLRequest delegate via the message loop.
[email protected]00e48bf2010-12-03 06:15:42435 MessageLoop::current()->PostTask(
436 FROM_HERE,
437 method_factory_.NewRunnableMethod(
438 &URLRequestHttpJob::OnStartCompleted, rv));
[email protected]0b45559b2009-06-12 21:45:11439}
440
[email protected]175adac2008-07-30 17:28:04441void URLRequestHttpJob::ContinueDespiteLastError() {
[email protected]9ec48752009-02-06 23:33:58442 // If the transaction was destroyed, then the job was cancelled.
443 if (!transaction_.get())
444 return;
445
initial.commit586acc5fe2008-07-26 22:42:52446 DCHECK(!response_info_) << "should not have a response yet";
447
448 // No matter what, we want to report our status as IO pending since we will
449 // be notifying our consumer asynchronously via OnStartCompleted.
450 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
451
452 int rv = transaction_->RestartIgnoringLastError(&start_callback_);
[email protected]4f5656c62010-12-13 10:47:09453 if (rv == ERR_IO_PENDING)
initial.commit586acc5fe2008-07-26 22:42:52454 return;
455
456 // The transaction started synchronously, but we need to notify the
[email protected]4f5656c62010-12-13 10:47:09457 // URLRequest delegate via the message loop.
[email protected]00e48bf2010-12-03 06:15:42458 MessageLoop::current()->PostTask(
459 FROM_HERE,
460 method_factory_.NewRunnableMethod(
461 &URLRequestHttpJob::OnStartCompleted, rv));
initial.commit586acc5fe2008-07-26 22:42:52462}
463
[email protected]4f5656c62010-12-13 10:47:09464bool URLRequestHttpJob::ReadRawData(IOBuffer* buf, int buf_size,
[email protected]9dea9e1f2009-01-29 00:30:47465 int *bytes_read) {
initial.commit586acc5fe2008-07-26 22:42:52466 DCHECK_NE(buf_size, 0);
467 DCHECK(bytes_read);
468 DCHECK(!read_in_progress_);
469
470 int rv = transaction_->Read(buf, buf_size, &read_callback_);
471 if (rv >= 0) {
472 *bytes_read = rv;
473 return true;
474 }
475
[email protected]4f5656c62010-12-13 10:47:09476 if (rv == ERR_IO_PENDING) {
initial.commit586acc5fe2008-07-26 22:42:52477 read_in_progress_ = true;
478 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
479 } else {
480 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
481 }
482
483 return false;
484}
485
[email protected]9dd90e52010-02-23 19:15:01486void URLRequestHttpJob::StopCaching() {
487 if (transaction_.get())
488 transaction_->StopCaching();
489}
490
[email protected]34602282010-02-03 22:14:15491void URLRequestHttpJob::OnCanGetCookiesCompleted(int policy) {
492 // If the request was destroyed, then there is no more work to do.
493 if (request_ && request_->delegate()) {
[email protected]52fa07502010-12-07 08:54:42494 if (request_->context()->cookie_store()) {
[email protected]4f5656c62010-12-13 10:47:09495 if (policy == ERR_ACCESS_DENIED) {
[email protected]52fa07502010-12-07 08:54:42496 request_->delegate()->OnGetCookies(request_, true);
[email protected]4f5656c62010-12-13 10:47:09497 } else if (policy == OK) {
[email protected]52fa07502010-12-07 08:54:42498 request_->delegate()->OnGetCookies(request_, false);
[email protected]4f5656c62010-12-13 10:47:09499 CookieOptions options;
[email protected]52fa07502010-12-07 08:54:42500 options.set_include_httponly();
501 std::string cookies =
502 request_->context()->cookie_store()->GetCookiesWithOptions(
503 request_->url(), options);
504 if (!cookies.empty()) {
505 request_info_.extra_headers.SetHeader(
[email protected]4f5656c62010-12-13 10:47:09506 HttpRequestHeaders::kCookie, cookies);
[email protected]52fa07502010-12-07 08:54:42507 }
[email protected]8c76ae22010-04-20 22:15:43508 }
[email protected]34602282010-02-03 22:14:15509 }
[email protected]9fb83e82010-07-02 18:24:55510 // We may have been canceled within OnGetCookies.
[email protected]3dbb80b2010-02-09 22:41:20511 if (GetStatus().is_success()) {
512 StartTransaction();
513 } else {
514 NotifyCanceled();
515 }
[email protected]34602282010-02-03 22:14:15516 }
517 Release(); // Balance AddRef taken in AddCookieHeaderAndStart
518}
519
520void URLRequestHttpJob::OnCanSetCookieCompleted(int policy) {
521 // If the request was destroyed, then there is no more work to do.
522 if (request_ && request_->delegate()) {
[email protected]52fa07502010-12-07 08:54:42523 if (request_->context()->cookie_store()) {
[email protected]4f5656c62010-12-13 10:47:09524 if (policy == ERR_ACCESS_DENIED) {
[email protected]52fa07502010-12-07 08:54:42525 request_->delegate()->OnSetCookie(
526 request_,
527 response_cookies_[response_cookies_save_index_],
[email protected]4f5656c62010-12-13 10:47:09528 CookieOptions(),
[email protected]52fa07502010-12-07 08:54:42529 true);
[email protected]4f5656c62010-12-13 10:47:09530 } else if (policy == OK || policy == OK_FOR_SESSION_ONLY) {
[email protected]52fa07502010-12-07 08:54:42531 // OK to save the current response cookie now.
[email protected]4f5656c62010-12-13 10:47:09532 CookieOptions options;
[email protected]52fa07502010-12-07 08:54:42533 options.set_include_httponly();
[email protected]4f5656c62010-12-13 10:47:09534 if (policy == OK_FOR_SESSION_ONLY)
[email protected]52fa07502010-12-07 08:54:42535 options.set_force_session();
536 request_->context()->cookie_store()->SetCookieWithOptions(
537 request_->url(), response_cookies_[response_cookies_save_index_],
538 options);
539 request_->delegate()->OnSetCookie(
540 request_,
541 response_cookies_[response_cookies_save_index_],
542 options,
543 false);
544 }
[email protected]34602282010-02-03 22:14:15545 }
546 response_cookies_save_index_++;
[email protected]9fb83e82010-07-02 18:24:55547 // We may have been canceled within OnSetCookie.
[email protected]3dbb80b2010-02-09 22:41:20548 if (GetStatus().is_success()) {
549 SaveNextCookie();
550 } else {
551 NotifyCanceled();
552 }
[email protected]34602282010-02-03 22:14:15553 }
554 Release(); // Balance AddRef taken in SaveNextCookie
555}
556
[email protected]175adac2008-07-30 17:28:04557void URLRequestHttpJob::OnStartCompleted(int result) {
initial.commit586acc5fe2008-07-26 22:42:52558 // If the request was destroyed, then there is no more work to do.
559 if (!request_ || !request_->delegate())
560 return;
561
562 // If the transaction was destroyed, then the job was cancelled, and
563 // we can just ignore this notification.
[email protected]af4876d2008-10-21 23:10:57564 if (!transaction_.get())
initial.commit586acc5fe2008-07-26 22:42:52565 return;
566
567 // Clear the IO_PENDING status
568 SetStatus(URLRequestStatus());
569
[email protected]4f5656c62010-12-13 10:47:09570 if (result == OK) {
[email protected]34602282010-02-03 22:14:15571 SaveCookiesAndNotifyHeadersComplete();
[email protected]a9cea7542009-05-20 04:30:23572 } else if (ShouldTreatAsCertificateError(result)) {
initial.commit586acc5fe2008-07-26 22:42:52573 // We encountered an SSL certificate error. Ask our delegate to decide
574 // what we should do.
575 // TODO(wtc): also pass ssl_info.cert_status, or just pass the whole
576 // ssl_info.
577 request_->delegate()->OnSSLCertificateError(
578 request_, result, transaction_->GetResponseInfo()->ssl_info.cert);
[email protected]4f5656c62010-12-13 10:47:09579 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]0b45559b2009-06-12 21:45:11580 request_->delegate()->OnCertificateRequested(
581 request_, transaction_->GetResponseInfo()->cert_request_info);
initial.commit586acc5fe2008-07-26 22:42:52582 } else {
583 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
584 }
585}
586
[email protected]175adac2008-07-30 17:28:04587void URLRequestHttpJob::OnReadCompleted(int result) {
initial.commit586acc5fe2008-07-26 22:42:52588 read_in_progress_ = false;
589
590 if (result == 0) {
591 NotifyDone(URLRequestStatus());
592 } else if (result < 0) {
593 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result));
594 } else {
595 // Clear the IO_PENDING status
596 SetStatus(URLRequestStatus());
597 }
598
599 NotifyReadComplete(result);
600}
601
[email protected]a9cea7542009-05-20 04:30:23602bool URLRequestHttpJob::ShouldTreatAsCertificateError(int result) {
[email protected]4f5656c62010-12-13 10:47:09603 if (!IsCertificateError(result))
[email protected]a9cea7542009-05-20 04:30:23604 return false;
605
[email protected]77f6fb432009-09-05 14:21:09606 // Check whether our context is using Strict-Transport-Security.
[email protected]326e6792009-12-11 21:04:42607 if (!context_->transport_security_state())
[email protected]a9cea7542009-05-20 04:30:23608 return true;
609
[email protected]4f5656c62010-12-13 10:47:09610 TransportSecurityState::DomainState domain_state;
[email protected]326e6792009-12-11 21:04:42611 // TODO(agl): don't ignore opportunistic mode.
612 const bool r = context_->transport_security_state()->IsEnabledForHost(
613 &domain_state, request_info_.url.host());
614
615 return !r || domain_state.mode ==
[email protected]4f5656c62010-12-13 10:47:09616 TransportSecurityState::DomainState::MODE_OPPORTUNISTIC;
[email protected]a9cea7542009-05-20 04:30:23617}
618
[email protected]175adac2008-07-30 17:28:04619void URLRequestHttpJob::NotifyHeadersComplete() {
initial.commit586acc5fe2008-07-26 22:42:52620 DCHECK(!response_info_);
621
622 response_info_ = transaction_->GetResponseInfo();
623
[email protected]d8fd5132009-05-15 01:06:53624 // Save boolean, as we'll need this info at destruction time, and filters may
625 // also need this info.
626 is_cached_content_ = response_info_->was_cached;
627
[email protected]6b3f9642010-11-25 02:29:06628 if (!is_cached_content_) {
[email protected]4f5656c62010-12-13 10:47:09629 URLRequestThrottlerHeaderAdapter response_adapter(
[email protected]6b3f9642010-11-25 02:29:06630 response_info_->headers);
631 throttling_entry_->UpdateWithResponse(&response_adapter);
632 }
633
[email protected]77f6fb432009-09-05 14:21:09634 ProcessStrictTransportSecurityHeader();
[email protected]a9cea7542009-05-20 04:30:23635
[email protected]fe219872008-09-23 02:17:00636 if (SdchManager::Global() &&
637 SdchManager::Global()->IsInSupportedDomain(request_->url())) {
[email protected]60889422008-09-23 01:18:16638 static const std::string name = "Get-Dictionary";
639 std::string url_text;
640 void* iter = NULL;
641 // TODO(jar): We need to not fetch dictionaries the first time they are
642 // seen, but rather wait until we can justify their usefulness.
643 // For now, we will only fetch the first dictionary, which will at least
644 // require multiple suggestions before we get additional ones for this site.
645 // Eventually we should wait until a dictionary is requested several times
646 // before we even download it (so that we don't waste memory or bandwidth).
647 if (response_info_->headers->EnumerateHeader(&iter, name, &url_text)) {
[email protected]d55ad15d2009-02-17 19:40:50648 // request_->url() won't be valid in the destructor, so we use an
649 // alternate copy.
650 DCHECK(request_->url() == request_info_.url);
651 // Resolve suggested URL relative to request url.
652 sdch_dictionary_url_ = request_info_.url.Resolve(url_text);
[email protected]60889422008-09-23 01:18:16653 }
654 }
655
[email protected]0757e7702009-03-27 04:00:22656 // The HTTP transaction may be restarted several times for the purposes
657 // of sending authorization information. Each time it restarts, we get
658 // notified of the headers completion so that we can update the cookie store.
659 if (transaction_->IsReadyToRestartForAuth()) {
660 DCHECK(!response_info_->auth_challenge.get());
[email protected]13c8a092010-07-29 06:15:44661 RestartTransactionWithAuth(string16(), string16());
[email protected]0757e7702009-03-27 04:00:22662 return;
663 }
664
[email protected]4f5656c62010-12-13 10:47:09665 URLRequestJob::NotifyHeadersComplete();
initial.commit586acc5fe2008-07-26 22:42:52666}
667
[email protected]175adac2008-07-30 17:28:04668void URLRequestHttpJob::DestroyTransaction() {
[email protected]c6a4eb92010-03-03 23:51:19669 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52670
[email protected]af4876d2008-10-21 23:10:57671 transaction_.reset();
initial.commit586acc5fe2008-07-26 22:42:52672 response_info_ = NULL;
[email protected]fa4332d2010-11-23 09:59:09673 context_ = NULL;
initial.commit586acc5fe2008-07-26 22:42:52674}
675
[email protected]175adac2008-07-30 17:28:04676void URLRequestHttpJob::StartTransaction() {
initial.commit586acc5fe2008-07-26 22:42:52677 // NOTE: This method assumes that request_info_ is already setup properly.
678
[email protected]34602282010-02-03 22:14:15679 // If we already have a transaction, then we should restart the transaction
680 // with auth provided by username_ and password_.
initial.commit586acc5fe2008-07-26 22:42:52681
[email protected]99c07902010-08-17 18:59:52682 int rv;
[email protected]6b3f9642010-11-25 02:29:06683
[email protected]34602282010-02-03 22:14:15684 if (transaction_.get()) {
[email protected]99c07902010-08-17 18:59:52685 rv = transaction_->RestartWithAuth(username_, password_, &start_callback_);
[email protected]34602282010-02-03 22:14:15686 username_.clear();
687 password_.clear();
688 } else {
689 DCHECK(request_->context());
690 DCHECK(request_->context()->http_transaction_factory());
initial.commit586acc5fe2008-07-26 22:42:52691
[email protected]99c07902010-08-17 18:59:52692 rv = request_->context()->http_transaction_factory()->CreateTransaction(
693 &transaction_);
[email protected]4f5656c62010-12-13 10:47:09694 if (rv == OK) {
[email protected]6b3f9642010-11-25 02:29:06695 if (!throttling_entry_->IsDuringExponentialBackoff()) {
696 rv = transaction_->Start(
697 &request_info_, &start_callback_, request_->net_log());
698 } else {
699 // Special error code for the exponential back-off module.
[email protected]4f5656c62010-12-13 10:47:09700 rv = ERR_TEMPORARILY_THROTTLED;
[email protected]6b3f9642010-11-25 02:29:06701 }
[email protected]fa4332d2010-11-23 09:59:09702 // Make sure the context is alive for the duration of the
703 // transaction.
704 context_ = request_->context();
[email protected]34602282010-02-03 22:14:15705 }
initial.commit586acc5fe2008-07-26 22:42:52706 }
707
[email protected]4f5656c62010-12-13 10:47:09708 if (rv == ERR_IO_PENDING)
[email protected]34602282010-02-03 22:14:15709 return;
710
initial.commit586acc5fe2008-07-26 22:42:52711 // The transaction started synchronously, but we need to notify the
[email protected]4f5656c62010-12-13 10:47:09712 // URLRequest delegate via the message loop.
[email protected]00e48bf2010-12-03 06:15:42713 MessageLoop::current()->PostTask(
714 FROM_HERE,
715 method_factory_.NewRunnableMethod(
716 &URLRequestHttpJob::OnStartCompleted, rv));
initial.commit586acc5fe2008-07-26 22:42:52717}
718
[email protected]175adac2008-07-30 17:28:04719void URLRequestHttpJob::AddExtraHeaders() {
[email protected]5b90b5d2009-04-30 23:06:01720 // TODO(jar): Consider optimizing away SDCH advertising bytes when the URL is
721 // probably an img or such (and SDCH encoding is not likely).
722 bool advertise_sdch = SdchManager::Global() &&
723 SdchManager::Global()->IsInSupportedDomain(request_->url());
724 std::string avail_dictionaries;
725 if (advertise_sdch) {
726 SdchManager::Global()->GetAvailDictionaryList(request_->url(),
727 &avail_dictionaries);
728
729 // The AllowLatencyExperiment() is only true if we've successfully done a
730 // full SDCH compression recently in this browser session for this host.
731 // Note that for this path, there might be no applicable dictionaries, and
732 // hence we can't participate in the experiment.
733 if (!avail_dictionaries.empty() &&
734 SdchManager::Global()->AllowLatencyExperiment(request_->url())) {
735 // We are participating in the test (or control), and hence we'll
736 // eventually record statistics via either SDCH_EXPERIMENT_DECODE or
737 // SDCH_EXPERIMENT_HOLDBACK, and we'll need some packet timing data.
738 EnablePacketCounting(kSdchPacketHistogramCount);
[email protected]a88af5232009-06-05 01:34:53739 if (base::RandDouble() < .01) {
740 sdch_test_control_ = true; // 1% probability.
[email protected]5b90b5d2009-04-30 23:06:01741 advertise_sdch = false;
742 } else {
743 sdch_test_activated_ = true;
744 }
745 }
746 }
747
[email protected]423041b2008-10-27 17:39:28748 // Supply Accept-Encoding headers first so that it is more likely that they
749 // will be in the first transmitted packet. This can sometimes make it easier
750 // to filter and analyze the streams to assure that a proxy has not damaged
751 // these headers. Some proxies deliberately corrupt Accept-Encoding headers.
[email protected]5b90b5d2009-04-30 23:06:01752 if (!advertise_sdch) {
[email protected]423041b2008-10-27 17:39:28753 // Tell the server what compression formats we support (other than SDCH).
[email protected]8c76ae22010-04-20 22:15:43754 request_info_.extra_headers.SetHeader(
[email protected]4f5656c62010-12-13 10:47:09755 HttpRequestHeaders::kAcceptEncoding, "gzip,deflate");
[email protected]423041b2008-10-27 17:39:28756 } else {
[email protected]5b90b5d2009-04-30 23:06:01757 // Include SDCH in acceptable list.
[email protected]8c76ae22010-04-20 22:15:43758 request_info_.extra_headers.SetHeader(
[email protected]4f5656c62010-12-13 10:47:09759 HttpRequestHeaders::kAcceptEncoding, "gzip,deflate,sdch");
[email protected]423041b2008-10-27 17:39:28760 if (!avail_dictionaries.empty()) {
[email protected]8c76ae22010-04-20 22:15:43761 request_info_.extra_headers.SetHeader(
762 kAvailDictionaryHeader,
763 avail_dictionaries);
[email protected]5b90b5d2009-04-30 23:06:01764 sdch_dictionary_advertised_ = true;
765 // Since we're tagging this transaction as advertising a dictionary, we'll
766 // definately employ an SDCH filter (or tentative sdch filter) when we get
767 // a response. When done, we'll record histograms via SDCH_DECODE or
768 // SDCH_PASSTHROUGH. Hence we need to record packet arrival times.
769 EnablePacketCounting(kSdchPacketHistogramCount);
[email protected]423041b2008-10-27 17:39:28770 }
[email protected]423041b2008-10-27 17:39:28771 }
772
initial.commit586acc5fe2008-07-26 22:42:52773 URLRequestContext* context = request_->context();
774 if (context) {
[email protected]09a362d32009-09-24 18:01:33775 // Only add default Accept-Language and Accept-Charset if the request
776 // didn't have them specified.
[email protected]8c76ae22010-04-20 22:15:43777 if (!request_info_.extra_headers.HasHeader(
[email protected]4f5656c62010-12-13 10:47:09778 HttpRequestHeaders::kAcceptLanguage)) {
[email protected]8c76ae22010-04-20 22:15:43779 request_info_.extra_headers.SetHeader(
[email protected]4f5656c62010-12-13 10:47:09780 HttpRequestHeaders::kAcceptLanguage,
[email protected]8c76ae22010-04-20 22:15:43781 context->accept_language());
782 }
783 if (!request_info_.extra_headers.HasHeader(
[email protected]4f5656c62010-12-13 10:47:09784 HttpRequestHeaders::kAcceptCharset)) {
[email protected]8c76ae22010-04-20 22:15:43785 request_info_.extra_headers.SetHeader(
[email protected]4f5656c62010-12-13 10:47:09786 HttpRequestHeaders::kAcceptCharset,
[email protected]8c76ae22010-04-20 22:15:43787 context->accept_charset());
788 }
initial.commit586acc5fe2008-07-26 22:42:52789 }
initial.commit586acc5fe2008-07-26 22:42:52790}
791
[email protected]34602282010-02-03 22:14:15792void URLRequestHttpJob::AddCookieHeaderAndStart() {
793 // No matter what, we want to report our status as IO pending since we will
794 // be notifying our consumer asynchronously via OnStartCompleted.
795 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
[email protected]861fcd52009-08-26 02:33:46796
[email protected]34602282010-02-03 22:14:15797 AddRef(); // Balanced in OnCanGetCookiesCompleted
798
[email protected]4f5656c62010-12-13 10:47:09799 int policy = OK;
[email protected]34602282010-02-03 22:14:15800
[email protected]4f5656c62010-12-13 10:47:09801 if (request_info_.load_flags & LOAD_DO_NOT_SEND_COOKIES) {
802 policy = ERR_FAILED;
[email protected]34602282010-02-03 22:14:15803 } else if (request_->context()->cookie_policy()) {
804 policy = request_->context()->cookie_policy()->CanGetCookies(
805 request_->url(),
806 request_->first_party_for_cookies(),
807 &can_get_cookies_callback_);
[email protected]4f5656c62010-12-13 10:47:09808 if (policy == ERR_IO_PENDING)
[email protected]34602282010-02-03 22:14:15809 return; // Wait for completion callback
[email protected]0757e7702009-03-27 04:00:22810 }
[email protected]34602282010-02-03 22:14:15811
812 OnCanGetCookiesCompleted(policy);
[email protected]0757e7702009-03-27 04:00:22813}
814
[email protected]34602282010-02-03 22:14:15815void URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete() {
816 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52817
[email protected]4f5656c62010-12-13 10:47:09818 const HttpResponseInfo* response_info = transaction_->GetResponseInfo();
[email protected]34602282010-02-03 22:14:15819 DCHECK(response_info);
820
821 response_cookies_.clear();
822 response_cookies_save_index_ = 0;
823
824 FetchResponseCookies(response_info, &response_cookies_);
825
826 // Now, loop over the response cookies, and attempt to persist each.
827 SaveNextCookie();
828}
829
830void URLRequestHttpJob::SaveNextCookie() {
831 if (response_cookies_save_index_ == response_cookies_.size()) {
832 response_cookies_.clear();
833 response_cookies_save_index_ = 0;
834 SetStatus(URLRequestStatus()); // Clear the IO_PENDING status
835 NotifyHeadersComplete();
836 return;
837 }
838
839 // No matter what, we want to report our status as IO pending since we will
840 // be notifying our consumer asynchronously via OnStartCompleted.
841 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
842
843 AddRef(); // Balanced in OnCanSetCookieCompleted
844
[email protected]4f5656c62010-12-13 10:47:09845 int policy = OK;
[email protected]34602282010-02-03 22:14:15846
[email protected]4f5656c62010-12-13 10:47:09847 if (request_info_.load_flags & LOAD_DO_NOT_SAVE_COOKIES) {
848 policy = ERR_FAILED;
[email protected]34602282010-02-03 22:14:15849 } else if (request_->context()->cookie_policy()) {
850 policy = request_->context()->cookie_policy()->CanSetCookie(
851 request_->url(),
852 request_->first_party_for_cookies(),
853 response_cookies_[response_cookies_save_index_],
854 &can_set_cookie_callback_);
[email protected]4f5656c62010-12-13 10:47:09855 if (policy == ERR_IO_PENDING)
[email protected]34602282010-02-03 22:14:15856 return; // Wait for completion callback
857 }
858
859 OnCanSetCookieCompleted(policy);
860}
861
862void URLRequestHttpJob::FetchResponseCookies(
[email protected]4f5656c62010-12-13 10:47:09863 const HttpResponseInfo* response_info,
[email protected]34602282010-02-03 22:14:15864 std::vector<std::string>* cookies) {
initial.commit586acc5fe2008-07-26 22:42:52865 std::string name = "Set-Cookie";
866 std::string value;
867
868 void* iter = NULL;
[email protected]2adf2882010-09-27 08:30:37869 while (response_info->headers->EnumerateHeader(&iter, name, &value)) {
870 if (!value.empty())
871 cookies->push_back(value);
872 }
initial.commit586acc5fe2008-07-26 22:42:52873}
[email protected]a9cea7542009-05-20 04:30:23874
[email protected]77f6fb432009-09-05 14:21:09875void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() {
[email protected]a9cea7542009-05-20 04:30:23876 DCHECK(response_info_);
877
[email protected]a9cea7542009-05-20 04:30:23878 URLRequestContext* ctx = request_->context();
[email protected]326e6792009-12-11 21:04:42879 if (!ctx || !ctx->transport_security_state())
[email protected]a9cea7542009-05-20 04:30:23880 return;
881
[email protected]326e6792009-12-11 21:04:42882 const bool https = response_info_->ssl_info.is_valid();
883 const bool valid_https =
[email protected]4f5656c62010-12-13 10:47:09884 https && !IsCertStatusError(response_info_->ssl_info.cert_status);
[email protected]326e6792009-12-11 21:04:42885
[email protected]77f6fb432009-09-05 14:21:09886 std::string name = "Strict-Transport-Security";
[email protected]a9cea7542009-05-20 04:30:23887 std::string value;
888
[email protected]326e6792009-12-11 21:04:42889 int max_age;
890 bool include_subdomains;
891
[email protected]a9cea7542009-05-20 04:30:23892 void* iter = NULL;
[email protected]77f6fb432009-09-05 14:21:09893 while (response_info_->headers->EnumerateHeader(&iter, name, &value)) {
[email protected]4f5656c62010-12-13 10:47:09894 const bool ok = TransportSecurityState::ParseHeader(
[email protected]326e6792009-12-11 21:04:42895 value, &max_age, &include_subdomains);
896 if (!ok)
897 continue;
898 // We will only accept strict mode if we saw the header from an HTTPS
899 // connection with no certificate problems.
900 if (!valid_https)
901 continue;
902 base::Time current_time(base::Time::Now());
903 base::TimeDelta max_age_delta = base::TimeDelta::FromSeconds(max_age);
904
[email protected]4f5656c62010-12-13 10:47:09905 TransportSecurityState::DomainState domain_state;
[email protected]326e6792009-12-11 21:04:42906 domain_state.expiry = current_time + max_age_delta;
[email protected]4f5656c62010-12-13 10:47:09907 domain_state.mode = TransportSecurityState::DomainState::MODE_STRICT;
[email protected]326e6792009-12-11 21:04:42908 domain_state.include_subdomains = include_subdomains;
909
910 ctx->transport_security_state()->EnableHost(request_info_.url.host(),
911 domain_state);
912 }
913
914 // TODO(agl): change this over when we have fixed things at the server end.
915 // The string should be "Opportunistic-Transport-Security";
916 name = "X-Bodge-Transport-Security";
917
918 while (response_info_->headers->EnumerateHeader(&iter, name, &value)) {
[email protected]4f5656c62010-12-13 10:47:09919 const bool ok = TransportSecurityState::ParseHeader(
[email protected]326e6792009-12-11 21:04:42920 value, &max_age, &include_subdomains);
921 if (!ok)
922 continue;
923 // If we saw an opportunistic request over HTTPS, then clearly we can make
924 // HTTPS connections to the host so we should remember this.
925 if (https) {
926 base::Time current_time(base::Time::Now());
927 base::TimeDelta max_age_delta = base::TimeDelta::FromSeconds(max_age);
928
[email protected]4f5656c62010-12-13 10:47:09929 TransportSecurityState::DomainState domain_state;
[email protected]326e6792009-12-11 21:04:42930 domain_state.expiry = current_time + max_age_delta;
931 domain_state.mode =
[email protected]4f5656c62010-12-13 10:47:09932 TransportSecurityState::DomainState::MODE_SPDY_ONLY;
[email protected]326e6792009-12-11 21:04:42933 domain_state.include_subdomains = include_subdomains;
934
935 ctx->transport_security_state()->EnableHost(request_info_.url.host(),
936 domain_state);
937 continue;
938 }
939
940 if (!request())
941 break;
942
943 // At this point, we have a request for opportunistic encryption over HTTP.
944 // In this case we need to probe to check that we can make HTTPS
945 // connections to that host.
[email protected]4f5656c62010-12-13 10:47:09946 HTTPSProber* const prober = HTTPSProber::GetInstance();
[email protected]326e6792009-12-11 21:04:42947 if (prober->HaveProbed(request_info_.url.host()) ||
948 prober->InFlight(request_info_.url.host())) {
949 continue;
950 }
951
[email protected]4f5656c62010-12-13 10:47:09952 HTTPSProberDelegateImpl* delegate =
953 new HTTPSProberDelegateImpl(request_info_.url.host(), max_age,
954 include_subdomains,
955 ctx->transport_security_state());
[email protected]326e6792009-12-11 21:04:42956 if (!prober->ProbeHost(request_info_.url.host(), request()->context(),
957 delegate)) {
958 delete delegate;
959 }
[email protected]77f6fb432009-09-05 14:21:09960 }
[email protected]a9cea7542009-05-20 04:30:23961}
[email protected]4f5656c62010-12-13 10:47:09962
963} // namespace net