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