blob: 239f06c4bb0c1d974c4f3a3df7c878c196c450a9 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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"
Ben Murdoch9ab55632013-07-18 11:57:30 +01009#include "base/message_loop/message_loop.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010010#include "base/power_monitor/power_monitor.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010011#include "base/strings/string_number_conversions.h"
12#include "base/strings/string_util.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000013#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"
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000019#include "net/filter/filter.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000020#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),
Torne (Richard Coles)58218062012-11-14 11:43:16 +000036 network_delegate_(network_delegate),
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010037 weak_factory_(this) {
38 base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
39 if (power_monitor)
40 power_monitor->AddObserver(this);
Torne (Richard Coles)58218062012-11-14 11:43:16 +000041}
42
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000043void URLRequestJob::SetUpload(UploadDataStream* upload) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +000044}
45
46void URLRequestJob::SetExtraRequestHeaders(const HttpRequestHeaders& headers) {
47}
48
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000049void URLRequestJob::SetPriority(RequestPriority priority) {
50}
51
Torne (Richard Coles)58218062012-11-14 11:43:16 +000052void 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;
Torne (Richard Coles)58218062012-11-14 11:43:16 +000062}
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);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010073 DCHECK(filtered_read_buffer_.get() == NULL);
Torne (Richard Coles)58218062012-11-14 11:43:16 +000074 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
Ben Murdocheb525c52013-07-10 11:40:50 +0100108bool URLRequestJob::GetFullRequestHeaders(HttpRequestHeaders* headers) const {
109 // Most job types don't send request headers.
110 return false;
111}
112
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000113int64 URLRequestJob::GetTotalReceivedBytes() const {
114 return 0;
115}
116
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000117LoadState 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
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000132void URLRequestJob::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
133 // Only certain request types return more than just request start times.
134}
135
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000136bool 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
Ben Murdochc5cede92014-04-10 11:22:14 +0100160bool URLRequestJob::CopyFragmentOnRedirect(const GURL& location) const {
161 return true;
162}
163
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000164bool 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() {
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +0100205 DCHECK_NE(-1, deferred_redirect_info_.status_code);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000206
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +0100207 // 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.
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000210
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
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +0100214 RedirectInfo redirect_info = deferred_redirect_info_;
215 deferred_redirect_info_ = RedirectInfo();
216 FollowRedirect(redirect_info);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000217}
218
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000219void URLRequestJob::ResumeNetworkStart() {
220 // This should only be called for HTTP Jobs, and implemented in the derived
221 // class.
222 NOTREACHED();
223}
224
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000225bool 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() {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100245 base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
246 if (power_monitor)
247 power_monitor->RemoveObserver(this);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000248}
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
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100281bool 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
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000288CookieStore* URLRequestJob::GetCookieStore() const {
289 DCHECK(request_);
290
291 return request_->cookie_store();
292}
293
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000294void URLRequestJob::NotifyBeforeNetworkStart(bool* defer) {
295 if (!request_)
296 return;
297
298 request_->NotifyBeforeNetworkStart(defer);
299}
300
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000301void 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
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000323 if (request_)
324 request_->OnHeadersComplete();
325
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000326 GURL new_location;
327 int http_status_code;
328 if (IsRedirectResponse(&new_location, &http_status_code)) {
Ben Murdocheffb81e2014-03-31 11:51:25 +0100329 // Redirect response bodies are not read. Notify the transaction
330 // so it does not treat being stopped as an error.
331 DoneReadingRedirectResponse();
332
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +0100333 RedirectInfo redirect_info =
334 ComputeRedirectInfo(new_location, http_status_code);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000335
336 bool defer_redirect = false;
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +0100337 request_->NotifyReceivedRedirect(redirect_info, &defer_redirect);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000338
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) {
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +0100347 deferred_redirect_info_ = redirect_info;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000348 } else {
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +0100349 FollowRedirect(redirect_info);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000350 }
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.
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100358 if (auth_info.get()) {
359 request_->NotifyAuthRequired(auth_info.get());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000360 // 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.
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100385#if 0
386 DCHECK(!request_->status().is_io_pending());
387#endif
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000388 // 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_) {
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000429 // There may be relevant information in the response info even in the
430 // error case.
431 GetResponseInfo(&request_->response_info_);
432
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000433 request_->set_status(status);
434 request_->NotifyResponseStarted();
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000435 // We may have been deleted.
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000436 }
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.
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100470 base::MessageLoop::current()->PostTask(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000471 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
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +0000505void URLRequestJob::OnCallToDelegate() {
506 request_->OnCallToDelegate();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000507}
508
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +0000509void URLRequestJob::OnCallToDelegateComplete() {
510 request_->OnCallToDelegateComplete();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000511}
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
Ben Murdocheffb81e2014-03-31 11:51:25 +0100524void URLRequestJob::DoneReadingRedirectResponse() {
525}
526
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000527void URLRequestJob::FilteredDataRead(int bytes_read) {
Torne (Richard Coles)010d83a2014-05-14 12:12:37 +0100528 DCHECK(filter_);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000529 filter_->FlushStreamBuffer(bytes_read);
530}
531
532bool URLRequestJob::ReadFilteredData(int* bytes_read) {
Torne (Richard Coles)010d83a2014-05-14 12:12:37 +0100533 DCHECK(filter_);
534 DCHECK(filtered_read_buffer_);
535 DCHECK_GT(filtered_read_buffer_len_, 0);
536 DCHECK_LT(filtered_read_buffer_len_, 1000000); // Sanity check.
537 DCHECK(!raw_read_buffer_);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000538
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000539 *bytes_read = 0;
Torne (Richard Coles)010d83a2014-05-14 12:12:37 +0100540 bool rv = false;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000541
Torne (Richard Coles)010d83a2014-05-14 12:12:37 +0100542 for (;;) {
543 if (is_done())
544 return true;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000545
Torne (Richard Coles)010d83a2014-05-14 12:12:37 +0100546 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 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000556 } else {
Torne (Richard Coles)010d83a2014-05-14 12:12:37 +0100557 return false; // IO Pending (or error).
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000558 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000559 }
560
Torne (Richard Coles)010d83a2014-05-14 12:12:37 +0100561 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.
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000573 filter_needs_more_output_space_ = false;
Torne (Richard Coles)010d83a2014-05-14 12:12:37 +0100574 continue;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000575 }
Torne (Richard Coles)010d83a2014-05-14 12:12:37 +0100576 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;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000582 *bytes_read = filtered_data_len;
583 postfilter_bytes_read_ += filtered_data_len;
584 rv = true;
Torne (Richard Coles)010d83a2014-05-14 12:12:37 +0100585 break;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000586 }
Torne (Richard Coles)010d83a2014-05-14 12:12:37 +0100587 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 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000627 }
Torne (Richard Coles)010d83a2014-05-14 12:12:37 +0100628
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());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000635 }
Torne (Richard Coles)010d83a2014-05-14 12:12:37 +0100636 } else {
637 // we are done, or there is no data left.
638 rv = true;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000639 }
Torne (Richard Coles)010d83a2014-05-14 12:12:37 +0100640 break;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000641 }
642
643 if (rv) {
Torne (Richard Coles)010d83a2014-05-14 12:12:37 +0100644 // When we successfully finished a read, we no longer need to save the
645 // caller's buffers. Release our reference.
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000646 filtered_read_buffer_ = NULL;
647 filtered_read_buffer_len_ = 0;
648 }
649 return rv;
650}
651
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000652void URLRequestJob::DestroyFilters() {
653 filter_.reset();
654}
655
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000656const 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
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100669void URLRequestJob::SetProxyServer(const HostPortPair& proxy_server) {
670 request_->proxy_server_ = proxy_server;
671}
672
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000673bool 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());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100695 DCHECK(raw_read_buffer_.get() == NULL);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000696
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()) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000704 // 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
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +0100712void URLRequestJob::FollowRedirect(const RedirectInfo& redirect_info) {
713 int rv = request_->Redirect(redirect_info);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000714 if (rv != OK)
715 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
716}
717
718void URLRequestJob::OnRawReadComplete(int bytes_read) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100719 DCHECK(raw_read_buffer_.get());
Torne (Richard Coles)23730a62014-03-21 14:25:57 +0000720 // 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
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000728 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
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +0100756RedirectInfo 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
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000804} // namespace net