| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
| 8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
| 9 #include "base/file_version_info.h" | 9 #include "base/file_version_info.h" |
| 10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
| 11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
| 12 #include "net/base/cookie_monster.h" | 12 #include "net/base/cookie_monster.h" |
| 13 #include "net/base/filter.h" |
| 13 #include "net/base/load_flags.h" | 14 #include "net/base/load_flags.h" |
| 14 #include "net/base/net_errors.h" | 15 #include "net/base/net_errors.h" |
| 15 #include "net/base/net_util.h" | 16 #include "net/base/net_util.h" |
| 16 #include "net/base/sdch_manager.h" | 17 #include "net/base/sdch_manager.h" |
| 17 #include "net/http/http_response_info.h" | 18 #include "net/http/http_response_info.h" |
| 18 #include "net/http/http_transaction.h" | 19 #include "net/http/http_transaction.h" |
| 19 #include "net/http/http_transaction_factory.h" | 20 #include "net/http/http_transaction_factory.h" |
| 20 #include "net/url_request/url_request.h" | 21 #include "net/url_request/url_request.h" |
| 21 #include "net/url_request/url_request_error_job.h" | 22 #include "net/url_request/url_request_error_job.h" |
| 22 | 23 |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 int URLRequestHttpJob::GetResponseCode() { | 156 int URLRequestHttpJob::GetResponseCode() { |
| 156 DCHECK(transaction_.get()); | 157 DCHECK(transaction_.get()); |
| 157 | 158 |
| 158 if (!response_info_) | 159 if (!response_info_) |
| 159 return -1; | 160 return -1; |
| 160 | 161 |
| 161 return response_info_->headers->response_code(); | 162 return response_info_->headers->response_code(); |
| 162 } | 163 } |
| 163 | 164 |
| 164 bool URLRequestHttpJob::GetContentEncodings( | 165 bool URLRequestHttpJob::GetContentEncodings( |
| 165 std::vector<std::string>* encoding_types) { | 166 std::vector<Filter::FilterType>* encoding_types) { |
| 166 DCHECK(transaction_.get()); | 167 DCHECK(transaction_.get()); |
| 167 | |
| 168 if (!response_info_) | 168 if (!response_info_) |
| 169 return false; | 169 return false; |
| 170 DCHECK(encoding_types->empty()); |
| 170 | 171 |
| 171 std::string encoding_type; | 172 std::string encoding_type; |
| 172 void* iter = NULL; | 173 void* iter = NULL; |
| 173 while (response_info_->headers->EnumerateHeader(&iter, "Content-Encoding", | 174 while (response_info_->headers->EnumerateHeader(&iter, "Content-Encoding", |
| 174 &encoding_type)) { | 175 &encoding_type)) { |
| 175 encoding_types->push_back(StringToLowerASCII(encoding_type)); | 176 encoding_types->push_back(Filter::ConvertEncodingToType(encoding_type)); |
| 176 } | 177 } |
| 177 | 178 |
| 178 // TODO(jar): Transition to returning enums, rather than strings, and perform | 179 if (!encoding_types->empty()) { |
| 179 // all content encoding fixups here, rather than doing some in the | 180 std::string mime_type; |
| 180 // FilterFactor(). Note that enums generated can be more specific than mere | 181 GetMimeType(&mime_type); |
| 181 // restatement of strings. For example, rather than just having a GZIP | 182 Filter::FixupEncodingTypes(IsSdchResponse(), mime_type, encoding_types); |
| 182 // encoding we can have a GZIP_OPTIONAL encoding to help with odd SDCH related | |
| 183 // fixups. | |
| 184 | |
| 185 // TODO(jar): Refactor code so that content-encoding error recovery is | |
| 186 // testable via unit tests. | |
| 187 | |
| 188 if (!IsSdchResponse()) | |
| 189 return !encoding_types->empty(); | |
| 190 | |
| 191 // If content encoding included SDCH, then everything is fine. | |
| 192 if (!encoding_types->empty() && ("sdch" == encoding_types->front())) | |
| 193 return !encoding_types->empty(); | |
| 194 | |
| 195 // SDCH "search results" protective hack: To make sure we don't break the only | |
| 196 // currently deployed SDCH enabled server, be VERY cautious about proxies that | |
| 197 // strip all content-encoding to not include sdch. IF we don't see content | |
| 198 // encodings that seem to match what we'd expect from a server that asked us | |
| 199 // to use a dictionary (and we advertised said dictionary in the GET), then | |
| 200 // we set the encoding to (try to) use SDCH to decode. Note that SDCH will | |
| 201 // degrade into a pass-through filter if it doesn't have a viable dictionary | |
| 202 // hash in its header. Also note that a solo "sdch" will implicitly create | |
| 203 // a "sdch,gzip" decoding filter, where the gzip portion will degrade to a | |
| 204 // pass through if a gzip header is not encountered. Hence we can replace | |
| 205 // "gzip" with "sdch" and "everything will work." | |
| 206 // The one failure mode comes when we advertise a dictionary, and the server | |
| 207 // tries to *send* a gzipped file (not gzip encode content), and then we could | |
| 208 // do a gzip decode :-(. Since current server support does not ever see such | |
| 209 // a transfer, we are safe (for now). | |
| 210 | |
| 211 std::string mime_type; | |
| 212 GetMimeType(&mime_type); | |
| 213 if (std::string::npos != mime_type.find_first_of("text/html")) { | |
| 214 // Suspicious case: Advertised dictionary, but server didn't use sdch, even | |
| 215 // though it is text_html content. | |
| 216 if (encoding_types->empty()) | |
| 217 SdchManager::SdchErrorRecovery(SdchManager::ADDED_CONTENT_ENCODING); | |
| 218 else if (encoding_types->size() == 1) | |
| 219 SdchManager::SdchErrorRecovery(SdchManager::FIXED_CONTENT_ENCODING); | |
| 220 else | |
| 221 SdchManager::SdchErrorRecovery(SdchManager::FIXED_CONTENT_ENCODINGS); | |
| 222 encoding_types->clear(); | |
| 223 encoding_types->push_back("sdch"); // Handle SDCH/GZIP-opt encoding. | |
| 224 } | 183 } |
| 225 | |
| 226 return !encoding_types->empty(); | 184 return !encoding_types->empty(); |
| 227 } | 185 } |
| 228 | 186 |
| 229 bool URLRequestHttpJob::IsSdchResponse() const { | 187 bool URLRequestHttpJob::IsSdchResponse() const { |
| 230 return response_info_ && | 188 return response_info_ && |
| 231 (request_info_.load_flags & net::LOAD_SDCH_DICTIONARY_ADVERTISED); | 189 (request_info_.load_flags & net::LOAD_SDCH_DICTIONARY_ADVERTISED); |
| 232 } | 190 } |
| 233 | 191 |
| 234 bool URLRequestHttpJob::IsRedirectResponse(GURL* location, | 192 bool URLRequestHttpJob::IsRedirectResponse(GURL* location, |
| 235 int* http_status_code) { | 193 int* http_status_code) { |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 527 rv = net::ERR_FAILED; | 485 rv = net::ERR_FAILED; |
| 528 } | 486 } |
| 529 | 487 |
| 530 // The transaction started synchronously, but we need to notify the | 488 // The transaction started synchronously, but we need to notify the |
| 531 // URLRequest delegate via the message loop. | 489 // URLRequest delegate via the message loop. |
| 532 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( | 490 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( |
| 533 this, &URLRequestHttpJob::OnStartCompleted, rv)); | 491 this, &URLRequestHttpJob::OnStartCompleted, rv)); |
| 534 } | 492 } |
| 535 | 493 |
| 536 void URLRequestHttpJob::AddExtraHeaders() { | 494 void URLRequestHttpJob::AddExtraHeaders() { |
| 495 // Supply Accept-Encoding headers first so that it is more likely that they |
| 496 // will be in the first transmitted packet. This can sometimes make it easier |
| 497 // to filter and analyze the streams to assure that a proxy has not damaged |
| 498 // these headers. Some proxies deliberately corrupt Accept-Encoding headers. |
| 499 if (!SdchManager::Global() || |
| 500 !SdchManager::Global()->IsInSupportedDomain(request_->url())) { |
| 501 // Tell the server what compression formats we support (other than SDCH). |
| 502 request_info_.extra_headers += "Accept-Encoding: gzip,deflate,bzip2\r\n"; |
| 503 } else { |
| 504 // Supply SDCH related headers, as well as accepting that encoding. |
| 505 // Tell the server what compression formats we support. |
| 506 request_info_.extra_headers += "Accept-Encoding: " |
| 507 "gzip,deflate,bzip2,sdch\r\n"; |
| 508 |
| 509 // TODO(jar): See if it is worth optimizing away these bytes when the URL is |
| 510 // probably an img or such. (and SDCH encoding is not likely). |
| 511 std::string avail_dictionaries; |
| 512 SdchManager::Global()->GetAvailDictionaryList(request_->url(), |
| 513 &avail_dictionaries); |
| 514 if (!avail_dictionaries.empty()) { |
| 515 request_info_.extra_headers += "Avail-Dictionary: " |
| 516 + avail_dictionaries + "\r\n"; |
| 517 request_info_.load_flags |= net::LOAD_SDCH_DICTIONARY_ADVERTISED; |
| 518 } |
| 519 |
| 520 scoped_ptr<FileVersionInfo> file_version_info( |
| 521 FileVersionInfo::CreateFileVersionInfoForCurrentModule()); |
| 522 request_info_.extra_headers += "X-SDCH: Chrome "; |
| 523 request_info_.extra_headers += |
| 524 WideToASCII(file_version_info->product_version()); |
| 525 request_info_.extra_headers += "\r\n"; |
| 526 } |
| 527 |
| 537 URLRequestContext* context = request_->context(); | 528 URLRequestContext* context = request_->context(); |
| 538 if (context) { | 529 if (context) { |
| 539 // Add in the cookie header. TODO might we need more than one header? | 530 // Add in the cookie header. TODO might we need more than one header? |
| 540 if (context->cookie_store() && | 531 if (context->cookie_store() && |
| 541 context->cookie_policy()->CanGetCookies(request_->url(), | 532 context->cookie_policy()->CanGetCookies(request_->url(), |
| 542 request_->policy_url())) { | 533 request_->policy_url())) { |
| 543 std::string cookies = request_->context()->cookie_store()-> | 534 std::string cookies = request_->context()->cookie_store()-> |
| 544 GetCookiesWithOptions(request_->url(), | 535 GetCookiesWithOptions(request_->url(), |
| 545 net::CookieMonster::INCLUDE_HTTPONLY); | 536 net::CookieMonster::INCLUDE_HTTPONLY); |
| 546 if (!cookies.empty()) | 537 if (!cookies.empty()) |
| 547 request_info_.extra_headers += "Cookie: " + cookies + "\r\n"; | 538 request_info_.extra_headers += "Cookie: " + cookies + "\r\n"; |
| 548 } | 539 } |
| 549 if (!context->accept_language().empty()) | 540 if (!context->accept_language().empty()) |
| 550 request_info_.extra_headers += "Accept-Language: " + | 541 request_info_.extra_headers += "Accept-Language: " + |
| 551 context->accept_language() + "\r\n"; | 542 context->accept_language() + "\r\n"; |
| 552 if (!context->accept_charset().empty()) | 543 if (!context->accept_charset().empty()) |
| 553 request_info_.extra_headers += "Accept-Charset: " + | 544 request_info_.extra_headers += "Accept-Charset: " + |
| 554 context->accept_charset() + "\r\n"; | 545 context->accept_charset() + "\r\n"; |
| 555 } | 546 } |
| 556 | |
| 557 if (!SdchManager::Global() || | |
| 558 !SdchManager::Global()->IsInSupportedDomain(request_->url())) { | |
| 559 // Tell the server what compression formats we support (other than SDCH). | |
| 560 request_info_.extra_headers += "Accept-Encoding: gzip,deflate,bzip2\r\n"; | |
| 561 return; | |
| 562 } | |
| 563 | |
| 564 // Supply SDCH related headers, as well as accepting that encoding. | |
| 565 | |
| 566 // TODO(jar): See if it is worth optimizing away these bytes when the URL is | |
| 567 // probably an img or such. (and SDCH encoding is not likely). | |
| 568 std::string avail_dictionaries; | |
| 569 SdchManager::Global()->GetAvailDictionaryList(request_->url(), | |
| 570 &avail_dictionaries); | |
| 571 if (!avail_dictionaries.empty()) { | |
| 572 request_info_.extra_headers += "Avail-Dictionary: " | |
| 573 + avail_dictionaries + "\r\n"; | |
| 574 request_info_.load_flags |= net::LOAD_SDCH_DICTIONARY_ADVERTISED; | |
| 575 } | |
| 576 | |
| 577 scoped_ptr<FileVersionInfo> file_version_info( | |
| 578 FileVersionInfo::CreateFileVersionInfoForCurrentModule()); | |
| 579 request_info_.extra_headers += "X-SDCH: Chrome "; | |
| 580 request_info_.extra_headers += | |
| 581 WideToASCII(file_version_info->product_version()); | |
| 582 request_info_.extra_headers += "\r\n"; | |
| 583 | |
| 584 // Tell the server what compression formats we support. | |
| 585 request_info_.extra_headers += "Accept-Encoding: gzip,deflate,bzip2,sdch\r\n"; | |
| 586 } | 547 } |
| 587 | 548 |
| 588 void URLRequestHttpJob::FetchResponseCookies() { | 549 void URLRequestHttpJob::FetchResponseCookies() { |
| 589 DCHECK(response_info_); | 550 DCHECK(response_info_); |
| 590 DCHECK(response_cookies_.empty()); | 551 DCHECK(response_cookies_.empty()); |
| 591 | 552 |
| 592 std::string name = "Set-Cookie"; | 553 std::string name = "Set-Cookie"; |
| 593 std::string value; | 554 std::string value; |
| 594 | 555 |
| 595 void* iter = NULL; | 556 void* iter = NULL; |
| 596 while (response_info_->headers->EnumerateHeader(&iter, name, &value)) | 557 while (response_info_->headers->EnumerateHeader(&iter, name, &value)) |
| 597 response_cookies_.push_back(value); | 558 response_cookies_.push_back(value); |
| 598 } | 559 } |
| 599 | 560 |
| OLD | NEW |