blob: d29b31e804d9046f5a5657e26eb866fe7a7d5d3f [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() {
initial.commit586acc5fe2008-07-26 22:42:5267}
68
[email protected]175adac2008-07-30 17:28:0469void URLRequestHttpJob::SetUpload(net::UploadData* upload) {
[email protected]af4876d2008-10-21 23:10:5770 DCHECK(!transaction_.get()) << "cannot change once started";
initial.commit586acc5fe2008-07-26 22:42:5271 request_info_.upload_data = upload;
72}
73
[email protected]175adac2008-07-30 17:28:0474void URLRequestHttpJob::SetExtraRequestHeaders(
initial.commit586acc5fe2008-07-26 22:42:5275 const std::string& headers) {
[email protected]af4876d2008-10-21 23:10:5776 DCHECK(!transaction_.get()) << "cannot change once started";
initial.commit586acc5fe2008-07-26 22:42:5277 request_info_.extra_headers = headers;
78}
79
[email protected]175adac2008-07-30 17:28:0480void URLRequestHttpJob::Start() {
[email protected]af4876d2008-10-21 23:10:5781 DCHECK(!transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:5282
83 // TODO(darin): URLRequest::referrer() should return a GURL
84 GURL referrer(request_->referrer());
85
86 // Ensure that we do not send username and password fields in the referrer.
87 if (referrer.has_username() || referrer.has_password()) {
88 GURL::Replacements referrer_mods;
89 referrer_mods.ClearUsername();
90 referrer_mods.ClearPassword();
91 referrer = referrer.ReplaceComponents(referrer_mods);
92 }
93
94 request_info_.url = request_->url();
95 request_info_.referrer = referrer;
96 request_info_.method = request_->method();
97 request_info_.load_flags = request_->load_flags();
98
[email protected]6f681a42009-01-27 22:28:5499 if (request_->context()) {
100 request_info_.user_agent =
101 request_->context()->GetUserAgent(request_->url());
102 }
initial.commit586acc5fe2008-07-26 22:42:52103
104 AddExtraHeaders();
105
106 StartTransaction();
107}
108
[email protected]175adac2008-07-30 17:28:04109void URLRequestHttpJob::Kill() {
[email protected]af4876d2008-10-21 23:10:57110 if (!transaction_.get())
initial.commit586acc5fe2008-07-26 22:42:52111 return;
112
113 DestroyTransaction();
114 URLRequestJob::Kill();
115}
116
[email protected]175adac2008-07-30 17:28:04117net::LoadState URLRequestHttpJob::GetLoadState() const {
[email protected]af4876d2008-10-21 23:10:57118 return transaction_.get() ?
119 transaction_->GetLoadState() : net::LOAD_STATE_IDLE;
initial.commit586acc5fe2008-07-26 22:42:52120}
121
[email protected]175adac2008-07-30 17:28:04122uint64 URLRequestHttpJob::GetUploadProgress() const {
[email protected]af4876d2008-10-21 23:10:57123 return transaction_.get() ? transaction_->GetUploadProgress() : 0;
initial.commit586acc5fe2008-07-26 22:42:52124}
125
[email protected]175adac2008-07-30 17:28:04126bool URLRequestHttpJob::GetMimeType(std::string* mime_type) {
[email protected]af4876d2008-10-21 23:10:57127 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52128
129 if (!response_info_)
130 return false;
131
132 return response_info_->headers->GetMimeType(mime_type);
133}
134
[email protected]175adac2008-07-30 17:28:04135bool URLRequestHttpJob::GetCharset(std::string* charset) {
[email protected]af4876d2008-10-21 23:10:57136 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52137
138 if (!response_info_)
139 return false;
140
141 return response_info_->headers->GetCharset(charset);
142}
143
[email protected]175adac2008-07-30 17:28:04144void URLRequestHttpJob::GetResponseInfo(net::HttpResponseInfo* info) {
initial.commit586acc5fe2008-07-26 22:42:52145 DCHECK(request_);
[email protected]af4876d2008-10-21 23:10:57146 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52147
148 if (response_info_)
149 *info = *response_info_;
150}
151
[email protected]175adac2008-07-30 17:28:04152bool URLRequestHttpJob::GetResponseCookies(
initial.commit586acc5fe2008-07-26 22:42:52153 std::vector<std::string>* cookies) {
[email protected]af4876d2008-10-21 23:10:57154 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52155
156 if (!response_info_)
157 return false;
158
159 if (response_cookies_.empty())
160 FetchResponseCookies();
161
162 cookies->clear();
163 cookies->swap(response_cookies_);
164 return true;
165}
166
[email protected]175adac2008-07-30 17:28:04167int URLRequestHttpJob::GetResponseCode() {
[email protected]af4876d2008-10-21 23:10:57168 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52169
170 if (!response_info_)
171 return -1;
172
173 return response_info_->headers->response_code();
174}
175
[email protected]60889422008-09-23 01:18:16176bool URLRequestHttpJob::GetContentEncodings(
[email protected]423041b2008-10-27 17:39:28177 std::vector<Filter::FilterType>* encoding_types) {
[email protected]af4876d2008-10-21 23:10:57178 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52179 if (!response_info_)
180 return false;
[email protected]423041b2008-10-27 17:39:28181 DCHECK(encoding_types->empty());
initial.commit586acc5fe2008-07-26 22:42:52182
[email protected]60889422008-09-23 01:18:16183 std::string encoding_type;
184 void* iter = NULL;
185 while (response_info_->headers->EnumerateHeader(&iter, "Content-Encoding",
186 &encoding_type)) {
[email protected]423041b2008-10-27 17:39:28187 encoding_types->push_back(Filter::ConvertEncodingToType(encoding_type));
[email protected]60889422008-09-23 01:18:16188 }
[email protected]c631b6aa2008-10-15 21:21:37189
[email protected]423041b2008-10-27 17:39:28190 if (!encoding_types->empty()) {
191 std::string mime_type;
192 GetMimeType(&mime_type);
193 Filter::FixupEncodingTypes(IsSdchResponse(), mime_type, encoding_types);
[email protected]c631b6aa2008-10-15 21:21:37194 }
[email protected]60889422008-09-23 01:18:16195 return !encoding_types->empty();
initial.commit586acc5fe2008-07-26 22:42:52196}
197
[email protected]c631b6aa2008-10-15 21:21:37198bool URLRequestHttpJob::IsSdchResponse() const {
199 return response_info_ &&
200 (request_info_.load_flags & net::LOAD_SDCH_DICTIONARY_ADVERTISED);
201}
202
[email protected]175adac2008-07-30 17:28:04203bool URLRequestHttpJob::IsRedirectResponse(GURL* location,
204 int* http_status_code) {
initial.commit586acc5fe2008-07-26 22:42:52205 if (!response_info_)
206 return false;
207
208 std::string value;
209 if (!response_info_->headers->IsRedirect(&value))
210 return false;
211
[email protected]d1ec59082009-02-11 02:48:15212 // For HTTPS, if we didn't receive a server certificate, the response was
213 // from the proxy server (a response to the CONNECT request) rather than
214 // the server.
215 if (request_->url().SchemeIsSecure() && !response_info_->ssl_info.cert)
216 return false;
217
initial.commit586acc5fe2008-07-26 22:42:52218 *location = request_->url().Resolve(value);
219 *http_status_code = response_info_->headers->response_code();
220 return true;
221}
222
[email protected]175adac2008-07-30 17:28:04223bool URLRequestHttpJob::IsSafeRedirect(const GURL& location) {
initial.commit586acc5fe2008-07-26 22:42:52224 // We only allow redirects to certain "safe" protocols. This does not
225 // restrict redirects to externally handled protocols. Our consumer would
226 // need to take care of those.
227
228 if (!URLRequest::IsHandledURL(location))
229 return true;
230
231 static const char* kSafeSchemes[] = {
232 "http",
233 "https",
234 "ftp"
235 };
236
237 for (size_t i = 0; i < arraysize(kSafeSchemes); ++i) {
238 if (location.SchemeIs(kSafeSchemes[i]))
239 return true;
240 }
241
242 return false;
243}
244
[email protected]175adac2008-07-30 17:28:04245bool URLRequestHttpJob::NeedsAuth() {
initial.commit586acc5fe2008-07-26 22:42:52246 int code = GetResponseCode();
247 if (code == -1)
248 return false;
249
250 // Check if we need either Proxy or WWW Authentication. This could happen
251 // because we either provided no auth info, or provided incorrect info.
252 switch (code) {
253 case 407:
[email protected]a9bb6f692008-07-30 16:40:10254 if (proxy_auth_state_ == net::AUTH_STATE_CANCELED)
initial.commit586acc5fe2008-07-26 22:42:52255 return false;
[email protected]a9bb6f692008-07-30 16:40:10256 proxy_auth_state_ = net::AUTH_STATE_NEED_AUTH;
initial.commit586acc5fe2008-07-26 22:42:52257 return true;
258 case 401:
[email protected]a9bb6f692008-07-30 16:40:10259 if (server_auth_state_ == net::AUTH_STATE_CANCELED)
initial.commit586acc5fe2008-07-26 22:42:52260 return false;
[email protected]a9bb6f692008-07-30 16:40:10261 server_auth_state_ = net::AUTH_STATE_NEED_AUTH;
initial.commit586acc5fe2008-07-26 22:42:52262 return true;
263 }
264 return false;
265}
266
[email protected]175adac2008-07-30 17:28:04267void URLRequestHttpJob::GetAuthChallengeInfo(
[email protected]a9bb6f692008-07-30 16:40:10268 scoped_refptr<net::AuthChallengeInfo>* result) {
[email protected]af4876d2008-10-21 23:10:57269 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52270 DCHECK(response_info_);
271
272 // sanity checks:
[email protected]a9bb6f692008-07-30 16:40:10273 DCHECK(proxy_auth_state_ == net::AUTH_STATE_NEED_AUTH ||
274 server_auth_state_ == net::AUTH_STATE_NEED_AUTH);
initial.commit586acc5fe2008-07-26 22:42:52275 DCHECK(response_info_->headers->response_code() == 401 ||
276 response_info_->headers->response_code() == 407);
277
278 *result = response_info_->auth_challenge;
279}
280
[email protected]175adac2008-07-30 17:28:04281void URLRequestHttpJob::SetAuth(const std::wstring& username,
282 const std::wstring& password) {
[email protected]af4876d2008-10-21 23:10:57283 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52284
285 // Proxy gets set first, then WWW.
[email protected]a9bb6f692008-07-30 16:40:10286 if (proxy_auth_state_ == net::AUTH_STATE_NEED_AUTH) {
287 proxy_auth_state_ = net::AUTH_STATE_HAVE_AUTH;
initial.commit586acc5fe2008-07-26 22:42:52288 } else {
[email protected]a9bb6f692008-07-30 16:40:10289 DCHECK(server_auth_state_ == net::AUTH_STATE_NEED_AUTH);
290 server_auth_state_ = net::AUTH_STATE_HAVE_AUTH;
initial.commit586acc5fe2008-07-26 22:42:52291 }
292
293 // These will be reset in OnStartCompleted.
294 response_info_ = NULL;
295 response_cookies_.clear();
296
297 // No matter what, we want to report our status as IO pending since we will
298 // be notifying our consumer asynchronously via OnStartCompleted.
299 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
300
301 int rv = transaction_->RestartWithAuth(username, password,
302 &start_callback_);
303 if (rv == net::ERR_IO_PENDING)
304 return;
305
306 // The transaction started synchronously, but we need to notify the
307 // URLRequest delegate via the message loop.
308 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
[email protected]175adac2008-07-30 17:28:04309 this, &URLRequestHttpJob::OnStartCompleted, rv));
initial.commit586acc5fe2008-07-26 22:42:52310}
311
[email protected]175adac2008-07-30 17:28:04312void URLRequestHttpJob::CancelAuth() {
initial.commit586acc5fe2008-07-26 22:42:52313 // Proxy gets set first, then WWW.
[email protected]a9bb6f692008-07-30 16:40:10314 if (proxy_auth_state_ == net::AUTH_STATE_NEED_AUTH) {
315 proxy_auth_state_ = net::AUTH_STATE_CANCELED;
initial.commit586acc5fe2008-07-26 22:42:52316 } else {
[email protected]a9bb6f692008-07-30 16:40:10317 DCHECK(server_auth_state_ == net::AUTH_STATE_NEED_AUTH);
318 server_auth_state_ = net::AUTH_STATE_CANCELED;
initial.commit586acc5fe2008-07-26 22:42:52319 }
320
321 // These will be reset in OnStartCompleted.
322 response_info_ = NULL;
323 response_cookies_.clear();
324
325 // OK, let the consumer read the error page...
326 //
327 // Because we set the AUTH_STATE_CANCELED flag, NeedsAuth will return false,
328 // which will cause the consumer to receive OnResponseStarted instead of
329 // OnAuthRequired.
330 //
331 // We have to do this via InvokeLater to avoid "recursing" the consumer.
332 //
333 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
[email protected]175adac2008-07-30 17:28:04334 this, &URLRequestHttpJob::OnStartCompleted, net::OK));
initial.commit586acc5fe2008-07-26 22:42:52335}
336
[email protected]175adac2008-07-30 17:28:04337void URLRequestHttpJob::ContinueDespiteLastError() {
[email protected]9ec48752009-02-06 23:33:58338 // If the transaction was destroyed, then the job was cancelled.
339 if (!transaction_.get())
340 return;
341
initial.commit586acc5fe2008-07-26 22:42:52342 DCHECK(!response_info_) << "should not have a response yet";
343
344 // No matter what, we want to report our status as IO pending since we will
345 // be notifying our consumer asynchronously via OnStartCompleted.
346 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
347
348 int rv = transaction_->RestartIgnoringLastError(&start_callback_);
349 if (rv == net::ERR_IO_PENDING)
350 return;
351
352 // The transaction started synchronously, but we need to notify the
353 // URLRequest delegate via the message loop.
354 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
[email protected]175adac2008-07-30 17:28:04355 this, &URLRequestHttpJob::OnStartCompleted, rv));
initial.commit586acc5fe2008-07-26 22:42:52356}
357
[email protected]175adac2008-07-30 17:28:04358bool URLRequestHttpJob::GetMoreData() {
[email protected]af4876d2008-10-21 23:10:57359 return transaction_.get() && !read_in_progress_;
initial.commit586acc5fe2008-07-26 22:42:52360}
361
[email protected]9dea9e1f2009-01-29 00:30:47362bool URLRequestHttpJob::ReadRawData(net::IOBuffer* buf, int buf_size,
363 int *bytes_read) {
initial.commit586acc5fe2008-07-26 22:42:52364 DCHECK_NE(buf_size, 0);
365 DCHECK(bytes_read);
366 DCHECK(!read_in_progress_);
367
368 int rv = transaction_->Read(buf, buf_size, &read_callback_);
369 if (rv >= 0) {
370 *bytes_read = rv;
371 return true;
372 }
373
374 if (rv == net::ERR_IO_PENDING) {
375 read_in_progress_ = true;
376 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
377 } else {
378 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
379 }
380
381 return false;
382}
383
[email protected]175adac2008-07-30 17:28:04384void URLRequestHttpJob::OnStartCompleted(int result) {
initial.commit586acc5fe2008-07-26 22:42:52385 // If the request was destroyed, then there is no more work to do.
386 if (!request_ || !request_->delegate())
387 return;
388
389 // If the transaction was destroyed, then the job was cancelled, and
390 // we can just ignore this notification.
[email protected]af4876d2008-10-21 23:10:57391 if (!transaction_.get())
initial.commit586acc5fe2008-07-26 22:42:52392 return;
393
394 // Clear the IO_PENDING status
395 SetStatus(URLRequestStatus());
396
397 if (result == net::OK) {
398 NotifyHeadersComplete();
[email protected]4ed2755f2008-12-15 09:01:33399 } else if (net::IsCertificateError(result) &&
[email protected]bb975362009-01-21 01:00:22400 !CommandLine::ForCurrentProcess()->HasSwitch(
401 switches::kForceHTTPS)) {
initial.commit586acc5fe2008-07-26 22:42:52402 // We encountered an SSL certificate error. Ask our delegate to decide
403 // what we should do.
404 // TODO(wtc): also pass ssl_info.cert_status, or just pass the whole
405 // ssl_info.
406 request_->delegate()->OnSSLCertificateError(
407 request_, result, transaction_->GetResponseInfo()->ssl_info.cert);
408 } else {
409 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
410 }
411}
412
[email protected]175adac2008-07-30 17:28:04413void URLRequestHttpJob::OnReadCompleted(int result) {
initial.commit586acc5fe2008-07-26 22:42:52414 read_in_progress_ = false;
415
416 if (result == 0) {
417 NotifyDone(URLRequestStatus());
418 } else if (result < 0) {
419 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result));
420 } else {
421 // Clear the IO_PENDING status
422 SetStatus(URLRequestStatus());
423 }
424
425 NotifyReadComplete(result);
426}
427
[email protected]175adac2008-07-30 17:28:04428void URLRequestHttpJob::NotifyHeadersComplete() {
initial.commit586acc5fe2008-07-26 22:42:52429 DCHECK(!response_info_);
430
431 response_info_ = transaction_->GetResponseInfo();
432
433 // Get the Set-Cookie values, and send them to our cookie database.
[email protected]b8430722008-09-17 20:05:44434 if (!(request_info_.load_flags & net::LOAD_DO_NOT_SAVE_COOKIES)) {
435 URLRequestContext* ctx = request_->context();
436 if (ctx && ctx->cookie_store() &&
437 ctx->cookie_policy()->CanSetCookie(request_->url(),
438 request_->policy_url())) {
439 FetchResponseCookies();
[email protected]3a96c742008-11-19 19:46:27440 net::CookieMonster::CookieOptions options;
441 options.set_include_httponly();
442 ctx->cookie_store()->SetCookiesWithOptions(request_->url(),
443 response_cookies_,
444 options);
[email protected]b8430722008-09-17 20:05:44445 }
446 }
initial.commit586acc5fe2008-07-26 22:42:52447
[email protected]60889422008-09-23 01:18:16448 // Get list of SDCH dictionary requests, and schedule them to be loaded.
[email protected]fe219872008-09-23 02:17:00449 if (SdchManager::Global() &&
450 SdchManager::Global()->IsInSupportedDomain(request_->url())) {
[email protected]60889422008-09-23 01:18:16451 static const std::string name = "Get-Dictionary";
452 std::string url_text;
453 void* iter = NULL;
454 // TODO(jar): We need to not fetch dictionaries the first time they are
455 // seen, but rather wait until we can justify their usefulness.
456 // For now, we will only fetch the first dictionary, which will at least
457 // require multiple suggestions before we get additional ones for this site.
458 // Eventually we should wait until a dictionary is requested several times
459 // before we even download it (so that we don't waste memory or bandwidth).
460 if (response_info_->headers->EnumerateHeader(&iter, name, &url_text)) {
461 GURL dictionary_url = request_->url().Resolve(url_text);
462 SdchManager::Global()->FetchDictionary(request_->url(), dictionary_url);
463 }
464 }
465
initial.commit586acc5fe2008-07-26 22:42:52466 URLRequestJob::NotifyHeadersComplete();
467}
468
[email protected]175adac2008-07-30 17:28:04469void URLRequestHttpJob::DestroyTransaction() {
[email protected]af4876d2008-10-21 23:10:57470 DCHECK(transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52471
[email protected]af4876d2008-10-21 23:10:57472 transaction_.reset();
initial.commit586acc5fe2008-07-26 22:42:52473 response_info_ = NULL;
474}
475
[email protected]175adac2008-07-30 17:28:04476void URLRequestHttpJob::StartTransaction() {
initial.commit586acc5fe2008-07-26 22:42:52477 // NOTE: This method assumes that request_info_ is already setup properly.
478
479 // Create a transaction.
[email protected]af4876d2008-10-21 23:10:57480 DCHECK(!transaction_.get());
initial.commit586acc5fe2008-07-26 22:42:52481
482 DCHECK(request_->context());
483 DCHECK(request_->context()->http_transaction_factory());
484
[email protected]af4876d2008-10-21 23:10:57485 transaction_.reset(
486 request_->context()->http_transaction_factory()->CreateTransaction());
initial.commit586acc5fe2008-07-26 22:42:52487
488 // No matter what, we want to report our status as IO pending since we will
489 // be notifying our consumer asynchronously via OnStartCompleted.
490 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
491
492 int rv;
[email protected]af4876d2008-10-21 23:10:57493 if (transaction_.get()) {
initial.commit586acc5fe2008-07-26 22:42:52494 rv = transaction_->Start(&request_info_, &start_callback_);
495 if (rv == net::ERR_IO_PENDING)
496 return;
497 } else {
498 rv = net::ERR_FAILED;
499 }
500
501 // The transaction started synchronously, but we need to notify the
502 // URLRequest delegate via the message loop.
503 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
[email protected]175adac2008-07-30 17:28:04504 this, &URLRequestHttpJob::OnStartCompleted, rv));
initial.commit586acc5fe2008-07-26 22:42:52505}
506
[email protected]175adac2008-07-30 17:28:04507void URLRequestHttpJob::AddExtraHeaders() {
[email protected]423041b2008-10-27 17:39:28508 // Supply Accept-Encoding headers first so that it is more likely that they
509 // will be in the first transmitted packet. This can sometimes make it easier
510 // to filter and analyze the streams to assure that a proxy has not damaged
511 // these headers. Some proxies deliberately corrupt Accept-Encoding headers.
512 if (!SdchManager::Global() ||
513 !SdchManager::Global()->IsInSupportedDomain(request_->url())) {
514 // Tell the server what compression formats we support (other than SDCH).
515 request_info_.extra_headers += "Accept-Encoding: gzip,deflate,bzip2\r\n";
516 } else {
517 // Supply SDCH related headers, as well as accepting that encoding.
518 // Tell the server what compression formats we support.
519 request_info_.extra_headers += "Accept-Encoding: "
520 "gzip,deflate,bzip2,sdch\r\n";
521
522 // TODO(jar): See if it is worth optimizing away these bytes when the URL is
523 // probably an img or such. (and SDCH encoding is not likely).
524 std::string avail_dictionaries;
525 SdchManager::Global()->GetAvailDictionaryList(request_->url(),
526 &avail_dictionaries);
527 if (!avail_dictionaries.empty()) {
528 request_info_.extra_headers += "Avail-Dictionary: "
529 + avail_dictionaries + "\r\n";
530 request_info_.load_flags |= net::LOAD_SDCH_DICTIONARY_ADVERTISED;
531 }
[email protected]423041b2008-10-27 17:39:28532 }
533
initial.commit586acc5fe2008-07-26 22:42:52534 URLRequestContext* context = request_->context();
535 if (context) {
536 // Add in the cookie header. TODO might we need more than one header?
537 if (context->cookie_store() &&
538 context->cookie_policy()->CanGetCookies(request_->url(),
539 request_->policy_url())) {
[email protected]3a96c742008-11-19 19:46:27540 net::CookieMonster::CookieOptions options;
541 options.set_include_httponly();
initial.commit586acc5fe2008-07-26 22:42:52542 std::string cookies = request_->context()->cookie_store()->
[email protected]3a96c742008-11-19 19:46:27543 GetCookiesWithOptions(request_->url(), options);
initial.commit586acc5fe2008-07-26 22:42:52544 if (!cookies.empty())
545 request_info_.extra_headers += "Cookie: " + cookies + "\r\n";
546 }
547 if (!context->accept_language().empty())
548 request_info_.extra_headers += "Accept-Language: " +
549 context->accept_language() + "\r\n";
550 if (!context->accept_charset().empty())
551 request_info_.extra_headers += "Accept-Charset: " +
552 context->accept_charset() + "\r\n";
553 }
initial.commit586acc5fe2008-07-26 22:42:52554}
555
[email protected]175adac2008-07-30 17:28:04556void URLRequestHttpJob::FetchResponseCookies() {
initial.commit586acc5fe2008-07-26 22:42:52557 DCHECK(response_info_);
558 DCHECK(response_cookies_.empty());
559
560 std::string name = "Set-Cookie";
561 std::string value;
562
563 void* iter = NULL;
564 while (response_info_->headers->EnumerateHeader(&iter, name, &value))
565 response_cookies_.push_back(value);
566}
license.botbf09a502008-08-24 00:55:55567