Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1095)

Side by Side Diff: content/browser/renderer_host/buffered_resource_handler.cc

Issue 10578055: Rewrite guts of ResourceLoader and BufferedResourceHandler to suck less. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/renderer_host/buffered_resource_handler.h" 5 #include "content/browser/renderer_host/buffered_resource_handler.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 52
53 static base::Histogram* nosniff_empty_mime_type(NULL); 53 static base::Histogram* nosniff_empty_mime_type(NULL);
54 if (!nosniff_empty_mime_type) 54 if (!nosniff_empty_mime_type)
55 nosniff_empty_mime_type = base::BooleanHistogram::FactoryGet( 55 nosniff_empty_mime_type = base::BooleanHistogram::FactoryGet(
56 "nosniff.empty_mime_type", 56 "nosniff.empty_mime_type",
57 base::Histogram::kUmaTargetedHistogramFlag); 57 base::Histogram::kUmaTargetedHistogramFlag);
58 nosniff_empty_mime_type->AddBoolean(mime_type.empty()); 58 nosniff_empty_mime_type->AddBoolean(mime_type.empty());
59 } 59 }
60 } 60 }
61 61
62 // Used to write into an existing IOBuffer at a given offset.
63 class DependentIOBuffer : public net::WrappedIOBuffer {
64 public:
65 DependentIOBuffer(net::IOBuffer* buf, int offset)
66 : net::WrappedIOBuffer(buf->data() + offset),
67 buf_(buf) {
68 }
69
70 private:
71 ~DependentIOBuffer() {}
72
73 scoped_refptr<net::IOBuffer> buf_;
74 };
75
62 } // namespace 76 } // namespace
63 77
64 BufferedResourceHandler::BufferedResourceHandler( 78 BufferedResourceHandler::BufferedResourceHandler(
65 scoped_ptr<ResourceHandler> next_handler, 79 scoped_ptr<ResourceHandler> next_handler,
66 ResourceDispatcherHostImpl* host, 80 ResourceDispatcherHostImpl* host,
67 net::URLRequest* request) 81 net::URLRequest* request)
68 : LayeredResourceHandler(next_handler.Pass()), 82 : LayeredResourceHandler(next_handler.Pass()),
83 state_(STATE_STARTING),
69 host_(host), 84 host_(host),
70 request_(request), 85 request_(request),
71 read_buffer_size_(0), 86 read_buffer_size_(0),
72 bytes_read_(0), 87 bytes_read_(0),
73 sniff_content_(false), 88 must_download_(false),
74 wait_for_plugins_(false), 89 must_download_is_set_(false) {
75 deferred_waiting_for_plugins_(false), 90 }
76 buffering_(false), 91
77 next_handler_needs_response_started_(false), 92 BufferedResourceHandler::~BufferedResourceHandler() {
78 next_handler_needs_will_read_(false), 93 }
79 finished_(false) { 94
95 void BufferedResourceHandler::SetController(ResourceController* controller) {
96 ResourceHandler::SetController(controller);
97
98 // Downstream handlers see us as their ResourceController, which allows us to
99 // consume part or all of the resource response, and then later replay it to
100 // downstream handler.
101 DCHECK(next_handler_.get());
102 next_handler_->SetController(this);
80 } 103 }
81 104
82 bool BufferedResourceHandler::OnResponseStarted( 105 bool BufferedResourceHandler::OnResponseStarted(
83 int request_id, 106 int request_id,
84 ResourceResponse* response, 107 ResourceResponse* response,
85 bool* defer) { 108 bool* defer) {
86 response_ = response; 109 response_ = response;
87 110
88 if (!DelayResponse()) 111 // TODO(darin): It is very odd to special-case 304 responses at this level.
89 return CompleteResponseStarted(request_id, defer); 112 // We do so only because the code always has, see r24977 and r29355. The
113 // fact that 204 is no longer special-cased this way suggests that 304 need
114 // not be special-cased either.
115 //
116 // The network stack only forwards 304 responses that were not received in
117 // response to a conditional request (i.e., If-Modified-Since). Other 304
118 // responses end up being translated to 200 or whatever the cached response
119 // code happens to be. It should be very rare to see a 304 at this level.
90 120
91 if (wait_for_plugins_) { 121 if (!(response_->head.headers &&
92 deferred_waiting_for_plugins_ = true; 122 response_->head.headers->response_code() == 304)) {
93 *defer = true; 123 if (ShouldSniffContent()) {
124 state_ = STATE_BUFFERING;
125 return true;
126 }
127
128 if (response_->head.mime_type.empty()) {
129 // Ugg. The server told us not to sniff the content but didn't give us
130 // a mime type. What's a browser to do? Turns out, we're supposed to
131 // treat the response as "text/plain". This is the most secure option.
132 response_->head.mime_type.assign("text/plain");
133 }
94 } 134 }
95 return true; 135
136 state_ = STATE_PROCESSING;
137 return ProcessResponse(defer);
96 } 138 }
97 139
98 // We'll let the original event handler provide a buffer, and reuse it for 140 // We'll let the original event handler provide a buffer, and reuse it for
99 // subsequent reads until we're done buffering. 141 // subsequent reads until we're done buffering.
100 bool BufferedResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf, 142 bool BufferedResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
101 int* buf_size, int min_size) { 143 int* buf_size, int min_size) {
102 if (buffering_) { 144 if (state_ == STATE_STREAMING)
103 DCHECK(!my_buffer_.get()); 145 return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
104 my_buffer_ = new net::IOBuffer(net::kMaxBytesToSniff); 146
105 *buf = my_buffer_.get(); 147 DCHECK_EQ(-1, min_size);
106 *buf_size = net::kMaxBytesToSniff; 148
149 if (read_buffer_) {
150 CHECK_LT(bytes_read_, read_buffer_size_);
151 *buf = new DependentIOBuffer(read_buffer_, bytes_read_);
152 *buf_size = read_buffer_size_ - bytes_read_;
153 } else {
154 if (!next_handler_->OnWillRead(request_id, buf, buf_size, min_size))
155 return false;
156
157 read_buffer_ = *buf;
158 read_buffer_size_ = *buf_size;
159 DCHECK_GE(read_buffer_size_, net::kMaxBytesToSniff * 2);
160 }
161 return true;
162 }
163
164 bool BufferedResourceHandler::OnReadCompleted(int request_id, int bytes_read,
165 bool* defer) {
166 if (state_ == STATE_STREAMING)
167 return next_handler_->OnReadCompleted(request_id, bytes_read, defer);
168
169 DCHECK_EQ(state_, STATE_BUFFERING);
170 bytes_read_ += bytes_read;
171
172 if (!DetermineMimeType() && (bytes_read > 0))
173 return true; // Needs more data, so keep buffering.
174
175 state_ = STATE_PROCESSING;
176 return ProcessResponse(defer);
177 }
178
179 bool BufferedResourceHandler::OnResponseCompleted(
180 int request_id,
181 const net::URLRequestStatus& status,
182 const std::string& security_info) {
183 // Upon completion, act like a pass-through handler in case the downstream
184 // handler defers OnResponseCompleted.
185 state_ = STATE_STREAMING;
186
187 return next_handler_->OnResponseCompleted(request_id, status, security_info);
188 }
189
190 void BufferedResourceHandler::Resume() {
191 switch (state_) {
192 case STATE_BUFFERING:
193 case STATE_PROCESSING:
194 NOTREACHED();
195 break;
196 case STATE_REPLAYING:
197 MessageLoop::current()->PostTask(
198 FROM_HERE,
199 base::Bind(&BufferedResourceHandler::CallReplayReadCompleted,
200 AsWeakPtr()));
201 break;
202 case STATE_STARTING:
203 case STATE_STREAMING:
204 controller()->Resume();
205 break;
206 }
207 }
208
209 void BufferedResourceHandler::Cancel() {
210 controller()->Cancel();
211 }
212
213 bool BufferedResourceHandler::ProcessResponse(bool* defer) {
214 DCHECK_EQ(STATE_PROCESSING, state_);
215
216 // TODO(darin): Stop special-casing 304 responses.
217 if (!(response_->head.headers &&
218 response_->head.headers->response_code() == 304)) {
219 if (!SelectNextHandler(defer))
220 return false;
221 if (*defer)
222 return true;
223 }
224
225 state_ = STATE_REPLAYING;
226
227 int request_id = ResourceRequestInfo::ForRequest(request_)->GetRequestID();
228 if (!next_handler_->OnResponseStarted(request_id, response_, defer))
229 return false;
230
231 if (!read_buffer_) {
232 state_ = STATE_STREAMING;
107 return true; 233 return true;
108 } 234 }
109 235
110 if (finished_) 236 if (!*defer)
111 return false; 237 return ReplayReadCompleted(defer);
112 238
113 if (!next_handler_->OnWillRead(request_id, buf, buf_size, min_size))
114 return false;
115
116 read_buffer_ = *buf;
117 read_buffer_size_ = *buf_size;
118 DCHECK_GE(read_buffer_size_, net::kMaxBytesToSniff * 2);
119 bytes_read_ = 0;
120 return true; 239 return true;
121 } 240 }
122 241
123 bool BufferedResourceHandler::OnReadCompleted(int request_id, int* bytes_read, 242 bool BufferedResourceHandler::ShouldSniffContent() {
124 bool* defer) { 243 const std::string& mime_type = response_->head.mime_type;
125 if (sniff_content_) {
126 if (KeepBuffering(*bytes_read)) {
127 if (wait_for_plugins_)
128 *defer = deferred_waiting_for_plugins_ = true;
129 return true;
130 }
131
132 *bytes_read = bytes_read_;
133
134 // Done buffering, send the pending ResponseStarted event.
135 if (!CompleteResponseStarted(request_id, defer))
136 return false;
137 if (*defer)
138 return true;
139 } else if (wait_for_plugins_) {
140 *defer = deferred_waiting_for_plugins_ = true;
141 return true;
142 }
143
144 if (!ForwardPendingEventsToNextHandler(request_id, defer))
145 return false;
146 if (*defer)
147 return true;
148
149 // Release the reference that we acquired at OnWillRead.
150 read_buffer_ = NULL;
151 return next_handler_->OnReadCompleted(request_id, bytes_read, defer);
152 }
153
154 BufferedResourceHandler::~BufferedResourceHandler() {}
155
156 bool BufferedResourceHandler::DelayResponse() {
157 std::string mime_type;
158 request_->GetMimeType(&mime_type);
159 244
160 std::string content_type_options; 245 std::string content_type_options;
161 request_->GetResponseHeaderByName("x-content-type-options", 246 request_->GetResponseHeaderByName("x-content-type-options",
162 &content_type_options); 247 &content_type_options);
163 248
164 const bool sniffing_blocked = 249 bool sniffing_blocked =
165 LowerCaseEqualsASCII(content_type_options, "nosniff"); 250 LowerCaseEqualsASCII(content_type_options, "nosniff");
166 const bool not_modified_status = 251 bool we_would_like_to_sniff =
167 (response_->head.headers && 252 net::ShouldSniffMimeType(request_->url(), mime_type);
168 response_->head.headers->response_code() == 304);
169 const bool we_would_like_to_sniff = not_modified_status ?
170 false : net::ShouldSniffMimeType(request_->url(), mime_type);
171 253
172 RecordSnifferMetrics(sniffing_blocked, we_would_like_to_sniff, mime_type); 254 RecordSnifferMetrics(sniffing_blocked, we_would_like_to_sniff, mime_type);
173 255
174 if (!sniffing_blocked && we_would_like_to_sniff) { 256 if (!sniffing_blocked && we_would_like_to_sniff) {
175 // We're going to look at the data before deciding what the content type 257 // We're going to look at the data before deciding what the content type
176 // is. That means we need to delay sending the ResponseStarted message 258 // is. That means we need to delay sending the ResponseStarted message
177 // over the IPC channel. 259 // over the IPC channel.
178 sniff_content_ = true;
179 VLOG(1) << "To buffer: " << request_->url().spec(); 260 VLOG(1) << "To buffer: " << request_->url().spec();
180 return true; 261 return true;
181 } 262 }
182 263
183 if (sniffing_blocked && mime_type.empty() && !not_modified_status) {
184 // Ugg. The server told us not to sniff the content but didn't give us a
185 // mime type. What's a browser to do? Turns out, we're supposed to treat
186 // the response as "text/plain". This is the most secure option.
187 mime_type.assign("text/plain");
188 response_->head.mime_type.assign(mime_type);
189 }
190
191 if (!not_modified_status && ShouldWaitForPlugins()) {
192 wait_for_plugins_ = true;
193 return true;
194 }
195
196 return false; 264 return false;
197 } 265 }
198 266
199 bool BufferedResourceHandler::DidBufferEnough(int bytes_read) { 267 bool BufferedResourceHandler::DetermineMimeType() {
200 const int kRequiredLength = 256; 268 DCHECK_EQ(STATE_BUFFERING, state_);
201 269
202 return bytes_read >= kRequiredLength; 270 const std::string& type_hint = response_->head.mime_type;
271
272 std::string new_type;
273 bool made_final_decision =
274 net::SniffMimeType(read_buffer_->data(), bytes_read_, request_->url(),
275 type_hint, &new_type);
276
277 // SniffMimeType() returns false if there is not enough data to determine
278 // the mime type. However, even if it returns false, it returns a new type
279 // that is probably better than the current one.
280 response_->head.mime_type.assign(new_type);
281
282 return made_final_decision;
203 } 283 }
204 284
205 bool BufferedResourceHandler::KeepBuffering(int bytes_read) { 285 bool BufferedResourceHandler::SelectNextHandler(bool* defer) {
206 DCHECK(read_buffer_); 286 DCHECK(!response_->head.mime_type.empty());
207 if (my_buffer_) {
208 // We are using our own buffer to read, update the main buffer.
209 // TODO(darin): We should handle the case where read_buffer_size_ is small!
210 // See RedirectToFileResourceHandler::BufIsFull to see how this impairs
211 // downstream ResourceHandler implementations.
212 CHECK_LT(bytes_read + bytes_read_, read_buffer_size_);
213 memcpy(read_buffer_->data() + bytes_read_, my_buffer_->data(), bytes_read);
214 my_buffer_ = NULL;
215 }
216 bytes_read_ += bytes_read;
217 finished_ = (bytes_read == 0);
218 287
219 if (sniff_content_) { 288 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request_);
220 std::string type_hint, new_type; 289 const std::string& mime_type = response_->head.mime_type;
221 request_->GetMimeType(&type_hint);
222
223 if (!net::SniffMimeType(read_buffer_->data(), bytes_read_,
224 request_->url(), type_hint, &new_type)) {
225 // SniffMimeType() returns false if there is not enough data to determine
226 // the mime type. However, even if it returns false, it returns a new type
227 // that is probably better than the current one.
228 DCHECK_LT(bytes_read_, net::kMaxBytesToSniff);
229 if (!finished_) {
230 buffering_ = true;
231 return true;
232 }
233 }
234 sniff_content_ = false;
235 response_->head.mime_type.assign(new_type);
236
237 // We just sniffed the mime type, maybe there is a doctype to process.
238 if (ShouldWaitForPlugins())
239 wait_for_plugins_ = true;
240 }
241
242 buffering_ = false;
243
244 if (wait_for_plugins_)
245 return true;
246
247 return false;
248 }
249
250 bool BufferedResourceHandler::CompleteResponseStarted(int request_id,
251 bool* defer) {
252 ResourceRequestInfoImpl* info =
253 ResourceRequestInfoImpl::ForRequest(request_);
254 std::string mime_type;
255 request_->GetMimeType(&mime_type);
256 290
257 if (mime_type == "application/x-x509-user-cert") { 291 if (mime_type == "application/x-x509-user-cert") {
258 // Let X.509 certs be handled by the X509UserCertResourceHandler. 292 // Install X509 handler.
259
260 // This is entirely similar to how DownloadResourceHandler works except we
261 // are doing it for an X.509 client certificates.
262 // TODO(darin): This does not belong here!
263
264 if (response_->head.headers && // Can be NULL if FTP.
265 response_->head.headers->response_code() / 100 != 2) {
266 // The response code indicates that this is an error page, but we are
267 // expecting an X.509 user certificate. We follow Firefox here and show
268 // our own error page instead of handling the error page as a
269 // certificate.
270 // TODO(abarth): We should abstract the response_code test, but this kind
271 // of check is scattered throughout our codebase.
272 request_->CancelWithError(net::ERR_FILE_NOT_FOUND);
273 return false;
274 }
275
276 scoped_ptr<ResourceHandler> handler( 293 scoped_ptr<ResourceHandler> handler(
277 new X509UserCertResourceHandler(request_, 294 new X509UserCertResourceHandler(request_,
278 info->GetChildID(), 295 info->GetChildID(),
279 info->GetRouteID())); 296 info->GetRouteID()));
280 297 return UseAlternateNextHandler(handler.Pass());
281 return UseAlternateResourceHandler(request_id, handler.Pass(), defer);
282 } 298 }
283 299
284 if (info->allow_download() && ShouldDownload(NULL)) { 300 if (!info->allow_download())
285 // Forward the data to the download thread.
286 if (response_->head.headers && // Can be NULL if FTP.
287 response_->head.headers->response_code() / 100 != 2) {
288 // The response code indicates that this is an error page, but we don't
289 // know how to display the content. We follow Firefox here and show our
290 // own error page instead of triggering a download.
291 // TODO(abarth): We should abstract the response_code test, but this kind
292 // of check is scattered throughout our codebase.
293 request_->CancelWithError(net::ERR_FILE_NOT_FOUND);
294 return false;
295 }
296
297 info->set_is_download(true);
298
299 scoped_ptr<ResourceHandler> handler(
300 host_->CreateResourceHandlerForDownload(
301 request_,
302 true, // is_content_initiated
303 DownloadSaveInfo(),
304 DownloadResourceHandler::OnStartedCallback()));
305
306 return UseAlternateResourceHandler(request_id, handler.Pass(), defer);
307 }
308
309 if (*defer)
310 return true; 301 return true;
311 302
312 return next_handler_->OnResponseStarted(request_id, response_, defer); 303 if (!MustDownload()) {
313 } 304 if (net::IsSupportedMimeType(mime_type))
305 return true;
314 306
315 bool BufferedResourceHandler::ShouldWaitForPlugins() { 307 bool stale;
316 bool need_plugin_list; 308 bool has_plugin = HasSupportingPlugin(&stale);
317 if (!ShouldDownload(&need_plugin_list) || !need_plugin_list) 309 if (stale) {
318 return false; 310 // Refresh the plugins asynchronously.
319 311 PluginServiceImpl::GetInstance()->GetPlugins(
320 // Get the plugins asynchronously. 312 base::Bind(&BufferedResourceHandler::OnPluginsLoaded, AsWeakPtr()));
321 PluginServiceImpl::GetInstance()->GetPlugins( 313 *defer = true;
322 base::Bind(&BufferedResourceHandler::OnPluginsLoaded, AsWeakPtr())); 314 return true;
323 return true; 315 }
324 } 316 if (has_plugin)
325
326 // This test mirrors the decision that WebKit makes in
327 // WebFrameLoaderClient::dispatchDecidePolicyForMIMEType.
328 bool BufferedResourceHandler::ShouldDownload(bool* need_plugin_list) {
329 if (need_plugin_list)
330 *need_plugin_list = false;
331 std::string type = StringToLowerASCII(response_->head.mime_type);
332
333 // First, examine Content-Disposition.
334 std::string disposition;
335 request_->GetResponseHeaderByName("content-disposition", &disposition);
336 if (!disposition.empty()) {
337 net::HttpContentDisposition parsed_disposition(disposition, std::string());
338 if (parsed_disposition.is_attachment())
339 return true; 317 return true;
340 } 318 }
341 319
342 if (host_->delegate() && 320 // Install download handler
343 host_->delegate()->ShouldForceDownloadResource(request_->url(), type)) 321 info->set_is_download(true);
344 return true; 322 scoped_ptr<ResourceHandler> handler(
323 host_->CreateResourceHandlerForDownload(
324 request_,
325 true, // is_content_initiated
326 DownloadSaveInfo(),
327 DownloadResourceHandler::OnStartedCallback()));
328 return UseAlternateNextHandler(handler.Pass());
329 }
345 330
346 // MIME type checking. 331 bool BufferedResourceHandler::UseAlternateNextHandler(
347 if (net::IsSupportedMimeType(type)) 332 scoped_ptr<ResourceHandler> new_handler) {
333 if (response_->head.headers && // Can be NULL if FTP.
334 response_->head.headers->response_code() / 100 != 2) {
335 // The response code indicates that this is an error page, but we don't
336 // know how to display the content. We follow Firefox here and show our
337 // own error page instead of triggering a download.
338 // TODO(abarth): We should abstract the response_code test, but this kind
339 // of check is scattered throughout our codebase.
340 request_->CancelWithError(net::ERR_FILE_NOT_FOUND);
348 return false; 341 return false;
349
350 // Finally, check the plugin list.
351 bool allow_wildcard = false;
352 ResourceRequestInfoImpl* info =
353 ResourceRequestInfoImpl::ForRequest(request_);
354 bool stale = false;
355 webkit::WebPluginInfo plugin;
356 bool found = PluginServiceImpl::GetInstance()->GetPluginInfo(
357 info->GetChildID(), info->GetRouteID(), info->GetContext(),
358 request_->url(), GURL(), type, allow_wildcard,
359 &stale, &plugin, NULL);
360
361 if (need_plugin_list) {
362 if (stale) {
363 *need_plugin_list = true;
364 return true;
365 }
366 } else {
367 DCHECK(!stale);
368 } 342 }
369 343
370 return !found; 344 int request_id = ResourceRequestInfo::ForRequest(request_)->GetRequestID();
371 }
372 345
373 bool BufferedResourceHandler::UseAlternateResourceHandler(
374 int request_id,
375 scoped_ptr<ResourceHandler> handler,
376 bool* defer) {
377 // Inform the original ResourceHandler that this will be handled entirely by 346 // Inform the original ResourceHandler that this will be handled entirely by
378 // the new ResourceHandler. 347 // the new ResourceHandler.
379 // TODO(darin): We should probably check the return values of these. 348 // TODO(darin): We should probably check the return values of these.
380 bool defer_ignored = false; 349 bool defer_ignored = false;
381 next_handler_->OnResponseStarted(request_id, response_, &defer_ignored); 350 next_handler_->OnResponseStarted(request_id, response_, &defer_ignored);
382 DCHECK(!defer_ignored); 351 DCHECK(!defer_ignored);
383 net::URLRequestStatus status(net::URLRequestStatus::HANDLED_EXTERNALLY, 0); 352 net::URLRequestStatus status(net::URLRequestStatus::HANDLED_EXTERNALLY, 0);
384 next_handler_->OnResponseCompleted(request_id, status, std::string()); 353 next_handler_->OnResponseCompleted(request_id, status, std::string());
385 354
386 // This is handled entirely within the new ResourceHandler, so just reset the 355 // This is handled entirely within the new ResourceHandler, so just reset the
387 // original ResourceHandler. 356 // original ResourceHandler.
388 next_handler_ = handler.Pass(); 357 next_handler_ = new_handler.Pass();
389 next_handler_->SetController(controller()); 358 next_handler_->SetController(this);
390 359
391 next_handler_needs_response_started_ = true; 360 return CopyReadBufferToNextHandler(request_id);
392 next_handler_needs_will_read_ = true;
393
394 return ForwardPendingEventsToNextHandler(request_id, defer);
395 } 361 }
396 362
397 bool BufferedResourceHandler::ForwardPendingEventsToNextHandler(int request_id, 363 bool BufferedResourceHandler::ReplayReadCompleted(bool* defer) {
398 bool* defer) { 364 DCHECK(read_buffer_);
399 if (next_handler_needs_response_started_) { 365
400 if (!next_handler_->OnResponseStarted(request_id, response_, defer)) 366 int request_id = ResourceRequestInfo::ForRequest(request_)->GetRequestID();
401 return false; 367 bool result = next_handler_->OnReadCompleted(request_id, bytes_read_, defer);
402 // If the request was deferred during OnResponseStarted, we need to avoid 368
403 // calling OnResponseStarted again. 369 read_buffer_ = NULL;
404 next_handler_needs_response_started_ = false; 370 read_buffer_size_ = 0;
405 if (*defer) 371 bytes_read_ = 0;
406 return true; 372
373 state_ = STATE_STREAMING;
374
375 return result;
376 }
377
378 void BufferedResourceHandler::CallReplayReadCompleted() {
379 bool defer = false;
380 if (!ReplayReadCompleted(&defer)) {
381 controller()->Cancel();
382 } else if (!defer) {
383 state_ = STATE_STREAMING;
384 controller()->Resume();
385 }
386 }
387
388 bool BufferedResourceHandler::MustDownload() {
389 if (must_download_is_set_)
390 return must_download_;
391
392 must_download_is_set_ = true;
393
394 std::string disposition;
395 request_->GetResponseHeaderByName("content-disposition", &disposition);
396 if (!disposition.empty() &&
397 net::HttpContentDisposition(disposition, std::string()).is_attachment()) {
398 must_download_ = true;
399 } else if (host_->delegate() &&
400 host_->delegate()->ShouldForceDownloadResource(
401 request_->url(), response_->head.mime_type)) {
402 must_download_ = true;
403 } else {
404 must_download_ = false;
407 } 405 }
408 406
409 if (next_handler_needs_will_read_) { 407 return must_download_;
410 CopyReadBufferToNextHandler(request_id);
411 next_handler_needs_will_read_ = false;
412 }
413 return true;
414 } 408 }
415 409
416 void BufferedResourceHandler::CopyReadBufferToNextHandler(int request_id) { 410 bool BufferedResourceHandler::HasSupportingPlugin(bool* stale) {
411 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request_);
412
413 bool allow_wildcard = false;
414 webkit::WebPluginInfo plugin;
415 return PluginServiceImpl::GetInstance()->GetPluginInfo(
416 info->GetChildID(), info->GetRouteID(), info->GetContext(),
417 request_->url(), GURL(), response_->head.mime_type, allow_wildcard,
418 stale, &plugin, NULL);
419 }
420
421 bool BufferedResourceHandler::CopyReadBufferToNextHandler(int request_id) {
417 if (!bytes_read_) 422 if (!bytes_read_)
418 return; 423 return true;
419 424
420 net::IOBuffer* buf = NULL; 425 net::IOBuffer* buf = NULL;
421 int buf_len = 0; 426 int buf_len = 0;
422 if (next_handler_->OnWillRead(request_id, &buf, &buf_len, bytes_read_)) { 427 if (!next_handler_->OnWillRead(request_id, &buf, &buf_len, bytes_read_))
423 CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0)); 428 return false;
424 memcpy(buf->data(), read_buffer_->data(), bytes_read_); 429
425 } 430 CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0));
431 memcpy(buf->data(), read_buffer_->data(), bytes_read_);
432 return true;
426 } 433 }
427 434
428 void BufferedResourceHandler::OnPluginsLoaded( 435 void BufferedResourceHandler::OnPluginsLoaded(
429 const std::vector<webkit::WebPluginInfo>& plugins) { 436 const std::vector<webkit::WebPluginInfo>& plugins) {
430 bool needs_resume = deferred_waiting_for_plugins_;
431 deferred_waiting_for_plugins_ = false;
432
433 wait_for_plugins_ = false;
434 if (!request_)
435 return;
436
437 ResourceRequestInfoImpl* info =
438 ResourceRequestInfoImpl::ForRequest(request_);
439 int request_id = info->GetRequestID();
440
441 bool defer = false; 437 bool defer = false;
442 if (!CompleteResponseStarted(request_id, &defer)) { 438 if (!ProcessResponse(&defer)) {
443 controller()->Cancel(); 439 controller()->Cancel();
444 } else if (!defer && needs_resume) { 440 } else if (!defer) {
445 controller()->Resume(); 441 controller()->Resume();
446 } 442 }
447 } 443 }
448 444
449 } // namespace content 445 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/renderer_host/buffered_resource_handler.h ('k') | content/browser/renderer_host/cross_site_resource_handler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698