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 |