blob: 8dc1507b1f9f3bb64f95b8a4de6a89ee8b4a404d [file] [log] [blame]
[email protected]fecef222012-01-05 02:26:151// Copyright (c) 2012 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"
[email protected]4f9e5c82011-11-17 16:04:568#include "base/bind.h"
[email protected]084262c2011-12-01 21:12:479#include "base/bind_helpers.h"
[email protected]4ed2755f2008-12-15 09:01:3310#include "base/command_line.h"
[email protected]39ce5c02008-08-22 04:03:4411#include "base/compiler_specific.h"
[email protected]60889422008-09-23 01:18:1612#include "base/file_util.h"
13#include "base/file_version_info.h"
initial.commit586acc5fe2008-07-26 22:42:5214#include "base/message_loop.h"
[email protected]8684a8812011-03-22 13:59:3815#include "base/metrics/field_trial.h"
[email protected]ec23f522011-02-22 21:01:3816#include "base/metrics/histogram.h"
[email protected]5b90b5d2009-04-30 23:06:0117#include "base/rand_util.h"
initial.commit586acc5fe2008-07-26 22:42:5218#include "base/string_util.h"
[email protected]dd29bcd72011-03-24 00:03:4419#include "base/time.h"
[email protected]a9cea7542009-05-20 04:30:2320#include "net/base/cert_status_flags.h"
[email protected]423041b2008-10-27 17:39:2821#include "net/base/filter.h"
[email protected]6d81b482011-02-22 19:47:1922#include "net/base/host_port_pair.h"
[email protected]b8430722008-09-17 20:05:4423#include "net/base/load_flags.h"
[email protected]dd29bcd72011-03-24 00:03:4424#include "net/base/mime_util.h"
initial.commit586acc5fe2008-07-26 22:42:5225#include "net/base/net_errors.h"
26#include "net/base/net_util.h"
[email protected]636eccd2011-06-28 12:28:0127#include "net/base/network_delegate.h"
[email protected]60889422008-09-23 01:18:1628#include "net/base/sdch_manager.h"
[email protected]0b45559b2009-06-12 21:45:1129#include "net/base/ssl_cert_request_info.h"
[email protected]ee1edb472011-05-05 23:31:4630#include "net/base/ssl_config_service.h"
[email protected]aa84a7e2012-03-15 21:29:0631#include "net/cookies/cookie_monster.h"
[email protected]7a299a92012-10-24 23:54:5032#include "net/http/http_network_session.h"
[email protected]8c76ae22010-04-20 22:15:4333#include "net/http/http_request_headers.h"
[email protected]319d9e6f2009-02-18 19:47:2134#include "net/http/http_response_headers.h"
initial.commit586acc5fe2008-07-26 22:42:5235#include "net/http/http_response_info.h"
[email protected]9094b602012-02-27 21:44:5836#include "net/http/http_status_code.h"
initial.commit586acc5fe2008-07-26 22:42:5237#include "net/http/http_transaction.h"
[email protected]5a07c192012-07-30 20:18:2238#include "net/http/http_transaction_delegate.h"
initial.commit586acc5fe2008-07-26 22:42:5239#include "net/http/http_transaction_factory.h"
[email protected]0757e7702009-03-27 04:00:2240#include "net/http/http_util.h"
[email protected]7f269182011-10-16 01:58:3441#include "net/url_request/fraudulent_certificate_reporter.h"
[email protected]ee4c30d2012-11-07 15:08:4342#include "net/url_request/http_user_agent_settings.h"
initial.commit586acc5fe2008-07-26 22:42:5243#include "net/url_request/url_request.h"
[email protected]319d9e6f2009-02-18 19:47:2144#include "net/url_request/url_request_context.h"
initial.commit586acc5fe2008-07-26 22:42:5245#include "net/url_request/url_request_error_job.h"
[email protected]06965e02009-09-04 21:36:4246#include "net/url_request/url_request_redirect_job.h"
[email protected]6b3f9642010-11-25 02:29:0647#include "net/url_request/url_request_throttler_header_adapter.h"
48#include "net/url_request/url_request_throttler_manager.h"
initial.commit586acc5fe2008-07-26 22:42:5249
[email protected]8c76ae22010-04-20 22:15:4350static const char kAvailDictionaryHeader[] = "Avail-Dictionary";
51
[email protected]4f5656c62010-12-13 10:47:0952namespace net {
53
[email protected]2e92354c2011-03-25 20:49:5354class URLRequestHttpJob::HttpFilterContext : public FilterContext {
55 public:
56 explicit HttpFilterContext(URLRequestHttpJob* job);
57 virtual ~HttpFilterContext();
58
59 // FilterContext implementation.
[email protected]1e43b6812012-08-19 19:14:0060 virtual bool GetMimeType(std::string* mime_type) const OVERRIDE;
61 virtual bool GetURL(GURL* gurl) const OVERRIDE;
62 virtual base::Time GetRequestTime() const OVERRIDE;
63 virtual bool IsCachedContent() const OVERRIDE;
64 virtual bool IsDownload() const OVERRIDE;
65 virtual bool IsSdchResponse() const OVERRIDE;
66 virtual int64 GetByteReadCount() const OVERRIDE;
67 virtual int GetResponseCode() const OVERRIDE;
68 virtual void RecordPacketStats(StatisticSelector statistic) const OVERRIDE;
[email protected]2e92354c2011-03-25 20:49:5369
[email protected]46668fe52011-05-04 19:03:2370 // Method to allow us to reset filter context for a response that should have
71 // been SDCH encoded when there is an update due to an explicit HTTP header.
72 void ResetSdchResponseToFalse();
73
[email protected]2e92354c2011-03-25 20:49:5374 private:
75 URLRequestHttpJob* job_;
76
77 DISALLOW_COPY_AND_ASSIGN(HttpFilterContext);
78};
79
[email protected]5a07c192012-07-30 20:18:2280class URLRequestHttpJob::HttpTransactionDelegateImpl
81 : public HttpTransactionDelegate {
82 public:
83 explicit HttpTransactionDelegateImpl(URLRequest* request)
84 : request_(request),
[email protected]a9e0d1412012-08-20 22:13:0185 network_delegate_(request->context()->network_delegate()),
86 cache_active_(false),
87 network_active_(false) {
[email protected]5a07c192012-07-30 20:18:2288 }
89 virtual ~HttpTransactionDelegateImpl() {
90 OnDetachRequest();
91 }
92 void OnDetachRequest() {
93 if (request_ == NULL || network_delegate_ == NULL)
94 return;
[email protected]a9e0d1412012-08-20 22:13:0195 network_delegate_->NotifyRequestWaitStateChange(
[email protected]5a07c192012-07-30 20:18:2296 *request_,
[email protected]a9e0d1412012-08-20 22:13:0197 NetworkDelegate::REQUEST_WAIT_STATE_RESET);
98 cache_active_ = false;
99 network_active_ = false;
[email protected]5a07c192012-07-30 20:18:22100 request_ = NULL;
101 }
102 virtual void OnCacheActionStart() OVERRIDE {
103 if (request_ == NULL || network_delegate_ == NULL)
104 return;
[email protected]a9e0d1412012-08-20 22:13:01105 DCHECK(!cache_active_ && !network_active_);
106 cache_active_ = true;
107 network_delegate_->NotifyRequestWaitStateChange(
[email protected]5a07c192012-07-30 20:18:22108 *request_,
[email protected]a9e0d1412012-08-20 22:13:01109 NetworkDelegate::REQUEST_WAIT_STATE_CACHE_START);
[email protected]5a07c192012-07-30 20:18:22110 }
111 virtual void OnCacheActionFinish() OVERRIDE {
112 if (request_ == NULL || network_delegate_ == NULL)
113 return;
[email protected]a9e0d1412012-08-20 22:13:01114 DCHECK(cache_active_ && !network_active_);
115 cache_active_ = false;
116 network_delegate_->NotifyRequestWaitStateChange(
[email protected]5a07c192012-07-30 20:18:22117 *request_,
[email protected]a9e0d1412012-08-20 22:13:01118 NetworkDelegate::REQUEST_WAIT_STATE_CACHE_FINISH);
119 }
120 virtual void OnNetworkActionStart() OVERRIDE {
121 if (request_ == NULL || network_delegate_ == NULL)
122 return;
123 DCHECK(!cache_active_ && !network_active_);
124 network_active_ = true;
125 network_delegate_->NotifyRequestWaitStateChange(
126 *request_,
127 NetworkDelegate::REQUEST_WAIT_STATE_NETWORK_START);
128 }
129 virtual void OnNetworkActionFinish() OVERRIDE {
130 if (request_ == NULL || network_delegate_ == NULL)
131 return;
132 DCHECK(!cache_active_ && network_active_);
133 network_active_ = false;
134 network_delegate_->NotifyRequestWaitStateChange(
135 *request_,
136 NetworkDelegate::REQUEST_WAIT_STATE_NETWORK_FINISH);
[email protected]5a07c192012-07-30 20:18:22137 }
138 private:
139 URLRequest* request_;
140 NetworkDelegate* network_delegate_;
[email protected]a9e0d1412012-08-20 22:13:01141 bool cache_active_;
142 bool network_active_;
[email protected]5a07c192012-07-30 20:18:22143};
144
[email protected]fc01f232011-03-17 19:06:01145URLRequestHttpJob::HttpFilterContext::HttpFilterContext(URLRequestHttpJob* job)
146 : job_(job) {
147 DCHECK(job_);
148}
149
150URLRequestHttpJob::HttpFilterContext::~HttpFilterContext() {
151}
152
153bool URLRequestHttpJob::HttpFilterContext::GetMimeType(
154 std::string* mime_type) const {
155 return job_->GetMimeType(mime_type);
156}
157
158bool URLRequestHttpJob::HttpFilterContext::GetURL(GURL* gurl) const {
159 if (!job_->request())
160 return false;
161 *gurl = job_->request()->url();
162 return true;
163}
164
165base::Time URLRequestHttpJob::HttpFilterContext::GetRequestTime() const {
166 return job_->request() ? job_->request()->request_time() : base::Time();
167}
168
169bool URLRequestHttpJob::HttpFilterContext::IsCachedContent() const {
[email protected]dd29bcd72011-03-24 00:03:44170 return job_->is_cached_content_;
[email protected]fc01f232011-03-17 19:06:01171}
172
173bool URLRequestHttpJob::HttpFilterContext::IsDownload() const {
174 return (job_->request_info_.load_flags & LOAD_IS_DOWNLOAD) != 0;
175}
176
[email protected]46668fe52011-05-04 19:03:23177void URLRequestHttpJob::HttpFilterContext::ResetSdchResponseToFalse() {
178 DCHECK(job_->sdch_dictionary_advertised_);
179 job_->sdch_dictionary_advertised_ = false;
180}
181
[email protected]fc01f232011-03-17 19:06:01182bool URLRequestHttpJob::HttpFilterContext::IsSdchResponse() const {
183 return job_->sdch_dictionary_advertised_;
184}
185
186int64 URLRequestHttpJob::HttpFilterContext::GetByteReadCount() const {
187 return job_->filter_input_byte_count();
188}
189
190int URLRequestHttpJob::HttpFilterContext::GetResponseCode() const {
191 return job_->GetResponseCode();
192}
193
194void URLRequestHttpJob::HttpFilterContext::RecordPacketStats(
195 StatisticSelector statistic) const {
196 job_->RecordPacketStats(statistic);
197}
198
initial.commit586acc5fe2008-07-26 22:42:52199// TODO(darin): make sure the port blocking code is not lost
initial.commit586acc5fe2008-07-26 22:42:52200// static
[email protected]4f5656c62010-12-13 10:47:09201URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request,
[email protected]9f170462012-08-24 01:06:58202 NetworkDelegate* network_delegate,
[email protected]4f5656c62010-12-13 10:47:09203 const std::string& scheme) {
initial.commit586acc5fe2008-07-26 22:42:52204 DCHECK(scheme == "http" || scheme == "https");
205
[email protected]81293f482012-08-13 19:35:45206 if (!request->context()->http_transaction_factory()) {
initial.commit586acc5fe2008-07-26 22:42:52207 NOTREACHED() << "requires a valid context";
[email protected]9f170462012-08-24 01:06:58208 return new URLRequestErrorJob(
209 request, network_delegate, ERR_INVALID_ARGUMENT);
initial.commit586acc5fe2008-07-26 22:42:52210 }
211
[email protected]ce572df2012-05-04 19:47:17212 GURL redirect_url;
[email protected]8ccc69f2012-11-28 19:52:14213 if (request->GetHSTSRedirect(&redirect_url)) {
214 return new URLRequestRedirectJob(
215 request, network_delegate, redirect_url,
216 // Use status code 307 to preserve the method, so POST requests work.
217 URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT);
218 }
[email protected]ee4c30d2012-11-07 15:08:43219 return new URLRequestHttpJob(request,
220 network_delegate,
221 request->context()->http_user_agent_settings());
initial.commit586acc5fe2008-07-26 22:42:52222}
223
[email protected]5394e422011-01-20 22:07:43224
[email protected]ee4c30d2012-11-07 15:08:43225URLRequestHttpJob::URLRequestHttpJob(
226 URLRequest* request,
227 NetworkDelegate* network_delegate,
228 const HttpUserAgentSettings* http_user_agent_settings)
[email protected]9f170462012-08-24 01:06:58229 : URLRequestJob(request, network_delegate),
initial.commit586acc5fe2008-07-26 22:42:52230 response_info_(NULL),
[email protected]34602282010-02-03 22:14:15231 response_cookies_save_index_(0),
[email protected]4f5656c62010-12-13 10:47:09232 proxy_auth_state_(AUTH_STATE_DONT_NEED_AUTH),
233 server_auth_state_(AUTH_STATE_DONT_NEED_AUTH),
[email protected]34602282010-02-03 22:14:15234 ALLOW_THIS_IN_INITIALIZER_LIST(start_callback_(
[email protected]49639fa2011-12-20 23:22:41235 base::Bind(&URLRequestHttpJob::OnStartCompleted,
236 base::Unretained(this)))),
[email protected]636eccd2011-06-28 12:28:01237 ALLOW_THIS_IN_INITIALIZER_LIST(notify_before_headers_sent_callback_(
[email protected]084262c2011-12-01 21:12:47238 base::Bind(&URLRequestHttpJob::NotifyBeforeSendHeadersCallback,
239 base::Unretained(this)))),
[email protected]3589e552008-08-20 23:11:34240 read_in_progress_(false),
[email protected]2aecf7382009-06-17 04:14:27241 transaction_(NULL),
[email protected]a73a2802012-05-02 19:20:15242 throttling_entry_(NULL),
[email protected]5b90b5d2009-04-30 23:06:01243 sdch_dictionary_advertised_(false),
244 sdch_test_activated_(false),
[email protected]d8fd5132009-05-15 01:06:53245 sdch_test_control_(false),
[email protected]00e48bf2010-12-03 06:15:42246 is_cached_content_(false),
[email protected]ec23f522011-02-22 21:01:38247 request_creation_time_(),
[email protected]dd29bcd72011-03-24 00:03:44248 packet_timing_enabled_(false),
[email protected]bbaea8f2011-06-24 00:11:01249 done_(false),
[email protected]dd29bcd72011-03-24 00:03:44250 bytes_observed_in_packets_(0),
[email protected]dd29bcd72011-03-24 00:03:44251 request_time_snapshot_(),
252 final_packet_time_(),
[email protected]2e92354c2011-03-25 20:49:53253 ALLOW_THIS_IN_INITIALIZER_LIST(
254 filter_context_(new HttpFilterContext(this))),
[email protected]098b29112011-12-20 21:12:34255 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
[email protected]084262c2011-12-01 21:12:47256 ALLOW_THIS_IN_INITIALIZER_LIST(on_headers_received_callback_(
257 base::Bind(&URLRequestHttpJob::OnHeadersReceivedCallback,
258 base::Unretained(this)))),
[email protected]5a07c192012-07-30 20:18:22259 awaiting_callback_(false),
[email protected]ee4c30d2012-11-07 15:08:43260 http_transaction_delegate_(new HttpTransactionDelegateImpl(request)),
261 http_user_agent_settings_(http_user_agent_settings) {
[email protected]a73a2802012-05-02 19:20:15262 URLRequestThrottlerManager* manager = request->context()->throttler_manager();
263 if (manager)
264 throttling_entry_ = manager->RegisterRequestUrl(request->url());
265
[email protected]ec23f522011-02-22 21:01:38266 ResetTimer();
initial.commit586acc5fe2008-07-26 22:42:52267}
268
[email protected]175adac2008-07-30 17:28:04269void URLRequestHttpJob::NotifyHeadersComplete() {
initial.commit586acc5fe2008-07-26 22:42:52270 DCHECK(!response_info_);
271
272 response_info_ = transaction_->GetResponseInfo();
273
[email protected]d8fd5132009-05-15 01:06:53274 // Save boolean, as we'll need this info at destruction time, and filters may
275 // also need this info.
276 is_cached_content_ = response_info_->was_cached;
277
[email protected]a73a2802012-05-02 19:20:15278 if (!is_cached_content_ && throttling_entry_) {
[email protected]ea8141e2011-10-05 13:12:51279 URLRequestThrottlerHeaderAdapter response_adapter(GetResponseHeaders());
[email protected]2fd33ee92011-03-25 22:30:21280 throttling_entry_->UpdateWithResponse(request_info_.url.host(),
281 &response_adapter);
[email protected]6b3f9642010-11-25 02:29:06282 }
283
[email protected]fecef222012-01-05 02:26:15284 // The ordering of these calls is not important.
[email protected]77f6fb432009-09-05 14:21:09285 ProcessStrictTransportSecurityHeader();
[email protected]fecef222012-01-05 02:26:15286 ProcessPublicKeyPinsHeader();
[email protected]a9cea7542009-05-20 04:30:23287
[email protected]fe219872008-09-23 02:17:00288 if (SdchManager::Global() &&
289 SdchManager::Global()->IsInSupportedDomain(request_->url())) {
[email protected]264300242011-11-07 06:03:30290 const std::string name = "Get-Dictionary";
[email protected]60889422008-09-23 01:18:16291 std::string url_text;
292 void* iter = NULL;
293 // TODO(jar): We need to not fetch dictionaries the first time they are
294 // seen, but rather wait until we can justify their usefulness.
295 // For now, we will only fetch the first dictionary, which will at least
296 // require multiple suggestions before we get additional ones for this site.
297 // Eventually we should wait until a dictionary is requested several times
298 // before we even download it (so that we don't waste memory or bandwidth).
[email protected]ea8141e2011-10-05 13:12:51299 if (GetResponseHeaders()->EnumerateHeader(&iter, name, &url_text)) {
[email protected]d55ad15d2009-02-17 19:40:50300 // request_->url() won't be valid in the destructor, so we use an
301 // alternate copy.
[email protected]dd29bcd72011-03-24 00:03:44302 DCHECK_EQ(request_->url(), request_info_.url);
[email protected]d55ad15d2009-02-17 19:40:50303 // Resolve suggested URL relative to request url.
304 sdch_dictionary_url_ = request_info_.url.Resolve(url_text);
[email protected]60889422008-09-23 01:18:16305 }
306 }
307
[email protected]0757e7702009-03-27 04:00:22308 // The HTTP transaction may be restarted several times for the purposes
309 // of sending authorization information. Each time it restarts, we get
310 // notified of the headers completion so that we can update the cookie store.
311 if (transaction_->IsReadyToRestartForAuth()) {
312 DCHECK(!response_info_->auth_challenge.get());
[email protected]87a09a92011-07-14 15:50:50313 // TODO(battre): This breaks the webrequest API for
314 // URLRequestTestHTTP.BasicAuthWithCookies
[email protected]5796dc942011-07-14 19:26:10315 // where OnBeforeSendHeaders -> OnSendHeaders -> OnBeforeSendHeaders
[email protected]87a09a92011-07-14 15:50:50316 // occurs.
[email protected]f3cf9802011-10-28 18:44:58317 RestartTransactionWithAuth(AuthCredentials());
[email protected]0757e7702009-03-27 04:00:22318 return;
319 }
320
[email protected]4f5656c62010-12-13 10:47:09321 URLRequestJob::NotifyHeadersComplete();
initial.commit586acc5fe2008-07-26 22:42:52322}
323
[email protected]85c1dce2011-07-06 12:01:29324void URLRequestHttpJob::NotifyDone(const URLRequestStatus& status) {
[email protected]bbaea8f2011-06-24 00:11:01325 DoneWithRequest(FINISHED);
[email protected]dd29bcd72011-03-24 00:03:44326 URLRequestJob::NotifyDone(status);
327}
328
[email protected]175adac2008-07-30 17:28:04329void URLRequestHttpJob::DestroyTransaction() {
[email protected]c6a4eb92010-03-03 23:51:19330 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52331
[email protected]bbaea8f2011-06-24 00:11:01332 DoneWithRequest(ABORTED);
[email protected]af4876d2008-10-21 23:10:57333 transaction_.reset();
initial.commit586acc5fe2008-07-26 22:42:52334 response_info_ = NULL;
335}
336
[email protected]175adac2008-07-30 17:28:04337void URLRequestHttpJob::StartTransaction() {
[email protected]81293f482012-08-13 19:35:45338 if (request_->context()->network_delegate()) {
[email protected]636eccd2011-06-28 12:28:01339 int rv = request_->context()->network_delegate()->NotifyBeforeSendHeaders(
[email protected]084262c2011-12-01 21:12:47340 request_, notify_before_headers_sent_callback_,
[email protected]636eccd2011-06-28 12:28:01341 &request_info_.extra_headers);
342 // If an extension blocks the request, we rely on the callback to
[email protected]b4438d32012-09-27 06:15:30343 // MaybeStartTransactionInternal().
[email protected]636eccd2011-06-28 12:28:01344 if (rv == ERR_IO_PENDING) {
[email protected]9c235f042011-08-10 22:28:21345 SetBlockedOnDelegate();
[email protected]636eccd2011-06-28 12:28:01346 return;
347 }
[email protected]b4438d32012-09-27 06:15:30348 MaybeStartTransactionInternal(rv);
349 return;
[email protected]636eccd2011-06-28 12:28:01350 }
351 StartTransactionInternal();
352}
353
354void URLRequestHttpJob::NotifyBeforeSendHeadersCallback(int result) {
[email protected]9c235f042011-08-10 22:28:21355 SetUnblockedOnDelegate();
[email protected]636eccd2011-06-28 12:28:01356
[email protected]9045b8822012-01-13 20:35:35357 // Check that there are no callbacks to already canceled requests.
358 DCHECK_NE(URLRequestStatus::CANCELED, GetStatus().status());
359
[email protected]b4438d32012-09-27 06:15:30360 MaybeStartTransactionInternal(result);
361}
362
363void URLRequestHttpJob::MaybeStartTransactionInternal(int result) {
[email protected]636eccd2011-06-28 12:28:01364 if (result == OK) {
365 StartTransactionInternal();
366 } else {
[email protected]55b8a6c12012-06-13 22:03:42367 std::string source("delegate");
[email protected]636eccd2011-06-28 12:28:01368 request_->net_log().AddEvent(NetLog::TYPE_CANCELLED,
[email protected]55b8a6c12012-06-13 22:03:42369 NetLog::StringCallback("source", &source));
[email protected]636eccd2011-06-28 12:28:01370 NotifyCanceled();
[email protected]b4438d32012-09-27 06:15:30371 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
[email protected]636eccd2011-06-28 12:28:01372 }
373}
374
375void URLRequestHttpJob::StartTransactionInternal() {
initial.commit586acc5fe2008-07-26 22:42:52376 // NOTE: This method assumes that request_info_ is already setup properly.
377
[email protected]34602282010-02-03 22:14:15378 // If we already have a transaction, then we should restart the transaction
[email protected]f3cf9802011-10-28 18:44:58379 // with auth provided by auth_credentials_.
initial.commit586acc5fe2008-07-26 22:42:52380
[email protected]99c07902010-08-17 18:59:52381 int rv;
[email protected]6b3f9642010-11-25 02:29:06382
[email protected]81293f482012-08-13 19:35:45383 if (request_->context()->network_delegate()) {
[email protected]5796dc942011-07-14 19:26:10384 request_->context()->network_delegate()->NotifySendHeaders(
385 request_, request_info_.extra_headers);
386 }
387
[email protected]34602282010-02-03 22:14:15388 if (transaction_.get()) {
[email protected]49639fa2011-12-20 23:22:41389 rv = transaction_->RestartWithAuth(auth_credentials_, start_callback_);
[email protected]f3cf9802011-10-28 18:44:58390 auth_credentials_ = AuthCredentials();
[email protected]34602282010-02-03 22:14:15391 } else {
[email protected]34602282010-02-03 22:14:15392 DCHECK(request_->context()->http_transaction_factory());
initial.commit586acc5fe2008-07-26 22:42:52393
[email protected]99c07902010-08-17 18:59:52394 rv = request_->context()->http_transaction_factory()->CreateTransaction(
[email protected]5a07c192012-07-30 20:18:22395 &transaction_, http_transaction_delegate_.get());
[email protected]4f5656c62010-12-13 10:47:09396 if (rv == OK) {
[email protected]a1d4ab072012-06-07 13:21:15397 if (!throttling_entry_ ||
398 !throttling_entry_->ShouldRejectRequest(*request_)) {
[email protected]227b0e82011-03-25 21:11:53399 rv = transaction_->Start(
[email protected]49639fa2011-12-20 23:22:41400 &request_info_, start_callback_, request_->net_log());
[email protected]bbaea8f2011-06-24 00:11:01401 start_time_ = base::TimeTicks::Now();
[email protected]227b0e82011-03-25 21:11:53402 } else {
403 // Special error code for the exponential back-off module.
404 rv = ERR_TEMPORARILY_THROTTLED;
405 }
[email protected]34602282010-02-03 22:14:15406 }
initial.commit586acc5fe2008-07-26 22:42:52407 }
408
[email protected]4f5656c62010-12-13 10:47:09409 if (rv == ERR_IO_PENDING)
[email protected]34602282010-02-03 22:14:15410 return;
411
initial.commit586acc5fe2008-07-26 22:42:52412 // The transaction started synchronously, but we need to notify the
[email protected]4f5656c62010-12-13 10:47:09413 // URLRequest delegate via the message loop.
[email protected]00e48bf2010-12-03 06:15:42414 MessageLoop::current()->PostTask(
415 FROM_HERE,
[email protected]098b29112011-12-20 21:12:34416 base::Bind(&URLRequestHttpJob::OnStartCompleted,
417 weak_factory_.GetWeakPtr(), rv));
initial.commit586acc5fe2008-07-26 22:42:52418}
419
[email protected]175adac2008-07-30 17:28:04420void URLRequestHttpJob::AddExtraHeaders() {
[email protected]c7bef94c2011-06-21 18:05:51421 // Supply Accept-Encoding field only if it is not already provided.
422 // It should be provided IF the content is known to have restrictions on
423 // potential encoding, such as streaming multi-media.
424 // For details see bug 47381.
425 // TODO(jar, enal): jpeg files etc. should set up a request header if
426 // possible. Right now it is done only by buffered_resource_loader and
427 // simple_data_source.
428 if (!request_info_.extra_headers.HasHeader(
429 HttpRequestHeaders::kAcceptEncoding)) {
430 bool advertise_sdch = SdchManager::Global() &&
431 SdchManager::Global()->IsInSupportedDomain(request_->url());
432 std::string avail_dictionaries;
433 if (advertise_sdch) {
434 SdchManager::Global()->GetAvailDictionaryList(request_->url(),
435 &avail_dictionaries);
[email protected]5b90b5d2009-04-30 23:06:01436
[email protected]c7bef94c2011-06-21 18:05:51437 // The AllowLatencyExperiment() is only true if we've successfully done a
438 // full SDCH compression recently in this browser session for this host.
439 // Note that for this path, there might be no applicable dictionaries,
440 // and hence we can't participate in the experiment.
441 if (!avail_dictionaries.empty() &&
442 SdchManager::Global()->AllowLatencyExperiment(request_->url())) {
443 // We are participating in the test (or control), and hence we'll
444 // eventually record statistics via either SDCH_EXPERIMENT_DECODE or
445 // SDCH_EXPERIMENT_HOLDBACK, and we'll need some packet timing data.
446 packet_timing_enabled_ = true;
447 if (base::RandDouble() < .01) {
448 sdch_test_control_ = true; // 1% probability.
449 advertise_sdch = false;
450 } else {
451 sdch_test_activated_ = true;
452 }
[email protected]5b90b5d2009-04-30 23:06:01453 }
454 }
[email protected]5b90b5d2009-04-30 23:06:01455
[email protected]c7bef94c2011-06-21 18:05:51456 // Supply Accept-Encoding headers first so that it is more likely that they
457 // will be in the first transmitted packet. This can sometimes make it
458 // easier to filter and analyze the streams to assure that a proxy has not
459 // damaged these headers. Some proxies deliberately corrupt Accept-Encoding
460 // headers.
461 if (!advertise_sdch) {
462 // Tell the server what compression formats we support (other than SDCH).
[email protected]8c76ae22010-04-20 22:15:43463 request_info_.extra_headers.SetHeader(
[email protected]c7bef94c2011-06-21 18:05:51464 HttpRequestHeaders::kAcceptEncoding, "gzip,deflate");
465 } else {
466 // Include SDCH in acceptable list.
467 request_info_.extra_headers.SetHeader(
468 HttpRequestHeaders::kAcceptEncoding, "gzip,deflate,sdch");
469 if (!avail_dictionaries.empty()) {
470 request_info_.extra_headers.SetHeader(
471 kAvailDictionaryHeader,
472 avail_dictionaries);
473 sdch_dictionary_advertised_ = true;
474 // Since we're tagging this transaction as advertising a dictionary,
475 // we'll definitely employ an SDCH filter (or tentative sdch filter)
476 // when we get a response. When done, we'll record histograms via
477 // SDCH_DECODE or SDCH_PASSTHROUGH. Hence we need to record packet
478 // arrival times.
479 packet_timing_enabled_ = true;
480 }
[email protected]423041b2008-10-27 17:39:28481 }
[email protected]423041b2008-10-27 17:39:28482 }
483
[email protected]ee4c30d2012-11-07 15:08:43484 if (http_user_agent_settings_) {
485 // Only add default Accept-Language and Accept-Charset if the request
486 // didn't have them specified.
487 std::string accept_language =
488 http_user_agent_settings_->GetAcceptLanguage();
489 if (!accept_language.empty()) {
490 request_info_.extra_headers.SetHeaderIfMissing(
491 HttpRequestHeaders::kAcceptLanguage,
492 accept_language);
493 }
494 std::string accept_charset = http_user_agent_settings_->GetAcceptCharset();
495 if (!accept_charset.empty()) {
496 request_info_.extra_headers.SetHeaderIfMissing(
497 HttpRequestHeaders::kAcceptCharset,
498 accept_charset);
499 }
initial.commit586acc5fe2008-07-26 22:42:52500 }
initial.commit586acc5fe2008-07-26 22:42:52501}
502
[email protected]34602282010-02-03 22:14:15503void URLRequestHttpJob::AddCookieHeaderAndStart() {
504 // No matter what, we want to report our status as IO pending since we will
505 // be notifying our consumer asynchronously via OnStartCompleted.
506 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
[email protected]861fcd52009-08-26 02:33:46507
[email protected]ed24fad2011-05-10 22:44:01508 // If the request was destroyed, then there is no more work to do.
509 if (!request_)
510 return;
[email protected]34602282010-02-03 22:14:15511
[email protected]81293f482012-08-13 19:35:45512 CookieStore* cookie_store = request_->context()->cookie_store();
[email protected]1a6fff52011-10-20 21:00:16513 if (cookie_store && !(request_info_.load_flags & LOAD_DO_NOT_SEND_COOKIES)) {
514 net::CookieMonster* cookie_monster = cookie_store->GetCookieMonster();
515 if (cookie_monster) {
516 cookie_monster->GetAllCookiesForURLAsync(
517 request_->url(),
518 base::Bind(&URLRequestHttpJob::CheckCookiePolicyAndLoad,
[email protected]098b29112011-12-20 21:12:34519 weak_factory_.GetWeakPtr()));
[email protected]1a6fff52011-10-20 21:00:16520 } else {
[email protected]cec80c3d2012-12-04 12:17:41521 CheckCookiePolicyAndLoad(CookieList());
[email protected]1a6fff52011-10-20 21:00:16522 }
[email protected]03d845f2011-07-29 19:06:26523 } else {
524 DoStartTransaction();
525 }
526}
527
[email protected]1a6fff52011-10-20 21:00:16528void URLRequestHttpJob::DoLoadCookies() {
529 CookieOptions options;
530 options.set_include_httponly();
[email protected]dedec0b2013-02-28 04:50:10531 request_->context()->cookie_store()->GetCookiesWithOptionsAsync(
[email protected]1a6fff52011-10-20 21:00:16532 request_->url(), options,
533 base::Bind(&URLRequestHttpJob::OnCookiesLoaded,
[email protected]098b29112011-12-20 21:12:34534 weak_factory_.GetWeakPtr()));
[email protected]1a6fff52011-10-20 21:00:16535}
536
[email protected]03d845f2011-07-29 19:06:26537void URLRequestHttpJob::CheckCookiePolicyAndLoad(
538 const CookieList& cookie_list) {
[email protected]1a6fff52011-10-20 21:00:16539 if (CanGetCookies(cookie_list))
540 DoLoadCookies();
541 else
[email protected]54f4c9362011-07-25 21:54:46542 DoStartTransaction();
[email protected]54f4c9362011-07-25 21:54:46543}
544
[email protected]dedec0b2013-02-28 04:50:10545void URLRequestHttpJob::OnCookiesLoaded(const std::string& cookie_line) {
[email protected]218aa6a12011-09-13 17:38:38546 if (!cookie_line.empty()) {
[email protected]54f4c9362011-07-25 21:54:46547 request_info_.extra_headers.SetHeader(
[email protected]218aa6a12011-09-13 17:38:38548 HttpRequestHeaders::kCookie, cookie_line);
[email protected]54f4c9362011-07-25 21:54:46549 }
[email protected]54f4c9362011-07-25 21:54:46550 DoStartTransaction();
551}
552
553void URLRequestHttpJob::DoStartTransaction() {
[email protected]03d845f2011-07-29 19:06:26554 // We may have been canceled while retrieving cookies.
[email protected]9025016c2011-05-12 15:51:23555 if (GetStatus().is_success()) {
556 StartTransaction();
557 } else {
558 NotifyCanceled();
559 }
[email protected]0757e7702009-03-27 04:00:22560}
561
[email protected]ea8141e2011-10-05 13:12:51562void URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete(int result) {
563 if (result != net::OK) {
[email protected]55b8a6c12012-06-13 22:03:42564 std::string source("delegate");
[email protected]ea8141e2011-10-05 13:12:51565 request_->net_log().AddEvent(NetLog::TYPE_CANCELLED,
[email protected]55b8a6c12012-06-13 22:03:42566 NetLog::StringCallback("source", &source));
[email protected]ea8141e2011-10-05 13:12:51567 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
568 return;
569 }
570
[email protected]34602282010-02-03 22:14:15571 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52572
[email protected]4f5656c62010-12-13 10:47:09573 const HttpResponseInfo* response_info = transaction_->GetResponseInfo();
[email protected]34602282010-02-03 22:14:15574 DCHECK(response_info);
575
576 response_cookies_.clear();
577 response_cookies_save_index_ = 0;
578
[email protected]ea8141e2011-10-05 13:12:51579 FetchResponseCookies(&response_cookies_);
[email protected]34602282010-02-03 22:14:15580
[email protected]5095cd72012-11-01 10:29:16581 if (!GetResponseHeaders()->GetDateValue(&response_date_))
582 response_date_ = base::Time();
583
[email protected]34602282010-02-03 22:14:15584 // Now, loop over the response cookies, and attempt to persist each.
585 SaveNextCookie();
586}
587
[email protected]263163f2012-06-14 22:40:34588// If the save occurs synchronously, SaveNextCookie will loop and save the next
589// cookie. If the save is deferred, the callback is responsible for continuing
590// to iterate through the cookies.
591// TODO(erikwright): Modify the CookieStore API to indicate via return value
592// whether it completed synchronously or asynchronously.
593// See http://crbug.com/131066.
[email protected]34602282010-02-03 22:14:15594void URLRequestHttpJob::SaveNextCookie() {
[email protected]263163f2012-06-14 22:40:34595 // No matter what, we want to report our status as IO pending since we will
596 // be notifying our consumer asynchronously via OnStartCompleted.
597 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
598
599 // Used to communicate with the callback. See the implementation of
600 // OnCookieSaved.
601 scoped_refptr<SharedBoolean> callback_pending = new SharedBoolean(false);
602 scoped_refptr<SharedBoolean> save_next_cookie_running =
603 new SharedBoolean(true);
604
605 if (!(request_info_.load_flags & LOAD_DO_NOT_SAVE_COOKIES) &&
606 request_->context()->cookie_store() &&
607 response_cookies_.size() > 0) {
608 CookieOptions options;
609 options.set_include_httponly();
[email protected]5095cd72012-11-01 10:29:16610 options.set_server_time(response_date_);
[email protected]263163f2012-06-14 22:40:34611
612 net::CookieStore::SetCookiesCallback callback(
613 base::Bind(&URLRequestHttpJob::OnCookieSaved,
614 weak_factory_.GetWeakPtr(),
615 save_next_cookie_running,
616 callback_pending));
617
618 // Loop through the cookies as long as SetCookieWithOptionsAsync completes
619 // synchronously.
620 while (!callback_pending->data &&
621 response_cookies_save_index_ < response_cookies_.size()) {
622 if (CanSetCookie(
623 response_cookies_[response_cookies_save_index_], &options)) {
624 callback_pending->data = true;
625 request_->context()->cookie_store()->SetCookieWithOptionsAsync(
626 request_->url(), response_cookies_[response_cookies_save_index_],
627 options, callback);
628 }
629 ++response_cookies_save_index_;
630 }
631 }
632
633 save_next_cookie_running->data = false;
634
635 if (!callback_pending->data) {
[email protected]34602282010-02-03 22:14:15636 response_cookies_.clear();
637 response_cookies_save_index_ = 0;
638 SetStatus(URLRequestStatus()); // Clear the IO_PENDING status
639 NotifyHeadersComplete();
640 return;
641 }
[email protected]263163f2012-06-14 22:40:34642}
[email protected]34602282010-02-03 22:14:15643
[email protected]263163f2012-06-14 22:40:34644// |save_next_cookie_running| is true when the callback is bound and set to
645// false when SaveNextCookie exits, allowing the callback to determine if the
646// save occurred synchronously or asynchronously.
647// |callback_pending| is false when the callback is invoked and will be set to
648// true by the callback, allowing SaveNextCookie to detect whether the save
649// occurred synchronously.
650// See SaveNextCookie() for more information.
651void URLRequestHttpJob::OnCookieSaved(
652 scoped_refptr<SharedBoolean> save_next_cookie_running,
653 scoped_refptr<SharedBoolean> callback_pending,
654 bool cookie_status) {
655 callback_pending->data = false;
[email protected]34602282010-02-03 22:14:15656
[email protected]263163f2012-06-14 22:40:34657 // If we were called synchronously, return.
658 if (save_next_cookie_running->data) {
659 return;
[email protected]34602282010-02-03 22:14:15660 }
661
[email protected]263163f2012-06-14 22:40:34662 // We were called asynchronously, so trigger the next save.
[email protected]9025016c2011-05-12 15:51:23663 // We may have been canceled within OnSetCookie.
664 if (GetStatus().is_success()) {
665 SaveNextCookie();
666 } else {
667 NotifyCanceled();
668 }
[email protected]34602282010-02-03 22:14:15669}
670
671void URLRequestHttpJob::FetchResponseCookies(
[email protected]34602282010-02-03 22:14:15672 std::vector<std::string>* cookies) {
[email protected]264300242011-11-07 06:03:30673 const std::string name = "Set-Cookie";
initial.commit586acc5fe2008-07-26 22:42:52674 std::string value;
675
676 void* iter = NULL;
[email protected]ea8141e2011-10-05 13:12:51677 HttpResponseHeaders* headers = GetResponseHeaders();
678 while (headers->EnumerateHeader(&iter, name, &value)) {
[email protected]2adf2882010-09-27 08:30:37679 if (!value.empty())
680 cookies->push_back(value);
681 }
initial.commit586acc5fe2008-07-26 22:42:52682}
[email protected]a9cea7542009-05-20 04:30:23683
[email protected]000d9df02012-01-18 20:01:46684// NOTE: |ProcessStrictTransportSecurityHeader| and
685// |ProcessPublicKeyPinsHeader| have very similar structures, by design.
[email protected]77f6fb432009-09-05 14:21:09686void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() {
[email protected]a9cea7542009-05-20 04:30:23687 DCHECK(response_info_);
[email protected]6ed72be2013-01-08 22:07:33688 TransportSecurityState* security_state =
689 request_->context()->transport_security_state();
[email protected]e88006f2012-01-11 06:15:07690 const SSLInfo& ssl_info = response_info_->ssl_info;
[email protected]a9cea7542009-05-20 04:30:23691
[email protected]6ed72be2013-01-08 22:07:33692 // Only accept HSTS headers on HTTPS connections that have no
693 // certificate errors.
[email protected]e88006f2012-01-11 06:15:07694 if (!ssl_info.is_valid() || IsCertStatusError(ssl_info.cert_status) ||
[email protected]6ed72be2013-01-08 22:07:33695 !security_state)
[email protected]e88006f2012-01-11 06:15:07696 return;
[email protected]326e6792009-12-11 21:04:42697
[email protected]242d8562012-10-30 21:20:46698 // http://tools.ietf.org/html/draft-ietf-websec-strict-transport-sec:
699 //
700 // If a UA receives more than one STS header field in a HTTP response
701 // message over secure transport, then the UA MUST process only the
702 // first such header field.
[email protected]6ed72be2013-01-08 22:07:33703 HttpResponseHeaders* headers = GetResponseHeaders();
704 std::string value;
705 if (headers->EnumerateHeader(NULL, "Strict-Transport-Security", &value))
706 security_state->AddHSTSHeader(request_info_.url.host(), value);
[email protected]a9cea7542009-05-20 04:30:23707}
[email protected]4f5656c62010-12-13 10:47:09708
[email protected]fecef222012-01-05 02:26:15709void URLRequestHttpJob::ProcessPublicKeyPinsHeader() {
710 DCHECK(response_info_);
[email protected]6ed72be2013-01-08 22:07:33711 TransportSecurityState* security_state =
712 request_->context()->transport_security_state();
[email protected]fecef222012-01-05 02:26:15713 const SSLInfo& ssl_info = response_info_->ssl_info;
714
[email protected]6ed72be2013-01-08 22:07:33715 // Only accept HPKP headers on HTTPS connections that have no
[email protected]e88006f2012-01-11 06:15:07716 // certificate errors.
[email protected]fecef222012-01-05 02:26:15717 if (!ssl_info.is_valid() || IsCertStatusError(ssl_info.cert_status) ||
[email protected]6ed72be2013-01-08 22:07:33718 !security_state)
[email protected]fecef222012-01-05 02:26:15719 return;
[email protected]fecef222012-01-05 02:26:15720
[email protected]6ed72be2013-01-08 22:07:33721 // http://tools.ietf.org/html/draft-ietf-websec-key-pinning:
722 //
723 // If a UA receives more than one PKP header field in an HTTP
724 // response message over secure transport, then the UA MUST process
725 // only the first such header field.
[email protected]fecef222012-01-05 02:26:15726 HttpResponseHeaders* headers = GetResponseHeaders();
[email protected]fecef222012-01-05 02:26:15727 std::string value;
[email protected]6ed72be2013-01-08 22:07:33728 if (headers->EnumerateHeader(NULL, "Public-Key-Pins", &value))
729 security_state->AddHPKPHeader(request_info_.url.host(), value, ssl_info);
[email protected]fecef222012-01-05 02:26:15730}
731
[email protected]5394e422011-01-20 22:07:43732void URLRequestHttpJob::OnStartCompleted(int result) {
[email protected]ec23f522011-02-22 21:01:38733 RecordTimer();
734
[email protected]5394e422011-01-20 22:07:43735 // If the request was destroyed, then there is no more work to do.
[email protected]a83dd332011-07-13 10:41:01736 if (!request_)
[email protected]5394e422011-01-20 22:07:43737 return;
738
739 // If the transaction was destroyed, then the job was cancelled, and
740 // we can just ignore this notification.
741 if (!transaction_.get())
742 return;
743
744 // Clear the IO_PENDING status
745 SetStatus(URLRequestStatus());
746
[email protected]ef2bf422012-05-11 03:27:09747 const URLRequestContext* context = request_->context();
748
[email protected]f3572592011-12-12 21:36:31749 if (result == ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN &&
750 transaction_->GetResponseInfo() != NULL) {
751 FraudulentCertificateReporter* reporter =
[email protected]ef2bf422012-05-11 03:27:09752 context->fraudulent_certificate_reporter();
[email protected]f3572592011-12-12 21:36:31753 if (reporter != NULL) {
754 const SSLInfo& ssl_info = transaction_->GetResponseInfo()->ssl_info;
[email protected]551ff5172011-11-10 18:35:31755 bool sni_available = SSLConfigService::IsSNIAvailable(
[email protected]ef2bf422012-05-11 03:27:09756 context->ssl_config_service());
[email protected]f3572592011-12-12 21:36:31757 const std::string& host = request_->url().host();
[email protected]b7996452011-10-31 19:30:56758
[email protected]f3572592011-12-12 21:36:31759 reporter->SendReport(host, ssl_info, sni_available);
[email protected]381e8852011-04-14 14:30:58760 }
761 }
[email protected]551ff5172011-11-10 18:35:31762
[email protected]5394e422011-01-20 22:07:43763 if (result == OK) {
[email protected]ea8141e2011-10-05 13:12:51764 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
[email protected]81293f482012-08-13 19:35:45765 if (context->network_delegate()) {
[email protected]ea8141e2011-10-05 13:12:51766 // Note that |this| may not be deleted until
767 // |on_headers_received_callback_| or
768 // |NetworkDelegate::URLRequestDestroyed()| has been called.
[email protected]ef2bf422012-05-11 03:27:09769 int error = context->network_delegate()->
[email protected]084262c2011-12-01 21:12:47770 NotifyHeadersReceived(request_, on_headers_received_callback_,
[email protected]ea8141e2011-10-05 13:12:51771 headers, &override_response_headers_);
772 if (error != net::OK) {
773 if (error == net::ERR_IO_PENDING) {
774 awaiting_callback_ = true;
[email protected]0a12e452012-11-14 05:04:30775 SetBlockedOnDelegate();
[email protected]ea8141e2011-10-05 13:12:51776 } else {
[email protected]55b8a6c12012-06-13 22:03:42777 std::string source("delegate");
[email protected]ea8141e2011-10-05 13:12:51778 request_->net_log().AddEvent(NetLog::TYPE_CANCELLED,
[email protected]55b8a6c12012-06-13 22:03:42779 NetLog::StringCallback("source",
780 &source));
[email protected]ea8141e2011-10-05 13:12:51781 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, error));
782 }
783 return;
784 }
785 }
786
787 SaveCookiesAndNotifyHeadersComplete(net::OK);
[email protected]e5624f02011-09-27 19:43:53788 } else if (IsCertificateError(result)) {
[email protected]5394e422011-01-20 22:07:43789 // We encountered an SSL certificate error. Ask our delegate to decide
790 // what we should do.
[email protected]e5624f02011-09-27 19:43:53791
792 TransportSecurityState::DomainState domain_state;
[email protected]ef2bf422012-05-11 03:27:09793 const URLRequestContext* context = request_->context();
[email protected]843329e2013-01-22 22:06:09794 const bool fatal = context->transport_security_state() &&
[email protected]ef2bf422012-05-11 03:27:09795 context->transport_security_state()->GetDomainState(
[email protected]f43b89f32012-05-01 19:39:48796 request_info_.url.host(),
[email protected]ef2bf422012-05-11 03:27:09797 SSLConfigService::IsSNIAvailable(context->ssl_config_service()),
[email protected]843329e2013-01-22 22:06:09798 &domain_state) &&
799 domain_state.ShouldSSLErrorsBeFatal();
[email protected]46d117e2012-01-18 01:53:14800 NotifySSLCertificateError(transaction_->GetResponseInfo()->ssl_info, fatal);
[email protected]5394e422011-01-20 22:07:43801 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]a83dd332011-07-13 10:41:01802 NotifyCertificateRequested(
803 transaction_->GetResponseInfo()->cert_request_info);
[email protected]5394e422011-01-20 22:07:43804 } else {
805 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
806 }
807}
808
[email protected]ea8141e2011-10-05 13:12:51809void URLRequestHttpJob::OnHeadersReceivedCallback(int result) {
[email protected]0a12e452012-11-14 05:04:30810 SetUnblockedOnDelegate();
[email protected]ea8141e2011-10-05 13:12:51811 awaiting_callback_ = false;
[email protected]9045b8822012-01-13 20:35:35812
813 // Check that there are no callbacks to already canceled requests.
814 DCHECK_NE(URLRequestStatus::CANCELED, GetStatus().status());
815
[email protected]ea8141e2011-10-05 13:12:51816 SaveCookiesAndNotifyHeadersComplete(result);
817}
818
[email protected]5394e422011-01-20 22:07:43819void URLRequestHttpJob::OnReadCompleted(int result) {
820 read_in_progress_ = false;
821
[email protected]f001bd6a2011-12-08 04:31:37822 if (ShouldFixMismatchedContentLength(result))
[email protected]5543cbb2012-04-20 16:35:23823 result = OK;
[email protected]f001bd6a2011-12-08 04:31:37824
[email protected]5543cbb2012-04-20 16:35:23825 if (result == OK) {
[email protected]5394e422011-01-20 22:07:43826 NotifyDone(URLRequestStatus());
827 } else if (result < 0) {
828 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result));
829 } else {
830 // Clear the IO_PENDING status
831 SetStatus(URLRequestStatus());
832 }
833
834 NotifyReadComplete(result);
835}
836
[email protected]5394e422011-01-20 22:07:43837void URLRequestHttpJob::RestartTransactionWithAuth(
[email protected]f3cf9802011-10-28 18:44:58838 const AuthCredentials& credentials) {
839 auth_credentials_ = credentials;
[email protected]5394e422011-01-20 22:07:43840
841 // These will be reset in OnStartCompleted.
842 response_info_ = NULL;
843 response_cookies_.clear();
844
[email protected]ec23f522011-02-22 21:01:38845 ResetTimer();
846
[email protected]5394e422011-01-20 22:07:43847 // Update the cookies, since the cookie store may have been updated from the
848 // headers in the 401/407. Since cookies were already appended to
849 // extra_headers, we need to strip them out before adding them again.
[email protected]ea8141e2011-10-05 13:12:51850 request_info_.extra_headers.RemoveHeader(HttpRequestHeaders::kCookie);
[email protected]5394e422011-01-20 22:07:43851
852 AddCookieHeaderAndStart();
853}
854
[email protected]0736d9e2012-11-28 19:50:40855void URLRequestHttpJob::SetUpload(UploadDataStream* upload) {
[email protected]5394e422011-01-20 22:07:43856 DCHECK(!transaction_.get()) << "cannot change once started";
[email protected]0736d9e2012-11-28 19:50:40857 request_info_.upload_data_stream = upload;
[email protected]5394e422011-01-20 22:07:43858}
859
860void URLRequestHttpJob::SetExtraRequestHeaders(
861 const HttpRequestHeaders& headers) {
862 DCHECK(!transaction_.get()) << "cannot change once started";
863 request_info_.extra_headers.CopyFrom(headers);
864}
865
866void URLRequestHttpJob::Start() {
867 DCHECK(!transaction_.get());
868
869 // Ensure that we do not send username and password fields in the referrer.
870 GURL referrer(request_->GetSanitizedReferrer());
871
872 request_info_.url = request_->url();
[email protected]5394e422011-01-20 22:07:43873 request_info_.method = request_->method();
874 request_info_.load_flags = request_->load_flags();
875 request_info_.priority = request_->priority();
[email protected]4875ba12011-03-30 22:31:51876 request_info_.request_id = request_->identifier();
[email protected]5394e422011-01-20 22:07:43877
[email protected]c10450102011-06-27 09:06:16878 // Strip Referer from request_info_.extra_headers to prevent, e.g., plugins
879 // from overriding headers that are controlled using other means. Otherwise a
880 // plugin could set a referrer although sending the referrer is inhibited.
881 request_info_.extra_headers.RemoveHeader(HttpRequestHeaders::kReferer);
882
883 // Our consumer should have made sure that this is a safe referrer. See for
884 // instance WebCore::FrameLoader::HideReferrer.
885 if (referrer.is_valid()) {
886 request_info_.extra_headers.SetHeader(HttpRequestHeaders::kReferer,
887 referrer.spec());
888 }
889
[email protected]81293f482012-08-13 19:35:45890 request_info_.extra_headers.SetHeaderIfMissing(
891 HttpRequestHeaders::kUserAgent,
[email protected]ee4c30d2012-11-07 15:08:43892 http_user_agent_settings_ ?
893 http_user_agent_settings_->GetUserAgent(request_->url()) :
894 EmptyString());
[email protected]5394e422011-01-20 22:07:43895
896 AddExtraHeaders();
897 AddCookieHeaderAndStart();
898}
899
900void URLRequestHttpJob::Kill() {
[email protected]a9e0d1412012-08-20 22:13:01901 http_transaction_delegate_->OnDetachRequest();
902
[email protected]5394e422011-01-20 22:07:43903 if (!transaction_.get())
904 return;
905
[email protected]098b29112011-12-20 21:12:34906 weak_factory_.InvalidateWeakPtrs();
[email protected]5394e422011-01-20 22:07:43907 DestroyTransaction();
908 URLRequestJob::Kill();
909}
910
911LoadState URLRequestHttpJob::GetLoadState() const {
912 return transaction_.get() ?
913 transaction_->GetLoadState() : LOAD_STATE_IDLE;
914}
915
[email protected]7335ab02012-08-30 22:30:42916UploadProgress URLRequestHttpJob::GetUploadProgress() const {
917 return transaction_.get() ?
918 transaction_->GetUploadProgress() : UploadProgress();
[email protected]5394e422011-01-20 22:07:43919}
920
921bool URLRequestHttpJob::GetMimeType(std::string* mime_type) const {
922 DCHECK(transaction_.get());
923
924 if (!response_info_)
925 return false;
926
[email protected]ea8141e2011-10-05 13:12:51927 return GetResponseHeaders()->GetMimeType(mime_type);
[email protected]5394e422011-01-20 22:07:43928}
929
930bool URLRequestHttpJob::GetCharset(std::string* charset) {
931 DCHECK(transaction_.get());
932
933 if (!response_info_)
934 return false;
935
[email protected]ea8141e2011-10-05 13:12:51936 return GetResponseHeaders()->GetCharset(charset);
[email protected]5394e422011-01-20 22:07:43937}
938
939void URLRequestHttpJob::GetResponseInfo(HttpResponseInfo* info) {
940 DCHECK(request_);
941 DCHECK(transaction_.get());
942
[email protected]ea8141e2011-10-05 13:12:51943 if (response_info_) {
[email protected]5394e422011-01-20 22:07:43944 *info = *response_info_;
[email protected]ea8141e2011-10-05 13:12:51945 if (override_response_headers_)
946 info->headers = override_response_headers_;
947 }
[email protected]5394e422011-01-20 22:07:43948}
949
[email protected]58e32bb2013-01-21 18:23:25950void URLRequestHttpJob::GetLoadTimingInfo(
951 LoadTimingInfo* load_timing_info) const {
952 if (transaction_)
953 transaction_->GetLoadTimingInfo(load_timing_info);
954}
955
[email protected]ea8141e2011-10-05 13:12:51956bool URLRequestHttpJob::GetResponseCookies(std::vector<std::string>* cookies) {
[email protected]5394e422011-01-20 22:07:43957 DCHECK(transaction_.get());
958
959 if (!response_info_)
960 return false;
961
962 // TODO(darin): Why are we extracting response cookies again? Perhaps we
963 // should just leverage response_cookies_.
964
965 cookies->clear();
[email protected]ea8141e2011-10-05 13:12:51966 FetchResponseCookies(cookies);
[email protected]5394e422011-01-20 22:07:43967 return true;
968}
969
970int URLRequestHttpJob::GetResponseCode() const {
971 DCHECK(transaction_.get());
972
973 if (!response_info_)
974 return -1;
975
[email protected]ea8141e2011-10-05 13:12:51976 return GetResponseHeaders()->response_code();
[email protected]5394e422011-01-20 22:07:43977}
978
[email protected]5a3b4d32011-03-17 01:24:05979Filter* URLRequestHttpJob::SetupFilter() const {
[email protected]5394e422011-01-20 22:07:43980 DCHECK(transaction_.get());
981 if (!response_info_)
[email protected]5a3b4d32011-03-17 01:24:05982 return NULL;
[email protected]5394e422011-01-20 22:07:43983
[email protected]5a3b4d32011-03-17 01:24:05984 std::vector<Filter::FilterType> encoding_types;
[email protected]5394e422011-01-20 22:07:43985 std::string encoding_type;
[email protected]ea8141e2011-10-05 13:12:51986 HttpResponseHeaders* headers = GetResponseHeaders();
[email protected]5394e422011-01-20 22:07:43987 void* iter = NULL;
[email protected]ea8141e2011-10-05 13:12:51988 while (headers->EnumerateHeader(&iter, "Content-Encoding", &encoding_type)) {
[email protected]5a3b4d32011-03-17 01:24:05989 encoding_types.push_back(Filter::ConvertEncodingToType(encoding_type));
[email protected]5394e422011-01-20 22:07:43990 }
991
[email protected]46668fe52011-05-04 19:03:23992 if (filter_context_->IsSdchResponse()) {
993 // We are wary of proxies that discard or damage SDCH encoding. If a server
994 // explicitly states that this is not SDCH content, then we can correct our
995 // assumption that this is an SDCH response, and avoid the need to recover
996 // as though the content is corrupted (when we discover it is not SDCH
997 // encoded).
998 std::string sdch_response_status;
999 iter = NULL;
[email protected]ea8141e2011-10-05 13:12:511000 while (headers->EnumerateHeader(&iter, "X-Sdch-Encode",
1001 &sdch_response_status)) {
[email protected]46668fe52011-05-04 19:03:231002 if (sdch_response_status == "0") {
1003 filter_context_->ResetSdchResponseToFalse();
1004 break;
1005 }
1006 }
1007 }
1008
[email protected]5394e422011-01-20 22:07:431009 // Even if encoding types are empty, there is a chance that we need to add
1010 // some decoding, as some proxies strip encoding completely. In such cases,
1011 // we may need to add (for example) SDCH filtering (when the context suggests
1012 // it is appropriate).
[email protected]2e92354c2011-03-25 20:49:531013 Filter::FixupEncodingTypes(*filter_context_, &encoding_types);
[email protected]5394e422011-01-20 22:07:431014
[email protected]5a3b4d32011-03-17 01:24:051015 return !encoding_types.empty()
[email protected]2e92354c2011-03-25 20:49:531016 ? Filter::Factory(encoding_types, *filter_context_) : NULL;
[email protected]5394e422011-01-20 22:07:431017}
1018
[email protected]5394e422011-01-20 22:07:431019bool URLRequestHttpJob::IsSafeRedirect(const GURL& location) {
1020 // We only allow redirects to certain "safe" protocols. This does not
1021 // restrict redirects to externally handled protocols. Our consumer would
1022 // need to take care of those.
1023
1024 if (!URLRequest::IsHandledURL(location))
1025 return true;
1026
1027 static const char* kSafeSchemes[] = {
1028 "http",
1029 "https",
1030 "ftp"
1031 };
1032
1033 for (size_t i = 0; i < arraysize(kSafeSchemes); ++i) {
1034 if (location.SchemeIs(kSafeSchemes[i]))
1035 return true;
1036 }
1037
1038 return false;
1039}
1040
1041bool URLRequestHttpJob::NeedsAuth() {
1042 int code = GetResponseCode();
1043 if (code == -1)
1044 return false;
1045
1046 // Check if we need either Proxy or WWW Authentication. This could happen
1047 // because we either provided no auth info, or provided incorrect info.
1048 switch (code) {
1049 case 407:
1050 if (proxy_auth_state_ == AUTH_STATE_CANCELED)
1051 return false;
1052 proxy_auth_state_ = AUTH_STATE_NEED_AUTH;
1053 return true;
1054 case 401:
1055 if (server_auth_state_ == AUTH_STATE_CANCELED)
1056 return false;
1057 server_auth_state_ = AUTH_STATE_NEED_AUTH;
1058 return true;
1059 }
1060 return false;
1061}
1062
1063void URLRequestHttpJob::GetAuthChallengeInfo(
1064 scoped_refptr<AuthChallengeInfo>* result) {
1065 DCHECK(transaction_.get());
1066 DCHECK(response_info_);
1067
1068 // sanity checks:
1069 DCHECK(proxy_auth_state_ == AUTH_STATE_NEED_AUTH ||
1070 server_auth_state_ == AUTH_STATE_NEED_AUTH);
[email protected]9094b602012-02-27 21:44:581071 DCHECK((GetResponseHeaders()->response_code() == HTTP_UNAUTHORIZED) ||
1072 (GetResponseHeaders()->response_code() ==
1073 HTTP_PROXY_AUTHENTICATION_REQUIRED));
[email protected]5394e422011-01-20 22:07:431074
1075 *result = response_info_->auth_challenge;
1076}
1077
[email protected]f3cf9802011-10-28 18:44:581078void URLRequestHttpJob::SetAuth(const AuthCredentials& credentials) {
[email protected]5394e422011-01-20 22:07:431079 DCHECK(transaction_.get());
1080
1081 // Proxy gets set first, then WWW.
1082 if (proxy_auth_state_ == AUTH_STATE_NEED_AUTH) {
1083 proxy_auth_state_ = AUTH_STATE_HAVE_AUTH;
1084 } else {
[email protected]dd29bcd72011-03-24 00:03:441085 DCHECK_EQ(server_auth_state_, AUTH_STATE_NEED_AUTH);
[email protected]5394e422011-01-20 22:07:431086 server_auth_state_ = AUTH_STATE_HAVE_AUTH;
1087 }
1088
[email protected]f3cf9802011-10-28 18:44:581089 RestartTransactionWithAuth(credentials);
[email protected]5394e422011-01-20 22:07:431090}
1091
1092void URLRequestHttpJob::CancelAuth() {
1093 // Proxy gets set first, then WWW.
1094 if (proxy_auth_state_ == AUTH_STATE_NEED_AUTH) {
1095 proxy_auth_state_ = AUTH_STATE_CANCELED;
1096 } else {
[email protected]dd29bcd72011-03-24 00:03:441097 DCHECK_EQ(server_auth_state_, AUTH_STATE_NEED_AUTH);
[email protected]5394e422011-01-20 22:07:431098 server_auth_state_ = AUTH_STATE_CANCELED;
1099 }
1100
1101 // These will be reset in OnStartCompleted.
1102 response_info_ = NULL;
1103 response_cookies_.clear();
1104
[email protected]ec23f522011-02-22 21:01:381105 ResetTimer();
1106
[email protected]5394e422011-01-20 22:07:431107 // OK, let the consumer read the error page...
1108 //
1109 // Because we set the AUTH_STATE_CANCELED flag, NeedsAuth will return false,
1110 // which will cause the consumer to receive OnResponseStarted instead of
1111 // OnAuthRequired.
1112 //
1113 // We have to do this via InvokeLater to avoid "recursing" the consumer.
1114 //
1115 MessageLoop::current()->PostTask(
1116 FROM_HERE,
[email protected]098b29112011-12-20 21:12:341117 base::Bind(&URLRequestHttpJob::OnStartCompleted,
1118 weak_factory_.GetWeakPtr(), OK));
[email protected]5394e422011-01-20 22:07:431119}
1120
1121void URLRequestHttpJob::ContinueWithCertificate(
1122 X509Certificate* client_cert) {
1123 DCHECK(transaction_.get());
1124
1125 DCHECK(!response_info_) << "should not have a response yet";
1126
[email protected]ec23f522011-02-22 21:01:381127 ResetTimer();
1128
[email protected]5394e422011-01-20 22:07:431129 // No matter what, we want to report our status as IO pending since we will
1130 // be notifying our consumer asynchronously via OnStartCompleted.
1131 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
1132
[email protected]49639fa2011-12-20 23:22:411133 int rv = transaction_->RestartWithCertificate(client_cert, start_callback_);
[email protected]5394e422011-01-20 22:07:431134 if (rv == ERR_IO_PENDING)
1135 return;
1136
1137 // The transaction started synchronously, but we need to notify the
1138 // URLRequest delegate via the message loop.
1139 MessageLoop::current()->PostTask(
1140 FROM_HERE,
[email protected]098b29112011-12-20 21:12:341141 base::Bind(&URLRequestHttpJob::OnStartCompleted,
1142 weak_factory_.GetWeakPtr(), rv));
[email protected]5394e422011-01-20 22:07:431143}
1144
1145void URLRequestHttpJob::ContinueDespiteLastError() {
1146 // If the transaction was destroyed, then the job was cancelled.
1147 if (!transaction_.get())
1148 return;
1149
1150 DCHECK(!response_info_) << "should not have a response yet";
1151
[email protected]ec23f522011-02-22 21:01:381152 ResetTimer();
1153
[email protected]5394e422011-01-20 22:07:431154 // No matter what, we want to report our status as IO pending since we will
1155 // be notifying our consumer asynchronously via OnStartCompleted.
1156 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
1157
[email protected]49639fa2011-12-20 23:22:411158 int rv = transaction_->RestartIgnoringLastError(start_callback_);
[email protected]5394e422011-01-20 22:07:431159 if (rv == ERR_IO_PENDING)
1160 return;
1161
1162 // The transaction started synchronously, but we need to notify the
1163 // URLRequest delegate via the message loop.
1164 MessageLoop::current()->PostTask(
1165 FROM_HERE,
[email protected]098b29112011-12-20 21:12:341166 base::Bind(&URLRequestHttpJob::OnStartCompleted,
1167 weak_factory_.GetWeakPtr(), rv));
[email protected]5394e422011-01-20 22:07:431168}
1169
[email protected]f001bd6a2011-12-08 04:31:371170bool URLRequestHttpJob::ShouldFixMismatchedContentLength(int rv) const {
1171 // Some servers send the body compressed, but specify the content length as
1172 // the uncompressed size. Although this violates the HTTP spec we want to
1173 // support it (as IE and FireFox do), but *only* for an exact match.
1174 // See http://crbug.com/79694.
[email protected]5543cbb2012-04-20 16:35:231175 if (rv == net::ERR_CONTENT_LENGTH_MISMATCH ||
1176 rv == net::ERR_INCOMPLETE_CHUNKED_ENCODING) {
[email protected]f001bd6a2011-12-08 04:31:371177 if (request_ && request_->response_headers()) {
1178 int64 expected_length = request_->response_headers()->GetContentLength();
1179 VLOG(1) << __FUNCTION__ << "() "
1180 << "\"" << request_->url().spec() << "\""
1181 << " content-length = " << expected_length
1182 << " pre total = " << prefilter_bytes_read()
1183 << " post total = " << postfilter_bytes_read();
1184 if (postfilter_bytes_read() == expected_length) {
1185 // Clear the error.
1186 return true;
1187 }
1188 }
1189 }
1190 return false;
1191}
1192
[email protected]5394e422011-01-20 22:07:431193bool URLRequestHttpJob::ReadRawData(IOBuffer* buf, int buf_size,
[email protected]b7996452011-10-31 19:30:561194 int* bytes_read) {
[email protected]5394e422011-01-20 22:07:431195 DCHECK_NE(buf_size, 0);
1196 DCHECK(bytes_read);
1197 DCHECK(!read_in_progress_);
1198
[email protected]49639fa2011-12-20 23:22:411199 int rv = transaction_->Read(
1200 buf, buf_size,
1201 base::Bind(&URLRequestHttpJob::OnReadCompleted, base::Unretained(this)));
[email protected]85c1dce2011-07-06 12:01:291202
[email protected]f001bd6a2011-12-08 04:31:371203 if (ShouldFixMismatchedContentLength(rv))
1204 rv = 0;
1205
[email protected]5394e422011-01-20 22:07:431206 if (rv >= 0) {
1207 *bytes_read = rv;
[email protected]bbaea8f2011-06-24 00:11:011208 if (!rv)
1209 DoneWithRequest(FINISHED);
[email protected]5394e422011-01-20 22:07:431210 return true;
1211 }
1212
1213 if (rv == ERR_IO_PENDING) {
1214 read_in_progress_ = true;
1215 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
1216 } else {
1217 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
1218 }
1219
1220 return false;
1221}
1222
1223void URLRequestHttpJob::StopCaching() {
1224 if (transaction_.get())
1225 transaction_->StopCaching();
1226}
1227
[email protected]5c04f722011-08-12 17:52:471228void URLRequestHttpJob::DoneReading() {
1229 if (transaction_.get())
1230 transaction_->DoneReading();
1231 DoneWithRequest(FINISHED);
1232}
1233
[email protected]6d81b482011-02-22 19:47:191234HostPortPair URLRequestHttpJob::GetSocketAddress() const {
1235 return response_info_ ? response_info_->socket_address : HostPortPair();
1236}
1237
[email protected]5394e422011-01-20 22:07:431238URLRequestHttpJob::~URLRequestHttpJob() {
[email protected]ea8141e2011-10-05 13:12:511239 CHECK(!awaiting_callback_);
1240
[email protected]5394e422011-01-20 22:07:431241 DCHECK(!sdch_test_control_ || !sdch_test_activated_);
[email protected]dd29bcd72011-03-24 00:03:441242 if (!is_cached_content_) {
[email protected]5394e422011-01-20 22:07:431243 if (sdch_test_control_)
[email protected]fc01f232011-03-17 19:06:011244 RecordPacketStats(FilterContext::SDCH_EXPERIMENT_HOLDBACK);
[email protected]5394e422011-01-20 22:07:431245 if (sdch_test_activated_)
[email protected]fc01f232011-03-17 19:06:011246 RecordPacketStats(FilterContext::SDCH_EXPERIMENT_DECODE);
[email protected]5394e422011-01-20 22:07:431247 }
[email protected]dd29bcd72011-03-24 00:03:441248 // Make sure SDCH filters are told to emit histogram data while
1249 // filter_context_ is still alive.
[email protected]5394e422011-01-20 22:07:431250 DestroyFilters();
1251
1252 if (sdch_dictionary_url_.is_valid()) {
1253 // Prior to reaching the destructor, request_ has been set to a NULL
1254 // pointer, so request_->url() is no longer valid in the destructor, and we
1255 // use an alternate copy |request_info_.url|.
1256 SdchManager* manager = SdchManager::Global();
1257 // To be extra safe, since this is a "different time" from when we decided
1258 // to get the dictionary, we'll validate that an SdchManager is available.
1259 // At shutdown time, care is taken to be sure that we don't delete this
1260 // globally useful instance "too soon," so this check is just defensive
1261 // coding to assure that IF the system is shutting down, we don't have any
1262 // problem if the manager was deleted ahead of time.
1263 if (manager) // Defensive programming.
1264 manager->FetchDictionary(request_info_.url, sdch_dictionary_url_);
1265 }
[email protected]bbaea8f2011-06-24 00:11:011266 DoneWithRequest(ABORTED);
[email protected]5394e422011-01-20 22:07:431267}
1268
[email protected]ec23f522011-02-22 21:01:381269void URLRequestHttpJob::RecordTimer() {
1270 if (request_creation_time_.is_null()) {
1271 NOTREACHED()
1272 << "The same transaction shouldn't start twice without new timing.";
1273 return;
1274 }
1275
[email protected]320a29f12011-03-21 14:47:411276 base::TimeDelta to_start = base::Time::Now() - request_creation_time_;
[email protected]ec23f522011-02-22 21:01:381277 request_creation_time_ = base::Time();
[email protected]8684a8812011-03-22 13:59:381278
[email protected]5c68d692011-08-24 04:59:411279 UMA_HISTOGRAM_MEDIUM_TIMES("Net.HttpTimeToFirstByte", to_start);
1280
[email protected]135c126a2012-10-31 15:39:251281 static const bool use_overlapped_read_histogram =
1282 base::FieldTrialList::TrialExists("OverlappedReadImpact");
1283 if (use_overlapped_read_histogram) {
1284 UMA_HISTOGRAM_MEDIUM_TIMES(
1285 base::FieldTrial::MakeName("Net.HttpTimeToFirstByte",
1286 "OverlappedReadImpact"),
1287 to_start);
1288 }
1289
[email protected]5c68d692011-08-24 04:59:411290 static const bool use_warm_socket_impact_histogram =
1291 base::FieldTrialList::TrialExists("WarmSocketImpact");
1292 if (use_warm_socket_impact_histogram) {
1293 UMA_HISTOGRAM_MEDIUM_TIMES(
1294 base::FieldTrial::MakeName("Net.HttpTimeToFirstByte",
1295 "WarmSocketImpact"),
1296 to_start);
1297 }
1298
[email protected]ce0a5a92011-12-27 19:56:141299 static const bool use_prefetch_histogram =
1300 base::FieldTrialList::TrialExists("Prefetch");
1301 if (use_prefetch_histogram) {
1302 UMA_HISTOGRAM_MEDIUM_TIMES(
1303 base::FieldTrial::MakeName("Net.HttpTimeToFirstByte",
1304 "Prefetch"),
1305 to_start);
1306 }
[email protected]ca17f372011-12-27 17:44:431307 static const bool use_prerender_histogram =
1308 base::FieldTrialList::TrialExists("Prerender");
1309 if (use_prerender_histogram) {
[email protected]8684a8812011-03-22 13:59:381310 UMA_HISTOGRAM_MEDIUM_TIMES(
1311 base::FieldTrial::MakeName("Net.HttpTimeToFirstByte",
[email protected]ca17f372011-12-27 17:44:431312 "Prerender"),
[email protected]8684a8812011-03-22 13:59:381313 to_start);
1314 }
[email protected]ec23f522011-02-22 21:01:381315}
1316
1317void URLRequestHttpJob::ResetTimer() {
1318 if (!request_creation_time_.is_null()) {
1319 NOTREACHED()
1320 << "The timer was reset before it was recorded.";
1321 return;
1322 }
1323 request_creation_time_ = base::Time::Now();
1324}
1325
[email protected]dd29bcd72011-03-24 00:03:441326void URLRequestHttpJob::UpdatePacketReadTimes() {
1327 if (!packet_timing_enabled_)
1328 return;
1329
1330 if (filter_input_byte_count() <= bytes_observed_in_packets_) {
1331 DCHECK_EQ(filter_input_byte_count(), bytes_observed_in_packets_);
1332 return; // No new bytes have arrived.
1333 }
1334
[email protected]d6b55392011-08-05 04:04:351335 final_packet_time_ = base::Time::Now();
[email protected]dd29bcd72011-03-24 00:03:441336 if (!bytes_observed_in_packets_)
1337 request_time_snapshot_ = request_ ? request_->request_time() : base::Time();
1338
[email protected]dd29bcd72011-03-24 00:03:441339 bytes_observed_in_packets_ = filter_input_byte_count();
1340}
1341
1342void URLRequestHttpJob::RecordPacketStats(
1343 FilterContext::StatisticSelector statistic) const {
1344 if (!packet_timing_enabled_ || (final_packet_time_ == base::Time()))
1345 return;
1346
1347 base::TimeDelta duration = final_packet_time_ - request_time_snapshot_;
1348 switch (statistic) {
1349 case FilterContext::SDCH_DECODE: {
[email protected]dd29bcd72011-03-24 00:03:441350 UMA_HISTOGRAM_CUSTOM_COUNTS("Sdch3.Network_Decode_Bytes_Processed_b",
1351 static_cast<int>(bytes_observed_in_packets_), 500, 100000, 100);
[email protected]dd29bcd72011-03-24 00:03:441352 return;
1353 }
1354 case FilterContext::SDCH_PASSTHROUGH: {
1355 // Despite advertising a dictionary, we handled non-sdch compressed
1356 // content.
[email protected]dd29bcd72011-03-24 00:03:441357 return;
1358 }
1359
1360 case FilterContext::SDCH_EXPERIMENT_DECODE: {
[email protected]d6b55392011-08-05 04:04:351361 UMA_HISTOGRAM_CUSTOM_TIMES("Sdch3.Experiment2_Decode",
[email protected]dd29bcd72011-03-24 00:03:441362 duration,
1363 base::TimeDelta::FromMilliseconds(20),
1364 base::TimeDelta::FromMinutes(10), 100);
[email protected]dd29bcd72011-03-24 00:03:441365 return;
1366 }
1367 case FilterContext::SDCH_EXPERIMENT_HOLDBACK: {
[email protected]d6b55392011-08-05 04:04:351368 UMA_HISTOGRAM_CUSTOM_TIMES("Sdch3.Experiment2_Holdback",
[email protected]dd29bcd72011-03-24 00:03:441369 duration,
1370 base::TimeDelta::FromMilliseconds(20),
1371 base::TimeDelta::FromMinutes(10), 100);
[email protected]dd29bcd72011-03-24 00:03:441372 return;
1373 }
1374 default:
1375 NOTREACHED();
1376 return;
1377 }
1378}
1379
1380// The common type of histogram we use for all compression-tracking histograms.
1381#define COMPRESSION_HISTOGRAM(name, sample) \
1382 do { \
1383 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.Compress." name, sample, \
1384 500, 1000000, 100); \
[email protected]b7996452011-10-31 19:30:561385 } while (0)
[email protected]dd29bcd72011-03-24 00:03:441386
1387void URLRequestHttpJob::RecordCompressionHistograms() {
1388 DCHECK(request_);
1389 if (!request_)
1390 return;
1391
1392 if (is_cached_content_ || // Don't record cached content
1393 !GetStatus().is_success() || // Don't record failed content
1394 !IsCompressibleContent() || // Only record compressible content
1395 !prefilter_bytes_read()) // Zero-byte responses aren't useful.
1396 return;
1397
1398 // Miniature requests aren't really compressible. Don't count them.
1399 const int kMinSize = 16;
1400 if (prefilter_bytes_read() < kMinSize)
1401 return;
1402
1403 // Only record for http or https urls.
1404 bool is_http = request_->url().SchemeIs("http");
1405 bool is_https = request_->url().SchemeIs("https");
1406 if (!is_http && !is_https)
1407 return;
1408
1409 int compressed_B = prefilter_bytes_read();
1410 int decompressed_B = postfilter_bytes_read();
1411 bool was_filtered = HasFilter();
1412
1413 // We want to record how often downloaded resources are compressed.
1414 // But, we recognize that different protocols may have different
1415 // properties. So, for each request, we'll put it into one of 3
1416 // groups:
1417 // a) SSL resources
1418 // Proxies cannot tamper with compression headers with SSL.
1419 // b) Non-SSL, loaded-via-proxy resources
1420 // In this case, we know a proxy might have interfered.
1421 // c) Non-SSL, loaded-without-proxy resources
1422 // In this case, we know there was no explicit proxy. However,
1423 // it is possible that a transparent proxy was still interfering.
1424 //
1425 // For each group, we record the same 3 histograms.
1426
1427 if (is_https) {
1428 if (was_filtered) {
1429 COMPRESSION_HISTOGRAM("SSL.BytesBeforeCompression", compressed_B);
1430 COMPRESSION_HISTOGRAM("SSL.BytesAfterCompression", decompressed_B);
1431 } else {
1432 COMPRESSION_HISTOGRAM("SSL.ShouldHaveBeenCompressed", decompressed_B);
1433 }
1434 return;
1435 }
1436
1437 if (request_->was_fetched_via_proxy()) {
1438 if (was_filtered) {
1439 COMPRESSION_HISTOGRAM("Proxy.BytesBeforeCompression", compressed_B);
1440 COMPRESSION_HISTOGRAM("Proxy.BytesAfterCompression", decompressed_B);
1441 } else {
1442 COMPRESSION_HISTOGRAM("Proxy.ShouldHaveBeenCompressed", decompressed_B);
1443 }
1444 return;
1445 }
1446
1447 if (was_filtered) {
1448 COMPRESSION_HISTOGRAM("NoProxy.BytesBeforeCompression", compressed_B);
1449 COMPRESSION_HISTOGRAM("NoProxy.BytesAfterCompression", decompressed_B);
1450 } else {
1451 COMPRESSION_HISTOGRAM("NoProxy.ShouldHaveBeenCompressed", decompressed_B);
1452 }
1453}
1454
1455bool URLRequestHttpJob::IsCompressibleContent() const {
1456 std::string mime_type;
1457 return GetMimeType(&mime_type) &&
1458 (IsSupportedJavascriptMimeType(mime_type.c_str()) ||
1459 IsSupportedNonImageMimeType(mime_type.c_str()));
1460}
1461
[email protected]bbaea8f2011-06-24 00:11:011462void URLRequestHttpJob::RecordPerfHistograms(CompletionCause reason) {
1463 if (start_time_.is_null())
1464 return;
1465
1466 base::TimeDelta total_time = base::TimeTicks::Now() - start_time_;
1467 UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTime", total_time);
1468
1469 if (reason == FINISHED) {
1470 UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeSuccess", total_time);
1471 } else {
1472 UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeCancel", total_time);
1473 }
1474
[email protected]4b4d20242012-02-23 18:27:461475 if (response_info_) {
1476 if (response_info_->was_cached) {
1477 UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeCached", total_time);
1478 } else {
1479 UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeNotCached", total_time);
[email protected]b73656ca2011-07-22 17:42:171480 }
[email protected]bbaea8f2011-06-24 00:11:011481 }
1482
[email protected]135c126a2012-10-31 15:39:251483 static const bool use_overlapped_read_histogram =
1484 base::FieldTrialList::TrialExists("OverlappedReadImpact");
1485 if (use_overlapped_read_histogram) {
1486 UMA_HISTOGRAM_TIMES(
1487 base::FieldTrial::MakeName("Net.HttpJob.TotalTime",
1488 "OverlappedReadImpact"),
1489 total_time);
1490
1491 if (reason == FINISHED) {
1492 UMA_HISTOGRAM_TIMES(
1493 base::FieldTrial::MakeName("Net.HttpJob.TotalTimeSuccess",
1494 "OverlappedReadImpact"),
1495 total_time);
1496 } else {
1497 UMA_HISTOGRAM_TIMES(
1498 base::FieldTrial::MakeName("Net.HttpJob.TotalTimeCancel",
1499 "OverlappedReadImpact"),
1500 total_time);
1501 }
1502
1503 if (response_info_) {
1504 if (response_info_->was_cached) {
1505 UMA_HISTOGRAM_TIMES(
1506 base::FieldTrial::MakeName("Net.HttpJob.TotalTimeCached",
1507 "OverlappedReadImpact"),
1508 total_time);
1509 } else {
1510 UMA_HISTOGRAM_TIMES(
1511 base::FieldTrial::MakeName("Net.HttpJob.TotalTimeNotCached",
1512 "OverlappedReadImpact"),
1513 total_time);
1514 }
1515 }
1516 }
1517
[email protected]908dc2b02012-11-27 23:16:261518 static const bool cache_sensitivity_analysis =
1519 base::FieldTrialList::TrialExists("CacheSensitivityAnalysis");
1520 if (cache_sensitivity_analysis) {
1521 UMA_HISTOGRAM_TIMES(
1522 base::FieldTrial::MakeName("Net.HttpJob.TotalTime",
1523 "CacheSensitivityAnalysis"),
1524 total_time);
1525
1526 if (reason == FINISHED) {
1527 UMA_HISTOGRAM_TIMES(
1528 base::FieldTrial::MakeName("Net.HttpJob.TotalTimeSuccess",
1529 "CacheSensitivityAnalysis"),
1530 total_time);
1531 } else {
1532 UMA_HISTOGRAM_TIMES(
1533 base::FieldTrial::MakeName("Net.HttpJob.TotalTimeCancel",
1534 "CacheSensitivityAnalysis"),
1535 total_time);
1536 }
1537
1538 if (response_info_) {
1539 if (response_info_->was_cached) {
1540 UMA_HISTOGRAM_TIMES(
1541 base::FieldTrial::MakeName("Net.HttpJob.TotalTimeCached",
1542 "CacheSensitivityAnalysis"),
1543 total_time);
1544 } else {
1545 UMA_HISTOGRAM_TIMES(
1546 base::FieldTrial::MakeName("Net.HttpJob.TotalTimeNotCached",
1547 "CacheSensitivityAnalysis"),
1548 total_time);
1549 }
1550 }
1551 }
1552
[email protected]bbaea8f2011-06-24 00:11:011553 start_time_ = base::TimeTicks();
1554}
1555
1556void URLRequestHttpJob::DoneWithRequest(CompletionCause reason) {
1557 if (done_)
1558 return;
1559 done_ = true;
[email protected]bbaea8f2011-06-24 00:11:011560 RecordPerfHistograms(reason);
[email protected]7a299a92012-10-24 23:54:501561 if (reason == FINISHED) {
1562 request_->set_received_response_content_length(prefilter_bytes_read());
[email protected]bbaea8f2011-06-24 00:11:011563 RecordCompressionHistograms();
[email protected]7a299a92012-10-24 23:54:501564 }
[email protected]bbaea8f2011-06-24 00:11:011565}
1566
[email protected]ea8141e2011-10-05 13:12:511567HttpResponseHeaders* URLRequestHttpJob::GetResponseHeaders() const {
1568 DCHECK(transaction_.get());
1569 DCHECK(transaction_->GetResponseInfo());
1570 return override_response_headers_.get() ?
1571 override_response_headers_ :
1572 transaction_->GetResponseInfo()->headers;
1573}
1574
1575void URLRequestHttpJob::NotifyURLRequestDestroyed() {
1576 awaiting_callback_ = false;
1577}
1578
[email protected]5a07c192012-07-30 20:18:221579void URLRequestHttpJob::OnDetachRequest() {
1580 http_transaction_delegate_->OnDetachRequest();
1581}
1582
[email protected]4f5656c62010-12-13 10:47:091583} // namespace net