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_job.h" 6 7#include "base/bind.h" 8#include "base/compiler_specific.h" 9#include "base/message_loop/message_loop.h" 10#include "base/power_monitor/power_monitor.h" 11#include "base/strings/string_number_conversions.h" 12#include "base/strings/string_util.h" 13#include "net/base/auth.h" 14#include "net/base/host_port_pair.h" 15#include "net/base/io_buffer.h" 16#include "net/base/load_states.h" 17#include "net/base/net_errors.h" 18#include "net/base/network_delegate.h" 19#include "net/filter/filter.h" 20#include "net/http/http_response_headers.h" 21#include "net/url_request/url_request.h" 22 23namespace net { 24 25URLRequestJob::URLRequestJob(URLRequest* request, 26 NetworkDelegate* network_delegate) 27 : request_(request), 28 done_(false), 29 prefilter_bytes_read_(0), 30 postfilter_bytes_read_(0), 31 filter_input_byte_count_(0), 32 filter_needs_more_output_space_(false), 33 filtered_read_buffer_len_(0), 34 has_handled_response_(false), 35 expected_content_size_(-1), 36 network_delegate_(network_delegate), 37 weak_factory_(this) { 38 base::PowerMonitor* power_monitor = base::PowerMonitor::Get(); 39 if (power_monitor) 40 power_monitor->AddObserver(this); 41} 42 43void URLRequestJob::SetUpload(UploadDataStream* upload) { 44} 45 46void URLRequestJob::SetExtraRequestHeaders(const HttpRequestHeaders& headers) { 47} 48 49void URLRequestJob::SetPriority(RequestPriority priority) { 50} 51 52void URLRequestJob::Kill() { 53 weak_factory_.InvalidateWeakPtrs(); 54 // Make sure the request is notified that we are done. We assume that the 55 // request took care of setting its error status before calling Kill. 56 if (request_) 57 NotifyCanceled(); 58} 59 60void URLRequestJob::DetachRequest() { 61 request_ = NULL; 62} 63 64// This function calls ReadData to get stream data. If a filter exists, passes 65// the data to the attached filter. Then returns the output from filter back to 66// the caller. 67bool URLRequestJob::Read(IOBuffer* buf, int buf_size, int *bytes_read) { 68 bool rv = false; 69 70 DCHECK_LT(buf_size, 1000000); // Sanity check. 71 DCHECK(buf); 72 DCHECK(bytes_read); 73 DCHECK(filtered_read_buffer_.get() == NULL); 74 DCHECK_EQ(0, filtered_read_buffer_len_); 75 76 *bytes_read = 0; 77 78 // Skip Filter if not present. 79 if (!filter_.get()) { 80 rv = ReadRawDataHelper(buf, buf_size, bytes_read); 81 } else { 82 // Save the caller's buffers while we do IO 83 // in the filter's buffers. 84 filtered_read_buffer_ = buf; 85 filtered_read_buffer_len_ = buf_size; 86 87 if (ReadFilteredData(bytes_read)) { 88 rv = true; // We have data to return. 89 90 // It is fine to call DoneReading even if ReadFilteredData receives 0 91 // bytes from the net, but we avoid making that call if we know for 92 // sure that's the case (ReadRawDataHelper path). 93 if (*bytes_read == 0) 94 DoneReading(); 95 } else { 96 rv = false; // Error, or a new IO is pending. 97 } 98 } 99 if (rv && *bytes_read == 0) 100 NotifyDone(URLRequestStatus()); 101 return rv; 102} 103 104void URLRequestJob::StopCaching() { 105 // Nothing to do here. 106} 107 108bool URLRequestJob::GetFullRequestHeaders(HttpRequestHeaders* headers) const { 109 // Most job types don't send request headers. 110 return false; 111} 112 113int64 URLRequestJob::GetTotalReceivedBytes() const { 114 return 0; 115} 116 117LoadState URLRequestJob::GetLoadState() const { 118 return LOAD_STATE_IDLE; 119} 120 121UploadProgress URLRequestJob::GetUploadProgress() const { 122 return UploadProgress(); 123} 124 125bool URLRequestJob::GetCharset(std::string* charset) { 126 return false; 127} 128 129void URLRequestJob::GetResponseInfo(HttpResponseInfo* info) { 130} 131 132void URLRequestJob::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const { 133 // Only certain request types return more than just request start times. 134} 135 136bool URLRequestJob::GetResponseCookies(std::vector<std::string>* cookies) { 137 return false; 138} 139 140Filter* URLRequestJob::SetupFilter() const { 141 return NULL; 142} 143 144bool URLRequestJob::IsRedirectResponse(GURL* location, 145 int* http_status_code) { 146 // For non-HTTP jobs, headers will be null. 147 HttpResponseHeaders* headers = request_->response_headers(); 148 if (!headers) 149 return false; 150 151 std::string value; 152 if (!headers->IsRedirect(&value)) 153 return false; 154 155 *location = request_->url().Resolve(value); 156 *http_status_code = headers->response_code(); 157 return true; 158} 159 160bool URLRequestJob::CopyFragmentOnRedirect(const GURL& location) const { 161 return true; 162} 163 164bool URLRequestJob::IsSafeRedirect(const GURL& location) { 165 return true; 166} 167 168bool URLRequestJob::NeedsAuth() { 169 return false; 170} 171 172void URLRequestJob::GetAuthChallengeInfo( 173 scoped_refptr<AuthChallengeInfo>* auth_info) { 174 // This will only be called if NeedsAuth() returns true, in which 175 // case the derived class should implement this! 176 NOTREACHED(); 177} 178 179void URLRequestJob::SetAuth(const AuthCredentials& credentials) { 180 // This will only be called if NeedsAuth() returns true, in which 181 // case the derived class should implement this! 182 NOTREACHED(); 183} 184 185void URLRequestJob::CancelAuth() { 186 // This will only be called if NeedsAuth() returns true, in which 187 // case the derived class should implement this! 188 NOTREACHED(); 189} 190 191void URLRequestJob::ContinueWithCertificate( 192 X509Certificate* client_cert) { 193 // The derived class should implement this! 194 NOTREACHED(); 195} 196 197void URLRequestJob::ContinueDespiteLastError() { 198 // Implementations should know how to recover from errors they generate. 199 // If this code was reached, we are trying to recover from an error that 200 // we don't know how to recover from. 201 NOTREACHED(); 202} 203 204void URLRequestJob::FollowDeferredRedirect() { 205 DCHECK_NE(-1, deferred_redirect_info_.status_code); 206 207 // NOTE: deferred_redirect_info_ may be invalid, and attempting to follow it 208 // will fail inside FollowRedirect. The DCHECK above asserts that we called 209 // OnReceivedRedirect. 210 211 // It is also possible that FollowRedirect will drop the last reference to 212 // this job, so we need to reset our members before calling it. 213 214 RedirectInfo redirect_info = deferred_redirect_info_; 215 deferred_redirect_info_ = RedirectInfo(); 216 FollowRedirect(redirect_info); 217} 218 219void URLRequestJob::ResumeNetworkStart() { 220 // This should only be called for HTTP Jobs, and implemented in the derived 221 // class. 222 NOTREACHED(); 223} 224 225bool URLRequestJob::GetMimeType(std::string* mime_type) const { 226 return false; 227} 228 229int URLRequestJob::GetResponseCode() const { 230 return -1; 231} 232 233HostPortPair URLRequestJob::GetSocketAddress() const { 234 return HostPortPair(); 235} 236 237void URLRequestJob::OnSuspend() { 238 Kill(); 239} 240 241void URLRequestJob::NotifyURLRequestDestroyed() { 242} 243 244URLRequestJob::~URLRequestJob() { 245 base::PowerMonitor* power_monitor = base::PowerMonitor::Get(); 246 if (power_monitor) 247 power_monitor->RemoveObserver(this); 248} 249 250void URLRequestJob::NotifyCertificateRequested( 251 SSLCertRequestInfo* cert_request_info) { 252 if (!request_) 253 return; // The request was destroyed, so there is no more work to do. 254 255 request_->NotifyCertificateRequested(cert_request_info); 256} 257 258void URLRequestJob::NotifySSLCertificateError(const SSLInfo& ssl_info, 259 bool fatal) { 260 if (!request_) 261 return; // The request was destroyed, so there is no more work to do. 262 263 request_->NotifySSLCertificateError(ssl_info, fatal); 264} 265 266bool URLRequestJob::CanGetCookies(const CookieList& cookie_list) const { 267 if (!request_) 268 return false; // The request was destroyed, so there is no more work to do. 269 270 return request_->CanGetCookies(cookie_list); 271} 272 273bool URLRequestJob::CanSetCookie(const std::string& cookie_line, 274 CookieOptions* options) const { 275 if (!request_) 276 return false; // The request was destroyed, so there is no more work to do. 277 278 return request_->CanSetCookie(cookie_line, options); 279} 280 281bool URLRequestJob::CanEnablePrivacyMode() const { 282 if (!request_) 283 return false; // The request was destroyed, so there is no more work to do. 284 285 return request_->CanEnablePrivacyMode(); 286} 287 288CookieStore* URLRequestJob::GetCookieStore() const { 289 DCHECK(request_); 290 291 return request_->cookie_store(); 292} 293 294void URLRequestJob::NotifyBeforeNetworkStart(bool* defer) { 295 if (!request_) 296 return; 297 298 request_->NotifyBeforeNetworkStart(defer); 299} 300 301void URLRequestJob::NotifyHeadersComplete() { 302 if (!request_ || !request_->has_delegate()) 303 return; // The request was destroyed, so there is no more work to do. 304 305 if (has_handled_response_) 306 return; 307 308 DCHECK(!request_->status().is_io_pending()); 309 310 // Initialize to the current time, and let the subclass optionally override 311 // the time stamps if it has that information. The default request_time is 312 // set by URLRequest before it calls our Start method. 313 request_->response_info_.response_time = base::Time::Now(); 314 GetResponseInfo(&request_->response_info_); 315 316 // When notifying the delegate, the delegate can release the request 317 // (and thus release 'this'). After calling to the delgate, we must 318 // check the request pointer to see if it still exists, and return 319 // immediately if it has been destroyed. self_preservation ensures our 320 // survival until we can get out of this method. 321 scoped_refptr<URLRequestJob> self_preservation(this); 322 323 if (request_) 324 request_->OnHeadersComplete(); 325 326 GURL new_location; 327 int http_status_code; 328 if (IsRedirectResponse(&new_location, &http_status_code)) { 329 // Redirect response bodies are not read. Notify the transaction 330 // so it does not treat being stopped as an error. 331 DoneReadingRedirectResponse(); 332 333 RedirectInfo redirect_info = 334 ComputeRedirectInfo(new_location, http_status_code); 335 336 bool defer_redirect = false; 337 request_->NotifyReceivedRedirect(redirect_info, &defer_redirect); 338 339 // Ensure that the request wasn't detached or destroyed in 340 // NotifyReceivedRedirect 341 if (!request_ || !request_->has_delegate()) 342 return; 343 344 // If we were not cancelled, then maybe follow the redirect. 345 if (request_->status().is_success()) { 346 if (defer_redirect) { 347 deferred_redirect_info_ = redirect_info; 348 } else { 349 FollowRedirect(redirect_info); 350 } 351 return; 352 } 353 } else if (NeedsAuth()) { 354 scoped_refptr<AuthChallengeInfo> auth_info; 355 GetAuthChallengeInfo(&auth_info); 356 // Need to check for a NULL auth_info because the server may have failed 357 // to send a challenge with the 401 response. 358 if (auth_info.get()) { 359 request_->NotifyAuthRequired(auth_info.get()); 360 // Wait for SetAuth or CancelAuth to be called. 361 return; 362 } 363 } 364 365 has_handled_response_ = true; 366 if (request_->status().is_success()) 367 filter_.reset(SetupFilter()); 368 369 if (!filter_.get()) { 370 std::string content_length; 371 request_->GetResponseHeaderByName("content-length", &content_length); 372 if (!content_length.empty()) 373 base::StringToInt64(content_length, &expected_content_size_); 374 } 375 376 request_->NotifyResponseStarted(); 377} 378 379void URLRequestJob::NotifyReadComplete(int bytes_read) { 380 if (!request_ || !request_->has_delegate()) 381 return; // The request was destroyed, so there is no more work to do. 382 383 // TODO(darin): Bug 1004233. Re-enable this test once all of the chrome 384 // unit_tests have been fixed to not trip this. 385#if 0 386 DCHECK(!request_->status().is_io_pending()); 387#endif 388 // The headers should be complete before reads complete 389 DCHECK(has_handled_response_); 390 391 OnRawReadComplete(bytes_read); 392 393 // Don't notify if we had an error. 394 if (!request_->status().is_success()) 395 return; 396 397 // When notifying the delegate, the delegate can release the request 398 // (and thus release 'this'). After calling to the delegate, we must 399 // check the request pointer to see if it still exists, and return 400 // immediately if it has been destroyed. self_preservation ensures our 401 // survival until we can get out of this method. 402 scoped_refptr<URLRequestJob> self_preservation(this); 403 404 if (filter_.get()) { 405 // Tell the filter that it has more data 406 FilteredDataRead(bytes_read); 407 408 // Filter the data. 409 int filter_bytes_read = 0; 410 if (ReadFilteredData(&filter_bytes_read)) { 411 if (!filter_bytes_read) 412 DoneReading(); 413 request_->NotifyReadCompleted(filter_bytes_read); 414 } 415 } else { 416 request_->NotifyReadCompleted(bytes_read); 417 } 418 DVLOG(1) << __FUNCTION__ << "() " 419 << "\"" << (request_ ? request_->url().spec() : "???") << "\"" 420 << " pre bytes read = " << bytes_read 421 << " pre total = " << prefilter_bytes_read_ 422 << " post total = " << postfilter_bytes_read_; 423} 424 425void URLRequestJob::NotifyStartError(const URLRequestStatus &status) { 426 DCHECK(!has_handled_response_); 427 has_handled_response_ = true; 428 if (request_) { 429 // There may be relevant information in the response info even in the 430 // error case. 431 GetResponseInfo(&request_->response_info_); 432 433 request_->set_status(status); 434 request_->NotifyResponseStarted(); 435 // We may have been deleted. 436 } 437} 438 439void URLRequestJob::NotifyDone(const URLRequestStatus &status) { 440 DCHECK(!done_) << "Job sending done notification twice"; 441 if (done_) 442 return; 443 done_ = true; 444 445 // Unless there was an error, we should have at least tried to handle 446 // the response before getting here. 447 DCHECK(has_handled_response_ || !status.is_success()); 448 449 // As with NotifyReadComplete, we need to take care to notice if we were 450 // destroyed during a delegate callback. 451 if (request_) { 452 request_->set_is_pending(false); 453 // With async IO, it's quite possible to have a few outstanding 454 // requests. We could receive a request to Cancel, followed shortly 455 // by a successful IO. For tracking the status(), once there is 456 // an error, we do not change the status back to success. To 457 // enforce this, only set the status if the job is so far 458 // successful. 459 if (request_->status().is_success()) { 460 if (status.status() == URLRequestStatus::FAILED) { 461 request_->net_log().AddEventWithNetErrorCode(NetLog::TYPE_FAILED, 462 status.error()); 463 } 464 request_->set_status(status); 465 } 466 } 467 468 // Complete this notification later. This prevents us from re-entering the 469 // delegate if we're done because of a synchronous call. 470 base::MessageLoop::current()->PostTask( 471 FROM_HERE, 472 base::Bind(&URLRequestJob::CompleteNotifyDone, 473 weak_factory_.GetWeakPtr())); 474} 475 476void URLRequestJob::CompleteNotifyDone() { 477 // Check if we should notify the delegate that we're done because of an error. 478 if (request_ && 479 !request_->status().is_success() && 480 request_->has_delegate()) { 481 // We report the error differently depending on whether we've called 482 // OnResponseStarted yet. 483 if (has_handled_response_) { 484 // We signal the error by calling OnReadComplete with a bytes_read of -1. 485 request_->NotifyReadCompleted(-1); 486 } else { 487 has_handled_response_ = true; 488 request_->NotifyResponseStarted(); 489 } 490 } 491} 492 493void URLRequestJob::NotifyCanceled() { 494 if (!done_) { 495 NotifyDone(URLRequestStatus(URLRequestStatus::CANCELED, ERR_ABORTED)); 496 } 497} 498 499void URLRequestJob::NotifyRestartRequired() { 500 DCHECK(!has_handled_response_); 501 if (GetStatus().status() != URLRequestStatus::CANCELED) 502 request_->Restart(); 503} 504 505void URLRequestJob::OnCallToDelegate() { 506 request_->OnCallToDelegate(); 507} 508 509void URLRequestJob::OnCallToDelegateComplete() { 510 request_->OnCallToDelegateComplete(); 511} 512 513bool URLRequestJob::ReadRawData(IOBuffer* buf, int buf_size, 514 int *bytes_read) { 515 DCHECK(bytes_read); 516 *bytes_read = 0; 517 return true; 518} 519 520void URLRequestJob::DoneReading() { 521 // Do nothing. 522} 523 524void URLRequestJob::DoneReadingRedirectResponse() { 525} 526 527void URLRequestJob::FilteredDataRead(int bytes_read) { 528 DCHECK(filter_); 529 filter_->FlushStreamBuffer(bytes_read); 530} 531 532bool URLRequestJob::ReadFilteredData(int* bytes_read) { 533 DCHECK(filter_); 534 DCHECK(filtered_read_buffer_.get()); 535 DCHECK_GT(filtered_read_buffer_len_, 0); 536 DCHECK_LT(filtered_read_buffer_len_, 1000000); // Sanity check. 537 DCHECK(!raw_read_buffer_.get()); 538 539 *bytes_read = 0; 540 bool rv = false; 541 542 for (;;) { 543 if (is_done()) 544 return true; 545 546 if (!filter_needs_more_output_space_ && !filter_->stream_data_len()) { 547 // We don't have any raw data to work with, so read from the transaction. 548 int filtered_data_read; 549 if (ReadRawDataForFilter(&filtered_data_read)) { 550 if (filtered_data_read > 0) { 551 // Give data to filter. 552 filter_->FlushStreamBuffer(filtered_data_read); 553 } else { 554 return true; // EOF. 555 } 556 } else { 557 return false; // IO Pending (or error). 558 } 559 } 560 561 if ((filter_->stream_data_len() || filter_needs_more_output_space_) && 562 !is_done()) { 563 // Get filtered data. 564 int filtered_data_len = filtered_read_buffer_len_; 565 int output_buffer_size = filtered_data_len; 566 Filter::FilterStatus status = 567 filter_->ReadData(filtered_read_buffer_->data(), &filtered_data_len); 568 569 if (filter_needs_more_output_space_ && !filtered_data_len) { 570 // filter_needs_more_output_space_ was mistaken... there are no more 571 // bytes and we should have at least tried to fill up the filter's input 572 // buffer. Correct the state, and try again. 573 filter_needs_more_output_space_ = false; 574 continue; 575 } 576 filter_needs_more_output_space_ = 577 (filtered_data_len == output_buffer_size); 578 579 switch (status) { 580 case Filter::FILTER_DONE: { 581 filter_needs_more_output_space_ = false; 582 *bytes_read = filtered_data_len; 583 postfilter_bytes_read_ += filtered_data_len; 584 rv = true; 585 break; 586 } 587 case Filter::FILTER_NEED_MORE_DATA: { 588 // We have finished filtering all data currently in the buffer. 589 // There might be some space left in the output buffer. One can 590 // consider reading more data from the stream to feed the filter 591 // and filling up the output buffer. This leads to more complicated 592 // buffer management and data notification mechanisms. 593 // We can revisit this issue if there is a real perf need. 594 if (filtered_data_len > 0) { 595 *bytes_read = filtered_data_len; 596 postfilter_bytes_read_ += filtered_data_len; 597 rv = true; 598 } else { 599 // Read again since we haven't received enough data yet (e.g., we 600 // may not have a complete gzip header yet). 601 continue; 602 } 603 break; 604 } 605 case Filter::FILTER_OK: { 606 *bytes_read = filtered_data_len; 607 postfilter_bytes_read_ += filtered_data_len; 608 rv = true; 609 break; 610 } 611 case Filter::FILTER_ERROR: { 612 DVLOG(1) << __FUNCTION__ << "() " 613 << "\"" << (request_ ? request_->url().spec() : "???") 614 << "\"" << " Filter Error"; 615 filter_needs_more_output_space_ = false; 616 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, 617 ERR_CONTENT_DECODING_FAILED)); 618 rv = false; 619 break; 620 } 621 default: { 622 NOTREACHED(); 623 filter_needs_more_output_space_ = false; 624 rv = false; 625 break; 626 } 627 } 628 629 // If logging all bytes is enabled, log the filtered bytes read. 630 if (rv && request() && request()->net_log().IsLoggingBytes() && 631 filtered_data_len > 0) { 632 request()->net_log().AddByteTransferEvent( 633 NetLog::TYPE_URL_REQUEST_JOB_FILTERED_BYTES_READ, 634 filtered_data_len, filtered_read_buffer_->data()); 635 } 636 } else { 637 // we are done, or there is no data left. 638 rv = true; 639 } 640 break; 641 } 642 643 if (rv) { 644 // When we successfully finished a read, we no longer need to save the 645 // caller's buffers. Release our reference. 646 filtered_read_buffer_ = NULL; 647 filtered_read_buffer_len_ = 0; 648 } 649 return rv; 650} 651 652void URLRequestJob::DestroyFilters() { 653 filter_.reset(); 654} 655 656const URLRequestStatus URLRequestJob::GetStatus() { 657 if (request_) 658 return request_->status(); 659 // If the request is gone, we must be cancelled. 660 return URLRequestStatus(URLRequestStatus::CANCELED, 661 ERR_ABORTED); 662} 663 664void URLRequestJob::SetStatus(const URLRequestStatus &status) { 665 if (request_) 666 request_->set_status(status); 667} 668 669void URLRequestJob::SetProxyServer(const HostPortPair& proxy_server) { 670 request_->proxy_server_ = proxy_server; 671} 672 673bool URLRequestJob::ReadRawDataForFilter(int* bytes_read) { 674 bool rv = false; 675 676 DCHECK(bytes_read); 677 DCHECK(filter_.get()); 678 679 *bytes_read = 0; 680 681 // Get more pre-filtered data if needed. 682 // TODO(mbelshe): is it possible that the filter needs *MORE* data 683 // when there is some data already in the buffer? 684 if (!filter_->stream_data_len() && !is_done()) { 685 IOBuffer* stream_buffer = filter_->stream_buffer(); 686 int stream_buffer_size = filter_->stream_buffer_size(); 687 rv = ReadRawDataHelper(stream_buffer, stream_buffer_size, bytes_read); 688 } 689 return rv; 690} 691 692bool URLRequestJob::ReadRawDataHelper(IOBuffer* buf, int buf_size, 693 int* bytes_read) { 694 DCHECK(!request_->status().is_io_pending()); 695 DCHECK(raw_read_buffer_.get() == NULL); 696 697 // Keep a pointer to the read buffer, so we have access to it in the 698 // OnRawReadComplete() callback in the event that the read completes 699 // asynchronously. 700 raw_read_buffer_ = buf; 701 bool rv = ReadRawData(buf, buf_size, bytes_read); 702 703 if (!request_->status().is_io_pending()) { 704 // If the read completes synchronously, either success or failure, 705 // invoke the OnRawReadComplete callback so we can account for the 706 // completed read. 707 OnRawReadComplete(*bytes_read); 708 } 709 return rv; 710} 711 712void URLRequestJob::FollowRedirect(const RedirectInfo& redirect_info) { 713 int rv = request_->Redirect(redirect_info); 714 if (rv != OK) 715 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv)); 716} 717 718void URLRequestJob::OnRawReadComplete(int bytes_read) { 719 DCHECK(raw_read_buffer_.get()); 720 // If |filter_| is non-NULL, bytes will be logged after it is applied instead. 721 if (!filter_.get() && request() && request()->net_log().IsLoggingBytes() && 722 bytes_read > 0) { 723 request()->net_log().AddByteTransferEvent( 724 NetLog::TYPE_URL_REQUEST_JOB_BYTES_READ, 725 bytes_read, raw_read_buffer_->data()); 726 } 727 728 if (bytes_read > 0) { 729 RecordBytesRead(bytes_read); 730 } 731 raw_read_buffer_ = NULL; 732} 733 734void URLRequestJob::RecordBytesRead(int bytes_read) { 735 filter_input_byte_count_ += bytes_read; 736 prefilter_bytes_read_ += bytes_read; 737 if (!filter_.get()) 738 postfilter_bytes_read_ += bytes_read; 739 DVLOG(2) << __FUNCTION__ << "() " 740 << "\"" << (request_ ? request_->url().spec() : "???") << "\"" 741 << " pre bytes read = " << bytes_read 742 << " pre total = " << prefilter_bytes_read_ 743 << " post total = " << postfilter_bytes_read_; 744 UpdatePacketReadTimes(); // Facilitate stats recording if it is active. 745 if (network_delegate_) 746 network_delegate_->NotifyRawBytesRead(*request_, bytes_read); 747} 748 749bool URLRequestJob::FilterHasData() { 750 return filter_.get() && filter_->stream_data_len(); 751} 752 753void URLRequestJob::UpdatePacketReadTimes() { 754} 755 756RedirectInfo URLRequestJob::ComputeRedirectInfo(const GURL& location, 757 int http_status_code) { 758 const GURL& url = request_->url(); 759 760 RedirectInfo redirect_info; 761 762 redirect_info.status_code = http_status_code; 763 764 // The request method may change, depending on the status code. 765 redirect_info.new_method = URLRequest::ComputeMethodForRedirect( 766 request_->method(), http_status_code); 767 768 // Move the reference fragment of the old location to the new one if the 769 // new one has none. This duplicates mozilla's behavior. 770 if (url.is_valid() && url.has_ref() && !location.has_ref() && 771 CopyFragmentOnRedirect(location)) { 772 GURL::Replacements replacements; 773 // Reference the |ref| directly out of the original URL to avoid a 774 // malloc. 775 replacements.SetRef(url.spec().data(), 776 url.parsed_for_possibly_invalid_spec().ref); 777 redirect_info.new_url = location.ReplaceComponents(replacements); 778 } else { 779 redirect_info.new_url = location; 780 } 781 782 // Update the first-party URL if appropriate. 783 if (request_->first_party_url_policy() == 784 URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT) { 785 redirect_info.new_first_party_for_cookies = redirect_info.new_url; 786 } else { 787 redirect_info.new_first_party_for_cookies = 788 request_->first_party_for_cookies(); 789 } 790 791 // Suppress the referrer if we're redirecting out of https. 792 if (request_->referrer_policy() == 793 URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE && 794 GURL(request_->referrer()).SchemeIsSecure() && 795 !redirect_info.new_url.SchemeIsSecure()) { 796 redirect_info.new_referrer.clear(); 797 } else { 798 redirect_info.new_referrer = request_->referrer(); 799 } 800 801 return redirect_info; 802} 803 804} // namespace net 805