1 // Copyright (c) 2012 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/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/compiler_specific.h"
11 #include "base/debug/stack_trace.h"
12 #include "base/lazy_instance.h"
13 #include "base/memory/singleton.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/metrics/histogram.h"
16 #include "base/metrics/stats_counters.h"
17 #include "base/metrics/user_metrics.h"
18 #include "base/stl_util.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/synchronization/lock.h"
21 #include "base/values.h"
22 #include "net/base/auth.h"
23 #include "net/base/host_port_pair.h"
24 #include "net/base/load_flags.h"
25 #include "net/base/load_timing_info.h"
26 #include "net/base/net_errors.h"
27 #include "net/base/net_log.h"
28 #include "net/base/network_change_notifier.h"
29 #include "net/base/network_delegate.h"
30 #include "net/base/upload_data_stream.h"
31 #include "net/http/http_response_headers.h"
32 #include "net/http/http_util.h"
33 #include "net/ssl/ssl_cert_request_info.h"
34 #include "net/url_request/url_request_context.h"
35 #include "net/url_request/url_request_error_job.h"
36 #include "net/url_request/url_request_job.h"
37 #include "net/url_request/url_request_job_manager.h"
38 #include "net/url_request/url_request_netlog_params.h"
39 #include "net/url_request/url_request_redirect_job.h"
40
41 using base::Time;
42 using std::string;
43
44 namespace net {
45
46 namespace {
47
48 // Max number of http redirects to follow. Same number as gecko.
49 const int kMaxRedirects = 20;
50
51 // Discard headers which have meaning in POST (Content-Length, Content-Type,
52 // Origin).
StripPostSpecificHeaders(HttpRequestHeaders * headers)53 void StripPostSpecificHeaders(HttpRequestHeaders* headers) {
54 // These are headers that may be attached to a POST.
55 headers->RemoveHeader(HttpRequestHeaders::kContentLength);
56 headers->RemoveHeader(HttpRequestHeaders::kContentType);
57 headers->RemoveHeader(HttpRequestHeaders::kOrigin);
58 }
59
60 // TODO(battre): Delete this, see http://crbug.com/89321:
61 // This counter keeps track of the identifiers used for URL requests so far.
62 // 0 is reserved to represent an invalid ID.
63 uint64 g_next_url_request_identifier = 1;
64
65 // This lock protects g_next_url_request_identifier.
66 base::LazyInstance<base::Lock>::Leaky
67 g_next_url_request_identifier_lock = LAZY_INSTANCE_INITIALIZER;
68
69 // Returns an prior unused identifier for URL requests.
GenerateURLRequestIdentifier()70 uint64 GenerateURLRequestIdentifier() {
71 base::AutoLock lock(g_next_url_request_identifier_lock.Get());
72 return g_next_url_request_identifier++;
73 }
74
75 // True once the first URLRequest was started.
76 bool g_url_requests_started = false;
77
78 // True if cookies are accepted by default.
79 bool g_default_can_use_cookies = true;
80
81 // When the URLRequest first assempts load timing information, it has the times
82 // at which each event occurred. The API requires the time which the request
83 // was blocked on each phase. This function handles the conversion.
84 //
85 // In the case of reusing a SPDY session, old proxy results may have been
86 // reused, so proxy resolution times may be before the request was started.
87 //
88 // Due to preconnect and late binding, it is also possible for the connection
89 // attempt to start before a request has been started, or proxy resolution
90 // completed.
91 //
92 // This functions fixes both those cases.
ConvertRealLoadTimesToBlockingTimes(net::LoadTimingInfo * load_timing_info)93 void ConvertRealLoadTimesToBlockingTimes(
94 net::LoadTimingInfo* load_timing_info) {
95 DCHECK(!load_timing_info->request_start.is_null());
96
97 // Earliest time possible for the request to be blocking on connect events.
98 base::TimeTicks block_on_connect = load_timing_info->request_start;
99
100 if (!load_timing_info->proxy_resolve_start.is_null()) {
101 DCHECK(!load_timing_info->proxy_resolve_end.is_null());
102
103 // Make sure the proxy times are after request start.
104 if (load_timing_info->proxy_resolve_start < load_timing_info->request_start)
105 load_timing_info->proxy_resolve_start = load_timing_info->request_start;
106 if (load_timing_info->proxy_resolve_end < load_timing_info->request_start)
107 load_timing_info->proxy_resolve_end = load_timing_info->request_start;
108
109 // Connect times must also be after the proxy times.
110 block_on_connect = load_timing_info->proxy_resolve_end;
111 }
112
113 // Make sure connection times are after start and proxy times.
114
115 net::LoadTimingInfo::ConnectTiming* connect_timing =
116 &load_timing_info->connect_timing;
117 if (!connect_timing->dns_start.is_null()) {
118 DCHECK(!connect_timing->dns_end.is_null());
119 if (connect_timing->dns_start < block_on_connect)
120 connect_timing->dns_start = block_on_connect;
121 if (connect_timing->dns_end < block_on_connect)
122 connect_timing->dns_end = block_on_connect;
123 }
124
125 if (!connect_timing->connect_start.is_null()) {
126 DCHECK(!connect_timing->connect_end.is_null());
127 if (connect_timing->connect_start < block_on_connect)
128 connect_timing->connect_start = block_on_connect;
129 if (connect_timing->connect_end < block_on_connect)
130 connect_timing->connect_end = block_on_connect;
131 }
132
133 if (!connect_timing->ssl_start.is_null()) {
134 DCHECK(!connect_timing->ssl_end.is_null());
135 if (connect_timing->ssl_start < block_on_connect)
136 connect_timing->ssl_start = block_on_connect;
137 if (connect_timing->ssl_end < block_on_connect)
138 connect_timing->ssl_end = block_on_connect;
139 }
140 }
141
142 } // namespace
143
RegisterRequestInterceptor(Interceptor * interceptor)144 void URLRequest::Deprecated::RegisterRequestInterceptor(
145 Interceptor* interceptor) {
146 URLRequest::RegisterRequestInterceptor(interceptor);
147 }
148
UnregisterRequestInterceptor(Interceptor * interceptor)149 void URLRequest::Deprecated::UnregisterRequestInterceptor(
150 Interceptor* interceptor) {
151 URLRequest::UnregisterRequestInterceptor(interceptor);
152 }
153
154 ///////////////////////////////////////////////////////////////////////////////
155 // URLRequest::Interceptor
156
MaybeInterceptRedirect(URLRequest * request,NetworkDelegate * network_delegate,const GURL & location)157 URLRequestJob* URLRequest::Interceptor::MaybeInterceptRedirect(
158 URLRequest* request,
159 NetworkDelegate* network_delegate,
160 const GURL& location) {
161 return NULL;
162 }
163
MaybeInterceptResponse(URLRequest * request,NetworkDelegate * network_delegate)164 URLRequestJob* URLRequest::Interceptor::MaybeInterceptResponse(
165 URLRequest* request, NetworkDelegate* network_delegate) {
166 return NULL;
167 }
168
169 ///////////////////////////////////////////////////////////////////////////////
170 // URLRequest::Delegate
171
OnReceivedRedirect(URLRequest * request,const GURL & new_url,bool * defer_redirect)172 void URLRequest::Delegate::OnReceivedRedirect(URLRequest* request,
173 const GURL& new_url,
174 bool* defer_redirect) {
175 }
176
OnAuthRequired(URLRequest * request,AuthChallengeInfo * auth_info)177 void URLRequest::Delegate::OnAuthRequired(URLRequest* request,
178 AuthChallengeInfo* auth_info) {
179 request->CancelAuth();
180 }
181
OnCertificateRequested(URLRequest * request,SSLCertRequestInfo * cert_request_info)182 void URLRequest::Delegate::OnCertificateRequested(
183 URLRequest* request,
184 SSLCertRequestInfo* cert_request_info) {
185 request->Cancel();
186 }
187
OnSSLCertificateError(URLRequest * request,const SSLInfo & ssl_info,bool is_hsts_ok)188 void URLRequest::Delegate::OnSSLCertificateError(URLRequest* request,
189 const SSLInfo& ssl_info,
190 bool is_hsts_ok) {
191 request->Cancel();
192 }
193
OnBeforeNetworkStart(URLRequest * request,bool * defer)194 void URLRequest::Delegate::OnBeforeNetworkStart(URLRequest* request,
195 bool* defer) {
196 }
197
198 ///////////////////////////////////////////////////////////////////////////////
199 // URLRequest
200
URLRequest(const GURL & url,RequestPriority priority,Delegate * delegate,const URLRequestContext * context)201 URLRequest::URLRequest(const GURL& url,
202 RequestPriority priority,
203 Delegate* delegate,
204 const URLRequestContext* context)
205 : identifier_(GenerateURLRequestIdentifier()) {
206 Init(url, priority, delegate, context, NULL);
207 }
208
URLRequest(const GURL & url,RequestPriority priority,Delegate * delegate,const URLRequestContext * context,CookieStore * cookie_store)209 URLRequest::URLRequest(const GURL& url,
210 RequestPriority priority,
211 Delegate* delegate,
212 const URLRequestContext* context,
213 CookieStore* cookie_store)
214 : identifier_(GenerateURLRequestIdentifier()) {
215 Init(url, priority, delegate, context, cookie_store);
216 }
217
~URLRequest()218 URLRequest::~URLRequest() {
219 Cancel();
220
221 if (network_delegate_) {
222 network_delegate_->NotifyURLRequestDestroyed(this);
223 if (job_.get())
224 job_->NotifyURLRequestDestroyed();
225 }
226
227 if (job_.get())
228 OrphanJob();
229
230 int deleted = context_->url_requests()->erase(this);
231 CHECK_EQ(1, deleted);
232
233 int net_error = OK;
234 // Log error only on failure, not cancellation, as even successful requests
235 // are "cancelled" on destruction.
236 if (status_.status() == URLRequestStatus::FAILED)
237 net_error = status_.error();
238 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_REQUEST_ALIVE, net_error);
239 }
240
241 // static
RegisterRequestInterceptor(Interceptor * interceptor)242 void URLRequest::RegisterRequestInterceptor(Interceptor* interceptor) {
243 URLRequestJobManager::GetInstance()->RegisterRequestInterceptor(interceptor);
244 }
245
246 // static
UnregisterRequestInterceptor(Interceptor * interceptor)247 void URLRequest::UnregisterRequestInterceptor(Interceptor* interceptor) {
248 URLRequestJobManager::GetInstance()->UnregisterRequestInterceptor(
249 interceptor);
250 }
251
Init(const GURL & url,RequestPriority priority,Delegate * delegate,const URLRequestContext * context,CookieStore * cookie_store)252 void URLRequest::Init(const GURL& url,
253 RequestPriority priority,
254 Delegate* delegate,
255 const URLRequestContext* context,
256 CookieStore* cookie_store) {
257 context_ = context;
258 network_delegate_ = context->network_delegate();
259 net_log_ = BoundNetLog::Make(context->net_log(), NetLog::SOURCE_URL_REQUEST);
260 url_chain_.push_back(url);
261 method_ = "GET";
262 referrer_policy_ = CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
263 load_flags_ = LOAD_NORMAL;
264 delegate_ = delegate;
265 is_pending_ = false;
266 is_redirecting_ = false;
267 redirect_limit_ = kMaxRedirects;
268 priority_ = priority;
269 calling_delegate_ = false;
270 use_blocked_by_as_load_param_ =false;
271 before_request_callback_ = base::Bind(&URLRequest::BeforeRequestComplete,
272 base::Unretained(this));
273 has_notified_completion_ = false;
274 received_response_content_length_ = 0;
275 creation_time_ = base::TimeTicks::Now();
276 notified_before_network_start_ = false;
277
278 SIMPLE_STATS_COUNTER("URLRequestCount");
279
280 // Sanity check out environment.
281 DCHECK(base::MessageLoop::current())
282 << "The current base::MessageLoop must exist";
283
284 CHECK(context);
285 context->url_requests()->insert(this);
286 cookie_store_ = cookie_store;
287 if (cookie_store_ == NULL)
288 cookie_store_ = context->cookie_store();
289
290 net_log_.BeginEvent(NetLog::TYPE_REQUEST_ALIVE);
291 }
292
EnableChunkedUpload()293 void URLRequest::EnableChunkedUpload() {
294 DCHECK(!upload_data_stream_ || upload_data_stream_->is_chunked());
295 if (!upload_data_stream_) {
296 upload_data_stream_.reset(
297 new UploadDataStream(UploadDataStream::CHUNKED, 0));
298 }
299 }
300
AppendChunkToUpload(const char * bytes,int bytes_len,bool is_last_chunk)301 void URLRequest::AppendChunkToUpload(const char* bytes,
302 int bytes_len,
303 bool is_last_chunk) {
304 DCHECK(upload_data_stream_);
305 DCHECK(upload_data_stream_->is_chunked());
306 DCHECK_GT(bytes_len, 0);
307 upload_data_stream_->AppendChunk(bytes, bytes_len, is_last_chunk);
308 }
309
set_upload(scoped_ptr<UploadDataStream> upload)310 void URLRequest::set_upload(scoped_ptr<UploadDataStream> upload) {
311 DCHECK(!upload->is_chunked());
312 upload_data_stream_ = upload.Pass();
313 }
314
get_upload() const315 const UploadDataStream* URLRequest::get_upload() const {
316 return upload_data_stream_.get();
317 }
318
has_upload() const319 bool URLRequest::has_upload() const {
320 return upload_data_stream_.get() != NULL;
321 }
322
SetExtraRequestHeaderById(int id,const string & value,bool overwrite)323 void URLRequest::SetExtraRequestHeaderById(int id, const string& value,
324 bool overwrite) {
325 DCHECK(!is_pending_ || is_redirecting_);
326 NOTREACHED() << "implement me!";
327 }
328
SetExtraRequestHeaderByName(const string & name,const string & value,bool overwrite)329 void URLRequest::SetExtraRequestHeaderByName(const string& name,
330 const string& value,
331 bool overwrite) {
332 DCHECK(!is_pending_ || is_redirecting_);
333 if (overwrite) {
334 extra_request_headers_.SetHeader(name, value);
335 } else {
336 extra_request_headers_.SetHeaderIfMissing(name, value);
337 }
338 }
339
RemoveRequestHeaderByName(const string & name)340 void URLRequest::RemoveRequestHeaderByName(const string& name) {
341 DCHECK(!is_pending_ || is_redirecting_);
342 extra_request_headers_.RemoveHeader(name);
343 }
344
SetExtraRequestHeaders(const HttpRequestHeaders & headers)345 void URLRequest::SetExtraRequestHeaders(
346 const HttpRequestHeaders& headers) {
347 DCHECK(!is_pending_);
348 extra_request_headers_ = headers;
349
350 // NOTE: This method will likely become non-trivial once the other setters
351 // for request headers are implemented.
352 }
353
GetFullRequestHeaders(HttpRequestHeaders * headers) const354 bool URLRequest::GetFullRequestHeaders(HttpRequestHeaders* headers) const {
355 if (!job_.get())
356 return false;
357
358 return job_->GetFullRequestHeaders(headers);
359 }
360
GetTotalReceivedBytes() const361 int64 URLRequest::GetTotalReceivedBytes() const {
362 if (!job_.get())
363 return 0;
364
365 return job_->GetTotalReceivedBytes();
366 }
367
GetLoadState() const368 LoadStateWithParam URLRequest::GetLoadState() const {
369 // The !blocked_by_.empty() check allows |this| to report it's blocked on a
370 // delegate before it has been started.
371 if (calling_delegate_ || !blocked_by_.empty()) {
372 return LoadStateWithParam(
373 LOAD_STATE_WAITING_FOR_DELEGATE,
374 use_blocked_by_as_load_param_ ? base::UTF8ToUTF16(blocked_by_) :
375 base::string16());
376 }
377 return LoadStateWithParam(job_.get() ? job_->GetLoadState() : LOAD_STATE_IDLE,
378 base::string16());
379 }
380
GetStateAsValue() const381 base::Value* URLRequest::GetStateAsValue() const {
382 base::DictionaryValue* dict = new base::DictionaryValue();
383 dict->SetString("url", original_url().possibly_invalid_spec());
384
385 if (url_chain_.size() > 1) {
386 base::ListValue* list = new base::ListValue();
387 for (std::vector<GURL>::const_iterator url = url_chain_.begin();
388 url != url_chain_.end(); ++url) {
389 list->AppendString(url->possibly_invalid_spec());
390 }
391 dict->Set("url_chain", list);
392 }
393
394 dict->SetInteger("load_flags", load_flags_);
395
396 LoadStateWithParam load_state = GetLoadState();
397 dict->SetInteger("load_state", load_state.state);
398 if (!load_state.param.empty())
399 dict->SetString("load_state_param", load_state.param);
400 if (!blocked_by_.empty())
401 dict->SetString("delegate_info", blocked_by_);
402
403 dict->SetString("method", method_);
404 dict->SetBoolean("has_upload", has_upload());
405 dict->SetBoolean("is_pending", is_pending_);
406
407 // Add the status of the request. The status should always be IO_PENDING, and
408 // the error should always be OK, unless something is holding onto a request
409 // that has finished or a request was leaked. Neither of these should happen.
410 switch (status_.status()) {
411 case URLRequestStatus::SUCCESS:
412 dict->SetString("status", "SUCCESS");
413 break;
414 case URLRequestStatus::IO_PENDING:
415 dict->SetString("status", "IO_PENDING");
416 break;
417 case URLRequestStatus::CANCELED:
418 dict->SetString("status", "CANCELED");
419 break;
420 case URLRequestStatus::FAILED:
421 dict->SetString("status", "FAILED");
422 break;
423 }
424 if (status_.error() != OK)
425 dict->SetInteger("net_error", status_.error());
426 return dict;
427 }
428
LogBlockedBy(const char * blocked_by)429 void URLRequest::LogBlockedBy(const char* blocked_by) {
430 DCHECK(blocked_by);
431 DCHECK_GT(strlen(blocked_by), 0u);
432
433 // Only log information to NetLog during startup and certain deferring calls
434 // to delegates. For all reads but the first, do nothing.
435 if (!calling_delegate_ && !response_info_.request_time.is_null())
436 return;
437
438 LogUnblocked();
439 blocked_by_ = blocked_by;
440 use_blocked_by_as_load_param_ = false;
441
442 net_log_.BeginEvent(
443 NetLog::TYPE_DELEGATE_INFO,
444 NetLog::StringCallback("delegate_info", &blocked_by_));
445 }
446
LogAndReportBlockedBy(const char * source)447 void URLRequest::LogAndReportBlockedBy(const char* source) {
448 LogBlockedBy(source);
449 use_blocked_by_as_load_param_ = true;
450 }
451
LogUnblocked()452 void URLRequest::LogUnblocked() {
453 if (blocked_by_.empty())
454 return;
455
456 net_log_.EndEvent(NetLog::TYPE_DELEGATE_INFO);
457 blocked_by_.clear();
458 }
459
GetUploadProgress() const460 UploadProgress URLRequest::GetUploadProgress() const {
461 if (!job_.get()) {
462 // We haven't started or the request was cancelled
463 return UploadProgress();
464 }
465 if (final_upload_progress_.position()) {
466 // The first job completed and none of the subsequent series of
467 // GETs when following redirects will upload anything, so we return the
468 // cached results from the initial job, the POST.
469 return final_upload_progress_;
470 }
471 return job_->GetUploadProgress();
472 }
473
GetResponseHeaderById(int id,string * value)474 void URLRequest::GetResponseHeaderById(int id, string* value) {
475 DCHECK(job_.get());
476 NOTREACHED() << "implement me!";
477 }
478
GetResponseHeaderByName(const string & name,string * value)479 void URLRequest::GetResponseHeaderByName(const string& name, string* value) {
480 DCHECK(value);
481 if (response_info_.headers.get()) {
482 response_info_.headers->GetNormalizedHeader(name, value);
483 } else {
484 value->clear();
485 }
486 }
487
GetAllResponseHeaders(string * headers)488 void URLRequest::GetAllResponseHeaders(string* headers) {
489 DCHECK(headers);
490 if (response_info_.headers.get()) {
491 response_info_.headers->GetNormalizedHeaders(headers);
492 } else {
493 headers->clear();
494 }
495 }
496
GetSocketAddress() const497 HostPortPair URLRequest::GetSocketAddress() const {
498 DCHECK(job_.get());
499 return job_->GetSocketAddress();
500 }
501
response_headers() const502 HttpResponseHeaders* URLRequest::response_headers() const {
503 return response_info_.headers.get();
504 }
505
GetLoadTimingInfo(LoadTimingInfo * load_timing_info) const506 void URLRequest::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
507 *load_timing_info = load_timing_info_;
508 }
509
GetResponseCookies(ResponseCookies * cookies)510 bool URLRequest::GetResponseCookies(ResponseCookies* cookies) {
511 DCHECK(job_.get());
512 return job_->GetResponseCookies(cookies);
513 }
514
GetMimeType(string * mime_type)515 void URLRequest::GetMimeType(string* mime_type) {
516 DCHECK(job_.get());
517 job_->GetMimeType(mime_type);
518 }
519
GetCharset(string * charset)520 void URLRequest::GetCharset(string* charset) {
521 DCHECK(job_.get());
522 job_->GetCharset(charset);
523 }
524
GetResponseCode() const525 int URLRequest::GetResponseCode() const {
526 DCHECK(job_.get());
527 return job_->GetResponseCode();
528 }
529
SetLoadFlags(int flags)530 void URLRequest::SetLoadFlags(int flags) {
531 if ((load_flags_ & LOAD_IGNORE_LIMITS) != (flags & LOAD_IGNORE_LIMITS)) {
532 DCHECK(!job_);
533 DCHECK(flags & LOAD_IGNORE_LIMITS);
534 DCHECK_EQ(priority_, MAXIMUM_PRIORITY);
535 }
536 load_flags_ = flags;
537
538 // This should be a no-op given the above DCHECKs, but do this
539 // anyway for release mode.
540 if ((load_flags_ & LOAD_IGNORE_LIMITS) != 0)
541 SetPriority(MAXIMUM_PRIORITY);
542 }
543
544 // static
SetDefaultCookiePolicyToBlock()545 void URLRequest::SetDefaultCookiePolicyToBlock() {
546 CHECK(!g_url_requests_started);
547 g_default_can_use_cookies = false;
548 }
549
550 // static
IsHandledProtocol(const std::string & scheme)551 bool URLRequest::IsHandledProtocol(const std::string& scheme) {
552 return URLRequestJobManager::SupportsScheme(scheme);
553 }
554
555 // static
IsHandledURL(const GURL & url)556 bool URLRequest::IsHandledURL(const GURL& url) {
557 if (!url.is_valid()) {
558 // We handle error cases.
559 return true;
560 }
561
562 return IsHandledProtocol(url.scheme());
563 }
564
set_first_party_for_cookies(const GURL & first_party_for_cookies)565 void URLRequest::set_first_party_for_cookies(
566 const GURL& first_party_for_cookies) {
567 first_party_for_cookies_ = first_party_for_cookies;
568 }
569
set_method(const std::string & method)570 void URLRequest::set_method(const std::string& method) {
571 DCHECK(!is_pending_);
572 method_ = method;
573 }
574
575 // static
ComputeMethodForRedirect(const std::string & method,int http_status_code)576 std::string URLRequest::ComputeMethodForRedirect(
577 const std::string& method,
578 int http_status_code) {
579 // For 303 redirects, all request methods except HEAD are converted to GET,
580 // as per the latest httpbis draft. The draft also allows POST requests to
581 // be converted to GETs when following 301/302 redirects, for historical
582 // reasons. Most major browsers do this and so shall we. Both RFC 2616 and
583 // the httpbis draft say to prompt the user to confirm the generation of new
584 // requests, other than GET and HEAD requests, but IE omits these prompts and
585 // so shall we.
586 // See: https://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-17#section-7.3
587 if ((http_status_code == 303 && method != "HEAD") ||
588 ((http_status_code == 301 || http_status_code == 302) &&
589 method == "POST")) {
590 return "GET";
591 }
592 return method;
593 }
594
SetReferrer(const std::string & referrer)595 void URLRequest::SetReferrer(const std::string& referrer) {
596 DCHECK(!is_pending_);
597 GURL referrer_url(referrer);
598 UMA_HISTOGRAM_BOOLEAN("Net.URLRequest_SetReferrer_IsEmptyOrValid",
599 referrer_url.is_empty() || referrer_url.is_valid());
600 if (referrer_url.is_valid()) {
601 referrer_ = referrer_url.GetAsReferrer().spec();
602 } else {
603 referrer_ = referrer;
604 }
605 }
606
set_referrer_policy(ReferrerPolicy referrer_policy)607 void URLRequest::set_referrer_policy(ReferrerPolicy referrer_policy) {
608 DCHECK(!is_pending_);
609 referrer_policy_ = referrer_policy;
610 }
611
set_delegate(Delegate * delegate)612 void URLRequest::set_delegate(Delegate* delegate) {
613 delegate_ = delegate;
614 }
615
Start()616 void URLRequest::Start() {
617 // Some values can be NULL, but the job factory must not be.
618 DCHECK(context_->job_factory());
619
620 DCHECK_EQ(network_delegate_, context_->network_delegate());
621 // Anything that sets |blocked_by_| before start should have cleaned up after
622 // itself.
623 DCHECK(blocked_by_.empty());
624
625 g_url_requests_started = true;
626 response_info_.request_time = base::Time::Now();
627
628 load_timing_info_ = LoadTimingInfo();
629 load_timing_info_.request_start_time = response_info_.request_time;
630 load_timing_info_.request_start = base::TimeTicks::Now();
631
632 // Only notify the delegate for the initial request.
633 if (network_delegate_) {
634 OnCallToDelegate();
635 int error = network_delegate_->NotifyBeforeURLRequest(
636 this, before_request_callback_, &delegate_redirect_url_);
637 // If ERR_IO_PENDING is returned, the delegate will invoke
638 // |before_request_callback_| later.
639 if (error != ERR_IO_PENDING)
640 BeforeRequestComplete(error);
641 return;
642 }
643
644 StartJob(URLRequestJobManager::GetInstance()->CreateJob(
645 this, network_delegate_));
646 }
647
648 ///////////////////////////////////////////////////////////////////////////////
649
BeforeRequestComplete(int error)650 void URLRequest::BeforeRequestComplete(int error) {
651 DCHECK(!job_.get());
652 DCHECK_NE(ERR_IO_PENDING, error);
653 DCHECK_EQ(network_delegate_, context_->network_delegate());
654
655 // Check that there are no callbacks to already canceled requests.
656 DCHECK_NE(URLRequestStatus::CANCELED, status_.status());
657
658 OnCallToDelegateComplete();
659
660 if (error != OK) {
661 std::string source("delegate");
662 net_log_.AddEvent(NetLog::TYPE_CANCELLED,
663 NetLog::StringCallback("source", &source));
664 StartJob(new URLRequestErrorJob(this, network_delegate_, error));
665 } else if (!delegate_redirect_url_.is_empty()) {
666 GURL new_url;
667 new_url.Swap(&delegate_redirect_url_);
668
669 URLRequestRedirectJob* job = new URLRequestRedirectJob(
670 this, network_delegate_, new_url,
671 // Use status code 307 to preserve the method, so POST requests work.
672 URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT, "Delegate");
673 StartJob(job);
674 } else {
675 StartJob(URLRequestJobManager::GetInstance()->CreateJob(
676 this, network_delegate_));
677 }
678 }
679
StartJob(URLRequestJob * job)680 void URLRequest::StartJob(URLRequestJob* job) {
681 DCHECK(!is_pending_);
682 DCHECK(!job_.get());
683
684 net_log_.BeginEvent(
685 NetLog::TYPE_URL_REQUEST_START_JOB,
686 base::Bind(&NetLogURLRequestStartCallback,
687 &url(), &method_, load_flags_, priority_,
688 upload_data_stream_ ? upload_data_stream_->identifier() : -1));
689
690 job_ = job;
691 job_->SetExtraRequestHeaders(extra_request_headers_);
692 job_->SetPriority(priority_);
693
694 if (upload_data_stream_.get())
695 job_->SetUpload(upload_data_stream_.get());
696
697 is_pending_ = true;
698 is_redirecting_ = false;
699
700 response_info_.was_cached = false;
701
702 // If the referrer is secure, but the requested URL is not, the referrer
703 // policy should be something non-default. If you hit this, please file a
704 // bug.
705 if (referrer_policy_ ==
706 CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE &&
707 GURL(referrer_).SchemeIsSecure() && !url().SchemeIsSecure()) {
708 #if !defined(OFFICIAL_BUILD)
709 LOG(FATAL) << "Trying to send secure referrer for insecure load";
710 #endif
711 referrer_.clear();
712 base::RecordAction(
713 base::UserMetricsAction("Net.URLRequest_StartJob_InvalidReferrer"));
714 }
715
716 // Don't allow errors to be sent from within Start().
717 // TODO(brettw) this may cause NotifyDone to be sent synchronously,
718 // we probably don't want this: they should be sent asynchronously so
719 // the caller does not get reentered.
720 job_->Start();
721 }
722
Restart()723 void URLRequest::Restart() {
724 // Should only be called if the original job didn't make any progress.
725 DCHECK(job_.get() && !job_->has_response_started());
726 RestartWithJob(
727 URLRequestJobManager::GetInstance()->CreateJob(this, network_delegate_));
728 }
729
RestartWithJob(URLRequestJob * job)730 void URLRequest::RestartWithJob(URLRequestJob *job) {
731 DCHECK(job->request() == this);
732 PrepareToRestart();
733 StartJob(job);
734 }
735
Cancel()736 void URLRequest::Cancel() {
737 DoCancel(ERR_ABORTED, SSLInfo());
738 }
739
CancelWithError(int error)740 void URLRequest::CancelWithError(int error) {
741 DoCancel(error, SSLInfo());
742 }
743
CancelWithSSLError(int error,const SSLInfo & ssl_info)744 void URLRequest::CancelWithSSLError(int error, const SSLInfo& ssl_info) {
745 // This should only be called on a started request.
746 if (!is_pending_ || !job_.get() || job_->has_response_started()) {
747 NOTREACHED();
748 return;
749 }
750 DoCancel(error, ssl_info);
751 }
752
DoCancel(int error,const SSLInfo & ssl_info)753 void URLRequest::DoCancel(int error, const SSLInfo& ssl_info) {
754 DCHECK(error < 0);
755 // If cancelled while calling a delegate, clear delegate info.
756 if (calling_delegate_) {
757 LogUnblocked();
758 OnCallToDelegateComplete();
759 }
760
761 // If the URL request already has an error status, then canceling is a no-op.
762 // Plus, we don't want to change the error status once it has been set.
763 if (status_.is_success()) {
764 status_.set_status(URLRequestStatus::CANCELED);
765 status_.set_error(error);
766 response_info_.ssl_info = ssl_info;
767
768 // If the request hasn't already been completed, log a cancellation event.
769 if (!has_notified_completion_) {
770 // Don't log an error code on ERR_ABORTED, since that's redundant.
771 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_CANCELLED,
772 error == ERR_ABORTED ? OK : error);
773 }
774 }
775
776 if (is_pending_ && job_.get())
777 job_->Kill();
778
779 // We need to notify about the end of this job here synchronously. The
780 // Job sends an asynchronous notification but by the time this is processed,
781 // our |context_| is NULL.
782 NotifyRequestCompleted();
783
784 // The Job will call our NotifyDone method asynchronously. This is done so
785 // that the Delegate implementation can call Cancel without having to worry
786 // about being called recursively.
787 }
788
Read(IOBuffer * dest,int dest_size,int * bytes_read)789 bool URLRequest::Read(IOBuffer* dest, int dest_size, int* bytes_read) {
790 DCHECK(job_.get());
791 DCHECK(bytes_read);
792 *bytes_read = 0;
793
794 // If this is the first read, end the delegate call that may have started in
795 // OnResponseStarted.
796 OnCallToDelegateComplete();
797
798 // This handles a cancel that happens while paused.
799 // TODO(ahendrickson): DCHECK() that it is not done after
800 // http://crbug.com/115705 is fixed.
801 if (job_->is_done())
802 return false;
803
804 if (dest_size == 0) {
805 // Caller is not too bright. I guess we've done what they asked.
806 return true;
807 }
808
809 // Once the request fails or is cancelled, read will just return 0 bytes
810 // to indicate end of stream.
811 if (!status_.is_success()) {
812 return true;
813 }
814
815 bool rv = job_->Read(dest, dest_size, bytes_read);
816 // If rv is false, the status cannot be success.
817 DCHECK(rv || status_.status() != URLRequestStatus::SUCCESS);
818 if (rv && *bytes_read <= 0 && status_.is_success())
819 NotifyRequestCompleted();
820 return rv;
821 }
822
StopCaching()823 void URLRequest::StopCaching() {
824 DCHECK(job_.get());
825 job_->StopCaching();
826 }
827
NotifyReceivedRedirect(const GURL & location,bool * defer_redirect)828 void URLRequest::NotifyReceivedRedirect(const GURL& location,
829 bool* defer_redirect) {
830 is_redirecting_ = true;
831
832 URLRequestJob* job =
833 URLRequestJobManager::GetInstance()->MaybeInterceptRedirect(
834 this, network_delegate_, location);
835 if (job) {
836 RestartWithJob(job);
837 } else if (delegate_) {
838 OnCallToDelegate();
839 delegate_->OnReceivedRedirect(this, location, defer_redirect);
840 // |this| may be have been destroyed here.
841 }
842 }
843
NotifyBeforeNetworkStart(bool * defer)844 void URLRequest::NotifyBeforeNetworkStart(bool* defer) {
845 if (delegate_ && !notified_before_network_start_) {
846 OnCallToDelegate();
847 delegate_->OnBeforeNetworkStart(this, defer);
848 if (!*defer)
849 OnCallToDelegateComplete();
850 notified_before_network_start_ = true;
851 }
852 }
853
ResumeNetworkStart()854 void URLRequest::ResumeNetworkStart() {
855 DCHECK(job_);
856 DCHECK(notified_before_network_start_);
857
858 OnCallToDelegateComplete();
859 job_->ResumeNetworkStart();
860 }
861
NotifyResponseStarted()862 void URLRequest::NotifyResponseStarted() {
863 int net_error = OK;
864 if (!status_.is_success())
865 net_error = status_.error();
866 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_URL_REQUEST_START_JOB,
867 net_error);
868
869 URLRequestJob* job =
870 URLRequestJobManager::GetInstance()->MaybeInterceptResponse(
871 this, network_delegate_);
872 if (job) {
873 RestartWithJob(job);
874 } else {
875 if (delegate_) {
876 // In some cases (e.g. an event was canceled), we might have sent the
877 // completion event and receive a NotifyResponseStarted() later.
878 if (!has_notified_completion_ && status_.is_success()) {
879 if (network_delegate_)
880 network_delegate_->NotifyResponseStarted(this);
881 }
882
883 // Notify in case the entire URL Request has been finished.
884 if (!has_notified_completion_ && !status_.is_success())
885 NotifyRequestCompleted();
886
887 OnCallToDelegate();
888 delegate_->OnResponseStarted(this);
889 // Nothing may appear below this line as OnResponseStarted may delete
890 // |this|.
891 }
892 }
893 }
894
FollowDeferredRedirect()895 void URLRequest::FollowDeferredRedirect() {
896 CHECK(job_.get());
897 CHECK(status_.is_success());
898
899 job_->FollowDeferredRedirect();
900 }
901
SetAuth(const AuthCredentials & credentials)902 void URLRequest::SetAuth(const AuthCredentials& credentials) {
903 DCHECK(job_.get());
904 DCHECK(job_->NeedsAuth());
905
906 job_->SetAuth(credentials);
907 }
908
CancelAuth()909 void URLRequest::CancelAuth() {
910 DCHECK(job_.get());
911 DCHECK(job_->NeedsAuth());
912
913 job_->CancelAuth();
914 }
915
ContinueWithCertificate(X509Certificate * client_cert)916 void URLRequest::ContinueWithCertificate(X509Certificate* client_cert) {
917 DCHECK(job_.get());
918
919 job_->ContinueWithCertificate(client_cert);
920 }
921
ContinueDespiteLastError()922 void URLRequest::ContinueDespiteLastError() {
923 DCHECK(job_.get());
924
925 job_->ContinueDespiteLastError();
926 }
927
PrepareToRestart()928 void URLRequest::PrepareToRestart() {
929 DCHECK(job_.get());
930
931 // Close the current URL_REQUEST_START_JOB, since we will be starting a new
932 // one.
933 net_log_.EndEvent(NetLog::TYPE_URL_REQUEST_START_JOB);
934
935 OrphanJob();
936
937 response_info_ = HttpResponseInfo();
938 response_info_.request_time = base::Time::Now();
939
940 load_timing_info_ = LoadTimingInfo();
941 load_timing_info_.request_start_time = response_info_.request_time;
942 load_timing_info_.request_start = base::TimeTicks::Now();
943
944 status_ = URLRequestStatus();
945 is_pending_ = false;
946 }
947
OrphanJob()948 void URLRequest::OrphanJob() {
949 // When calling this function, please check that URLRequestHttpJob is
950 // not in between calling NetworkDelegate::NotifyHeadersReceived receiving
951 // the call back. This is currently guaranteed by the following strategies:
952 // - OrphanJob is called on JobRestart, in this case the URLRequestJob cannot
953 // be receiving any headers at that time.
954 // - OrphanJob is called in ~URLRequest, in this case
955 // NetworkDelegate::NotifyURLRequestDestroyed notifies the NetworkDelegate
956 // that the callback becomes invalid.
957 job_->Kill();
958 job_->DetachRequest(); // ensures that the job will not call us again
959 job_ = NULL;
960 }
961
Redirect(const GURL & location,int http_status_code)962 int URLRequest::Redirect(const GURL& location, int http_status_code) {
963 // Matches call in NotifyReceivedRedirect.
964 OnCallToDelegateComplete();
965 if (net_log_.IsLogging()) {
966 net_log_.AddEvent(
967 NetLog::TYPE_URL_REQUEST_REDIRECTED,
968 NetLog::StringCallback("location", &location.possibly_invalid_spec()));
969 }
970
971 if (network_delegate_)
972 network_delegate_->NotifyBeforeRedirect(this, location);
973
974 if (redirect_limit_ <= 0) {
975 DVLOG(1) << "disallowing redirect: exceeds limit";
976 return ERR_TOO_MANY_REDIRECTS;
977 }
978
979 if (!location.is_valid())
980 return ERR_INVALID_URL;
981
982 if (!job_->IsSafeRedirect(location)) {
983 DVLOG(1) << "disallowing redirect: unsafe protocol";
984 return ERR_UNSAFE_REDIRECT;
985 }
986
987 if (!final_upload_progress_.position())
988 final_upload_progress_ = job_->GetUploadProgress();
989 PrepareToRestart();
990
991 std::string new_method(ComputeMethodForRedirect(method_, http_status_code));
992 if (new_method != method_) {
993 if (method_ == "POST") {
994 // If being switched from POST, must remove headers that were specific to
995 // the POST and don't have meaning in other methods. For example the
996 // inclusion of a multipart Content-Type header in GET can cause problems
997 // with some servers:
998 // http://code.google.com/p/chromium/issues/detail?id=843
999 StripPostSpecificHeaders(&extra_request_headers_);
1000 }
1001 upload_data_stream_.reset();
1002 method_.swap(new_method);
1003 }
1004
1005 // Suppress the referrer if we're redirecting out of https.
1006 if (referrer_policy_ ==
1007 CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE &&
1008 GURL(referrer_).SchemeIsSecure() && !location.SchemeIsSecure()) {
1009 referrer_.clear();
1010 }
1011
1012 url_chain_.push_back(location);
1013 --redirect_limit_;
1014
1015 Start();
1016 return OK;
1017 }
1018
context() const1019 const URLRequestContext* URLRequest::context() const {
1020 return context_;
1021 }
1022
GetExpectedContentSize() const1023 int64 URLRequest::GetExpectedContentSize() const {
1024 int64 expected_content_size = -1;
1025 if (job_.get())
1026 expected_content_size = job_->expected_content_size();
1027
1028 return expected_content_size;
1029 }
1030
SetPriority(RequestPriority priority)1031 void URLRequest::SetPriority(RequestPriority priority) {
1032 DCHECK_GE(priority, MINIMUM_PRIORITY);
1033 DCHECK_LE(priority, MAXIMUM_PRIORITY);
1034
1035 if ((load_flags_ & LOAD_IGNORE_LIMITS) && (priority != MAXIMUM_PRIORITY)) {
1036 NOTREACHED();
1037 // Maintain the invariant that requests with IGNORE_LIMITS set
1038 // have MAXIMUM_PRIORITY for release mode.
1039 return;
1040 }
1041
1042 if (priority_ == priority)
1043 return;
1044
1045 priority_ = priority;
1046 if (job_.get()) {
1047 net_log_.AddEvent(NetLog::TYPE_URL_REQUEST_SET_PRIORITY,
1048 NetLog::IntegerCallback("priority", priority_));
1049 job_->SetPriority(priority_);
1050 }
1051 }
1052
GetHSTSRedirect(GURL * redirect_url) const1053 bool URLRequest::GetHSTSRedirect(GURL* redirect_url) const {
1054 const GURL& url = this->url();
1055 if (!url.SchemeIs("http"))
1056 return false;
1057 TransportSecurityState* state = context()->transport_security_state();
1058 if (state &&
1059 state->ShouldUpgradeToSSL(
1060 url.host(),
1061 SSLConfigService::IsSNIAvailable(context()->ssl_config_service()))) {
1062 url::Replacements<char> replacements;
1063 const char kNewScheme[] = "https";
1064 replacements.SetScheme(kNewScheme, url::Component(0, strlen(kNewScheme)));
1065 *redirect_url = url.ReplaceComponents(replacements);
1066 return true;
1067 }
1068 return false;
1069 }
1070
NotifyAuthRequired(AuthChallengeInfo * auth_info)1071 void URLRequest::NotifyAuthRequired(AuthChallengeInfo* auth_info) {
1072 NetworkDelegate::AuthRequiredResponse rv =
1073 NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1074 auth_info_ = auth_info;
1075 if (network_delegate_) {
1076 OnCallToDelegate();
1077 rv = network_delegate_->NotifyAuthRequired(
1078 this,
1079 *auth_info,
1080 base::Bind(&URLRequest::NotifyAuthRequiredComplete,
1081 base::Unretained(this)),
1082 &auth_credentials_);
1083 if (rv == NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING)
1084 return;
1085 }
1086
1087 NotifyAuthRequiredComplete(rv);
1088 }
1089
NotifyAuthRequiredComplete(NetworkDelegate::AuthRequiredResponse result)1090 void URLRequest::NotifyAuthRequiredComplete(
1091 NetworkDelegate::AuthRequiredResponse result) {
1092 OnCallToDelegateComplete();
1093
1094 // Check that there are no callbacks to already canceled requests.
1095 DCHECK_NE(URLRequestStatus::CANCELED, status_.status());
1096
1097 // NotifyAuthRequired may be called multiple times, such as
1098 // when an authentication attempt fails. Clear out the data
1099 // so it can be reset on another round.
1100 AuthCredentials credentials = auth_credentials_;
1101 auth_credentials_ = AuthCredentials();
1102 scoped_refptr<AuthChallengeInfo> auth_info;
1103 auth_info.swap(auth_info_);
1104
1105 switch (result) {
1106 case NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION:
1107 // Defer to the URLRequest::Delegate, since the NetworkDelegate
1108 // didn't take an action.
1109 if (delegate_)
1110 delegate_->OnAuthRequired(this, auth_info.get());
1111 break;
1112
1113 case NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH:
1114 SetAuth(credentials);
1115 break;
1116
1117 case NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH:
1118 CancelAuth();
1119 break;
1120
1121 case NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING:
1122 NOTREACHED();
1123 break;
1124 }
1125 }
1126
NotifyCertificateRequested(SSLCertRequestInfo * cert_request_info)1127 void URLRequest::NotifyCertificateRequested(
1128 SSLCertRequestInfo* cert_request_info) {
1129 if (delegate_)
1130 delegate_->OnCertificateRequested(this, cert_request_info);
1131 }
1132
NotifySSLCertificateError(const SSLInfo & ssl_info,bool fatal)1133 void URLRequest::NotifySSLCertificateError(const SSLInfo& ssl_info,
1134 bool fatal) {
1135 if (delegate_)
1136 delegate_->OnSSLCertificateError(this, ssl_info, fatal);
1137 }
1138
CanGetCookies(const CookieList & cookie_list) const1139 bool URLRequest::CanGetCookies(const CookieList& cookie_list) const {
1140 DCHECK(!(load_flags_ & LOAD_DO_NOT_SEND_COOKIES));
1141 if (network_delegate_) {
1142 return network_delegate_->CanGetCookies(*this, cookie_list);
1143 }
1144 return g_default_can_use_cookies;
1145 }
1146
CanSetCookie(const std::string & cookie_line,CookieOptions * options) const1147 bool URLRequest::CanSetCookie(const std::string& cookie_line,
1148 CookieOptions* options) const {
1149 DCHECK(!(load_flags_ & LOAD_DO_NOT_SAVE_COOKIES));
1150 if (network_delegate_) {
1151 return network_delegate_->CanSetCookie(*this, cookie_line, options);
1152 }
1153 return g_default_can_use_cookies;
1154 }
1155
CanEnablePrivacyMode() const1156 bool URLRequest::CanEnablePrivacyMode() const {
1157 if (network_delegate_) {
1158 return network_delegate_->CanEnablePrivacyMode(url(),
1159 first_party_for_cookies_);
1160 }
1161 return !g_default_can_use_cookies;
1162 }
1163
1164
NotifyReadCompleted(int bytes_read)1165 void URLRequest::NotifyReadCompleted(int bytes_read) {
1166 // Notify in case the entire URL Request has been finished.
1167 if (bytes_read <= 0)
1168 NotifyRequestCompleted();
1169
1170 // Notify NetworkChangeNotifier that we just received network data.
1171 // This is to identify cases where the NetworkChangeNotifier thinks we
1172 // are off-line but we are still receiving network data (crbug.com/124069),
1173 // and to get rough network connection measurements.
1174 if (bytes_read > 0 && !was_cached())
1175 NetworkChangeNotifier::NotifyDataReceived(*this, bytes_read);
1176
1177 if (delegate_)
1178 delegate_->OnReadCompleted(this, bytes_read);
1179
1180 // Nothing below this line as OnReadCompleted may delete |this|.
1181 }
1182
OnHeadersComplete()1183 void URLRequest::OnHeadersComplete() {
1184 // Cache load timing information now, as information will be lost once the
1185 // socket is closed and the ClientSocketHandle is Reset, which will happen
1186 // once the body is complete. The start times should already be populated.
1187 if (job_.get()) {
1188 // Keep a copy of the two times the URLRequest sets.
1189 base::TimeTicks request_start = load_timing_info_.request_start;
1190 base::Time request_start_time = load_timing_info_.request_start_time;
1191
1192 // Clear load times. Shouldn't be neded, but gives the GetLoadTimingInfo a
1193 // consistent place to start from.
1194 load_timing_info_ = LoadTimingInfo();
1195 job_->GetLoadTimingInfo(&load_timing_info_);
1196
1197 load_timing_info_.request_start = request_start;
1198 load_timing_info_.request_start_time = request_start_time;
1199
1200 ConvertRealLoadTimesToBlockingTimes(&load_timing_info_);
1201 }
1202 }
1203
NotifyRequestCompleted()1204 void URLRequest::NotifyRequestCompleted() {
1205 // TODO(battre): Get rid of this check, according to willchan it should
1206 // not be needed.
1207 if (has_notified_completion_)
1208 return;
1209
1210 is_pending_ = false;
1211 is_redirecting_ = false;
1212 has_notified_completion_ = true;
1213 if (network_delegate_)
1214 network_delegate_->NotifyCompleted(this, job_.get() != NULL);
1215 }
1216
OnCallToDelegate()1217 void URLRequest::OnCallToDelegate() {
1218 DCHECK(!calling_delegate_);
1219 DCHECK(blocked_by_.empty());
1220 calling_delegate_ = true;
1221 net_log_.BeginEvent(NetLog::TYPE_URL_REQUEST_DELEGATE);
1222 }
1223
OnCallToDelegateComplete()1224 void URLRequest::OnCallToDelegateComplete() {
1225 // This should have been cleared before resuming the request.
1226 DCHECK(blocked_by_.empty());
1227 if (!calling_delegate_)
1228 return;
1229 calling_delegate_ = false;
1230 net_log_.EndEvent(NetLog::TYPE_URL_REQUEST_DELEGATE);
1231 }
1232
set_stack_trace(const base::debug::StackTrace & stack_trace)1233 void URLRequest::set_stack_trace(const base::debug::StackTrace& stack_trace) {
1234 base::debug::StackTrace* stack_trace_copy =
1235 new base::debug::StackTrace(NULL, 0);
1236 *stack_trace_copy = stack_trace;
1237 stack_trace_.reset(stack_trace_copy);
1238 }
1239
stack_trace() const1240 const base::debug::StackTrace* URLRequest::stack_trace() const {
1241 return stack_trace_.get();
1242 }
1243
1244 } // namespace net
1245