Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / loader / detachable_resource_handler.cc
1 // Copyright 2013 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 "content/browser/loader/detachable_resource_handler.h"
6
7 #include "base/logging.h"
8 #include "base/time/time.h"
9 #include "content/browser/loader/resource_request_info_impl.h"
10 #include "net/base/io_buffer.h"
11 #include "net/base/net_errors.h"
12 #include "net/url_request/url_request.h"
13 #include "net/url_request/url_request_status.h"
14
15 namespace {
16 // This matches the maximum allocation size of AsyncResourceHandler.
17 const int kReadBufSize = 32 * 1024;
18 }
19
20 namespace content {
21
22 DetachableResourceHandler::DetachableResourceHandler(
23     net::URLRequest* request,
24     base::TimeDelta cancel_delay,
25     scoped_ptr<ResourceHandler> next_handler)
26     : ResourceHandler(request),
27       next_handler_(next_handler.Pass()),
28       cancel_delay_(cancel_delay),
29       is_deferred_(false),
30       is_finished_(false) {
31   GetRequestInfo()->set_detachable_handler(this);
32 }
33
34 DetachableResourceHandler::~DetachableResourceHandler() {
35   // Cleanup back-pointer stored on the request info.
36   GetRequestInfo()->set_detachable_handler(NULL);
37 }
38
39 void DetachableResourceHandler::Detach() {
40   if (is_detached())
41     return;
42
43   if (!is_finished_) {
44     // Simulate a cancel on the next handler before destroying it.
45     net::URLRequestStatus status(net::URLRequestStatus::CANCELED,
46                                  net::ERR_ABORTED);
47     bool defer_ignored = false;
48     next_handler_->OnResponseCompleted(status, std::string(), &defer_ignored);
49     DCHECK(!defer_ignored);
50     // If |next_handler_| were to defer its shutdown in OnResponseCompleted,
51     // this would destroy it anyway. Fortunately, AsyncResourceHandler never
52     // does this anyway, so DCHECK it. BufferedResourceHandler and RVH shutdown
53     // already ignore deferred ResourceHandler shutdown, but
54     // DetachableResourceHandler and the detach-on-renderer-cancel logic
55     // introduces a case where this occurs when the renderer cancels a resource.
56   }
57   // A OnWillRead / OnReadCompleted pair may still be in progress, but
58   // OnWillRead passes back a scoped_refptr, so downstream handler's buffer will
59   // survive long enough to complete that read. From there, future reads will
60   // drain into |read_buffer_|. (If |next_handler_| is an AsyncResourceHandler,
61   // the net::IOBuffer takes a reference to the ResourceBuffer which owns the
62   // shared memory.)
63   next_handler_.reset();
64
65   // Time the request out if it takes too long.
66   detached_timer_.reset(new base::OneShotTimer<DetachableResourceHandler>());
67   detached_timer_->Start(
68       FROM_HERE, cancel_delay_, this, &DetachableResourceHandler::Cancel);
69
70   // Resume if necessary. The request may have been deferred, say, waiting on a
71   // full buffer in AsyncResourceHandler. Now that it has been detached, resume
72   // and drain it.
73   if (is_deferred_) {
74     // The nested ResourceHandler may have logged that it's blocking the
75     // request.  Log it as no longer doing so, to avoid a DCHECK on resume.
76     request()->LogUnblocked();
77     Resume();
78   }
79 }
80
81 void DetachableResourceHandler::SetController(ResourceController* controller) {
82   ResourceHandler::SetController(controller);
83
84   // Intercept the ResourceController for downstream handlers to keep track of
85   // whether the request is deferred.
86   if (next_handler_)
87     next_handler_->SetController(this);
88 }
89
90 bool DetachableResourceHandler::OnUploadProgress(uint64 position, uint64 size) {
91   if (!next_handler_)
92     return true;
93
94   return next_handler_->OnUploadProgress(position, size);
95 }
96
97 bool DetachableResourceHandler::OnRequestRedirected(
98     const net::RedirectInfo& redirect_info,
99     ResourceResponse* response,
100     bool* defer) {
101   DCHECK(!is_deferred_);
102
103   if (!next_handler_)
104     return true;
105
106   bool ret = next_handler_->OnRequestRedirected(
107       redirect_info, response, &is_deferred_);
108   *defer = is_deferred_;
109   return ret;
110 }
111
112 bool DetachableResourceHandler::OnResponseStarted(ResourceResponse* response,
113                                                   bool* defer) {
114   DCHECK(!is_deferred_);
115
116   if (!next_handler_)
117     return true;
118
119   bool ret =
120       next_handler_->OnResponseStarted(response, &is_deferred_);
121   *defer = is_deferred_;
122   return ret;
123 }
124
125 bool DetachableResourceHandler::OnWillStart(const GURL& url, bool* defer) {
126   DCHECK(!is_deferred_);
127
128   if (!next_handler_)
129     return true;
130
131   bool ret = next_handler_->OnWillStart(url, &is_deferred_);
132   *defer = is_deferred_;
133   return ret;
134 }
135
136 bool DetachableResourceHandler::OnBeforeNetworkStart(const GURL& url,
137                                                      bool* defer) {
138   DCHECK(!is_deferred_);
139
140   if (!next_handler_)
141     return true;
142
143   bool ret =
144       next_handler_->OnBeforeNetworkStart(url, &is_deferred_);
145   *defer = is_deferred_;
146   return ret;
147 }
148
149 bool DetachableResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
150                                            int* buf_size,
151                                            int min_size) {
152   if (!next_handler_) {
153     DCHECK_EQ(-1, min_size);
154     if (!read_buffer_.get())
155       read_buffer_ = new net::IOBuffer(kReadBufSize);
156     *buf = read_buffer_;
157     *buf_size = kReadBufSize;
158     return true;
159   }
160
161   return next_handler_->OnWillRead(buf, buf_size, min_size);
162 }
163
164 bool DetachableResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
165   DCHECK(!is_deferred_);
166
167   if (!next_handler_)
168     return true;
169
170   bool ret =
171       next_handler_->OnReadCompleted(bytes_read, &is_deferred_);
172   *defer = is_deferred_;
173   return ret;
174 }
175
176 void DetachableResourceHandler::OnResponseCompleted(
177     const net::URLRequestStatus& status,
178     const std::string& security_info,
179     bool* defer) {
180   // No DCHECK(!is_deferred_) as the request may have been cancelled while
181   // deferred.
182
183   if (!next_handler_)
184     return;
185
186   is_finished_ = true;
187
188   next_handler_->OnResponseCompleted(status, security_info, &is_deferred_);
189   *defer = is_deferred_;
190 }
191
192 void DetachableResourceHandler::OnDataDownloaded(int bytes_downloaded) {
193   if (!next_handler_)
194     return;
195
196   next_handler_->OnDataDownloaded(bytes_downloaded);
197 }
198
199 void DetachableResourceHandler::Resume() {
200   DCHECK(is_deferred_);
201   is_deferred_ = false;
202   controller()->Resume();
203 }
204
205 void DetachableResourceHandler::Cancel() {
206   controller()->Cancel();
207 }
208
209 void DetachableResourceHandler::CancelAndIgnore() {
210   controller()->CancelAndIgnore();
211 }
212
213 void DetachableResourceHandler::CancelWithError(int error_code) {
214   controller()->CancelWithError(error_code);
215 }
216
217 }  // namespace content