OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/url_request/url_request_http_job.h" | 5 #include "net/url_request/url_request_http_job.h" |
6 | 6 |
7 #include "base/base_switches.h" | 7 #include "base/base_switches.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/bind_helpers.h" | 9 #include "base/bind_helpers.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 explicit HttpFilterContext(URLRequestHttpJob* job); | 58 explicit HttpFilterContext(URLRequestHttpJob* job); |
59 ~HttpFilterContext() override; | 59 ~HttpFilterContext() override; |
60 | 60 |
61 // FilterContext implementation. | 61 // FilterContext implementation. |
62 bool GetMimeType(std::string* mime_type) const override; | 62 bool GetMimeType(std::string* mime_type) const override; |
63 bool GetURL(GURL* gurl) const override; | 63 bool GetURL(GURL* gurl) const override; |
64 bool GetContentDisposition(std::string* disposition) const override; | 64 bool GetContentDisposition(std::string* disposition) const override; |
65 base::Time GetRequestTime() const override; | 65 base::Time GetRequestTime() const override; |
66 bool IsCachedContent() const override; | 66 bool IsCachedContent() const override; |
67 bool IsDownload() const override; | 67 bool IsDownload() const override; |
68 bool SdchResponseExpected() const override; | 68 SdchManager::DictionarySet* SdchDictionariesAdvertised() const override; |
69 int64 GetByteReadCount() const override; | 69 int64 GetByteReadCount() const override; |
70 int GetResponseCode() const override; | 70 int GetResponseCode() const override; |
71 const URLRequestContext* GetURLRequestContext() const override; | 71 const URLRequestContext* GetURLRequestContext() const override; |
72 void RecordPacketStats(StatisticSelector statistic) const override; | 72 void RecordPacketStats(StatisticSelector statistic) const override; |
73 | 73 |
74 // Method to allow us to reset filter context for a response that should have | |
75 // been SDCH encoded when there is an update due to an explicit HTTP header. | |
76 void ResetSdchResponseToFalse(); | |
77 | |
78 private: | 74 private: |
79 URLRequestHttpJob* job_; | 75 URLRequestHttpJob* job_; |
80 | 76 |
81 DISALLOW_COPY_AND_ASSIGN(HttpFilterContext); | 77 DISALLOW_COPY_AND_ASSIGN(HttpFilterContext); |
82 }; | 78 }; |
83 | 79 |
84 URLRequestHttpJob::HttpFilterContext::HttpFilterContext(URLRequestHttpJob* job) | 80 URLRequestHttpJob::HttpFilterContext::HttpFilterContext(URLRequestHttpJob* job) |
85 : job_(job) { | 81 : job_(job) { |
86 DCHECK(job_); | 82 DCHECK(job_); |
87 } | 83 } |
(...skipping 25 matching lines...) Expand all Loading... |
113 } | 109 } |
114 | 110 |
115 bool URLRequestHttpJob::HttpFilterContext::IsCachedContent() const { | 111 bool URLRequestHttpJob::HttpFilterContext::IsCachedContent() const { |
116 return job_->is_cached_content_; | 112 return job_->is_cached_content_; |
117 } | 113 } |
118 | 114 |
119 bool URLRequestHttpJob::HttpFilterContext::IsDownload() const { | 115 bool URLRequestHttpJob::HttpFilterContext::IsDownload() const { |
120 return (job_->request_info_.load_flags & LOAD_IS_DOWNLOAD) != 0; | 116 return (job_->request_info_.load_flags & LOAD_IS_DOWNLOAD) != 0; |
121 } | 117 } |
122 | 118 |
123 void URLRequestHttpJob::HttpFilterContext::ResetSdchResponseToFalse() { | 119 SdchManager::DictionarySet* |
124 DCHECK(job_->sdch_dictionary_advertised_); | 120 URLRequestHttpJob::HttpFilterContext::SdchDictionariesAdvertised() const { |
125 job_->sdch_dictionary_advertised_ = false; | 121 return job_->dictionaries_advertised_.get(); |
126 } | |
127 | |
128 bool URLRequestHttpJob::HttpFilterContext::SdchResponseExpected() const { | |
129 return job_->sdch_dictionary_advertised_; | |
130 } | 122 } |
131 | 123 |
132 int64 URLRequestHttpJob::HttpFilterContext::GetByteReadCount() const { | 124 int64 URLRequestHttpJob::HttpFilterContext::GetByteReadCount() const { |
133 return job_->filter_input_byte_count(); | 125 return job_->filter_input_byte_count(); |
134 } | 126 } |
135 | 127 |
136 int URLRequestHttpJob::HttpFilterContext::GetResponseCode() const { | 128 int URLRequestHttpJob::HttpFilterContext::GetResponseCode() const { |
137 return job_->GetResponseCode(); | 129 return job_->GetResponseCode(); |
138 } | 130 } |
139 | 131 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 response_cookies_save_index_(0), | 175 response_cookies_save_index_(0), |
184 proxy_auth_state_(AUTH_STATE_DONT_NEED_AUTH), | 176 proxy_auth_state_(AUTH_STATE_DONT_NEED_AUTH), |
185 server_auth_state_(AUTH_STATE_DONT_NEED_AUTH), | 177 server_auth_state_(AUTH_STATE_DONT_NEED_AUTH), |
186 start_callback_(base::Bind(&URLRequestHttpJob::OnStartCompleted, | 178 start_callback_(base::Bind(&URLRequestHttpJob::OnStartCompleted, |
187 base::Unretained(this))), | 179 base::Unretained(this))), |
188 notify_before_headers_sent_callback_( | 180 notify_before_headers_sent_callback_( |
189 base::Bind(&URLRequestHttpJob::NotifyBeforeSendHeadersCallback, | 181 base::Bind(&URLRequestHttpJob::NotifyBeforeSendHeadersCallback, |
190 base::Unretained(this))), | 182 base::Unretained(this))), |
191 read_in_progress_(false), | 183 read_in_progress_(false), |
192 throttling_entry_(NULL), | 184 throttling_entry_(NULL), |
193 sdch_dictionary_advertised_(false), | |
194 sdch_test_activated_(false), | 185 sdch_test_activated_(false), |
195 sdch_test_control_(false), | 186 sdch_test_control_(false), |
196 is_cached_content_(false), | 187 is_cached_content_(false), |
197 request_creation_time_(), | 188 request_creation_time_(), |
198 packet_timing_enabled_(false), | 189 packet_timing_enabled_(false), |
199 done_(false), | 190 done_(false), |
200 bytes_observed_in_packets_(0), | 191 bytes_observed_in_packets_(0), |
201 request_time_snapshot_(), | 192 request_time_snapshot_(), |
202 final_packet_time_(), | 193 final_packet_time_(), |
203 filter_context_(new HttpFilterContext(this)), | 194 filter_context_(new HttpFilterContext(this)), |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 if (!is_cached_content_ && throttling_entry_.get()) { | 304 if (!is_cached_content_ && throttling_entry_.get()) { |
314 URLRequestThrottlerHeaderAdapter response_adapter(GetResponseHeaders()); | 305 URLRequestThrottlerHeaderAdapter response_adapter(GetResponseHeaders()); |
315 throttling_entry_->UpdateWithResponse(request_info_.url.host(), | 306 throttling_entry_->UpdateWithResponse(request_info_.url.host(), |
316 &response_adapter); | 307 &response_adapter); |
317 } | 308 } |
318 | 309 |
319 // The ordering of these calls is not important. | 310 // The ordering of these calls is not important. |
320 ProcessStrictTransportSecurityHeader(); | 311 ProcessStrictTransportSecurityHeader(); |
321 ProcessPublicKeyPinsHeader(); | 312 ProcessPublicKeyPinsHeader(); |
322 | 313 |
| 314 // Handle the server notification of a new SDCH dictionary. |
323 SdchManager* sdch_manager(request()->context()->sdch_manager()); | 315 SdchManager* sdch_manager(request()->context()->sdch_manager()); |
324 if (sdch_manager && sdch_manager->IsInSupportedDomain(request_->url())) { | 316 if (sdch_manager && sdch_manager->IsInSupportedDomain(request_->url())) { |
325 const std::string name = "Get-Dictionary"; | 317 const std::string name = "Get-Dictionary"; |
326 std::string url_text; | 318 std::string url_text; |
327 void* iter = NULL; | 319 void* iter = NULL; |
328 // TODO(jar): We need to not fetch dictionaries the first time they are | 320 // TODO(jar): We need to not fetch dictionaries the first time they are |
329 // seen, but rather wait until we can justify their usefulness. | 321 // seen, but rather wait until we can justify their usefulness. |
330 // For now, we will only fetch the first dictionary, which will at least | 322 // For now, we will only fetch the first dictionary, which will at least |
331 // require multiple suggestions before we get additional ones for this site. | 323 // require multiple suggestions before we get additional ones for this site. |
332 // Eventually we should wait until a dictionary is requested several times | 324 // Eventually we should wait until a dictionary is requested several times |
333 // before we even download it (so that we don't waste memory or bandwidth). | 325 // before we even download it (so that we don't waste memory or bandwidth). |
334 if (GetResponseHeaders()->EnumerateHeader(&iter, name, &url_text)) { | 326 if (GetResponseHeaders()->EnumerateHeader(&iter, name, &url_text)) { |
335 // Resolve suggested URL relative to request url. | 327 // Resolve suggested URL relative to request url. |
336 GURL sdch_dictionary_url = request_->url().Resolve(url_text); | 328 GURL sdch_dictionary_url = request_->url().Resolve(url_text); |
337 if (sdch_dictionary_url.is_valid()) { | 329 if (sdch_dictionary_url.is_valid()) { |
338 sdch_manager->OnGetDictionary(request_->url(), sdch_dictionary_url); | 330 sdch_manager->OnGetDictionary(request_->url(), sdch_dictionary_url); |
339 } | 331 } |
340 } | 332 } |
341 } | 333 } |
342 | 334 |
| 335 // Handle the server signalling no SDCH encoding. |
| 336 if (dictionaries_advertised_.get()) { |
| 337 // We are wary of proxies that discard or damage SDCH encoding. If a server |
| 338 // explicitly states that this is not SDCH content, then we can correct our |
| 339 // assumption that this is an SDCH response, and avoid the need to recover |
| 340 // as though the content is corrupted (when we discover it is not SDCH |
| 341 // encoded). |
| 342 std::string sdch_response_status; |
| 343 void* iter = NULL; |
| 344 while (GetResponseHeaders()->EnumerateHeader(&iter, "X-Sdch-Encode", |
| 345 &sdch_response_status)) { |
| 346 if (sdch_response_status == "0") { |
| 347 dictionaries_advertised_.reset(); |
| 348 break; |
| 349 } |
| 350 } |
| 351 } |
| 352 |
343 // The HTTP transaction may be restarted several times for the purposes | 353 // The HTTP transaction may be restarted several times for the purposes |
344 // of sending authorization information. Each time it restarts, we get | 354 // of sending authorization information. Each time it restarts, we get |
345 // notified of the headers completion so that we can update the cookie store. | 355 // notified of the headers completion so that we can update the cookie store. |
346 if (transaction_->IsReadyToRestartForAuth()) { | 356 if (transaction_->IsReadyToRestartForAuth()) { |
347 DCHECK(!response_info_->auth_challenge.get()); | 357 DCHECK(!response_info_->auth_challenge.get()); |
348 // TODO(battre): This breaks the webrequest API for | 358 // TODO(battre): This breaks the webrequest API for |
349 // URLRequestTestHTTP.BasicAuthWithCookies | 359 // URLRequestTestHTTP.BasicAuthWithCookies |
350 // where OnBeforeSendHeaders -> OnSendHeaders -> OnBeforeSendHeaders | 360 // where OnBeforeSendHeaders -> OnSendHeaders -> OnBeforeSendHeaders |
351 // occurs. | 361 // occurs. |
352 RestartTransactionWithAuth(AuthCredentials()); | 362 RestartTransactionWithAuth(AuthCredentials()); |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
483 // simple_data_source. | 493 // simple_data_source. |
484 if (!request_info_.extra_headers.HasHeader( | 494 if (!request_info_.extra_headers.HasHeader( |
485 HttpRequestHeaders::kAcceptEncoding)) { | 495 HttpRequestHeaders::kAcceptEncoding)) { |
486 bool advertise_sdch = sdch_manager && | 496 bool advertise_sdch = sdch_manager && |
487 // We don't support SDCH responses to POST as there is a possibility | 497 // We don't support SDCH responses to POST as there is a possibility |
488 // of having SDCH encoded responses returned (e.g. by the cache) | 498 // of having SDCH encoded responses returned (e.g. by the cache) |
489 // which we cannot decode, and in those situations, we will need | 499 // which we cannot decode, and in those situations, we will need |
490 // to retransmit the request without SDCH, which is illegal for a POST. | 500 // to retransmit the request without SDCH, which is illegal for a POST. |
491 request()->method() != "POST" && | 501 request()->method() != "POST" && |
492 sdch_manager->IsInSupportedDomain(request_->url()); | 502 sdch_manager->IsInSupportedDomain(request_->url()); |
493 std::string avail_dictionaries; | |
494 if (advertise_sdch) { | 503 if (advertise_sdch) { |
495 sdch_manager->GetAvailDictionaryList(request_->url(), | 504 dictionaries_advertised_ = |
496 &avail_dictionaries); | 505 sdch_manager->GetDictionarySet(request_->url()); |
| 506 } |
497 | 507 |
498 // The AllowLatencyExperiment() is only true if we've successfully done a | 508 // The AllowLatencyExperiment() is only true if we've successfully done a |
499 // full SDCH compression recently in this browser session for this host. | 509 // full SDCH compression recently in this browser session for this host. |
500 // Note that for this path, there might be no applicable dictionaries, | 510 // Note that for this path, there might be no applicable dictionaries, |
501 // and hence we can't participate in the experiment. | 511 // and hence we can't participate in the experiment. |
502 if (!avail_dictionaries.empty() && | 512 if (dictionaries_advertised_.get() && |
503 sdch_manager->AllowLatencyExperiment(request_->url())) { | 513 sdch_manager->AllowLatencyExperiment(request_->url())) { |
504 // We are participating in the test (or control), and hence we'll | 514 // We are participating in the test (or control), and hence we'll |
505 // eventually record statistics via either SDCH_EXPERIMENT_DECODE or | 515 // eventually record statistics via either SDCH_EXPERIMENT_DECODE or |
506 // SDCH_EXPERIMENT_HOLDBACK, and we'll need some packet timing data. | 516 // SDCH_EXPERIMENT_HOLDBACK, and we'll need some packet timing data. |
507 packet_timing_enabled_ = true; | 517 packet_timing_enabled_ = true; |
508 if (base::RandDouble() < .01) { | 518 if (base::RandDouble() < .01) { |
509 sdch_test_control_ = true; // 1% probability. | 519 sdch_test_control_ = true; // 1% probability. |
510 advertise_sdch = false; | 520 dictionaries_advertised_.reset(); |
511 } else { | 521 advertise_sdch = false; |
512 sdch_test_activated_ = true; | 522 } else { |
513 } | 523 sdch_test_activated_ = true; |
514 } | 524 } |
515 } | 525 } |
516 | 526 |
517 // Supply Accept-Encoding headers first so that it is more likely that they | 527 // Supply Accept-Encoding headers first so that it is more likely that they |
518 // will be in the first transmitted packet. This can sometimes make it | 528 // will be in the first transmitted packet. This can sometimes make it |
519 // easier to filter and analyze the streams to assure that a proxy has not | 529 // easier to filter and analyze the streams to assure that a proxy has not |
520 // damaged these headers. Some proxies deliberately corrupt Accept-Encoding | 530 // damaged these headers. Some proxies deliberately corrupt Accept-Encoding |
521 // headers. | 531 // headers. |
522 if (!advertise_sdch) { | 532 if (!advertise_sdch) { |
523 // Tell the server what compression formats we support (other than SDCH). | 533 // Tell the server what compression formats we support (other than SDCH). |
524 request_info_.extra_headers.SetHeader( | 534 request_info_.extra_headers.SetHeader( |
525 HttpRequestHeaders::kAcceptEncoding, "gzip, deflate"); | 535 HttpRequestHeaders::kAcceptEncoding, "gzip, deflate"); |
526 } else { | 536 } else { |
527 // Include SDCH in acceptable list. | 537 // Include SDCH in acceptable list. |
528 request_info_.extra_headers.SetHeader( | 538 request_info_.extra_headers.SetHeader( |
529 HttpRequestHeaders::kAcceptEncoding, "gzip, deflate, sdch"); | 539 HttpRequestHeaders::kAcceptEncoding, "gzip, deflate, sdch"); |
530 if (!avail_dictionaries.empty()) { | 540 if (dictionaries_advertised_.get()) { |
| 541 std::string avail_dictionaries; |
| 542 dictionaries_advertised_->GetDictionaryClientHashList( |
| 543 &avail_dictionaries); |
| 544 |
531 request_info_.extra_headers.SetHeader( | 545 request_info_.extra_headers.SetHeader( |
532 kAvailDictionaryHeader, | 546 kAvailDictionaryHeader, |
533 avail_dictionaries); | 547 avail_dictionaries); |
534 sdch_dictionary_advertised_ = true; | |
535 // Since we're tagging this transaction as advertising a dictionary, | 548 // Since we're tagging this transaction as advertising a dictionary, |
536 // we'll definitely employ an SDCH filter (or tentative sdch filter) | 549 // we'll definitely employ an SDCH filter (or tentative sdch filter) |
537 // when we get a response. When done, we'll record histograms via | 550 // when we get a response. When done, we'll record histograms via |
538 // SDCH_DECODE or SDCH_PASSTHROUGH. Hence we need to record packet | 551 // SDCH_DECODE or SDCH_PASSTHROUGH. Hence we need to record packet |
539 // arrival times. | 552 // arrival times. |
540 packet_timing_enabled_ = true; | 553 packet_timing_enabled_ = true; |
541 } | 554 } |
542 } | 555 } |
543 } | 556 } |
544 | 557 |
(...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1023 return NULL; | 1036 return NULL; |
1024 | 1037 |
1025 std::vector<Filter::FilterType> encoding_types; | 1038 std::vector<Filter::FilterType> encoding_types; |
1026 std::string encoding_type; | 1039 std::string encoding_type; |
1027 HttpResponseHeaders* headers = GetResponseHeaders(); | 1040 HttpResponseHeaders* headers = GetResponseHeaders(); |
1028 void* iter = NULL; | 1041 void* iter = NULL; |
1029 while (headers->EnumerateHeader(&iter, "Content-Encoding", &encoding_type)) { | 1042 while (headers->EnumerateHeader(&iter, "Content-Encoding", &encoding_type)) { |
1030 encoding_types.push_back(Filter::ConvertEncodingToType(encoding_type)); | 1043 encoding_types.push_back(Filter::ConvertEncodingToType(encoding_type)); |
1031 } | 1044 } |
1032 | 1045 |
1033 if (filter_context_->SdchResponseExpected()) { | |
1034 // We are wary of proxies that discard or damage SDCH encoding. If a server | |
1035 // explicitly states that this is not SDCH content, then we can correct our | |
1036 // assumption that this is an SDCH response, and avoid the need to recover | |
1037 // as though the content is corrupted (when we discover it is not SDCH | |
1038 // encoded). | |
1039 std::string sdch_response_status; | |
1040 iter = NULL; | |
1041 while (headers->EnumerateHeader(&iter, "X-Sdch-Encode", | |
1042 &sdch_response_status)) { | |
1043 if (sdch_response_status == "0") { | |
1044 filter_context_->ResetSdchResponseToFalse(); | |
1045 break; | |
1046 } | |
1047 } | |
1048 } | |
1049 | |
1050 // Even if encoding types are empty, there is a chance that we need to add | 1046 // Even if encoding types are empty, there is a chance that we need to add |
1051 // some decoding, as some proxies strip encoding completely. In such cases, | 1047 // some decoding, as some proxies strip encoding completely. In such cases, |
1052 // we may need to add (for example) SDCH filtering (when the context suggests | 1048 // we may need to add (for example) SDCH filtering (when the context suggests |
1053 // it is appropriate). | 1049 // it is appropriate). |
1054 Filter::FixupEncodingTypes(*filter_context_, &encoding_types); | 1050 Filter::FixupEncodingTypes(*filter_context_, &encoding_types); |
1055 | 1051 |
1056 return !encoding_types.empty() | 1052 return !encoding_types.empty() |
1057 ? Filter::Factory(encoding_types, *filter_context_) : NULL; | 1053 ? Filter::Factory(encoding_types, *filter_context_) : NULL; |
1058 } | 1054 } |
1059 | 1055 |
(...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1528 return override_response_headers_.get() ? | 1524 return override_response_headers_.get() ? |
1529 override_response_headers_.get() : | 1525 override_response_headers_.get() : |
1530 transaction_->GetResponseInfo()->headers.get(); | 1526 transaction_->GetResponseInfo()->headers.get(); |
1531 } | 1527 } |
1532 | 1528 |
1533 void URLRequestHttpJob::NotifyURLRequestDestroyed() { | 1529 void URLRequestHttpJob::NotifyURLRequestDestroyed() { |
1534 awaiting_callback_ = false; | 1530 awaiting_callback_ = false; |
1535 } | 1531 } |
1536 | 1532 |
1537 } // namespace net | 1533 } // namespace net |
OLD | NEW |