| 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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 explicit HttpFilterContext(URLRequestHttpJob* job); | 59 explicit HttpFilterContext(URLRequestHttpJob* job); |
| 60 ~HttpFilterContext() override; | 60 ~HttpFilterContext() override; |
| 61 | 61 |
| 62 // FilterContext implementation. | 62 // FilterContext implementation. |
| 63 bool GetMimeType(std::string* mime_type) const override; | 63 bool GetMimeType(std::string* mime_type) const override; |
| 64 bool GetURL(GURL* gurl) const override; | 64 bool GetURL(GURL* gurl) const override; |
| 65 bool GetContentDisposition(std::string* disposition) const override; | 65 bool GetContentDisposition(std::string* disposition) const override; |
| 66 base::Time GetRequestTime() const override; | 66 base::Time GetRequestTime() const override; |
| 67 bool IsCachedContent() const override; | 67 bool IsCachedContent() const override; |
| 68 bool IsDownload() const override; | 68 bool IsDownload() const override; |
| 69 bool SdchResponseExpected() const override; | 69 SdchManager::DictionarySet* SdchDictionariesAdvertised() const override; |
| 70 int64 GetByteReadCount() const override; | 70 int64 GetByteReadCount() const override; |
| 71 int GetResponseCode() const override; | 71 int GetResponseCode() const override; |
| 72 const URLRequestContext* GetURLRequestContext() const override; | 72 const URLRequestContext* GetURLRequestContext() const override; |
| 73 void RecordPacketStats(StatisticSelector statistic) const override; | 73 void RecordPacketStats(StatisticSelector statistic) const override; |
| 74 const BoundNetLog& GetNetLog() const override; | 74 const BoundNetLog& GetNetLog() const override; |
| 75 | 75 |
| 76 // Method to allow us to reset filter context for a response that should have | |
| 77 // been SDCH encoded when there is an update due to an explicit HTTP header. | |
| 78 void ResetSdchResponseToFalse(); | |
| 79 | |
| 80 private: | 76 private: |
| 81 URLRequestHttpJob* job_; | 77 URLRequestHttpJob* job_; |
| 82 | 78 |
| 83 // URLRequestHttpJob may be detached from URLRequest, but we still need to | 79 // URLRequestHttpJob may be detached from URLRequest, but we still need to |
| 84 // return something. | 80 // return something. |
| 85 BoundNetLog dummy_log_; | 81 BoundNetLog dummy_log_; |
| 86 | 82 |
| 87 DISALLOW_COPY_AND_ASSIGN(HttpFilterContext); | 83 DISALLOW_COPY_AND_ASSIGN(HttpFilterContext); |
| 88 }; | 84 }; |
| 89 | 85 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 119 } | 115 } |
| 120 | 116 |
| 121 bool URLRequestHttpJob::HttpFilterContext::IsCachedContent() const { | 117 bool URLRequestHttpJob::HttpFilterContext::IsCachedContent() const { |
| 122 return job_->is_cached_content_; | 118 return job_->is_cached_content_; |
| 123 } | 119 } |
| 124 | 120 |
| 125 bool URLRequestHttpJob::HttpFilterContext::IsDownload() const { | 121 bool URLRequestHttpJob::HttpFilterContext::IsDownload() const { |
| 126 return (job_->request_info_.load_flags & LOAD_IS_DOWNLOAD) != 0; | 122 return (job_->request_info_.load_flags & LOAD_IS_DOWNLOAD) != 0; |
| 127 } | 123 } |
| 128 | 124 |
| 129 void URLRequestHttpJob::HttpFilterContext::ResetSdchResponseToFalse() { | 125 SdchManager::DictionarySet* |
| 130 DCHECK(job_->sdch_dictionary_advertised_); | 126 URLRequestHttpJob::HttpFilterContext::SdchDictionariesAdvertised() const { |
| 131 job_->sdch_dictionary_advertised_ = false; | 127 return job_->dictionaries_advertised_.get(); |
| 132 } | |
| 133 | |
| 134 bool URLRequestHttpJob::HttpFilterContext::SdchResponseExpected() const { | |
| 135 return job_->sdch_dictionary_advertised_; | |
| 136 } | 128 } |
| 137 | 129 |
| 138 int64 URLRequestHttpJob::HttpFilterContext::GetByteReadCount() const { | 130 int64 URLRequestHttpJob::HttpFilterContext::GetByteReadCount() const { |
| 139 return job_->filter_input_byte_count(); | 131 return job_->filter_input_byte_count(); |
| 140 } | 132 } |
| 141 | 133 |
| 142 int URLRequestHttpJob::HttpFilterContext::GetResponseCode() const { | 134 int URLRequestHttpJob::HttpFilterContext::GetResponseCode() const { |
| 143 return job_->GetResponseCode(); | 135 return job_->GetResponseCode(); |
| 144 } | 136 } |
| 145 | 137 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 response_cookies_save_index_(0), | 185 response_cookies_save_index_(0), |
| 194 proxy_auth_state_(AUTH_STATE_DONT_NEED_AUTH), | 186 proxy_auth_state_(AUTH_STATE_DONT_NEED_AUTH), |
| 195 server_auth_state_(AUTH_STATE_DONT_NEED_AUTH), | 187 server_auth_state_(AUTH_STATE_DONT_NEED_AUTH), |
| 196 start_callback_(base::Bind(&URLRequestHttpJob::OnStartCompleted, | 188 start_callback_(base::Bind(&URLRequestHttpJob::OnStartCompleted, |
| 197 base::Unretained(this))), | 189 base::Unretained(this))), |
| 198 notify_before_headers_sent_callback_( | 190 notify_before_headers_sent_callback_( |
| 199 base::Bind(&URLRequestHttpJob::NotifyBeforeSendHeadersCallback, | 191 base::Bind(&URLRequestHttpJob::NotifyBeforeSendHeadersCallback, |
| 200 base::Unretained(this))), | 192 base::Unretained(this))), |
| 201 read_in_progress_(false), | 193 read_in_progress_(false), |
| 202 throttling_entry_(NULL), | 194 throttling_entry_(NULL), |
| 203 sdch_dictionary_advertised_(false), | |
| 204 sdch_test_activated_(false), | 195 sdch_test_activated_(false), |
| 205 sdch_test_control_(false), | 196 sdch_test_control_(false), |
| 206 is_cached_content_(false), | 197 is_cached_content_(false), |
| 207 request_creation_time_(), | 198 request_creation_time_(), |
| 208 packet_timing_enabled_(false), | 199 packet_timing_enabled_(false), |
| 209 done_(false), | 200 done_(false), |
| 210 bytes_observed_in_packets_(0), | 201 bytes_observed_in_packets_(0), |
| 211 request_time_snapshot_(), | 202 request_time_snapshot_(), |
| 212 final_packet_time_(), | 203 final_packet_time_(), |
| 213 filter_context_(new HttpFilterContext(this)), | 204 filter_context_(new HttpFilterContext(this)), |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 if (!is_cached_content_ && throttling_entry_.get()) { | 314 if (!is_cached_content_ && throttling_entry_.get()) { |
| 324 URLRequestThrottlerHeaderAdapter response_adapter(GetResponseHeaders()); | 315 URLRequestThrottlerHeaderAdapter response_adapter(GetResponseHeaders()); |
| 325 throttling_entry_->UpdateWithResponse(request_info_.url.host(), | 316 throttling_entry_->UpdateWithResponse(request_info_.url.host(), |
| 326 &response_adapter); | 317 &response_adapter); |
| 327 } | 318 } |
| 328 | 319 |
| 329 // The ordering of these calls is not important. | 320 // The ordering of these calls is not important. |
| 330 ProcessStrictTransportSecurityHeader(); | 321 ProcessStrictTransportSecurityHeader(); |
| 331 ProcessPublicKeyPinsHeader(); | 322 ProcessPublicKeyPinsHeader(); |
| 332 | 323 |
| 324 // Handle the server notification of a new SDCH dictionary. |
| 333 SdchManager* sdch_manager(request()->context()->sdch_manager()); | 325 SdchManager* sdch_manager(request()->context()->sdch_manager()); |
| 334 if (sdch_manager) { | 326 if (sdch_manager) { |
| 335 SdchProblemCode rv = sdch_manager->IsInSupportedDomain(request()->url()); | 327 SdchProblemCode rv = sdch_manager->IsInSupportedDomain(request()->url()); |
| 336 if (rv != SDCH_OK) { | 328 if (rv != SDCH_OK) { |
| 337 // If SDCH is just disabled, it is not a real error. | 329 // If SDCH is just disabled, it is not a real error. |
| 338 if (rv != SDCH_DISABLED && rv != SDCH_SECURE_SCHEME_NOT_SUPPORTED) { | 330 if (rv != SDCH_DISABLED && rv != SDCH_SECURE_SCHEME_NOT_SUPPORTED) { |
| 339 SdchManager::SdchErrorRecovery(rv); | 331 SdchManager::SdchErrorRecovery(rv); |
| 340 request()->net_log().AddEvent( | 332 request()->net_log().AddEvent( |
| 341 NetLog::TYPE_SDCH_DECODING_ERROR, | 333 NetLog::TYPE_SDCH_DECODING_ERROR, |
| 342 base::Bind(&NetLogSdchResourceProblemCallback, rv)); | 334 base::Bind(&NetLogSdchResourceProblemCallback, rv)); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 364 request_->net_log().AddEvent( | 356 request_->net_log().AddEvent( |
| 365 NetLog::TYPE_SDCH_DICTIONARY_ERROR, | 357 NetLog::TYPE_SDCH_DICTIONARY_ERROR, |
| 366 base::Bind(&NetLogSdchDictionaryFetchProblemCallback, rv, | 358 base::Bind(&NetLogSdchDictionaryFetchProblemCallback, rv, |
| 367 sdch_dictionary_url, false)); | 359 sdch_dictionary_url, false)); |
| 368 } | 360 } |
| 369 } | 361 } |
| 370 } | 362 } |
| 371 } | 363 } |
| 372 } | 364 } |
| 373 | 365 |
| 366 // Handle the server signalling no SDCH encoding. |
| 367 if (dictionaries_advertised_.get()) { |
| 368 // We are wary of proxies that discard or damage SDCH encoding. If a server |
| 369 // explicitly states that this is not SDCH content, then we can correct our |
| 370 // assumption that this is an SDCH response, and avoid the need to recover |
| 371 // as though the content is corrupted (when we discover it is not SDCH |
| 372 // encoded). |
| 373 std::string sdch_response_status; |
| 374 void* iter = NULL; |
| 375 while (GetResponseHeaders()->EnumerateHeader(&iter, "X-Sdch-Encode", |
| 376 &sdch_response_status)) { |
| 377 if (sdch_response_status == "0") { |
| 378 dictionaries_advertised_.reset(); |
| 379 break; |
| 380 } |
| 381 } |
| 382 } |
| 383 |
| 374 // The HTTP transaction may be restarted several times for the purposes | 384 // The HTTP transaction may be restarted several times for the purposes |
| 375 // of sending authorization information. Each time it restarts, we get | 385 // of sending authorization information. Each time it restarts, we get |
| 376 // notified of the headers completion so that we can update the cookie store. | 386 // notified of the headers completion so that we can update the cookie store. |
| 377 if (transaction_->IsReadyToRestartForAuth()) { | 387 if (transaction_->IsReadyToRestartForAuth()) { |
| 378 DCHECK(!response_info_->auth_challenge.get()); | 388 DCHECK(!response_info_->auth_challenge.get()); |
| 379 // TODO(battre): This breaks the webrequest API for | 389 // TODO(battre): This breaks the webrequest API for |
| 380 // URLRequestTestHTTP.BasicAuthWithCookies | 390 // URLRequestTestHTTP.BasicAuthWithCookies |
| 381 // where OnBeforeSendHeaders -> OnSendHeaders -> OnBeforeSendHeaders | 391 // where OnBeforeSendHeaders -> OnSendHeaders -> OnBeforeSendHeaders |
| 382 // occurs. | 392 // occurs. |
| 383 RestartTransactionWithAuth(AuthCredentials()); | 393 RestartTransactionWithAuth(AuthCredentials()); |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 advertise_sdch = false; | 535 advertise_sdch = false; |
| 526 // If SDCH is just disabled, it is not a real error. | 536 // If SDCH is just disabled, it is not a real error. |
| 527 if (rv != SDCH_DISABLED && rv != SDCH_SECURE_SCHEME_NOT_SUPPORTED) { | 537 if (rv != SDCH_DISABLED && rv != SDCH_SECURE_SCHEME_NOT_SUPPORTED) { |
| 528 SdchManager::SdchErrorRecovery(rv); | 538 SdchManager::SdchErrorRecovery(rv); |
| 529 request()->net_log().AddEvent( | 539 request()->net_log().AddEvent( |
| 530 NetLog::TYPE_SDCH_DECODING_ERROR, | 540 NetLog::TYPE_SDCH_DECODING_ERROR, |
| 531 base::Bind(&NetLogSdchResourceProblemCallback, rv)); | 541 base::Bind(&NetLogSdchResourceProblemCallback, rv)); |
| 532 } | 542 } |
| 533 } | 543 } |
| 534 } | 544 } |
| 535 std::string avail_dictionaries; | |
| 536 if (advertise_sdch) { | 545 if (advertise_sdch) { |
| 537 sdch_manager->GetAvailDictionaryList(request_->url(), | 546 dictionaries_advertised_ = |
| 538 &avail_dictionaries); | 547 sdch_manager->GetDictionarySet(request_->url()); |
| 548 } |
| 539 | 549 |
| 540 // The AllowLatencyExperiment() is only true if we've successfully done a | 550 // The AllowLatencyExperiment() is only true if we've successfully done a |
| 541 // full SDCH compression recently in this browser session for this host. | 551 // full SDCH compression recently in this browser session for this host. |
| 542 // Note that for this path, there might be no applicable dictionaries, | 552 // Note that for this path, there might be no applicable dictionaries, |
| 543 // and hence we can't participate in the experiment. | 553 // and hence we can't participate in the experiment. |
| 544 if (!avail_dictionaries.empty() && | 554 if (dictionaries_advertised_.get() && |
| 545 sdch_manager->AllowLatencyExperiment(request_->url())) { | 555 sdch_manager->AllowLatencyExperiment(request_->url())) { |
| 546 // We are participating in the test (or control), and hence we'll | 556 // We are participating in the test (or control), and hence we'll |
| 547 // eventually record statistics via either SDCH_EXPERIMENT_DECODE or | 557 // eventually record statistics via either SDCH_EXPERIMENT_DECODE or |
| 548 // SDCH_EXPERIMENT_HOLDBACK, and we'll need some packet timing data. | 558 // SDCH_EXPERIMENT_HOLDBACK, and we'll need some packet timing data. |
| 549 packet_timing_enabled_ = true; | 559 packet_timing_enabled_ = true; |
| 550 if (base::RandDouble() < .01) { | 560 if (base::RandDouble() < .01) { |
| 551 sdch_test_control_ = true; // 1% probability. | 561 sdch_test_control_ = true; // 1% probability. |
| 552 advertise_sdch = false; | 562 dictionaries_advertised_.reset(); |
| 553 } else { | 563 advertise_sdch = false; |
| 554 sdch_test_activated_ = true; | 564 } else { |
| 555 } | 565 sdch_test_activated_ = true; |
| 556 } | 566 } |
| 557 } | 567 } |
| 558 | 568 |
| 559 // Supply Accept-Encoding headers first so that it is more likely that they | 569 // Supply Accept-Encoding headers first so that it is more likely that they |
| 560 // will be in the first transmitted packet. This can sometimes make it | 570 // will be in the first transmitted packet. This can sometimes make it |
| 561 // easier to filter and analyze the streams to assure that a proxy has not | 571 // easier to filter and analyze the streams to assure that a proxy has not |
| 562 // damaged these headers. Some proxies deliberately corrupt Accept-Encoding | 572 // damaged these headers. Some proxies deliberately corrupt Accept-Encoding |
| 563 // headers. | 573 // headers. |
| 564 if (!advertise_sdch) { | 574 if (!advertise_sdch) { |
| 565 // Tell the server what compression formats we support (other than SDCH). | 575 // Tell the server what compression formats we support (other than SDCH). |
| 566 request_info_.extra_headers.SetHeader( | 576 request_info_.extra_headers.SetHeader( |
| 567 HttpRequestHeaders::kAcceptEncoding, "gzip, deflate"); | 577 HttpRequestHeaders::kAcceptEncoding, "gzip, deflate"); |
| 568 } else { | 578 } else { |
| 569 // Include SDCH in acceptable list. | 579 // Include SDCH in acceptable list. |
| 570 request_info_.extra_headers.SetHeader( | 580 request_info_.extra_headers.SetHeader( |
| 571 HttpRequestHeaders::kAcceptEncoding, "gzip, deflate, sdch"); | 581 HttpRequestHeaders::kAcceptEncoding, "gzip, deflate, sdch"); |
| 572 if (!avail_dictionaries.empty()) { | 582 if (dictionaries_advertised_.get()) { |
| 573 request_info_.extra_headers.SetHeader( | 583 request_info_.extra_headers.SetHeader( |
| 574 kAvailDictionaryHeader, | 584 kAvailDictionaryHeader, |
| 575 avail_dictionaries); | 585 dictionaries_advertised_->GetDictionaryClientHashList()); |
| 576 sdch_dictionary_advertised_ = true; | |
| 577 // Since we're tagging this transaction as advertising a dictionary, | 586 // Since we're tagging this transaction as advertising a dictionary, |
| 578 // we'll definitely employ an SDCH filter (or tentative sdch filter) | 587 // we'll definitely employ an SDCH filter (or tentative sdch filter) |
| 579 // when we get a response. When done, we'll record histograms via | 588 // when we get a response. When done, we'll record histograms via |
| 580 // SDCH_DECODE or SDCH_PASSTHROUGH. Hence we need to record packet | 589 // SDCH_DECODE or SDCH_PASSTHROUGH. Hence we need to record packet |
| 581 // arrival times. | 590 // arrival times. |
| 582 packet_timing_enabled_ = true; | 591 packet_timing_enabled_ = true; |
| 583 } | 592 } |
| 584 } | 593 } |
| 585 } | 594 } |
| 586 | 595 |
| (...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1065 return NULL; | 1074 return NULL; |
| 1066 | 1075 |
| 1067 std::vector<Filter::FilterType> encoding_types; | 1076 std::vector<Filter::FilterType> encoding_types; |
| 1068 std::string encoding_type; | 1077 std::string encoding_type; |
| 1069 HttpResponseHeaders* headers = GetResponseHeaders(); | 1078 HttpResponseHeaders* headers = GetResponseHeaders(); |
| 1070 void* iter = NULL; | 1079 void* iter = NULL; |
| 1071 while (headers->EnumerateHeader(&iter, "Content-Encoding", &encoding_type)) { | 1080 while (headers->EnumerateHeader(&iter, "Content-Encoding", &encoding_type)) { |
| 1072 encoding_types.push_back(Filter::ConvertEncodingToType(encoding_type)); | 1081 encoding_types.push_back(Filter::ConvertEncodingToType(encoding_type)); |
| 1073 } | 1082 } |
| 1074 | 1083 |
| 1075 if (filter_context_->SdchResponseExpected()) { | |
| 1076 // We are wary of proxies that discard or damage SDCH encoding. If a server | |
| 1077 // explicitly states that this is not SDCH content, then we can correct our | |
| 1078 // assumption that this is an SDCH response, and avoid the need to recover | |
| 1079 // as though the content is corrupted (when we discover it is not SDCH | |
| 1080 // encoded). | |
| 1081 std::string sdch_response_status; | |
| 1082 iter = NULL; | |
| 1083 while (headers->EnumerateHeader(&iter, "X-Sdch-Encode", | |
| 1084 &sdch_response_status)) { | |
| 1085 if (sdch_response_status == "0") { | |
| 1086 filter_context_->ResetSdchResponseToFalse(); | |
| 1087 break; | |
| 1088 } | |
| 1089 } | |
| 1090 } | |
| 1091 | |
| 1092 // Even if encoding types are empty, there is a chance that we need to add | 1084 // Even if encoding types are empty, there is a chance that we need to add |
| 1093 // some decoding, as some proxies strip encoding completely. In such cases, | 1085 // some decoding, as some proxies strip encoding completely. In such cases, |
| 1094 // we may need to add (for example) SDCH filtering (when the context suggests | 1086 // we may need to add (for example) SDCH filtering (when the context suggests |
| 1095 // it is appropriate). | 1087 // it is appropriate). |
| 1096 Filter::FixupEncodingTypes(*filter_context_, &encoding_types); | 1088 Filter::FixupEncodingTypes(*filter_context_, &encoding_types); |
| 1097 | 1089 |
| 1098 return !encoding_types.empty() | 1090 return !encoding_types.empty() |
| 1099 ? Filter::Factory(encoding_types, *filter_context_) : NULL; | 1091 ? Filter::Factory(encoding_types, *filter_context_) : NULL; |
| 1100 } | 1092 } |
| 1101 | 1093 |
| (...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1570 return override_response_headers_.get() ? | 1562 return override_response_headers_.get() ? |
| 1571 override_response_headers_.get() : | 1563 override_response_headers_.get() : |
| 1572 transaction_->GetResponseInfo()->headers.get(); | 1564 transaction_->GetResponseInfo()->headers.get(); |
| 1573 } | 1565 } |
| 1574 | 1566 |
| 1575 void URLRequestHttpJob::NotifyURLRequestDestroyed() { | 1567 void URLRequestHttpJob::NotifyURLRequestDestroyed() { |
| 1576 awaiting_callback_ = false; | 1568 awaiting_callback_ = false; |
| 1577 } | 1569 } |
| 1578 | 1570 |
| 1579 } // namespace net | 1571 } // namespace net |
| OLD | NEW |