blob: a0f128baed7b7e865cdb94296eb011ccd18c136c [file] [log] [blame]
[email protected]2e7aff62010-03-16 06:34:561// Copyright (c) 2010 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
5#include "chrome/browser/renderer_host/buffered_resource_handler.h"
6
[email protected]dd9b5462009-09-25 17:22:237#include <vector>
8
[email protected]306291392009-01-17 19:15:369#include "base/histogram.h"
[email protected]5203e6002009-07-29 03:42:0010#include "base/logging.h"
[email protected]319d9e6f2009-02-18 19:47:2111#include "base/string_util.h"
[email protected]35fa6a22009-08-15 00:04:0112#include "chrome/browser/chrome_thread.h"
[email protected]e3c404b2008-12-23 01:07:3213#include "chrome/browser/renderer_host/download_throttling_resource_handler.h"
14#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
[email protected]347867b72009-09-02 00:35:5815#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
[email protected]a755e1072009-10-23 16:58:3716#include "chrome/browser/renderer_host/x509_user_cert_resource_handler.h"
[email protected]6657afa62009-11-04 02:15:2017#include "chrome/common/extensions/user_script.h"
[email protected]7c927b62010-02-24 09:54:1318#include "chrome/common/resource_response.h"
[email protected]dcf7d352009-02-26 01:56:0219#include "chrome/common/url_constants.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]35fa6a22009-08-15 00:04:0125#include "webkit/glue/plugins/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]2753b392009-12-28 06:59:5232 static scoped_refptr<Histogram> nosniff_usage = BooleanHistogram::FactoryGet(
33 "nosniff.usage", Histogram::kUmaTargetedHistogramFlag);
[email protected]e8829a192009-12-06 00:09:3734 nosniff_usage->AddBoolean(sniffing_blocked);
[email protected]306291392009-01-17 19:15:3635
36 if (sniffing_blocked) {
[email protected]e8829a192009-12-06 00:09:3737 static scoped_refptr<Histogram> nosniff_otherwise =
[email protected]2753b392009-12-28 06:59:5238 BooleanHistogram::FactoryGet("nosniff.otherwise",
39 Histogram::kUmaTargetedHistogramFlag);
[email protected]e8829a192009-12-06 00:09:3740 nosniff_otherwise->AddBoolean(we_would_like_to_sniff);
[email protected]306291392009-01-17 19:15:3641
[email protected]e8829a192009-12-06 00:09:3742 static scoped_refptr<Histogram> nosniff_empty_mime_type =
[email protected]2753b392009-12-28 06:59:5243 BooleanHistogram::FactoryGet("nosniff.empty_mime_type",
44 Histogram::kUmaTargetedHistogramFlag);
[email protected]e8829a192009-12-06 00:09:3745 nosniff_empty_mime_type->AddBoolean(mime_type.empty());
[email protected]306291392009-01-17 19:15:3646 }
47}
48
49} // namespace
50
[email protected]e3c404b2008-12-23 01:07:3251BufferedResourceHandler::BufferedResourceHandler(ResourceHandler* handler,
52 ResourceDispatcherHost* host,
53 URLRequest* request)
54 : real_handler_(handler),
55 host_(host),
56 request_(request),
[email protected]dd9b5462009-09-25 17:22:2357 read_buffer_size_(0),
[email protected]e3c404b2008-12-23 01:07:3258 bytes_read_(0),
59 sniff_content_(false),
60 should_buffer_(false),
[email protected]35fa6a22009-08-15 00:04:0161 wait_for_plugins_(false),
[email protected]e3c404b2008-12-23 01:07:3262 buffering_(false),
63 finished_(false) {
64}
65
66bool BufferedResourceHandler::OnUploadProgress(int request_id,
67 uint64 position,
68 uint64 size) {
69 return real_handler_->OnUploadProgress(request_id, position, size);
70}
71
72bool BufferedResourceHandler::OnRequestRedirected(int request_id,
[email protected]6568a9e32009-07-30 18:01:3973 const GURL& new_url,
74 ResourceResponse* response,
75 bool* defer) {
76 return real_handler_->OnRequestRedirected(
77 request_id, new_url, response, defer);
[email protected]e3c404b2008-12-23 01:07:3278}
79
80bool BufferedResourceHandler::OnResponseStarted(int request_id,
81 ResourceResponse* response) {
82 response_ = response;
83 if (!DelayResponse())
84 return CompleteResponseStarted(request_id, false);
85 return true;
86}
87
[email protected]e3c404b2008-12-23 01:07:3288bool BufferedResourceHandler::OnResponseCompleted(
[email protected]c4891b32009-03-08 07:41:3189 int request_id,
90 const URLRequestStatus& status,
91 const std::string& security_info) {
92 return real_handler_->OnResponseCompleted(request_id, status, security_info);
[email protected]e3c404b2008-12-23 01:07:3293}
94
[email protected]35fa6a22009-08-15 00:04:0195void BufferedResourceHandler::OnRequestClosed() {
96 request_ = NULL;
97 real_handler_->OnRequestClosed();
98}
99
[email protected]afd832c2010-03-02 04:53:31100bool BufferedResourceHandler::OnWillStart(int request_id,
101 const GURL& url,
102 bool* defer) {
103 return real_handler_->OnWillStart(request_id, url, defer);
104}
105
[email protected]e3c404b2008-12-23 01:07:32106// We'll let the original event handler provide a buffer, and reuse it for
107// subsequent reads until we're done buffering.
[email protected]9dea9e1f2009-01-29 00:30:47108bool BufferedResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
109 int* buf_size, int min_size) {
[email protected]e3c404b2008-12-23 01:07:32110 if (buffering_) {
[email protected]9dea9e1f2009-01-29 00:30:47111 DCHECK(!my_buffer_.get());
[email protected]2e7aff62010-03-16 06:34:56112 my_buffer_ = new net::IOBuffer(net::kMaxBytesToSniff);
[email protected]9dea9e1f2009-01-29 00:30:47113 *buf = my_buffer_.get();
[email protected]2e7aff62010-03-16 06:34:56114 *buf_size = net::kMaxBytesToSniff;
[email protected]5203e6002009-07-29 03:42:00115 // TODO(willchan): Remove after debugging bug 16371.
116 CHECK((*buf)->data());
[email protected]e3c404b2008-12-23 01:07:32117 return true;
118 }
119
120 if (finished_)
121 return false;
122
[email protected]67199052009-06-12 21:15:33123 if (!real_handler_->OnWillRead(request_id, buf, buf_size, min_size)) {
124 return false;
125 }
[email protected]e3c404b2008-12-23 01:07:32126 read_buffer_ = *buf;
[email protected]5203e6002009-07-29 03:42:00127 // TODO(willchan): Remove after debugging bug 16371.
128 CHECK(read_buffer_->data());
[email protected]e3c404b2008-12-23 01:07:32129 read_buffer_size_ = *buf_size;
[email protected]2e7aff62010-03-16 06:34:56130 DCHECK_GE(read_buffer_size_, net::kMaxBytesToSniff * 2);
[email protected]e3c404b2008-12-23 01:07:32131 bytes_read_ = 0;
[email protected]67199052009-06-12 21:15:33132 return true;
[email protected]e3c404b2008-12-23 01:07:32133}
134
135bool BufferedResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
[email protected]e3c404b2008-12-23 01:07:32136 if (sniff_content_ || should_buffer_) {
137 if (KeepBuffering(*bytes_read))
138 return true;
139
140 LOG(INFO) << "Finished buffering " << request_->url().spec();
[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
155bool BufferedResourceHandler::DelayResponse() {
156 std::string mime_type;
157 request_->GetMimeType(&mime_type);
158
159 std::string content_type_options;
160 request_->GetResponseHeaderByName("x-content-type-options",
161 &content_type_options);
[email protected]306291392009-01-17 19:15:36162
[email protected]423bd5b842009-01-23 17:30:50163 const bool sniffing_blocked =
164 LowerCaseEqualsASCII(content_type_options, "nosniff");
[email protected]e19d7132009-10-16 23:33:57165 const bool not_modified_status =
166 response_->response_head.headers &&
167 response_->response_head.headers->response_code() == 304;
168 const bool we_would_like_to_sniff = not_modified_status ?
169 false : net::ShouldSniffMimeType(request_->url(), mime_type);
[email protected]306291392009-01-17 19:15:36170
171 RecordSnifferMetrics(sniffing_blocked, we_would_like_to_sniff, mime_type);
172
173 if (!sniffing_blocked && we_would_like_to_sniff) {
[email protected]e3c404b2008-12-23 01:07:32174 // We're going to look at the data before deciding what the content type
175 // is. That means we need to delay sending the ResponseStarted message
176 // over the IPC channel.
177 sniff_content_ = true;
178 LOG(INFO) << "To buffer: " << request_->url().spec();
179 return true;
180 }
181
[email protected]e19d7132009-10-16 23:33:57182 if (sniffing_blocked && mime_type.empty() && !not_modified_status) {
[email protected]423bd5b842009-01-23 17:30:50183 // Ugg. The server told us not to sniff the content but didn't give us a
184 // mime type. What's a browser to do? Turns out, we're supposed to treat
185 // the response as "text/plain". This is the most secure option.
186 mime_type.assign("text/plain");
187 response_->response_head.mime_type.assign(mime_type);
188 }
189
[email protected]b4599a12009-09-07 23:09:58190 if (mime_type == "application/rss+xml" ||
191 mime_type == "application/atom+xml") {
192 // Sad face. The server told us that they wanted us to treat the response
193 // as RSS or Atom. Unfortunately, we don't have a built-in feed previewer
194 // like other browsers. We can't just render the content as XML because
195 // web sites let third parties inject arbitrary script into their RSS
196 // feeds. That leaves us with little choice but to practically ignore the
197 // response. In the future, when we have an RSS feed previewer, we can
198 // remove this logic.
199 mime_type.assign("text/plain");
200 response_->response_head.mime_type.assign(mime_type);
201 }
202
[email protected]e3c404b2008-12-23 01:07:32203 if (ShouldBuffer(request_->url(), mime_type)) {
204 // This is a temporary fix for the fact that webkit expects to have
205 // enough data to decode the doctype in order to select the rendering
206 // mode.
207 should_buffer_ = true;
208 LOG(INFO) << "To buffer: " << request_->url().spec();
209 return true;
210 }
[email protected]35fa6a22009-08-15 00:04:01211
[email protected]e19d7132009-10-16 23:33:57212 if (!not_modified_status && ShouldWaitForPlugins()) {
[email protected]35fa6a22009-08-15 00:04:01213 wait_for_plugins_ = true;
214 return true;
215 }
216
[email protected]e3c404b2008-12-23 01:07:32217 return false;
218}
219
220bool BufferedResourceHandler::ShouldBuffer(const GURL& url,
221 const std::string& mime_type) {
222 // We are willing to buffer for HTTP and HTTPS.
223 bool sniffable_scheme = url.is_empty() ||
[email protected]dcf7d352009-02-26 01:56:02224 url.SchemeIs(chrome::kHttpScheme) ||
225 url.SchemeIs(chrome::kHttpsScheme);
[email protected]e3c404b2008-12-23 01:07:32226 if (!sniffable_scheme)
227 return false;
228
229 // Today, the only reason to buffer the request is to fix the doctype decoding
230 // performed by webkit: if there is not enough data it will go to quirks mode.
231 // We only expect the doctype check to apply to html documents.
232 return mime_type == "text/html";
233}
234
[email protected]35fa6a22009-08-15 00:04:01235bool BufferedResourceHandler::DidBufferEnough(int bytes_read) {
236 const int kRequiredLength = 256;
237
238 return bytes_read >= kRequiredLength;
239}
240
[email protected]e3c404b2008-12-23 01:07:32241bool BufferedResourceHandler::KeepBuffering(int bytes_read) {
242 DCHECK(read_buffer_);
[email protected]9dea9e1f2009-01-29 00:30:47243 if (my_buffer_) {
244 // We are using our own buffer to read, update the main buffer.
[email protected]2e7aff62010-03-16 06:34:56245 CHECK_LT(bytes_read + bytes_read_, read_buffer_size_);
[email protected]9dea9e1f2009-01-29 00:30:47246 memcpy(read_buffer_->data() + bytes_read_, my_buffer_->data(), bytes_read);
247 my_buffer_ = NULL;
248 }
[email protected]e3c404b2008-12-23 01:07:32249 bytes_read_ += bytes_read;
250 finished_ = (bytes_read == 0);
251
252 if (sniff_content_) {
253 std::string type_hint, new_type;
254 request_->GetMimeType(&type_hint);
255
[email protected]9dea9e1f2009-01-29 00:30:47256 if (!net::SniffMimeType(read_buffer_->data(), bytes_read_,
257 request_->url(), type_hint, &new_type)) {
[email protected]e3c404b2008-12-23 01:07:32258 // SniffMimeType() returns false if there is not enough data to determine
259 // the mime type. However, even if it returns false, it returns a new type
260 // that is probably better than the current one.
[email protected]2e7aff62010-03-16 06:34:56261 DCHECK_LT(bytes_read_, net::kMaxBytesToSniff);
[email protected]e3c404b2008-12-23 01:07:32262 if (!finished_) {
263 buffering_ = true;
264 return true;
265 }
266 }
267 sniff_content_ = false;
268 response_->response_head.mime_type.assign(new_type);
269
270 // We just sniffed the mime type, maybe there is a doctype to process.
[email protected]35fa6a22009-08-15 00:04:01271 if (ShouldBuffer(request_->url(), new_type)) {
[email protected]e3c404b2008-12-23 01:07:32272 should_buffer_ = true;
[email protected]35fa6a22009-08-15 00:04:01273 } else if (ShouldWaitForPlugins()) {
274 wait_for_plugins_ = true;
275 }
[email protected]e3c404b2008-12-23 01:07:32276 }
277
[email protected]35fa6a22009-08-15 00:04:01278 if (should_buffer_) {
279 if (!finished_ && !DidBufferEnough(bytes_read_)) {
[email protected]e3c404b2008-12-23 01:07:32280 buffering_ = true;
281 return true;
282 }
[email protected]35fa6a22009-08-15 00:04:01283
284 should_buffer_ = false;
285 if (ShouldWaitForPlugins())
286 wait_for_plugins_ = true;
[email protected]e3c404b2008-12-23 01:07:32287 }
[email protected]35fa6a22009-08-15 00:04:01288
[email protected]e3c404b2008-12-23 01:07:32289 buffering_ = false;
[email protected]35fa6a22009-08-15 00:04:01290
291 if (wait_for_plugins_)
292 return true;
293
[email protected]e3c404b2008-12-23 01:07:32294 return false;
295}
296
297bool BufferedResourceHandler::CompleteResponseStarted(int request_id,
298 bool in_complete) {
299 // Check to see if we should forward the data from this request to the
300 // download thread.
301 // TODO(paulg): Only download if the context from the renderer allows it.
[email protected]347867b72009-09-02 00:35:58302 ResourceDispatcherHostRequestInfo* info =
303 ResourceDispatcherHost::InfoForRequest(request_);
[email protected]a755e1072009-10-23 16:58:37304 std::string mime_type;
305 request_->GetMimeType(&mime_type);
306
307 // Check if this is an X.509 certificate, if yes, let it be handled
308 // by X509UserCertResourceHandler.
309 if (mime_type == "application/x-x509-user-cert") {
310
311 // 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
326 scoped_refptr<X509UserCertResourceHandler> x509_cert_handler =
327 new X509UserCertResourceHandler(host_, request_);
328
329 if (bytes_read_) {
330 // A Read has already occured and we need to copy the data into the
331 // EventHandler.
332 net::IOBuffer* buf = NULL;
333 int buf_len = 0;
334 x509_cert_handler->OnWillRead(request_id, &buf, &buf_len, bytes_read_);
335 CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0));
336 memcpy(buf->data(), read_buffer_->data(), bytes_read_);
337 }
338
339 // Inform the renderer that this will be handled entirely by the browser.
340 real_handler_->OnResponseStarted(info->request_id(), response_);
341 URLRequestStatus status(URLRequestStatus::HANDLED_EXTERNALLY, 0);
342 real_handler_->OnResponseCompleted(info->request_id(), status,
343 std::string());
344
345 // This is handled entirely within the browser, so just reset the handler.
346 real_handler_ = x509_cert_handler;
347 }
[email protected]e3c404b2008-12-23 01:07:32348
[email protected]347867b72009-09-02 00:35:58349 if (info->allow_download() && ShouldDownload(NULL)) {
[email protected]e3c404b2008-12-23 01:07:32350 if (response_->response_head.headers && // Can be NULL if FTP.
351 response_->response_head.headers->response_code() / 100 != 2) {
352 // The response code indicates that this is an error page, but we don't
353 // know how to display the content. We follow Firefox here and show our
354 // own error page instead of triggering a download.
355 // TODO(abarth): We should abstract the response_code test, but this kind
356 // of check is scattered throughout our codebase.
[email protected]c4891b32009-03-08 07:41:31357 request_->SimulateError(net::ERR_FILE_NOT_FOUND);
[email protected]e3c404b2008-12-23 01:07:32358 return false;
359 }
360
[email protected]347867b72009-09-02 00:35:58361 info->set_is_download(true);
[email protected]e3c404b2008-12-23 01:07:32362
363 scoped_refptr<DownloadThrottlingResourceHandler> download_handler =
364 new DownloadThrottlingResourceHandler(host_,
[email protected]a755e1072009-10-23 16:58:37365 request_,
366 request_->url(),
367 info->child_id(),
368 info->route_id(),
369 request_id,
370 in_complete);
[email protected]e3c404b2008-12-23 01:07:32371 if (bytes_read_) {
[email protected]a755e1072009-10-23 16:58:37372 // A Read has already occurred and we need to copy the data into the
[email protected]e3c404b2008-12-23 01:07:32373 // EventHandler.
[email protected]9dea9e1f2009-01-29 00:30:47374 net::IOBuffer* buf = NULL;
[email protected]e3c404b2008-12-23 01:07:32375 int buf_len = 0;
376 download_handler->OnWillRead(request_id, &buf, &buf_len, bytes_read_);
377 CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0));
[email protected]9dea9e1f2009-01-29 00:30:47378 memcpy(buf->data(), read_buffer_->data(), bytes_read_);
[email protected]e3c404b2008-12-23 01:07:32379 }
[email protected]3c9481d2009-02-24 21:25:53380
381 // Send the renderer a response that indicates that the request will be
382 // handled by an external source (the browser's DownloadManager).
[email protected]347867b72009-09-02 00:35:58383 real_handler_->OnResponseStarted(info->request_id(), response_);
[email protected]3c9481d2009-02-24 21:25:53384 URLRequestStatus status(URLRequestStatus::HANDLED_EXTERNALLY, 0);
[email protected]347867b72009-09-02 00:35:58385 real_handler_->OnResponseCompleted(info->request_id(), status,
[email protected]c4891b32009-03-08 07:41:31386 std::string());
[email protected]3c9481d2009-02-24 21:25:53387
388 // Ditch the old async handler that talks to the renderer for the new
389 // download handler that talks to the DownloadManager.
[email protected]e3c404b2008-12-23 01:07:32390 real_handler_ = download_handler;
391 }
392 return real_handler_->OnResponseStarted(request_id, response_);
393}
394
[email protected]35fa6a22009-08-15 00:04:01395bool BufferedResourceHandler::ShouldWaitForPlugins() {
396 bool need_plugin_list;
397 if (!ShouldDownload(&need_plugin_list) || !need_plugin_list)
398 return false;
[email protected]e3c404b2008-12-23 01:07:32399
[email protected]35fa6a22009-08-15 00:04:01400 // We don't want to keep buffering as our buffer will fill up.
[email protected]347867b72009-09-02 00:35:58401 ResourceDispatcherHostRequestInfo* info =
402 ResourceDispatcherHost::InfoForRequest(request_);
403 host_->PauseRequest(info->child_id(), info->request_id(), true);
[email protected]35fa6a22009-08-15 00:04:01404
[email protected]7f2e792e2009-11-30 23:18:29405 // Schedule plugin loading on the file thread.
406 ChromeThread::PostTask(
407 ChromeThread::FILE, FROM_HERE,
408 NewRunnableMethod(this, &BufferedResourceHandler::LoadPlugins));
[email protected]35fa6a22009-08-15 00:04:01409 return true;
410}
411
412// This test mirrors the decision that WebKit makes in
413// WebFrameLoaderClient::dispatchDecidePolicyForMIMEType.
414bool BufferedResourceHandler::ShouldDownload(bool* need_plugin_list) {
415 if (need_plugin_list)
416 *need_plugin_list = false;
417 std::string type = StringToLowerASCII(response_->response_head.mime_type);
418 std::string disposition;
419 request_->GetResponseHeaderByName("content-disposition", &disposition);
420 disposition = StringToLowerASCII(disposition);
421
422 // First, examine content-disposition.
423 if (!disposition.empty()) {
424 bool should_download = true;
425
426 // Some broken sites just send ...
427 // Content-Disposition: ; filename="file"
428 // ... screen those out here.
429 if (disposition[0] == ';')
430 should_download = false;
431
432 if (disposition.compare(0, 6, "inline") == 0)
433 should_download = false;
434
435 // Some broken sites just send ...
436 // Content-Disposition: filename="file"
437 // ... without a disposition token... Screen those out.
438 if (disposition.compare(0, 8, "filename") == 0)
439 should_download = false;
440
441 // Also in use is Content-Disposition: name="file"
442 if (disposition.compare(0, 4, "name") == 0)
443 should_download = false;
444
445 // We have a content-disposition of "attachment" or unknown.
446 // RFC 2183, section 2.8 says that an unknown disposition
447 // value should be treated as "attachment".
448 if (should_download)
449 return true;
450 }
451
[email protected]6657afa62009-11-04 02:15:20452 // Special-case user scripts to get downloaded instead of viewed.
453 if (UserScript::HasUserScriptFileExtension(request_->url()))
454 return true;
455
[email protected]35fa6a22009-08-15 00:04:01456 // MIME type checking.
457 if (net::IsSupportedMimeType(type))
458 return false;
459
460 if (need_plugin_list) {
461 if (!NPAPI::PluginList::Singleton()->PluginsLoaded()) {
462 *need_plugin_list = true;
463 return true;
464 }
465 } else {
466 DCHECK(NPAPI::PluginList::Singleton()->PluginsLoaded());
467 }
468
469 // Finally, check the plugin list.
470 WebPluginInfo info;
471 bool allow_wildcard = false;
472 return !NPAPI::PluginList::Singleton()->GetPluginInfo(
[email protected]610c0892009-09-08 19:46:18473 GURL(), type, allow_wildcard, &info, NULL);
[email protected]35fa6a22009-08-15 00:04:01474}
475
[email protected]7f2e792e2009-11-30 23:18:29476void BufferedResourceHandler::LoadPlugins() {
477 std::vector<WebPluginInfo> plugins;
478 NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
479
480 ChromeThread::PostTask(
481 ChromeThread::IO, FROM_HERE,
482 NewRunnableMethod(this, &BufferedResourceHandler::OnPluginsLoaded));
483}
484
485void BufferedResourceHandler::OnPluginsLoaded() {
[email protected]5658a602009-11-03 23:12:52486 wait_for_plugins_ = false;
[email protected]7f2e792e2009-11-30 23:18:29487 if (!request_)
488 return;
[email protected]5658a602009-11-03 23:12:52489
[email protected]7f2e792e2009-11-30 23:18:29490 ResourceDispatcherHostRequestInfo* info =
491 ResourceDispatcherHost::InfoForRequest(request_);
492 host_->PauseRequest(info->child_id(), info->request_id(), false);
493 if (!CompleteResponseStarted(info->request_id(), false))
494 host_->CancelRequest(info->child_id(), info->request_id(), false);
[email protected]e3c404b2008-12-23 01:07:32495}