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