blob: c7fc4359a2f2b6f7506e00bfdbd516d428aeaed4 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// 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
3// found in the LICENSE file.
initial.commit586acc5fe2008-07-26 22:42:524
[email protected]175adac2008-07-30 17:28:045#include "net/url_request/url_request_http_job.h"
initial.commit586acc5fe2008-07-26 22:42:526
[email protected]4ed2755f2008-12-15 09:01:337#include "base/base_switches.h"
8#include "base/command_line.h"
[email protected]39ce5c02008-08-22 04:03:449#include "base/compiler_specific.h"
[email protected]60889422008-09-23 01:18:1610#include "base/file_util.h"
11#include "base/file_version_info.h"
initial.commit586acc5fe2008-07-26 22:42:5212#include "base/message_loop.h"
13#include "base/string_util.h"
14#include "net/base/cookie_monster.h"
[email protected]423041b2008-10-27 17:39:2815#include "net/base/filter.h"
[email protected]b8430722008-09-17 20:05:4416#include "net/base/load_flags.h"
initial.commit586acc5fe2008-07-26 22:42:5217#include "net/base/net_errors.h"
18#include "net/base/net_util.h"
[email protected]60889422008-09-23 01:18:1619#include "net/base/sdch_manager.h"
initial.commit586acc5fe2008-07-26 22:42:5220#include "net/http/http_response_info.h"
21#include "net/http/http_transaction.h"
22#include "net/http/http_transaction_factory.h"
23#include "net/url_request/url_request.h"
24#include "net/url_request/url_request_error_job.h"
25
26// TODO(darin): make sure the port blocking code is not lost
27
initial.commit586acc5fe2008-07-26 22:42:5228// static
[email protected]175adac2008-07-30 17:28:0429URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request,
30 const std::string& scheme) {
initial.commit586acc5fe2008-07-26 22:42:5231 DCHECK(scheme == "http" || scheme == "https");
32
[email protected]8ac1a752008-07-31 19:40:3733 if (!net::IsPortAllowedByDefault(request->url().IntPort()))
initial.commit586acc5fe2008-07-26 22:42:5234 return new URLRequestErrorJob(request, net::ERR_UNSAFE_PORT);
35
36 if (!request->context() ||
37 !request->context()->http_transaction_factory()) {
38 NOTREACHED() << "requires a valid context";
39 return new URLRequestErrorJob(request, net::ERR_INVALID_ARGUMENT);
40 }
41
[email protected]4ed2755f2008-12-15 09:01:3342 // We cache the value of the switch because this code path is hit on every
43 // network request.
44 static const bool kForceHTTPS =
[email protected]bb975362009-01-21 01:00:2245 CommandLine::ForCurrentProcess()->HasSwitch(switches::kForceHTTPS);
[email protected]4ed2755f2008-12-15 09:01:3346 if (kForceHTTPS && scheme != "https")
47 return new URLRequestErrorJob(request, net::ERR_DISALLOWED_URL_SCHEME);
48
[email protected]175adac2008-07-30 17:28:0449 return new URLRequestHttpJob(request);
initial.commit586acc5fe2008-07-26 22:42:5250}
51
[email protected]175adac2008-07-30 17:28:0452URLRequestHttpJob::URLRequestHttpJob(URLRequest* request)
initial.commit586acc5fe2008-07-26 22:42:5253 : URLRequestJob(request),
initial.commit586acc5fe2008-07-26 22:42:5254 transaction_(NULL),
55 response_info_(NULL),
[email protected]a9bb6f692008-07-30 16:40:1056 proxy_auth_state_(net::AUTH_STATE_DONT_NEED_AUTH),
57 server_auth_state_(net::AUTH_STATE_DONT_NEED_AUTH),
[email protected]39ce5c02008-08-22 04:03:4458 ALLOW_THIS_IN_INITIALIZER_LIST(
59 start_callback_(this, &URLRequestHttpJob::OnStartCompleted)),
60 ALLOW_THIS_IN_INITIALIZER_LIST(
61 read_callback_(this, &URLRequestHttpJob::OnReadCompleted)),
[email protected]3589e552008-08-20 23:11:3462 read_in_progress_(false),
63 context_(request->context()) {
initial.commit586acc5fe2008-07-26 22:42:5264}
65
[email protected]175adac2008-07-30 17:28:0466URLRequestHttpJob::~URLRequestHttpJob() {
[email protected]7234e6c2009-02-11 21:37:0467 if (sdch_dictionary_url_.is_valid()) {
68 SdchManager::Global()->FetchDictionary(sdch_dictionary_url_);
69 }
initial.commit586acc5fe2008-07-26 22:42:5270}
71
[email protected]175adac2008-07-30 17:28:0472void URLRequestHttpJob::SetUpload(net::UploadData* upload) {
[email protected]af4876d2008-10-21 23:10:5773 DCHECK(!transaction_.get()) << "cannot change once started";
initial.commit586acc5fe2008-07-26 22:42:5274 request_info_.upload_data = upload;
75}
76
[email protected]175adac2008-07-30 17:28:0477void URLRequestHttpJob::SetExtraRequestHeaders(
initial.commit586acc5fe2008-07-26 22:42:5278 const std::string& headers) {
[email protected]af4876d2008-10-21 23:10:5779 DCHECK(!transaction_.get()) << "cannot change once started";
initial.commit586acc5fe2008-07-26 22:42:5280 request_info_.extra_headers = headers;
81}
82
[email protected]175adac2008-07-30 17:28:0483void URLRequestHttpJob::Start() {
[email protected]af4876d2008-10-21 23:10:5784 DCHECK(!transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:5285
86 // TODO(darin): URLRequest::referrer() should return a GURL
87 GURL referrer(request_->referrer());
88
89 // Ensure that we do not send username and password fields in the referrer.
90 if (referrer.has_username() || referrer.has_password()) {
91 GURL::Replacements referrer_mods;
92 referrer_mods.ClearUsername();
93 referrer_mods.ClearPassword();
94 referrer = referrer.ReplaceComponents(referrer_mods);
95 }
96
97 request_info_.url = request_->url();
98 request_info_.referrer = referrer;
99 request_info_.method = request_->method();
100 request_info_.load_flags = request_->load_flags();
101
[email protected]6f681a42009-01-27 22:28:54102 if (request_->context()) {
103 request_info_.user_agent =
104 request_->context()->GetUserAgent(request_->url());
105 }
initial.commit586acc5fe2008-07-26 22:42:52106
107 AddExtraHeaders();
108
109 StartTransaction();
110}
111
[email protected]175adac2008-07-30 17:28:04112void URLRequestHttpJob::Kill() {
[email protected]af4876d2008-10-21 23:10:57113 if (!transaction_.get())
initial.commit586acc5fe2008-07-26 22:42:52114 return;
115
116 DestroyTransaction();
117 URLRequestJob::Kill();
118}
119
[email protected]175adac2008-07-30 17:28:04120net::LoadState URLRequestHttpJob::GetLoadState() const {
[email protected]af4876d2008-10-21 23:10:57121 return transaction_.get() ?
122 transaction_->GetLoadState() : net::LOAD_STATE_IDLE;
initial.commit586acc5fe2008-07-26 22:42:52123}
124
[email protected]175adac2008-07-30 17:28:04125uint64 URLRequestHttpJob::GetUploadProgress() const {
[email protected]af4876d2008-10-21 23:10:57126 return transaction_.get() ? transaction_->GetUploadProgress() : 0;
initial.commit586acc5fe2008-07-26 22:42:52127}
128
[email protected]175adac2008-07-30 17:28:04129bool URLRequestHttpJob::GetMimeType(std::string* mime_type) {
[email protected]af4876d2008-10-21 23:10:57130 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52131
132 if (!response_info_)
133 return false;
134
135 return response_info_->headers->GetMimeType(mime_type);
136}
137
[email protected]175adac2008-07-30 17:28:04138bool URLRequestHttpJob::GetCharset(std::string* charset) {
[email protected]af4876d2008-10-21 23:10:57139 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52140
141 if (!response_info_)
142 return false;
143
144 return response_info_->headers->GetCharset(charset);
145}
146
[email protected]175adac2008-07-30 17:28:04147void URLRequestHttpJob::GetResponseInfo(net::HttpResponseInfo* info) {
initial.commit586acc5fe2008-07-26 22:42:52148 DCHECK(request_);
[email protected]af4876d2008-10-21 23:10:57149 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52150
151 if (response_info_)
152 *info = *response_info_;
153}
154
[email protected]175adac2008-07-30 17:28:04155bool URLRequestHttpJob::GetResponseCookies(
initial.commit586acc5fe2008-07-26 22:42:52156 std::vector<std::string>* cookies) {
[email protected]af4876d2008-10-21 23:10:57157 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52158
159 if (!response_info_)
160 return false;
161
162 if (response_cookies_.empty())
163 FetchResponseCookies();
164
165 cookies->clear();
166 cookies->swap(response_cookies_);
167 return true;
168}
169
[email protected]175adac2008-07-30 17:28:04170int URLRequestHttpJob::GetResponseCode() {
[email protected]af4876d2008-10-21 23:10:57171 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52172
173 if (!response_info_)
174 return -1;
175
176 return response_info_->headers->response_code();
177}
178
[email protected]60889422008-09-23 01:18:16179bool URLRequestHttpJob::GetContentEncodings(
[email protected]423041b2008-10-27 17:39:28180 std::vector<Filter::FilterType>* encoding_types) {
[email protected]af4876d2008-10-21 23:10:57181 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52182 if (!response_info_)
183 return false;
[email protected]423041b2008-10-27 17:39:28184 DCHECK(encoding_types->empty());
initial.commit586acc5fe2008-07-26 22:42:52185
[email protected]60889422008-09-23 01:18:16186 std::string encoding_type;
187 void* iter = NULL;
188 while (response_info_->headers->EnumerateHeader(&iter, "Content-Encoding",
189 &encoding_type)) {
[email protected]423041b2008-10-27 17:39:28190 encoding_types->push_back(Filter::ConvertEncodingToType(encoding_type));
[email protected]60889422008-09-23 01:18:16191 }
[email protected]c631b6aa2008-10-15 21:21:37192
[email protected]423041b2008-10-27 17:39:28193 if (!encoding_types->empty()) {
194 std::string mime_type;
195 GetMimeType(&mime_type);
196 Filter::FixupEncodingTypes(IsSdchResponse(), mime_type, encoding_types);
[email protected]c631b6aa2008-10-15 21:21:37197 }
[email protected]60889422008-09-23 01:18:16198 return !encoding_types->empty();
initial.commit586acc5fe2008-07-26 22:42:52199}
200
[email protected]c631b6aa2008-10-15 21:21:37201bool URLRequestHttpJob::IsSdchResponse() const {
202 return response_info_ &&
203 (request_info_.load_flags & net::LOAD_SDCH_DICTIONARY_ADVERTISED);
204}
205
[email protected]175adac2008-07-30 17:28:04206bool URLRequestHttpJob::IsRedirectResponse(GURL* location,
207 int* http_status_code) {
initial.commit586acc5fe2008-07-26 22:42:52208 if (!response_info_)
209 return false;
210
211 std::string value;
212 if (!response_info_->headers->IsRedirect(&value))
213 return false;
214
[email protected]d1ec59082009-02-11 02:48:15215 // For HTTPS, if we didn't receive a server certificate, the response was
216 // from the proxy server (a response to the CONNECT request) rather than
217 // the server.
218 if (request_->url().SchemeIsSecure() && !response_info_->ssl_info.cert)
219 return false;
220
initial.commit586acc5fe2008-07-26 22:42:52221 *location = request_->url().Resolve(value);
222 *http_status_code = response_info_->headers->response_code();
223 return true;
224}
225
[email protected]175adac2008-07-30 17:28:04226bool URLRequestHttpJob::IsSafeRedirect(const GURL& location) {
initial.commit586acc5fe2008-07-26 22:42:52227 // We only allow redirects to certain "safe" protocols. This does not
228 // restrict redirects to externally handled protocols. Our consumer would
229 // need to take care of those.
230
231 if (!URLRequest::IsHandledURL(location))
232 return true;
233
234 static const char* kSafeSchemes[] = {
235 "http",
236 "https",
237 "ftp"
238 };
239
240 for (size_t i = 0; i < arraysize(kSafeSchemes); ++i) {
241 if (location.SchemeIs(kSafeSchemes[i]))
242 return true;
243 }
244
245 return false;
246}
247
[email protected]175adac2008-07-30 17:28:04248bool URLRequestHttpJob::NeedsAuth() {
initial.commit586acc5fe2008-07-26 22:42:52249 int code = GetResponseCode();
250 if (code == -1)
251 return false;
252
253 // Check if we need either Proxy or WWW Authentication. This could happen
254 // because we either provided no auth info, or provided incorrect info.
255 switch (code) {
256 case 407:
[email protected]a9bb6f692008-07-30 16:40:10257 if (proxy_auth_state_ == net::AUTH_STATE_CANCELED)
initial.commit586acc5fe2008-07-26 22:42:52258 return false;
[email protected]a9bb6f692008-07-30 16:40:10259 proxy_auth_state_ = net::AUTH_STATE_NEED_AUTH;
initial.commit586acc5fe2008-07-26 22:42:52260 return true;
261 case 401:
[email protected]a9bb6f692008-07-30 16:40:10262 if (server_auth_state_ == net::AUTH_STATE_CANCELED)
initial.commit586acc5fe2008-07-26 22:42:52263 return false;
[email protected]a9bb6f692008-07-30 16:40:10264 server_auth_state_ = net::AUTH_STATE_NEED_AUTH;
initial.commit586acc5fe2008-07-26 22:42:52265 return true;
266 }
267 return false;
268}
269
[email protected]175adac2008-07-30 17:28:04270void URLRequestHttpJob::GetAuthChallengeInfo(
[email protected]a9bb6f692008-07-30 16:40:10271 scoped_refptr<net::AuthChallengeInfo>* result) {
[email protected]af4876d2008-10-21 23:10:57272 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52273 DCHECK(response_info_);
274
275 // sanity checks:
[email protected]a9bb6f692008-07-30 16:40:10276 DCHECK(proxy_auth_state_ == net::AUTH_STATE_NEED_AUTH ||
277 server_auth_state_ == net::AUTH_STATE_NEED_AUTH);
initial.commit586acc5fe2008-07-26 22:42:52278 DCHECK(response_info_->headers->response_code() == 401 ||
279 response_info_->headers->response_code() == 407);
280
281 *result = response_info_->auth_challenge;
282}
283
[email protected]175adac2008-07-30 17:28:04284void URLRequestHttpJob::SetAuth(const std::wstring& username,
285 const std::wstring& password) {
[email protected]af4876d2008-10-21 23:10:57286 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52287
288 // Proxy gets set first, then WWW.
[email protected]a9bb6f692008-07-30 16:40:10289 if (proxy_auth_state_ == net::AUTH_STATE_NEED_AUTH) {
290 proxy_auth_state_ = net::AUTH_STATE_HAVE_AUTH;
initial.commit586acc5fe2008-07-26 22:42:52291 } else {
[email protected]a9bb6f692008-07-30 16:40:10292 DCHECK(server_auth_state_ == net::AUTH_STATE_NEED_AUTH);
293 server_auth_state_ = net::AUTH_STATE_HAVE_AUTH;
initial.commit586acc5fe2008-07-26 22:42:52294 }
295
296 // These will be reset in OnStartCompleted.
297 response_info_ = NULL;
298 response_cookies_.clear();
299
300 // No matter what, we want to report our status as IO pending since we will
301 // be notifying our consumer asynchronously via OnStartCompleted.
302 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
303
304 int rv = transaction_->RestartWithAuth(username, password,
305 &start_callback_);
306 if (rv == net::ERR_IO_PENDING)
307 return;
308
309 // The transaction started synchronously, but we need to notify the
310 // URLRequest delegate via the message loop.
311 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
[email protected]175adac2008-07-30 17:28:04312 this, &URLRequestHttpJob::OnStartCompleted, rv));
initial.commit586acc5fe2008-07-26 22:42:52313}
314
[email protected]175adac2008-07-30 17:28:04315void URLRequestHttpJob::CancelAuth() {
initial.commit586acc5fe2008-07-26 22:42:52316 // Proxy gets set first, then WWW.
[email protected]a9bb6f692008-07-30 16:40:10317 if (proxy_auth_state_ == net::AUTH_STATE_NEED_AUTH) {
318 proxy_auth_state_ = net::AUTH_STATE_CANCELED;
initial.commit586acc5fe2008-07-26 22:42:52319 } else {
[email protected]a9bb6f692008-07-30 16:40:10320 DCHECK(server_auth_state_ == net::AUTH_STATE_NEED_AUTH);
321 server_auth_state_ = net::AUTH_STATE_CANCELED;
initial.commit586acc5fe2008-07-26 22:42:52322 }
323
324 // These will be reset in OnStartCompleted.
325 response_info_ = NULL;
326 response_cookies_.clear();
327
328 // OK, let the consumer read the error page...
329 //
330 // Because we set the AUTH_STATE_CANCELED flag, NeedsAuth will return false,
331 // which will cause the consumer to receive OnResponseStarted instead of
332 // OnAuthRequired.
333 //
334 // We have to do this via InvokeLater to avoid "recursing" the consumer.
335 //
336 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
[email protected]175adac2008-07-30 17:28:04337 this, &URLRequestHttpJob::OnStartCompleted, net::OK));
initial.commit586acc5fe2008-07-26 22:42:52338}
339
[email protected]175adac2008-07-30 17:28:04340void URLRequestHttpJob::ContinueDespiteLastError() {
[email protected]9ec48752009-02-06 23:33:58341 // If the transaction was destroyed, then the job was cancelled.
342 if (!transaction_.get())
343 return;
344
initial.commit586acc5fe2008-07-26 22:42:52345 DCHECK(!response_info_) << "should not have a response yet";
346
347 // No matter what, we want to report our status as IO pending since we will
348 // be notifying our consumer asynchronously via OnStartCompleted.
349 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
350
351 int rv = transaction_->RestartIgnoringLastError(&start_callback_);
352 if (rv == net::ERR_IO_PENDING)
353 return;
354
355 // The transaction started synchronously, but we need to notify the
356 // URLRequest delegate via the message loop.
357 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
[email protected]175adac2008-07-30 17:28:04358 this, &URLRequestHttpJob::OnStartCompleted, rv));
initial.commit586acc5fe2008-07-26 22:42:52359}
360
[email protected]175adac2008-07-30 17:28:04361bool URLRequestHttpJob::GetMoreData() {
[email protected]af4876d2008-10-21 23:10:57362 return transaction_.get() && !read_in_progress_;
initial.commit586acc5fe2008-07-26 22:42:52363}
364
[email protected]9dea9e1f2009-01-29 00:30:47365bool URLRequestHttpJob::ReadRawData(net::IOBuffer* buf, int buf_size,
366 int *bytes_read) {
initial.commit586acc5fe2008-07-26 22:42:52367 DCHECK_NE(buf_size, 0);
368 DCHECK(bytes_read);
369 DCHECK(!read_in_progress_);
370
371 int rv = transaction_->Read(buf, buf_size, &read_callback_);
372 if (rv >= 0) {
373 *bytes_read = rv;
374 return true;
375 }
376
377 if (rv == net::ERR_IO_PENDING) {
378 read_in_progress_ = true;
379 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
380 } else {
381 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
382 }
383
384 return false;
385}
386
[email protected]175adac2008-07-30 17:28:04387void URLRequestHttpJob::OnStartCompleted(int result) {
initial.commit586acc5fe2008-07-26 22:42:52388 // If the request was destroyed, then there is no more work to do.
389 if (!request_ || !request_->delegate())
390 return;
391
392 // If the transaction was destroyed, then the job was cancelled, and
393 // we can just ignore this notification.
[email protected]af4876d2008-10-21 23:10:57394 if (!transaction_.get())
initial.commit586acc5fe2008-07-26 22:42:52395 return;
396
397 // Clear the IO_PENDING status
398 SetStatus(URLRequestStatus());
399
400 if (result == net::OK) {
401 NotifyHeadersComplete();
[email protected]4ed2755f2008-12-15 09:01:33402 } else if (net::IsCertificateError(result) &&
[email protected]bb975362009-01-21 01:00:22403 !CommandLine::ForCurrentProcess()->HasSwitch(
404 switches::kForceHTTPS)) {
initial.commit586acc5fe2008-07-26 22:42:52405 // We encountered an SSL certificate error. Ask our delegate to decide
406 // what we should do.
407 // TODO(wtc): also pass ssl_info.cert_status, or just pass the whole
408 // ssl_info.
409 request_->delegate()->OnSSLCertificateError(
410 request_, result, transaction_->GetResponseInfo()->ssl_info.cert);
411 } else {
412 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
413 }
414}
415
[email protected]175adac2008-07-30 17:28:04416void URLRequestHttpJob::OnReadCompleted(int result) {
initial.commit586acc5fe2008-07-26 22:42:52417 read_in_progress_ = false;
418
419 if (result == 0) {
420 NotifyDone(URLRequestStatus());
421 } else if (result < 0) {
422 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result));
423 } else {
424 // Clear the IO_PENDING status
425 SetStatus(URLRequestStatus());
426 }
427
428 NotifyReadComplete(result);
429}
430
[email protected]175adac2008-07-30 17:28:04431void URLRequestHttpJob::NotifyHeadersComplete() {
initial.commit586acc5fe2008-07-26 22:42:52432 DCHECK(!response_info_);
433
434 response_info_ = transaction_->GetResponseInfo();
435
436 // Get the Set-Cookie values, and send them to our cookie database.
[email protected]b8430722008-09-17 20:05:44437 if (!(request_info_.load_flags & net::LOAD_DO_NOT_SAVE_COOKIES)) {
438 URLRequestContext* ctx = request_->context();
439 if (ctx && ctx->cookie_store() &&
440 ctx->cookie_policy()->CanSetCookie(request_->url(),
441 request_->policy_url())) {
442 FetchResponseCookies();
[email protected]3a96c742008-11-19 19:46:27443 net::CookieMonster::CookieOptions options;
444 options.set_include_httponly();
445 ctx->cookie_store()->SetCookiesWithOptions(request_->url(),
446 response_cookies_,
447 options);
[email protected]b8430722008-09-17 20:05:44448 }
449 }
initial.commit586acc5fe2008-07-26 22:42:52450
[email protected]fe219872008-09-23 02:17:00451 if (SdchManager::Global() &&
452 SdchManager::Global()->IsInSupportedDomain(request_->url())) {
[email protected]60889422008-09-23 01:18:16453 static const std::string name = "Get-Dictionary";
454 std::string url_text;
455 void* iter = NULL;
456 // TODO(jar): We need to not fetch dictionaries the first time they are
457 // seen, but rather wait until we can justify their usefulness.
458 // For now, we will only fetch the first dictionary, which will at least
459 // require multiple suggestions before we get additional ones for this site.
460 // Eventually we should wait until a dictionary is requested several times
461 // before we even download it (so that we don't waste memory or bandwidth).
462 if (response_info_->headers->EnumerateHeader(&iter, name, &url_text)) {
463 GURL dictionary_url = request_->url().Resolve(url_text);
[email protected]7234e6c2009-02-11 21:37:04464 if (SdchManager::Global()->CanFetchDictionary(request_->url(),
465 dictionary_url))
466 sdch_dictionary_url_ = dictionary_url;
[email protected]60889422008-09-23 01:18:16467 }
468 }
469
initial.commit586acc5fe2008-07-26 22:42:52470 URLRequestJob::NotifyHeadersComplete();
471}
472
[email protected]175adac2008-07-30 17:28:04473void URLRequestHttpJob::DestroyTransaction() {
[email protected]af4876d2008-10-21 23:10:57474 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52475
[email protected]af4876d2008-10-21 23:10:57476 transaction_.reset();
initial.commit586acc5fe2008-07-26 22:42:52477 response_info_ = NULL;
478}
479
[email protected]175adac2008-07-30 17:28:04480void URLRequestHttpJob::StartTransaction() {
initial.commit586acc5fe2008-07-26 22:42:52481 // NOTE: This method assumes that request_info_ is already setup properly.
482
483 // Create a transaction.
[email protected]af4876d2008-10-21 23:10:57484 DCHECK(!transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52485
486 DCHECK(request_->context());
487 DCHECK(request_->context()->http_transaction_factory());
488
[email protected]af4876d2008-10-21 23:10:57489 transaction_.reset(
490 request_->context()->http_transaction_factory()->CreateTransaction());
initial.commit586acc5fe2008-07-26 22:42:52491
492 // No matter what, we want to report our status as IO pending since we will
493 // be notifying our consumer asynchronously via OnStartCompleted.
494 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
495
496 int rv;
[email protected]af4876d2008-10-21 23:10:57497 if (transaction_.get()) {
initial.commit586acc5fe2008-07-26 22:42:52498 rv = transaction_->Start(&request_info_, &start_callback_);
499 if (rv == net::ERR_IO_PENDING)
500 return;
501 } else {
502 rv = net::ERR_FAILED;
503 }
504
505 // The transaction started synchronously, but we need to notify the
506 // URLRequest delegate via the message loop.
507 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
[email protected]175adac2008-07-30 17:28:04508 this, &URLRequestHttpJob::OnStartCompleted, rv));
initial.commit586acc5fe2008-07-26 22:42:52509}
510
[email protected]175adac2008-07-30 17:28:04511void URLRequestHttpJob::AddExtraHeaders() {
[email protected]423041b2008-10-27 17:39:28512 // Supply Accept-Encoding headers first so that it is more likely that they
513 // will be in the first transmitted packet. This can sometimes make it easier
514 // to filter and analyze the streams to assure that a proxy has not damaged
515 // these headers. Some proxies deliberately corrupt Accept-Encoding headers.
516 if (!SdchManager::Global() ||
517 !SdchManager::Global()->IsInSupportedDomain(request_->url())) {
518 // Tell the server what compression formats we support (other than SDCH).
519 request_info_.extra_headers += "Accept-Encoding: gzip,deflate,bzip2\r\n";
520 } else {
521 // Supply SDCH related headers, as well as accepting that encoding.
522 // Tell the server what compression formats we support.
523 request_info_.extra_headers += "Accept-Encoding: "
524 "gzip,deflate,bzip2,sdch\r\n";
525
526 // TODO(jar): See if it is worth optimizing away these bytes when the URL is
527 // probably an img or such. (and SDCH encoding is not likely).
528 std::string avail_dictionaries;
529 SdchManager::Global()->GetAvailDictionaryList(request_->url(),
530 &avail_dictionaries);
531 if (!avail_dictionaries.empty()) {
532 request_info_.extra_headers += "Avail-Dictionary: "
533 + avail_dictionaries + "\r\n";
534 request_info_.load_flags |= net::LOAD_SDCH_DICTIONARY_ADVERTISED;
535 }
[email protected]423041b2008-10-27 17:39:28536 }
537
initial.commit586acc5fe2008-07-26 22:42:52538 URLRequestContext* context = request_->context();
539 if (context) {
540 // Add in the cookie header. TODO might we need more than one header?
541 if (context->cookie_store() &&
542 context->cookie_policy()->CanGetCookies(request_->url(),
543 request_->policy_url())) {
[email protected]3a96c742008-11-19 19:46:27544 net::CookieMonster::CookieOptions options;
545 options.set_include_httponly();
initial.commit586acc5fe2008-07-26 22:42:52546 std::string cookies = request_->context()->cookie_store()->
[email protected]3a96c742008-11-19 19:46:27547 GetCookiesWithOptions(request_->url(), options);
initial.commit586acc5fe2008-07-26 22:42:52548 if (!cookies.empty())
549 request_info_.extra_headers += "Cookie: " + cookies + "\r\n";
550 }
551 if (!context->accept_language().empty())
552 request_info_.extra_headers += "Accept-Language: " +
553 context->accept_language() + "\r\n";
554 if (!context->accept_charset().empty())
555 request_info_.extra_headers += "Accept-Charset: " +
556 context->accept_charset() + "\r\n";
557 }
initial.commit586acc5fe2008-07-26 22:42:52558}
559
[email protected]175adac2008-07-30 17:28:04560void URLRequestHttpJob::FetchResponseCookies() {
initial.commit586acc5fe2008-07-26 22:42:52561 DCHECK(response_info_);
562 DCHECK(response_cookies_.empty());
563
564 std::string name = "Set-Cookie";
565 std::string value;
566
567 void* iter = NULL;
568 while (response_info_->headers->EnumerateHeader(&iter, name, &value))
569 response_cookies_.push_back(value);
570}
license.botbf09a502008-08-24 00:55:55571