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 NOTREACHED() << "implement me!";
225 }
226
SetExtraRequestHeaders(const HttpRequestHeaders & headers)227 void URLRequest::SetExtraRequestHeaders(
228 const HttpRequestHeaders& headers) {
229 DCHECK(!is_pending_);
230 extra_request_headers_ = headers;
231
232 // NOTE: This method will likely become non-trivial once the other setters
233 // for request headers are implemented.
234 }
235
GetLoadState() const236 LoadState URLRequest::GetLoadState() const {
237 return job_ ? job_->GetLoadState() : LOAD_STATE_IDLE;
238 }
239
GetUploadProgress() const240 uint64 URLRequest::GetUploadProgress() const {
241 if (!job_) {
242 // We haven't started or the request was cancelled
243 return 0;
244 }
245 if (final_upload_progress_) {
246 // The first job completed and none of the subsequent series of
247 // GETs when following redirects will upload anything, so we return the
248 // cached results from the initial job, the POST.
249 return final_upload_progress_;
250 }
251 return job_->GetUploadProgress();
252 }
253
GetResponseHeaderById(int id,string * value)254 void URLRequest::GetResponseHeaderById(int id, string* value) {
255 DCHECK(job_);
256 NOTREACHED() << "implement me!";
257 }
258
GetResponseHeaderByName(const string & name,string * value)259 void URLRequest::GetResponseHeaderByName(const string& name, string* value) {
260 DCHECK(value);
261 if (response_info_.headers) {
262 response_info_.headers->GetNormalizedHeader(name, value);
263 } else {
264 value->clear();
265 }
266 }
267
GetAllResponseHeaders(string * headers)268 void URLRequest::GetAllResponseHeaders(string* headers) {
269 DCHECK(headers);
270 if (response_info_.headers) {
271 response_info_.headers->GetNormalizedHeaders(headers);
272 } else {
273 headers->clear();
274 }
275 }
276
GetSocketAddress() const277 HostPortPair URLRequest::GetSocketAddress() const {
278 DCHECK(job_);
279 return job_->GetSocketAddress();
280 }
281
response_headers() const282 HttpResponseHeaders* URLRequest::response_headers() const {
283 return response_info_.headers.get();
284 }
285
GetResponseCookies(ResponseCookies * cookies)286 bool URLRequest::GetResponseCookies(ResponseCookies* cookies) {
287 DCHECK(job_);
288 return job_->GetResponseCookies(cookies);
289 }
290
GetMimeType(string * mime_type)291 void URLRequest::GetMimeType(string* mime_type) {
292 DCHECK(job_);
293 job_->GetMimeType(mime_type);
294 }
295
GetCharset(string * charset)296 void URLRequest::GetCharset(string* charset) {
297 DCHECK(job_);
298 job_->GetCharset(charset);
299 }
300
GetResponseCode()301 int URLRequest::GetResponseCode() {
302 DCHECK(job_);
303 return job_->GetResponseCode();
304 }
305
306 // static
IsHandledProtocol(const std::string & scheme)307 bool URLRequest::IsHandledProtocol(const std::string& scheme) {
308 return URLRequestJobManager::GetInstance()->SupportsScheme(scheme);
309 }
310
311 // static
IsHandledURL(const GURL & url)312 bool URLRequest::IsHandledURL(const GURL& url) {
313 if (!url.is_valid()) {
314 // We handle error cases.
315 return true;
316 }
317
318 return IsHandledProtocol(url.scheme());
319 }
320
321 // static
AllowFileAccess()322 void URLRequest::AllowFileAccess() {
323 URLRequestJobManager::GetInstance()->set_enable_file_access(true);
324 }
325
326 // static
IsFileAccessAllowed()327 bool URLRequest::IsFileAccessAllowed() {
328 return URLRequestJobManager::GetInstance()->enable_file_access();
329 }
330
331
set_first_party_for_cookies(const GURL & first_party_for_cookies)332 void URLRequest::set_first_party_for_cookies(
333 const GURL& first_party_for_cookies) {
334 first_party_for_cookies_ = first_party_for_cookies;
335 }
336
set_method(const std::string & method)337 void URLRequest::set_method(const std::string& method) {
338 DCHECK(!is_pending_);
339 method_ = method;
340 }
341
set_referrer(const std::string & referrer)342 void URLRequest::set_referrer(const std::string& referrer) {
343 DCHECK(!is_pending_);
344 referrer_ = referrer;
345 }
346
GetSanitizedReferrer() const347 GURL URLRequest::GetSanitizedReferrer() const {
348 GURL ret(referrer());
349
350 // Ensure that we do not send username and password fields in the referrer.
351 if (ret.has_username() || ret.has_password()) {
352 GURL::Replacements referrer_mods;
353 referrer_mods.ClearUsername();
354 referrer_mods.ClearPassword();
355 ret = ret.ReplaceComponents(referrer_mods);
356 }
357
358 return ret;
359 }
360
Start()361 void URLRequest::Start() {
362 response_info_.request_time = Time::Now();
363
364 // Only notify the delegate for the initial request.
365 if (context_ && context_->network_delegate()) {
366 if (context_->network_delegate()->NotifyBeforeURLRequest(
367 this, &before_request_callback_, &delegate_redirect_url_) ==
368 net::ERR_IO_PENDING) {
369 net_log_.BeginEvent(NetLog::TYPE_URL_REQUEST_BLOCKED_ON_EXTENSION, NULL);
370 return; // paused
371 }
372 }
373
374 StartInternal();
375 }
376
377 ///////////////////////////////////////////////////////////////////////////////
378
BeforeRequestComplete(int error)379 void URLRequest::BeforeRequestComplete(int error) {
380 DCHECK(!job_);
381 DCHECK_NE(ERR_IO_PENDING, error);
382
383 net_log_.EndEvent(NetLog::TYPE_URL_REQUEST_BLOCKED_ON_EXTENSION, NULL);
384 if (error != OK) {
385 StartJob(new URLRequestErrorJob(this, error));
386 } else if (!delegate_redirect_url_.is_empty()) {
387 GURL new_url;
388 new_url.Swap(&delegate_redirect_url_);
389 StartJob(new URLRequestRedirectJob(this, new_url));
390 } else {
391 StartInternal();
392 }
393 }
394
StartInternal()395 void URLRequest::StartInternal() {
396 StartJob(URLRequestJobManager::GetInstance()->CreateJob(this));
397 }
398
StartJob(URLRequestJob * job)399 void URLRequest::StartJob(URLRequestJob* job) {
400 DCHECK(!is_pending_);
401 DCHECK(!job_);
402
403 net_log_.BeginEvent(
404 NetLog::TYPE_URL_REQUEST_START_JOB,
405 make_scoped_refptr(new URLRequestStartEventParameters(
406 url(), method_, load_flags_, priority_)));
407
408 job_ = job;
409 job_->SetExtraRequestHeaders(extra_request_headers_);
410
411 if (upload_.get())
412 job_->SetUpload(upload_.get());
413
414 is_pending_ = true;
415
416 response_info_.was_cached = false;
417
418 // Don't allow errors to be sent from within Start().
419 // TODO(brettw) this may cause NotifyDone to be sent synchronously,
420 // we probably don't want this: they should be sent asynchronously so
421 // the caller does not get reentered.
422 job_->Start();
423 }
424
Restart()425 void URLRequest::Restart() {
426 // Should only be called if the original job didn't make any progress.
427 DCHECK(job_ && !job_->has_response_started());
428 RestartWithJob(URLRequestJobManager::GetInstance()->CreateJob(this));
429 }
430
RestartWithJob(URLRequestJob * job)431 void URLRequest::RestartWithJob(URLRequestJob *job) {
432 DCHECK(job->request() == this);
433 PrepareToRestart();
434 StartJob(job);
435 }
436
Cancel()437 void URLRequest::Cancel() {
438 DoCancel(ERR_ABORTED, SSLInfo());
439 }
440
SimulateError(int os_error)441 void URLRequest::SimulateError(int os_error) {
442 DoCancel(os_error, SSLInfo());
443 }
444
SimulateSSLError(int os_error,const SSLInfo & ssl_info)445 void URLRequest::SimulateSSLError(int os_error, const SSLInfo& ssl_info) {
446 // This should only be called on a started request.
447 if (!is_pending_ || !job_ || job_->has_response_started()) {
448 NOTREACHED();
449 return;
450 }
451 DoCancel(os_error, ssl_info);
452 }
453
DoCancel(int os_error,const SSLInfo & ssl_info)454 void URLRequest::DoCancel(int os_error, const SSLInfo& ssl_info) {
455 DCHECK(os_error < 0);
456
457 // If the URL request already has an error status, then canceling is a no-op.
458 // Plus, we don't want to change the error status once it has been set.
459 if (status_.is_success()) {
460 status_.set_status(URLRequestStatus::CANCELED);
461 status_.set_os_error(os_error);
462 response_info_.ssl_info = ssl_info;
463 }
464
465 // There's nothing to do if we are not waiting on a Job.
466 if (!is_pending_ || !job_)
467 return;
468
469 job_->Kill();
470
471 // The Job will call our NotifyDone method asynchronously. This is done so
472 // that the Delegate implementation can call Cancel without having to worry
473 // about being called recursively.
474 }
475
Read(IOBuffer * dest,int dest_size,int * bytes_read)476 bool URLRequest::Read(IOBuffer* dest, int dest_size, int* bytes_read) {
477 DCHECK(job_);
478 DCHECK(bytes_read);
479 DCHECK(!job_->is_done());
480 *bytes_read = 0;
481
482 if (dest_size == 0) {
483 // Caller is not too bright. I guess we've done what they asked.
484 return true;
485 }
486
487 // Once the request fails or is cancelled, read will just return 0 bytes
488 // to indicate end of stream.
489 if (!status_.is_success()) {
490 return true;
491 }
492
493 return job_->Read(dest, dest_size, bytes_read);
494 }
495
StopCaching()496 void URLRequest::StopCaching() {
497 DCHECK(job_);
498 job_->StopCaching();
499 }
500
ReceivedRedirect(const GURL & location,bool * defer_redirect)501 void URLRequest::ReceivedRedirect(const GURL& location, bool* defer_redirect) {
502 URLRequestJob* job =
503 URLRequestJobManager::GetInstance()->MaybeInterceptRedirect(this,
504 location);
505 if (job) {
506 RestartWithJob(job);
507 } else if (delegate_) {
508 delegate_->OnReceivedRedirect(this, location, defer_redirect);
509 }
510 }
511
ResponseStarted()512 void URLRequest::ResponseStarted() {
513 scoped_refptr<NetLog::EventParameters> params;
514 if (!status_.is_success())
515 params = new NetLogIntegerParameter("net_error", status_.os_error());
516 net_log_.EndEvent(NetLog::TYPE_URL_REQUEST_START_JOB, params);
517
518 URLRequestJob* job =
519 URLRequestJobManager::GetInstance()->MaybeInterceptResponse(this);
520 if (job) {
521 RestartWithJob(job);
522 } else {
523 if (context_ && context_->network_delegate())
524 context_->network_delegate()->NotifyResponseStarted(this);
525 if (delegate_)
526 delegate_->OnResponseStarted(this);
527 }
528 }
529
FollowDeferredRedirect()530 void URLRequest::FollowDeferredRedirect() {
531 CHECK(job_);
532 CHECK(status_.is_success());
533
534 job_->FollowDeferredRedirect();
535 }
536
SetAuth(const string16 & username,const string16 & password)537 void URLRequest::SetAuth(const string16& username, const string16& password) {
538 DCHECK(job_);
539 DCHECK(job_->NeedsAuth());
540
541 job_->SetAuth(username, password);
542 }
543
CancelAuth()544 void URLRequest::CancelAuth() {
545 DCHECK(job_);
546 DCHECK(job_->NeedsAuth());
547
548 job_->CancelAuth();
549 }
550
ContinueWithCertificate(X509Certificate * client_cert)551 void URLRequest::ContinueWithCertificate(X509Certificate* client_cert) {
552 DCHECK(job_);
553
554 job_->ContinueWithCertificate(client_cert);
555 }
556
ContinueDespiteLastError()557 void URLRequest::ContinueDespiteLastError() {
558 DCHECK(job_);
559
560 job_->ContinueDespiteLastError();
561 }
562
PrepareToRestart()563 void URLRequest::PrepareToRestart() {
564 DCHECK(job_);
565
566 // Close the current URL_REQUEST_START_JOB, since we will be starting a new
567 // one.
568 net_log_.EndEvent(NetLog::TYPE_URL_REQUEST_START_JOB, NULL);
569
570 OrphanJob();
571
572 response_info_ = HttpResponseInfo();
573 response_info_.request_time = Time::Now();
574 status_ = URLRequestStatus();
575 is_pending_ = false;
576 }
577
OrphanJob()578 void URLRequest::OrphanJob() {
579 job_->Kill();
580 job_->DetachRequest(); // ensures that the job will not call us again
581 job_ = NULL;
582 }
583
Redirect(const GURL & location,int http_status_code)584 int URLRequest::Redirect(const GURL& location, int http_status_code) {
585 if (net_log_.IsLoggingAllEvents()) {
586 net_log_.AddEvent(
587 NetLog::TYPE_URL_REQUEST_REDIRECTED,
588 make_scoped_refptr(new NetLogStringParameter(
589 "location", location.possibly_invalid_spec())));
590 }
591 if (redirect_limit_ <= 0) {
592 DVLOG(1) << "disallowing redirect: exceeds limit";
593 return ERR_TOO_MANY_REDIRECTS;
594 }
595
596 if (!location.is_valid())
597 return ERR_INVALID_URL;
598
599 if (!job_->IsSafeRedirect(location)) {
600 DVLOG(1) << "disallowing redirect: unsafe protocol";
601 return ERR_UNSAFE_REDIRECT;
602 }
603
604 bool strip_post_specific_headers = false;
605 if (http_status_code != 307) {
606 // NOTE: Even though RFC 2616 says to preserve the request method when
607 // following a 302 redirect, normal browsers don't do that. Instead, they
608 // all convert a POST into a GET in response to a 302 and so shall we. For
609 // 307 redirects, browsers preserve the method. The RFC says to prompt the
610 // user to confirm the generation of a new POST request, but IE omits this
611 // prompt and so shall we.
612 strip_post_specific_headers = method_ == "POST";
613 method_ = "GET";
614 upload_ = NULL;
615 }
616
617 // Suppress the referrer if we're redirecting out of https.
618 if (GURL(referrer_).SchemeIsSecure() && !location.SchemeIsSecure())
619 referrer_.clear();
620
621 url_chain_.push_back(location);
622 --redirect_limit_;
623
624 if (strip_post_specific_headers) {
625 // If being switched from POST to GET, must remove headers that were
626 // specific to the POST and don't have meaning in GET. For example
627 // the inclusion of a multipart Content-Type header in GET can cause
628 // problems with some servers:
629 // http://code.google.com/p/chromium/issues/detail?id=843
630 StripPostSpecificHeaders(&extra_request_headers_);
631 }
632
633 if (!final_upload_progress_)
634 final_upload_progress_ = job_->GetUploadProgress();
635
636 PrepareToRestart();
637 StartInternal();
638 return OK;
639 }
640
context() const641 URLRequestContext* URLRequest::context() const {
642 return context_.get();
643 }
644
set_context(URLRequestContext * context)645 void URLRequest::set_context(URLRequestContext* context) {
646 scoped_refptr<URLRequestContext> prev_context = context_;
647
648 context_ = context;
649
650 // If the context this request belongs to has changed, update the tracker.
651 if (prev_context != context) {
652 net_log_.EndEvent(NetLog::TYPE_REQUEST_ALIVE, NULL);
653 net_log_ = BoundNetLog();
654
655 if (context) {
656 net_log_ = BoundNetLog::Make(context->net_log(),
657 NetLog::SOURCE_URL_REQUEST);
658 net_log_.BeginEvent(NetLog::TYPE_REQUEST_ALIVE, NULL);
659 }
660 }
661 }
662
GetExpectedContentSize() const663 int64 URLRequest::GetExpectedContentSize() const {
664 int64 expected_content_size = -1;
665 if (job_)
666 expected_content_size = job_->expected_content_size();
667
668 return expected_content_size;
669 }
670
GetUserData(const void * key) const671 URLRequest::UserData* URLRequest::GetUserData(const void* key) const {
672 UserDataMap::const_iterator found = user_data_.find(key);
673 if (found != user_data_.end())
674 return found->second.get();
675 return NULL;
676 }
677
SetUserData(const void * key,UserData * data)678 void URLRequest::SetUserData(const void* key, UserData* data) {
679 user_data_[key] = linked_ptr<UserData>(data);
680 }
681
682 } // namespace net
683