| 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 |