blob: d1c233abf80bcb2f08c13016535d63bc4d6f4ded [file] [log] [blame]
[email protected]f90bf0d92011-01-13 02:12:441// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]e3c404b2008-12-23 01:07:322// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]1d8a3d1f2011-02-19 07:11:525#include "content/browser/renderer_host/buffered_resource_handler.h"
[email protected]e3c404b2008-12-23 01:07:326
[email protected]dd9b5462009-09-25 17:22:237#include <vector>
8
[email protected]5203e6002009-07-29 03:42:009#include "base/logging.h"
[email protected]835d7c82010-10-14 04:38:3810#include "base/metrics/histogram.h"
[email protected]319d9e6f2009-02-18 19:47:2111#include "base/string_util.h"
[email protected]e3c404b2008-12-23 01:07:3212#include "chrome/browser/renderer_host/download_throttling_resource_handler.h"
[email protected]6657afa62009-11-04 02:15:2013#include "chrome/common/extensions/user_script.h"
[email protected]dcf7d352009-02-26 01:56:0214#include "chrome/common/url_constants.h"
[email protected]1625ffd2011-03-01 17:51:5015#include "content/browser/browser_thread.h"
[email protected]1d8a3d1f2011-02-19 07:11:5216#include "content/browser/renderer_host/resource_dispatcher_host.h"
17#include "content/browser/renderer_host/resource_dispatcher_host_request_info.h"
18#include "content/browser/renderer_host/x509_user_cert_resource_handler.h"
[email protected]94dc971d2011-03-05 19:08:3219#include "content/common/resource_response.h"
[email protected]dd9b5462009-09-25 17:22:2320#include "net/base/io_buffer.h"
[email protected]9dea9e1f2009-01-29 00:30:4721#include "net/base/mime_sniffer.h"
[email protected]35fa6a22009-08-15 00:04:0122#include "net/base/mime_util.h"
[email protected]dd9b5462009-09-25 17:22:2323#include "net/base/net_errors.h"
[email protected]319d9e6f2009-02-18 19:47:2124#include "net/http/http_response_headers.h"
[email protected]191eb3f72010-12-21 06:27:5025#include "webkit/plugins/npapi/plugin_list.h"
[email protected]e3c404b2008-12-23 01:07:3226
[email protected]306291392009-01-17 19:15:3627namespace {
28
29void RecordSnifferMetrics(bool sniffing_blocked,
30 bool we_would_like_to_sniff,
31 const std::string& mime_type) {
[email protected]81ce9f3b2011-04-05 04:48:5332 static base::Histogram* nosniff_usage(NULL);
33 if (!nosniff_usage)
34 nosniff_usage = base::BooleanHistogram::FactoryGet(
35 "nosniff.usage", base::Histogram::kUmaTargetedHistogramFlag);
[email protected]e8829a192009-12-06 00:09:3736 nosniff_usage->AddBoolean(sniffing_blocked);
[email protected]306291392009-01-17 19:15:3637
38 if (sniffing_blocked) {
[email protected]81ce9f3b2011-04-05 04:48:5339 static base::Histogram* nosniff_otherwise(NULL);
40 if (!nosniff_otherwise)
41 nosniff_otherwise = base::BooleanHistogram::FactoryGet(
42 "nosniff.otherwise", base::Histogram::kUmaTargetedHistogramFlag);
[email protected]e8829a192009-12-06 00:09:3743 nosniff_otherwise->AddBoolean(we_would_like_to_sniff);
[email protected]306291392009-01-17 19:15:3644
[email protected]81ce9f3b2011-04-05 04:48:5345 static base::Histogram* nosniff_empty_mime_type(NULL);
46 if (!nosniff_empty_mime_type)
47 nosniff_empty_mime_type = base::BooleanHistogram::FactoryGet(
48 "nosniff.empty_mime_type",
49 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]e8829a192009-12-06 00:09:3750 nosniff_empty_mime_type->AddBoolean(mime_type.empty());
[email protected]306291392009-01-17 19:15:3651 }
52}
53
54} // namespace
55
[email protected]e3c404b2008-12-23 01:07:3256BufferedResourceHandler::BufferedResourceHandler(ResourceHandler* handler,
57 ResourceDispatcherHost* host,
[email protected]6981d9632010-11-30 21:34:0258 net::URLRequest* request)
[email protected]e3c404b2008-12-23 01:07:3259 : real_handler_(handler),
60 host_(host),
61 request_(request),
[email protected]dd9b5462009-09-25 17:22:2362 read_buffer_size_(0),
[email protected]e3c404b2008-12-23 01:07:3263 bytes_read_(0),
64 sniff_content_(false),
65 should_buffer_(false),
[email protected]35fa6a22009-08-15 00:04:0166 wait_for_plugins_(false),
[email protected]e3c404b2008-12-23 01:07:3267 buffering_(false),
68 finished_(false) {
69}
70
71bool BufferedResourceHandler::OnUploadProgress(int request_id,
72 uint64 position,
73 uint64 size) {
74 return real_handler_->OnUploadProgress(request_id, position, size);
75}
76
77bool BufferedResourceHandler::OnRequestRedirected(int request_id,
[email protected]6568a9e32009-07-30 18:01:3978 const GURL& new_url,
79 ResourceResponse* response,
80 bool* defer) {
81 return real_handler_->OnRequestRedirected(
82 request_id, new_url, response, defer);
[email protected]e3c404b2008-12-23 01:07:3283}
84
85bool BufferedResourceHandler::OnResponseStarted(int request_id,
86 ResourceResponse* response) {
87 response_ = response;
88 if (!DelayResponse())
89 return CompleteResponseStarted(request_id, false);
90 return true;
91}
92
[email protected]e3c404b2008-12-23 01:07:3293bool BufferedResourceHandler::OnResponseCompleted(
[email protected]c4891b32009-03-08 07:41:3194 int request_id,
[email protected]f90bf0d92011-01-13 02:12:4495 const net::URLRequestStatus& status,
[email protected]c4891b32009-03-08 07:41:3196 const std::string& security_info) {
97 return real_handler_->OnResponseCompleted(request_id, status, security_info);
[email protected]e3c404b2008-12-23 01:07:3298}
99
[email protected]35fa6a22009-08-15 00:04:01100void BufferedResourceHandler::OnRequestClosed() {
101 request_ = NULL;
102 real_handler_->OnRequestClosed();
103}
104
[email protected]afd832c2010-03-02 04:53:31105bool BufferedResourceHandler::OnWillStart(int request_id,
106 const GURL& url,
107 bool* defer) {
108 return real_handler_->OnWillStart(request_id, url, defer);
109}
110
[email protected]e3c404b2008-12-23 01:07:32111// We'll let the original event handler provide a buffer, and reuse it for
112// subsequent reads until we're done buffering.
[email protected]9dea9e1f2009-01-29 00:30:47113bool BufferedResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
114 int* buf_size, int min_size) {
[email protected]e3c404b2008-12-23 01:07:32115 if (buffering_) {
[email protected]9dea9e1f2009-01-29 00:30:47116 DCHECK(!my_buffer_.get());
[email protected]2e7aff62010-03-16 06:34:56117 my_buffer_ = new net::IOBuffer(net::kMaxBytesToSniff);
[email protected]9dea9e1f2009-01-29 00:30:47118 *buf = my_buffer_.get();
[email protected]2e7aff62010-03-16 06:34:56119 *buf_size = net::kMaxBytesToSniff;
[email protected]e3c404b2008-12-23 01:07:32120 return true;
121 }
122
123 if (finished_)
124 return false;
125
[email protected]67199052009-06-12 21:15:33126 if (!real_handler_->OnWillRead(request_id, buf, buf_size, min_size)) {
127 return false;
128 }
[email protected]e3c404b2008-12-23 01:07:32129 read_buffer_ = *buf;
[email protected]e3c404b2008-12-23 01:07:32130 read_buffer_size_ = *buf_size;
[email protected]2e7aff62010-03-16 06:34:56131 DCHECK_GE(read_buffer_size_, net::kMaxBytesToSniff * 2);
[email protected]e3c404b2008-12-23 01:07:32132 bytes_read_ = 0;
[email protected]67199052009-06-12 21:15:33133 return true;
[email protected]e3c404b2008-12-23 01:07:32134}
135
136bool BufferedResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
[email protected]e3c404b2008-12-23 01:07:32137 if (sniff_content_ || should_buffer_) {
138 if (KeepBuffering(*bytes_read))
139 return true;
140
[email protected]e3c404b2008-12-23 01:07:32141 *bytes_read = bytes_read_;
142
143 // Done buffering, send the pending ResponseStarted event.
144 if (!CompleteResponseStarted(request_id, true))
145 return false;
[email protected]35fa6a22009-08-15 00:04:01146 } else if (wait_for_plugins_) {
147 return true;
[email protected]e3c404b2008-12-23 01:07:32148 }
149
[email protected]9dea9e1f2009-01-29 00:30:47150 // Release the reference that we acquired at OnWillRead.
151 read_buffer_ = NULL;
[email protected]e3c404b2008-12-23 01:07:32152 return real_handler_->OnReadCompleted(request_id, bytes_read);
153}
154
[email protected]38e08982010-10-22 17:28:43155BufferedResourceHandler::~BufferedResourceHandler() {}
156
[email protected]e3c404b2008-12-23 01:07:32157bool BufferedResourceHandler::DelayResponse() {
158 std::string mime_type;
159 request_->GetMimeType(&mime_type);
160
161 std::string content_type_options;
162 request_->GetResponseHeaderByName("x-content-type-options",
163 &content_type_options);
[email protected]306291392009-01-17 19:15:36164
[email protected]423bd5b842009-01-23 17:30:50165 const bool sniffing_blocked =
166 LowerCaseEqualsASCII(content_type_options, "nosniff");
[email protected]e19d7132009-10-16 23:33:57167 const bool not_modified_status =
168 response_->response_head.headers &&
169 response_->response_head.headers->response_code() == 304;
170 const bool we_would_like_to_sniff = not_modified_status ?
171 false : net::ShouldSniffMimeType(request_->url(), mime_type);
[email protected]306291392009-01-17 19:15:36172
173 RecordSnifferMetrics(sniffing_blocked, we_would_like_to_sniff, mime_type);
174
175 if (!sniffing_blocked && we_would_like_to_sniff) {
[email protected]e3c404b2008-12-23 01:07:32176 // We're going to look at the data before deciding what the content type
177 // is. That means we need to delay sending the ResponseStarted message
178 // over the IPC channel.
179 sniff_content_ = true;
[email protected]238667042010-10-23 01:40:00180 VLOG(1) << "To buffer: " << request_->url().spec();
[email protected]e3c404b2008-12-23 01:07:32181 return true;
182 }
183
[email protected]e19d7132009-10-16 23:33:57184 if (sniffing_blocked && mime_type.empty() && !not_modified_status) {
[email protected]423bd5b842009-01-23 17:30:50185 // Ugg. The server told us not to sniff the content but didn't give us a
186 // mime type. What's a browser to do? Turns out, we're supposed to treat
187 // the response as "text/plain". This is the most secure option.
188 mime_type.assign("text/plain");
189 response_->response_head.mime_type.assign(mime_type);
190 }
191
[email protected]b4599a12009-09-07 23:09:58192 if (mime_type == "application/rss+xml" ||
193 mime_type == "application/atom+xml") {
194 // Sad face. The server told us that they wanted us to treat the response
195 // as RSS or Atom. Unfortunately, we don't have a built-in feed previewer
196 // like other browsers. We can't just render the content as XML because
197 // web sites let third parties inject arbitrary script into their RSS
198 // feeds. That leaves us with little choice but to practically ignore the
199 // response. In the future, when we have an RSS feed previewer, we can
200 // remove this logic.
201 mime_type.assign("text/plain");
202 response_->response_head.mime_type.assign(mime_type);
203 }
204
[email protected]e3c404b2008-12-23 01:07:32205 if (ShouldBuffer(request_->url(), mime_type)) {
206 // This is a temporary fix for the fact that webkit expects to have
207 // enough data to decode the doctype in order to select the rendering
208 // mode.
209 should_buffer_ = true;
[email protected]e3c404b2008-12-23 01:07:32210 return true;
211 }
[email protected]35fa6a22009-08-15 00:04:01212
[email protected]e19d7132009-10-16 23:33:57213 if (!not_modified_status && ShouldWaitForPlugins()) {
[email protected]35fa6a22009-08-15 00:04:01214 wait_for_plugins_ = true;
215 return true;
216 }
217
[email protected]e3c404b2008-12-23 01:07:32218 return false;
219}
220
221bool BufferedResourceHandler::ShouldBuffer(const GURL& url,
222 const std::string& mime_type) {
223 // We are willing to buffer for HTTP and HTTPS.
224 bool sniffable_scheme = url.is_empty() ||
[email protected]dcf7d352009-02-26 01:56:02225 url.SchemeIs(chrome::kHttpScheme) ||
226 url.SchemeIs(chrome::kHttpsScheme);
[email protected]e3c404b2008-12-23 01:07:32227 if (!sniffable_scheme)
228 return false;
229
230 // Today, the only reason to buffer the request is to fix the doctype decoding
231 // performed by webkit: if there is not enough data it will go to quirks mode.
232 // We only expect the doctype check to apply to html documents.
233 return mime_type == "text/html";
234}
235
[email protected]35fa6a22009-08-15 00:04:01236bool BufferedResourceHandler::DidBufferEnough(int bytes_read) {
237 const int kRequiredLength = 256;
238
239 return bytes_read >= kRequiredLength;
240}
241
[email protected]e3c404b2008-12-23 01:07:32242bool BufferedResourceHandler::KeepBuffering(int bytes_read) {
243 DCHECK(read_buffer_);
[email protected]9dea9e1f2009-01-29 00:30:47244 if (my_buffer_) {
245 // We are using our own buffer to read, update the main buffer.
[email protected]c0dac3272010-07-28 08:04:45246 // TODO(darin): We should handle the case where read_buffer_size_ is small!
247 // See RedirectToFileResourceHandler::BufIsFull to see how this impairs
248 // downstream ResourceHandler implementations.
[email protected]2e7aff62010-03-16 06:34:56249 CHECK_LT(bytes_read + bytes_read_, read_buffer_size_);
[email protected]9dea9e1f2009-01-29 00:30:47250 memcpy(read_buffer_->data() + bytes_read_, my_buffer_->data(), bytes_read);
251 my_buffer_ = NULL;
252 }
[email protected]e3c404b2008-12-23 01:07:32253 bytes_read_ += bytes_read;
254 finished_ = (bytes_read == 0);
255
256 if (sniff_content_) {
257 std::string type_hint, new_type;
258 request_->GetMimeType(&type_hint);
259
[email protected]9dea9e1f2009-01-29 00:30:47260 if (!net::SniffMimeType(read_buffer_->data(), bytes_read_,
261 request_->url(), type_hint, &new_type)) {
[email protected]e3c404b2008-12-23 01:07:32262 // SniffMimeType() returns false if there is not enough data to determine
263 // the mime type. However, even if it returns false, it returns a new type
264 // that is probably better than the current one.
[email protected]2e7aff62010-03-16 06:34:56265 DCHECK_LT(bytes_read_, net::kMaxBytesToSniff);
[email protected]e3c404b2008-12-23 01:07:32266 if (!finished_) {
267 buffering_ = true;
268 return true;
269 }
270 }
271 sniff_content_ = false;
272 response_->response_head.mime_type.assign(new_type);
273
274 // We just sniffed the mime type, maybe there is a doctype to process.
[email protected]35fa6a22009-08-15 00:04:01275 if (ShouldBuffer(request_->url(), new_type)) {
[email protected]e3c404b2008-12-23 01:07:32276 should_buffer_ = true;
[email protected]35fa6a22009-08-15 00:04:01277 } else if (ShouldWaitForPlugins()) {
278 wait_for_plugins_ = true;
279 }
[email protected]e3c404b2008-12-23 01:07:32280 }
281
[email protected]35fa6a22009-08-15 00:04:01282 if (should_buffer_) {
283 if (!finished_ && !DidBufferEnough(bytes_read_)) {
[email protected]e3c404b2008-12-23 01:07:32284 buffering_ = true;
285 return true;
286 }
[email protected]35fa6a22009-08-15 00:04:01287
288 should_buffer_ = false;
289 if (ShouldWaitForPlugins())
290 wait_for_plugins_ = true;
[email protected]e3c404b2008-12-23 01:07:32291 }
[email protected]35fa6a22009-08-15 00:04:01292
[email protected]e3c404b2008-12-23 01:07:32293 buffering_ = false;
[email protected]35fa6a22009-08-15 00:04:01294
295 if (wait_for_plugins_)
296 return true;
297
[email protected]e3c404b2008-12-23 01:07:32298 return false;
299}
300
301bool BufferedResourceHandler::CompleteResponseStarted(int request_id,
302 bool in_complete) {
[email protected]347867b72009-09-02 00:35:58303 ResourceDispatcherHostRequestInfo* info =
304 ResourceDispatcherHost::InfoForRequest(request_);
[email protected]a755e1072009-10-23 16:58:37305 std::string mime_type;
306 request_->GetMimeType(&mime_type);
307
308 // Check if this is an X.509 certificate, if yes, let it be handled
309 // by X509UserCertResourceHandler.
310 if (mime_type == "application/x-x509-user-cert") {
[email protected]a755e1072009-10-23 16:58:37311 // This is entirely similar to how DownloadThrottlingResourceHandler
312 // works except we are doing it for an X.509 client certificates.
313
314 if (response_->response_head.headers && // Can be NULL if FTP.
315 response_->response_head.headers->response_code() / 100 != 2) {
316 // The response code indicates that this is an error page, but we are
317 // expecting an X.509 user certificate. We follow Firefox here and show
318 // our own error page instead of handling the error page as a
319 // certificate.
320 // TODO(abarth): We should abstract the response_code test, but this kind
321 // of check is scattered throughout our codebase.
322 request_->SimulateError(net::ERR_FILE_NOT_FOUND);
323 return false;
324 }
325
[email protected]0dc72bbe2010-04-08 15:29:17326 X509UserCertResourceHandler* x509_cert_handler =
[email protected]4a729ae72010-08-02 21:26:11327 new X509UserCertResourceHandler(host_, request_,
328 info->child_id(), info->route_id());
[email protected]0dc72bbe2010-04-08 15:29:17329 UseAlternateResourceHandler(request_id, x509_cert_handler);
[email protected]a755e1072009-10-23 16:58:37330 }
[email protected]e3c404b2008-12-23 01:07:32331
[email protected]0dc72bbe2010-04-08 15:29:17332 // Check to see if we should forward the data from this request to the
333 // download thread.
334 // TODO(paulg): Only download if the context from the renderer allows it.
[email protected]347867b72009-09-02 00:35:58335 if (info->allow_download() && ShouldDownload(NULL)) {
[email protected]e3c404b2008-12-23 01:07:32336 if (response_->response_head.headers && // Can be NULL if FTP.
337 response_->response_head.headers->response_code() / 100 != 2) {
338 // The response code indicates that this is an error page, but we don't
339 // know how to display the content. We follow Firefox here and show our
340 // own error page instead of triggering a download.
341 // TODO(abarth): We should abstract the response_code test, but this kind
342 // of check is scattered throughout our codebase.
[email protected]c4891b32009-03-08 07:41:31343 request_->SimulateError(net::ERR_FILE_NOT_FOUND);
[email protected]e3c404b2008-12-23 01:07:32344 return false;
345 }
346
[email protected]347867b72009-09-02 00:35:58347 info->set_is_download(true);
[email protected]e3c404b2008-12-23 01:07:32348
[email protected]0dc72bbe2010-04-08 15:29:17349 DownloadThrottlingResourceHandler* download_handler =
[email protected]e3c404b2008-12-23 01:07:32350 new DownloadThrottlingResourceHandler(host_,
[email protected]a755e1072009-10-23 16:58:37351 request_,
352 request_->url(),
353 info->child_id(),
354 info->route_id(),
355 request_id,
356 in_complete);
[email protected]0dc72bbe2010-04-08 15:29:17357 UseAlternateResourceHandler(request_id, download_handler);
[email protected]e3c404b2008-12-23 01:07:32358 }
359 return real_handler_->OnResponseStarted(request_id, response_);
360}
361
[email protected]35fa6a22009-08-15 00:04:01362bool BufferedResourceHandler::ShouldWaitForPlugins() {
363 bool need_plugin_list;
364 if (!ShouldDownload(&need_plugin_list) || !need_plugin_list)
365 return false;
[email protected]e3c404b2008-12-23 01:07:32366
[email protected]35fa6a22009-08-15 00:04:01367 // We don't want to keep buffering as our buffer will fill up.
[email protected]347867b72009-09-02 00:35:58368 ResourceDispatcherHostRequestInfo* info =
369 ResourceDispatcherHost::InfoForRequest(request_);
370 host_->PauseRequest(info->child_id(), info->request_id(), true);
[email protected]35fa6a22009-08-15 00:04:01371
[email protected]7f2e792e2009-11-30 23:18:29372 // Schedule plugin loading on the file thread.
[email protected]9a7e1502010-10-08 04:03:50373 BrowserThread::PostTask(
374 BrowserThread::FILE, FROM_HERE,
[email protected]7f2e792e2009-11-30 23:18:29375 NewRunnableMethod(this, &BufferedResourceHandler::LoadPlugins));
[email protected]35fa6a22009-08-15 00:04:01376 return true;
377}
378
379// This test mirrors the decision that WebKit makes in
380// WebFrameLoaderClient::dispatchDecidePolicyForMIMEType.
381bool BufferedResourceHandler::ShouldDownload(bool* need_plugin_list) {
382 if (need_plugin_list)
383 *need_plugin_list = false;
384 std::string type = StringToLowerASCII(response_->response_head.mime_type);
385 std::string disposition;
386 request_->GetResponseHeaderByName("content-disposition", &disposition);
387 disposition = StringToLowerASCII(disposition);
388
389 // First, examine content-disposition.
390 if (!disposition.empty()) {
391 bool should_download = true;
392
393 // Some broken sites just send ...
394 // Content-Disposition: ; filename="file"
395 // ... screen those out here.
396 if (disposition[0] == ';')
397 should_download = false;
398
399 if (disposition.compare(0, 6, "inline") == 0)
400 should_download = false;
401
402 // Some broken sites just send ...
403 // Content-Disposition: filename="file"
404 // ... without a disposition token... Screen those out.
405 if (disposition.compare(0, 8, "filename") == 0)
406 should_download = false;
407
408 // Also in use is Content-Disposition: name="file"
409 if (disposition.compare(0, 4, "name") == 0)
410 should_download = false;
411
412 // We have a content-disposition of "attachment" or unknown.
413 // RFC 2183, section 2.8 says that an unknown disposition
414 // value should be treated as "attachment".
415 if (should_download)
416 return true;
417 }
418
[email protected]6657afa62009-11-04 02:15:20419 // Special-case user scripts to get downloaded instead of viewed.
[email protected]bac4f4b2011-03-05 02:01:40420 if (UserScript::IsURLUserScript(request_->url(), type))
[email protected]6657afa62009-11-04 02:15:20421 return true;
422
[email protected]35fa6a22009-08-15 00:04:01423 // MIME type checking.
424 if (net::IsSupportedMimeType(type))
425 return false;
426
427 if (need_plugin_list) {
[email protected]191eb3f72010-12-21 06:27:50428 if (!webkit::npapi::PluginList::Singleton()->PluginsLoaded()) {
[email protected]35fa6a22009-08-15 00:04:01429 *need_plugin_list = true;
430 return true;
431 }
432 } else {
[email protected]191eb3f72010-12-21 06:27:50433 DCHECK(webkit::npapi::PluginList::Singleton()->PluginsLoaded());
[email protected]35fa6a22009-08-15 00:04:01434 }
435
436 // Finally, check the plugin list.
[email protected]191eb3f72010-12-21 06:27:50437 webkit::npapi::WebPluginInfo info;
[email protected]35fa6a22009-08-15 00:04:01438 bool allow_wildcard = false;
[email protected]191eb3f72010-12-21 06:27:50439 return !webkit::npapi::PluginList::Singleton()->GetPluginInfo(
[email protected]b83ff222011-01-24 17:37:12440 GURL(), type, allow_wildcard, &info, NULL) ||
441 !webkit::npapi::IsPluginEnabled(info);
[email protected]35fa6a22009-08-15 00:04:01442}
443
[email protected]0dc72bbe2010-04-08 15:29:17444void BufferedResourceHandler::UseAlternateResourceHandler(
445 int request_id,
446 ResourceHandler* handler) {
447 ResourceDispatcherHostRequestInfo* info =
448 ResourceDispatcherHost::InfoForRequest(request_);
449 if (bytes_read_) {
450 // A Read has already occured and we need to copy the data into the new
451 // ResourceHandler.
452 net::IOBuffer* buf = NULL;
453 int buf_len = 0;
454 handler->OnWillRead(request_id, &buf, &buf_len, bytes_read_);
455 CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0));
456 memcpy(buf->data(), read_buffer_->data(), bytes_read_);
457 }
458
459 // Inform the original ResourceHandler that this will be handled entirely by
460 // the new ResourceHandler.
461 real_handler_->OnResponseStarted(info->request_id(), response_);
[email protected]f90bf0d92011-01-13 02:12:44462 net::URLRequestStatus status(net::URLRequestStatus::HANDLED_EXTERNALLY, 0);
[email protected]0dc72bbe2010-04-08 15:29:17463 real_handler_->OnResponseCompleted(info->request_id(), status, std::string());
464
[email protected]11149bd2010-06-10 16:31:04465 // Remove the non-owning pointer to the CrossSiteResourceHandler, if any,
466 // from the extra request info because the CrossSiteResourceHandler (part of
467 // the original ResourceHandler chain) will be deleted by the next statement.
468 info->set_cross_site_handler(NULL);
469
[email protected]0dc72bbe2010-04-08 15:29:17470 // This is handled entirely within the new ResourceHandler, so just reset the
471 // original ResourceHandler.
472 real_handler_ = handler;
473}
474
[email protected]7f2e792e2009-11-30 23:18:29475void BufferedResourceHandler::LoadPlugins() {
[email protected]191eb3f72010-12-21 06:27:50476 std::vector<webkit::npapi::WebPluginInfo> plugins;
477 webkit::npapi::PluginList::Singleton()->GetPlugins(false, &plugins);
[email protected]7f2e792e2009-11-30 23:18:29478
[email protected]9a7e1502010-10-08 04:03:50479 BrowserThread::PostTask(
480 BrowserThread::IO, FROM_HERE,
[email protected]7f2e792e2009-11-30 23:18:29481 NewRunnableMethod(this, &BufferedResourceHandler::OnPluginsLoaded));
482}
483
484void BufferedResourceHandler::OnPluginsLoaded() {
[email protected]5658a602009-11-03 23:12:52485 wait_for_plugins_ = false;
[email protected]7f2e792e2009-11-30 23:18:29486 if (!request_)
487 return;
[email protected]5658a602009-11-03 23:12:52488
[email protected]7f2e792e2009-11-30 23:18:29489 ResourceDispatcherHostRequestInfo* info =
490 ResourceDispatcherHost::InfoForRequest(request_);
491 host_->PauseRequest(info->child_id(), info->request_id(), false);
492 if (!CompleteResponseStarted(info->request_id(), false))
493 host_->CancelRequest(info->child_id(), info->request_id(), false);
[email protected]e3c404b2008-12-23 01:07:32494}