• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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.
4 
5 #include "net/url_request/url_request.h"
6 
7 #include "base/compiler_specific.h"
8 #include "base/memory/singleton.h"
9 #include "base/message_loop.h"
10 #include "base/metrics/stats_counters.h"
11 #include "base/synchronization/lock.h"
12 #include "net/base/host_port_pair.h"
13 #include "net/base/load_flags.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/net_log.h"
16 #include "net/base/network_delegate.h"
17 #include "net/base/ssl_cert_request_info.h"
18 #include "net/base/upload_data.h"
19 #include "net/http/http_response_headers.h"
20 #include "net/http/http_util.h"
21 #include "net/url_request/url_request_context.h"
22 #include "net/url_request/url_request_error_job.h"
23 #include "net/url_request/url_request_job.h"
24 #include "net/url_request/url_request_job_manager.h"
25 #include "net/url_request/url_request_netlog_params.h"
26 #include "net/url_request/url_request_redirect_job.h"
27 
28 using base::Time;
29 using std::string;
30 
31 namespace net {
32 
33 namespace {
34 
35 // Max number of http redirects to follow.  Same number as gecko.
36 const int kMaxRedirects = 20;
37 
38 // Discard headers which have meaning in POST (Content-Length, Content-Type,
39 // Origin).
StripPostSpecificHeaders(HttpRequestHeaders * headers)40 void StripPostSpecificHeaders(HttpRequestHeaders* headers) {
41   // These are headers that may be attached to a POST.
42   headers->RemoveHeader(HttpRequestHeaders::kContentLength);
43   headers->RemoveHeader(HttpRequestHeaders::kContentType);
44   headers->RemoveHeader(HttpRequestHeaders::kOrigin);
45 }
46 
47 // This counter keeps track of the identifiers used for URL requests so far.
48 // 0 is reserved to represent an invalid ID.
49 uint64 g_next_url_request_identifier = 1;
50 
51 // This lock protects g_next_url_request_identifier.
52 base::Lock g_next_url_request_identifier_lock;
53 
54 // Returns an prior unused identifier for URL requests.
GenerateURLRequestIdentifier()55 uint64 GenerateURLRequestIdentifier() {
56   base::AutoLock lock(g_next_url_request_identifier_lock);
57   return g_next_url_request_identifier++;
58 }
59 
60 }  // namespace
61 
62 ///////////////////////////////////////////////////////////////////////////////
63 // URLRequest::Interceptor
64 
MaybeInterceptRedirect(URLRequest * request,const GURL & location)65 URLRequestJob* URLRequest::Interceptor::MaybeInterceptRedirect(
66     URLRequest* request,
67     const GURL& location) {
68   return NULL;
69 }
70 
MaybeInterceptResponse(URLRequest * request)71 URLRequestJob* URLRequest::Interceptor::MaybeInterceptResponse(
72     URLRequest* request) {
73   return NULL;
74 }
75 
76 ///////////////////////////////////////////////////////////////////////////////
77 // URLRequest::Delegate
78 
OnReceivedRedirect(URLRequest * request,const GURL & new_url,bool * defer_redirect)79 void URLRequest::Delegate::OnReceivedRedirect(URLRequest* request,
80                                               const GURL& new_url,
81                                               bool* defer_redirect) {
82 }
83 
OnAuthRequired(URLRequest * request,AuthChallengeInfo * auth_info)84 void URLRequest::Delegate::OnAuthRequired(URLRequest* request,
85                                           AuthChallengeInfo* auth_info) {
86   request->CancelAuth();
87 }
88 
OnCertificateRequested(URLRequest * request,SSLCertRequestInfo * cert_request_info)89 void URLRequest::Delegate::OnCertificateRequested(
90     URLRequest* request,
91     SSLCertRequestInfo* cert_request_info) {
92   request->ContinueWithCertificate(NULL);
93 }
94 
OnSSLCertificateError(URLRequest * request,int cert_error,X509Certificate * cert)95 void URLRequest::Delegate::OnSSLCertificateError(URLRequest* request,
96                                                  int cert_error,
97                                                  X509Certificate* cert) {
98   request->Cancel();
99 }
100 
OnGetCookies(URLRequest * request,bool blocked_by_policy)101 void URLRequest::Delegate::OnGetCookies(URLRequest* request,
102                                         bool blocked_by_policy) {
103 }
104 
OnSetCookie(URLRequest * request,const std::string & cookie_line,const CookieOptions & options,bool blocked_by_policy)105 void URLRequest::Delegate::OnSetCookie(URLRequest* request,
106                                        const std::string& cookie_line,
107                                        const CookieOptions& options,
108                                        bool blocked_by_policy) {
109 }
110 
111 ///////////////////////////////////////////////////////////////////////////////
112 // URLRequest
113 
URLRequest(const GURL & url,Delegate * delegate)114 URLRequest::URLRequest(const GURL& url, Delegate* delegate)
115     : url_chain_(1, url),
116       method_("GET"),
117       load_flags_(LOAD_NORMAL),
118       delegate_(delegate),
119       is_pending_(false),
120       redirect_limit_(kMaxRedirects),
121       final_upload_progress_(0),
122       priority_(LOWEST),
123       identifier_(GenerateURLRequestIdentifier()),
124       ALLOW_THIS_IN_INITIALIZER_LIST(
125           before_request_callback_(this, &URLRequest::BeforeRequestComplete)) {
126   SIMPLE_STATS_COUNTER("URLRequestCount");
127 
128   // Sanity check out environment.
129   DCHECK(MessageLoop::current()) <<
130       "The current MessageLoop must exist";
131   DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()) <<
132       "The current MessageLoop must be TYPE_IO";
133 }
134 
~URLRequest()135 URLRequest::~URLRequest() {
136   if (context_ && context_->network_delegate())
137     context_->network_delegate()->NotifyURLRequestDestroyed(this);
138 
139   Cancel();
140 
141   if (job_)
142     OrphanJob();
143 
144   set_context(NULL);
145 }
146 
147 // static
RegisterProtocolFactory(const string & scheme,ProtocolFactory * factory)148 URLRequest::ProtocolFactory* URLRequest::RegisterProtocolFactory(
149     const string& scheme, ProtocolFactory* factory) {
150   return URLRequestJobManager::GetInstance()->RegisterProtocolFactory(scheme,
151                                                                       factory);
152 }
153 
154 // static
RegisterRequestInterceptor(Interceptor * interceptor)155 void URLRequest::RegisterRequestInterceptor(Interceptor* interceptor) {
156   URLRequestJobManager::GetInstance()->RegisterRequestInterceptor(interceptor);
157 }
158 
159 // static
UnregisterRequestInterceptor(Interceptor * interceptor)160 void URLRequest::UnregisterRequestInterceptor(Interceptor* interceptor) {
161   URLRequestJobManager::GetInstance()->UnregisterRequestInterceptor(
162       interceptor);
163 }
164 
AppendBytesToUpload(const char * bytes,int bytes_len)165 void URLRequest::AppendBytesToUpload(const char* bytes, int bytes_len) {
166   DCHECK(bytes_len > 0 && bytes);
167   if (!upload_)
168     upload_ = new UploadData();
169   upload_->AppendBytes(bytes, bytes_len);
170 }
171 
AppendFileRangeToUpload(const FilePath & file_path,uint64 offset,uint64 length,const base::Time & expected_modification_time)172 void URLRequest::AppendFileRangeToUpload(
173     const FilePath& file_path,
174     uint64 offset,
175     uint64 length,
176     const base::Time& expected_modification_time) {
177   DCHECK(file_path.value().length() > 0 && length > 0);
178   if (!upload_)
179     upload_ = new UploadData();
180   upload_->AppendFileRange(file_path, offset, length,
181                            expected_modification_time);
182 }
183 
EnableChunkedUpload()184 void URLRequest::EnableChunkedUpload() {
185   DCHECK(!upload_ || upload_->is_chunked());
186   if (!upload_) {
187     upload_ = new UploadData();
188     upload_->set_is_chunked(true);
189   }
190 }
191 
AppendChunkToUpload(const char * bytes,int bytes_len,bool is_last_chunk)192 void URLRequest::AppendChunkToUpload(const char* bytes,
193                                      int bytes_len,
194                                      bool is_last_chunk) {
195   DCHECK(upload_);
196   DCHECK(upload_->is_chunked());
197   DCHECK_GT(bytes_len, 0);
198   upload_->AppendChunk(bytes, bytes_len, is_last_chunk);
199 }
200 
set_upload(UploadData * upload)201 void URLRequest::set_upload(UploadData* upload) {
202   upload_ = upload;
203 }
204 
205 // Get the upload data directly.
get_upload()206 UploadData* URLRequest::get_upload() {
207   return upload_.get();
208 }
209 
has_upload() const210 bool URLRequest::has_upload() const {
211   return upload_ != NULL;
212 }
213 
SetExtraRequestHeaderById(int id,const string & value,bool overwrite)214 void URLRequest::SetExtraRequestHeaderById(int id, const string& value,
215                                            bool overwrite) {
216   DCHECK(!is_pending_);
217   NOTREACHED() << "implement me!";
218 }
219 
SetExtraRequestHeaderByName(const string & name,const string & value,bool overwrite)220 void URLRequest::SetExtraRequestHeaderByName(const string& name,
221                                              const string& value,
222                                              bool overwrite) {
223   DCHECK(!is_pending_);
224   if (overwrite) {
225     extra_request_headers_.SetHeader(name, value);
226   } else {
227     extra_request_headers_.SetHeaderIfMissing(name, value);
228   }
229 }
230 
SetExtraRequestHeaders(const HttpRequestHeaders & headers)231 void URLRequest::SetExtraRequestHeaders(
232     const HttpRequestHeaders& headers) {
233   DCHECK(!is_pending_);
234   extra_request_headers_ = headers;
235 
236   // NOTE: This method will likely become non-trivial once the other setters
237   // for request headers are implemented.
238 }
239 
GetLoadState() const240 LoadState URLRequest::GetLoadState() const {
241   return job_ ? job_->GetLoadState() : LOAD_STATE_IDLE;
242 }
243 
GetUploadProgress() const244 uint64 URLRequest::GetUploadProgress() const {
245   if (!job_) {
246     // We haven't started or the request was cancelled
247     return 0;
248   }
249   if (final_upload_progress_) {
250     // The first job completed and none of the subsequent series of
251     // GETs when following redirects will upload anything, so we return the
252     // cached results from the initial job, the POST.
253     return final_upload_progress_;
254   }
255   return job_->GetUploadProgress();
256 }
257 
GetResponseHeaderById(int id,string * value)258 void URLRequest::GetResponseHeaderById(int id, string* value) {
259   DCHECK(job_);
260   NOTREACHED() << "implement me!";
261 }
262 
GetResponseHeaderByName(const string & name,string * value)263 void URLRequest::GetResponseHeaderByName(const string& name, string* value) {
264   DCHECK(value);
265   if (response_info_.headers) {
266     response_info_.headers->GetNormalizedHeader(name, value);
267   } else {
268     value->clear();
269   }
270 }
271 
GetAllResponseHeaders(string * headers)272 void URLRequest::GetAllResponseHeaders(string* headers) {
273   DCHECK(headers);
274   if (response_info_.headers) {
275     response_info_.headers->GetNormalizedHeaders(headers);
276   } else {
277     headers->clear();
278   }
279 }
280 
GetSocketAddress() const281 HostPortPair URLRequest::GetSocketAddress() const {
282   DCHECK(job_);
283   return job_->GetSocketAddress();
284 }
285 
response_headers() const286 HttpResponseHeaders* URLRequest::response_headers() const {
287   return response_info_.headers.get();
288 }
289 
GetResponseCookies(ResponseCookies * cookies)290 bool URLRequest::GetResponseCookies(ResponseCookies* cookies) {
291   DCHECK(job_);
292   return job_->GetResponseCookies(cookies);
293 }
294 
GetMimeType(string * mime_type)295 void URLRequest::GetMimeType(string* mime_type) {
296   DCHECK(job_);
297   job_->GetMimeType(mime_type);
298 }
299 
GetCharset(string * charset)300 void URLRequest::GetCharset(string* charset) {
301   DCHECK(job_);
302   job_->GetCharset(charset);
303 }
304 
GetResponseCode()305 int URLRequest::GetResponseCode() {
306   DCHECK(job_);
307   return job_->GetResponseCode();
308 }
309 
310 // static
IsHandledProtocol(const std::string & scheme)311 bool URLRequest::IsHandledProtocol(const std::string& scheme) {
312   return URLRequestJobManager::GetInstance()->SupportsScheme(scheme);
313 }
314 
315 // static
IsHandledURL(const GURL & url)316 bool URLRequest::IsHandledURL(const GURL& url) {
317   if (!url.is_valid()) {
318     // We handle error cases.
319     return true;
320   }
321 
322   return IsHandledProtocol(url.scheme());
323 }
324 
325 // static
AllowFileAccess()326 void URLRequest::AllowFileAccess() {
327   URLRequestJobManager::GetInstance()->set_enable_file_access(true);
328 }
329 
330 // static
IsFileAccessAllowed()331 bool URLRequest::IsFileAccessAllowed() {
332   return URLRequestJobManager::GetInstance()->enable_file_access();
333 }
334 
335 
set_first_party_for_cookies(const GURL & first_party_for_cookies)336 void URLRequest::set_first_party_for_cookies(
337     const GURL& first_party_for_cookies) {
338   first_party_for_cookies_ = first_party_for_cookies;
339 }
340 
set_method(const std::string & method)341 void URLRequest::set_method(const std::string& method) {
342   DCHECK(!is_pending_);
343   method_ = method;
344 }
345 
set_referrer(const std::string & referrer)346 void URLRequest::set_referrer(const std::string& referrer) {
347   DCHECK(!is_pending_);
348   referrer_ = referrer;
349 }
350 
GetSanitizedReferrer() const351 GURL URLRequest::GetSanitizedReferrer() const {
352   GURL ret(referrer());
353 
354   // Ensure that we do not send username and password fields in the referrer.
355   if (ret.has_username() || ret.has_password()) {
356     GURL::Replacements referrer_mods;
357     referrer_mods.ClearUsername();
358     referrer_mods.ClearPassword();
359     ret = ret.ReplaceComponents(referrer_mods);
360   }
361 
362   return ret;
363 }
364 
Start()365 void URLRequest::Start() {
366   response_info_.request_time = Time::Now();
367 
368   // Only notify the delegate for the initial request.
369   if (context_ && context_->network_delegate()) {
370     if (context_->network_delegate()->NotifyBeforeURLRequest(
371             this, &before_request_callback_, &delegate_redirect_url_) ==
372             net::ERR_IO_PENDING) {
373       net_log_.BeginEvent(NetLog::TYPE_URL_REQUEST_BLOCKED_ON_EXTENSION, NULL);
374       return;  // paused
375     }
376   }
377 
378   StartInternal();
379 }
380 
381 ///////////////////////////////////////////////////////////////////////////////
382 
BeforeRequestComplete(int error)383 void URLRequest::BeforeRequestComplete(int error) {
384   DCHECK(!job_);
385   DCHECK_NE(ERR_IO_PENDING, error);
386 
387   net_log_.EndEvent(NetLog::TYPE_URL_REQUEST_BLOCKED_ON_EXTENSION, NULL);
388   if (error != OK) {
389     StartJob(new URLRequestErrorJob(this, error));
390   } else if (!delegate_redirect_url_.is_empty()) {
391     GURL new_url;
392     new_url.Swap(&delegate_redirect_url_);
393     StartJob(new URLRequestRedirectJob(this, new_url));
394   } else {
395     StartInternal();
396   }
397 }
398 
StartInternal()399 void URLRequest::StartInternal() {
400   StartJob(URLRequestJobManager::GetInstance()->CreateJob(this));
401 }
402 
StartJob(URLRequestJob * job)403 void URLRequest::StartJob(URLRequestJob* job) {
404   DCHECK(!is_pending_);
405   DCHECK(!job_);
406 
407   net_log_.BeginEvent(
408       NetLog::TYPE_URL_REQUEST_START_JOB,
409       make_scoped_refptr(new URLRequestStartEventParameters(
410           url(), method_, load_flags_, priority_)));
411 
412   job_ = job;
413   job_->SetExtraRequestHeaders(extra_request_headers_);
414 
415   if (upload_.get())
416     job_->SetUpload(upload_.get());
417 
418   is_pending_ = true;
419 
420   response_info_.was_cached = false;
421 
422   // Don't allow errors to be sent from within Start().
423   // TODO(brettw) this may cause NotifyDone to be sent synchronously,
424   // we probably don't want this: they should be sent asynchronously so
425   // the caller does not get reentered.
426   job_->Start();
427 }
428 
Restart()429 void URLRequest::Restart() {
430   // Should only be called if the original job didn't make any progress.
431   DCHECK(job_ && !job_->has_response_started());
432   RestartWithJob(URLRequestJobManager::GetInstance()->CreateJob(this));
433 }
434 
RestartWithJob(URLRequestJob * job)435 void URLRequest::RestartWithJob(URLRequestJob *job) {
436   DCHECK(job->request() == this);
437   PrepareToRestart();
438   StartJob(job);
439 }
440 
Cancel()441 void URLRequest::Cancel() {
442   DoCancel(ERR_ABORTED, SSLInfo());
443 }
444 
SimulateError(int os_error)445 void URLRequest::SimulateError(int os_error) {
446   DoCancel(os_error, SSLInfo());
447 }
448 
SimulateSSLError(int os_error,const SSLInfo & ssl_info)449 void URLRequest::SimulateSSLError(int os_error, const SSLInfo& ssl_info) {
450   // This should only be called on a started request.
451   if (!is_pending_ || !job_ || job_->has_response_started()) {
452     NOTREACHED();
453     return;
454   }
455   DoCancel(os_error, ssl_info);
456 }
457 
DoCancel(int os_error,const SSLInfo & ssl_info)458 void URLRequest::DoCancel(int os_error, const SSLInfo& ssl_info) {
459   DCHECK(os_error < 0);
460 
461   // If the URL request already has an error status, then canceling is a no-op.
462   // Plus, we don't want to change the error status once it has been set.
463   if (status_.is_success()) {
464     status_.set_status(URLRequestStatus::CANCELED);
465     status_.set_os_error(os_error);
466     response_info_.ssl_info = ssl_info;
467   }
468 
469   // There's nothing to do if we are not waiting on a Job.
470   if (!is_pending_ || !job_)
471     return;
472 
473   job_->Kill();
474 
475   // The Job will call our NotifyDone method asynchronously.  This is done so
476   // that the Delegate implementation can call Cancel without having to worry
477   // about being called recursively.
478 }
479 
Read(IOBuffer * dest,int dest_size,int * bytes_read)480 bool URLRequest::Read(IOBuffer* dest, int dest_size, int* bytes_read) {
481   DCHECK(job_);
482   DCHECK(bytes_read);
483   DCHECK(!job_->is_done());
484   *bytes_read = 0;
485 
486   if (dest_size == 0) {
487     // Caller is not too bright.  I guess we've done what they asked.
488     return true;
489   }
490 
491   // Once the request fails or is cancelled, read will just return 0 bytes
492   // to indicate end of stream.
493   if (!status_.is_success()) {
494     return true;
495   }
496 
497   return job_->Read(dest, dest_size, bytes_read);
498 }
499 
StopCaching()500 void URLRequest::StopCaching() {
501   DCHECK(job_);
502   job_->StopCaching();
503 }
504 
ReceivedRedirect(const GURL & location,bool * defer_redirect)505 void URLRequest::ReceivedRedirect(const GURL& location, bool* defer_redirect) {
506   URLRequestJob* job =
507       URLRequestJobManager::GetInstance()->MaybeInterceptRedirect(this,
508                                                                   location);
509   if (job) {
510     RestartWithJob(job);
511   } else if (delegate_) {
512     delegate_->OnReceivedRedirect(this, location, defer_redirect);
513   }
514 }
515 
ResponseStarted()516 void URLRequest::ResponseStarted() {
517   scoped_refptr<NetLog::EventParameters> params;
518   if (!status_.is_success())
519     params = new NetLogIntegerParameter("net_error", status_.os_error());
520   net_log_.EndEvent(NetLog::TYPE_URL_REQUEST_START_JOB, params);
521 
522   URLRequestJob* job =
523       URLRequestJobManager::GetInstance()->MaybeInterceptResponse(this);
524   if (job) {
525     RestartWithJob(job);
526   } else {
527     if (context_ && context_->network_delegate())
528       context_->network_delegate()->NotifyResponseStarted(this);
529     if (delegate_)
530       delegate_->OnResponseStarted(this);
531   }
532 }
533 
FollowDeferredRedirect()534 void URLRequest::FollowDeferredRedirect() {
535   CHECK(job_);
536   CHECK(status_.is_success());
537 
538   job_->FollowDeferredRedirect();
539 }
540 
SetAuth(const string16 & username,const string16 & password)541 void URLRequest::SetAuth(const string16& username, const string16& password) {
542   DCHECK(job_);
543   DCHECK(job_->NeedsAuth());
544 
545   job_->SetAuth(username, password);
546 }
547 
CancelAuth()548 void URLRequest::CancelAuth() {
549   DCHECK(job_);
550   DCHECK(job_->NeedsAuth());
551 
552   job_->CancelAuth();
553 }
554 
ContinueWithCertificate(X509Certificate * client_cert)555 void URLRequest::ContinueWithCertificate(X509Certificate* client_cert) {
556   DCHECK(job_);
557 
558   job_->ContinueWithCertificate(client_cert);
559 }
560 
ContinueDespiteLastError()561 void URLRequest::ContinueDespiteLastError() {
562   DCHECK(job_);
563 
564   job_->ContinueDespiteLastError();
565 }
566 
PrepareToRestart()567 void URLRequest::PrepareToRestart() {
568   DCHECK(job_);
569 
570   // Close the current URL_REQUEST_START_JOB, since we will be starting a new
571   // one.
572   net_log_.EndEvent(NetLog::TYPE_URL_REQUEST_START_JOB, NULL);
573 
574   OrphanJob();
575 
576   response_info_ = HttpResponseInfo();
577   response_info_.request_time = Time::Now();
578   status_ = URLRequestStatus();
579   is_pending_ = false;
580 }
581 
OrphanJob()582 void URLRequest::OrphanJob() {
583   job_->Kill();
584   job_->DetachRequest();  // ensures that the job will not call us again
585   job_ = NULL;
586 }
587 
Redirect(const GURL & location,int http_status_code)588 int URLRequest::Redirect(const GURL& location, int http_status_code) {
589   if (net_log_.IsLoggingAllEvents()) {
590     net_log_.AddEvent(
591         NetLog::TYPE_URL_REQUEST_REDIRECTED,
592         make_scoped_refptr(new NetLogStringParameter(
593             "location", location.possibly_invalid_spec())));
594   }
595   if (redirect_limit_ <= 0) {
596     DVLOG(1) << "disallowing redirect: exceeds limit";
597     return ERR_TOO_MANY_REDIRECTS;
598   }
599 
600   if (!location.is_valid())
601     return ERR_INVALID_URL;
602 
603   if (!job_->IsSafeRedirect(location)) {
604     DVLOG(1) << "disallowing redirect: unsafe protocol";
605     return ERR_UNSAFE_REDIRECT;
606   }
607 
608   bool strip_post_specific_headers = false;
609   if (http_status_code != 307) {
610     // NOTE: Even though RFC 2616 says to preserve the request method when
611     // following a 302 redirect, normal browsers don't do that.  Instead, they
612     // all convert a POST into a GET in response to a 302 and so shall we.  For
613     // 307 redirects, browsers preserve the method.  The RFC says to prompt the
614     // user to confirm the generation of a new POST request, but IE omits this
615     // prompt and so shall we.
616     strip_post_specific_headers = method_ == "POST";
617     method_ = "GET";
618     upload_ = NULL;
619   }
620 
621   // Suppress the referrer if we're redirecting out of https.
622   if (GURL(referrer_).SchemeIsSecure() && !location.SchemeIsSecure())
623     referrer_.clear();
624 
625   url_chain_.push_back(location);
626   --redirect_limit_;
627 
628   if (strip_post_specific_headers) {
629     // If being switched from POST to GET, must remove headers that were
630     // specific to the POST and don't have meaning in GET. For example
631     // the inclusion of a multipart Content-Type header in GET can cause
632     // problems with some servers:
633     // http://code.google.com/p/chromium/issues/detail?id=843
634     StripPostSpecificHeaders(&extra_request_headers_);
635   }
636 
637   if (!final_upload_progress_)
638     final_upload_progress_ = job_->GetUploadProgress();
639 
640   PrepareToRestart();
641   StartInternal();
642   return OK;
643 }
644 
context() const645 URLRequestContext* URLRequest::context() const {
646   return context_.get();
647 }
648 
set_context(URLRequestContext * context)649 void URLRequest::set_context(URLRequestContext* context) {
650   scoped_refptr<URLRequestContext> prev_context = context_;
651 
652   context_ = context;
653 
654   // If the context this request belongs to has changed, update the tracker.
655   if (prev_context != context) {
656     net_log_.EndEvent(NetLog::TYPE_REQUEST_ALIVE, NULL);
657     net_log_ = BoundNetLog();
658 
659     if (context) {
660       net_log_ = BoundNetLog::Make(context->net_log(),
661                                    NetLog::SOURCE_URL_REQUEST);
662       net_log_.BeginEvent(NetLog::TYPE_REQUEST_ALIVE, NULL);
663     }
664   }
665 }
666 
GetExpectedContentSize() const667 int64 URLRequest::GetExpectedContentSize() const {
668   int64 expected_content_size = -1;
669   if (job_)
670     expected_content_size = job_->expected_content_size();
671 
672   return expected_content_size;
673 }
674 
GetUserData(const void * key) const675 URLRequest::UserData* URLRequest::GetUserData(const void* key) const {
676   UserDataMap::const_iterator found = user_data_.find(key);
677   if (found != user_data_.end())
678     return found->second.get();
679   return NULL;
680 }
681 
SetUserData(const void * key,UserData * data)682 void URLRequest::SetUserData(const void* key, UserData* data) {
683   user_data_[key] = linked_ptr<UserData>(data);
684 }
685 
686 }  // namespace net
687