blob: 68514ad2fad029313307542ef59b9b589623fe93 [file] [log] [blame]
[email protected]347867b72009-09-02 00:35:581// Copyright (c) 2009 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]f7a015e2009-08-15 02:50:1912#include "chrome/browser/browser_process.h"
[email protected]35fa6a22009-08-15 00:04:0113#include "chrome/browser/chrome_thread.h"
[email protected]e3c404b2008-12-23 01:07:3214#include "chrome/browser/renderer_host/download_throttling_resource_handler.h"
15#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
[email protected]347867b72009-09-02 00:35:5816#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
[email protected]a755e1072009-10-23 16:58:3717#include "chrome/browser/renderer_host/x509_user_cert_resource_handler.h"
[email protected]dcf7d352009-02-26 01:56:0218#include "chrome/common/url_constants.h"
[email protected]dd9b5462009-09-25 17:22:2319#include "net/base/io_buffer.h"
[email protected]9dea9e1f2009-01-29 00:30:4720#include "net/base/mime_sniffer.h"
[email protected]35fa6a22009-08-15 00:04:0121#include "net/base/mime_util.h"
[email protected]dd9b5462009-09-25 17:22:2322#include "net/base/net_errors.h"
[email protected]319d9e6f2009-02-18 19:47:2123#include "net/http/http_response_headers.h"
[email protected]35fa6a22009-08-15 00:04:0124#include "webkit/glue/plugins/plugin_list.h"
[email protected]e3c404b2008-12-23 01:07:3225
[email protected]306291392009-01-17 19:15:3626namespace {
27
[email protected]9dea9e1f2009-01-29 00:30:4728const int kMaxBytesToSniff = 512;
29
[email protected]306291392009-01-17 19:15:3630void RecordSnifferMetrics(bool sniffing_blocked,
31 bool we_would_like_to_sniff,
32 const std::string& mime_type) {
[email protected]553dba62009-02-24 19:08:2333 static BooleanHistogram nosniff_usage("nosniff.usage");
[email protected]306291392009-01-17 19:15:3634 nosniff_usage.SetFlags(kUmaTargetedHistogramFlag);
35 nosniff_usage.AddBoolean(sniffing_blocked);
36
37 if (sniffing_blocked) {
[email protected]553dba62009-02-24 19:08:2338 static BooleanHistogram nosniff_otherwise("nosniff.otherwise");
[email protected]306291392009-01-17 19:15:3639 nosniff_otherwise.SetFlags(kUmaTargetedHistogramFlag);
40 nosniff_otherwise.AddBoolean(we_would_like_to_sniff);
41
[email protected]553dba62009-02-24 19:08:2342 static BooleanHistogram nosniff_empty_mime_type("nosniff.empty_mime_type");
[email protected]306291392009-01-17 19:15:3643 nosniff_empty_mime_type.SetFlags(kUmaTargetedHistogramFlag);
44 nosniff_empty_mime_type.AddBoolean(mime_type.empty());
45 }
46}
47
48} // namespace
49
[email protected]e3c404b2008-12-23 01:07:3250BufferedResourceHandler::BufferedResourceHandler(ResourceHandler* handler,
51 ResourceDispatcherHost* host,
52 URLRequest* request)
53 : real_handler_(handler),
54 host_(host),
55 request_(request),
[email protected]dd9b5462009-09-25 17:22:2356 read_buffer_size_(0),
[email protected]e3c404b2008-12-23 01:07:3257 bytes_read_(0),
58 sniff_content_(false),
59 should_buffer_(false),
[email protected]35fa6a22009-08-15 00:04:0160 wait_for_plugins_(false),
[email protected]e3c404b2008-12-23 01:07:3261 buffering_(false),
62 finished_(false) {
63}
64
65bool BufferedResourceHandler::OnUploadProgress(int request_id,
66 uint64 position,
67 uint64 size) {
68 return real_handler_->OnUploadProgress(request_id, position, size);
69}
70
71bool BufferedResourceHandler::OnRequestRedirected(int request_id,
[email protected]6568a9e32009-07-30 18:01:3972 const GURL& new_url,
73 ResourceResponse* response,
74 bool* defer) {
75 return real_handler_->OnRequestRedirected(
76 request_id, new_url, response, defer);
[email protected]e3c404b2008-12-23 01:07:3277}
78
79bool BufferedResourceHandler::OnResponseStarted(int request_id,
80 ResourceResponse* response) {
81 response_ = response;
82 if (!DelayResponse())
83 return CompleteResponseStarted(request_id, false);
84 return true;
85}
86
[email protected]e3c404b2008-12-23 01:07:3287bool BufferedResourceHandler::OnResponseCompleted(
[email protected]c4891b32009-03-08 07:41:3188 int request_id,
89 const URLRequestStatus& status,
90 const std::string& security_info) {
91 return real_handler_->OnResponseCompleted(request_id, status, security_info);
[email protected]e3c404b2008-12-23 01:07:3292}
93
[email protected]35fa6a22009-08-15 00:04:0194void BufferedResourceHandler::OnRequestClosed() {
95 request_ = NULL;
96 real_handler_->OnRequestClosed();
97}
98
[email protected]e3c404b2008-12-23 01:07:3299// We'll let the original event handler provide a buffer, and reuse it for
100// subsequent reads until we're done buffering.
[email protected]9dea9e1f2009-01-29 00:30:47101bool BufferedResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
102 int* buf_size, int min_size) {
[email protected]e3c404b2008-12-23 01:07:32103 if (buffering_) {
[email protected]9dea9e1f2009-01-29 00:30:47104 DCHECK(!my_buffer_.get());
105 my_buffer_ = new net::IOBuffer(kMaxBytesToSniff);
106 *buf = my_buffer_.get();
107 *buf_size = kMaxBytesToSniff;
[email protected]5203e6002009-07-29 03:42:00108 // TODO(willchan): Remove after debugging bug 16371.
109 CHECK((*buf)->data());
[email protected]e3c404b2008-12-23 01:07:32110 return true;
111 }
112
113 if (finished_)
114 return false;
115
[email protected]67199052009-06-12 21:15:33116 if (!real_handler_->OnWillRead(request_id, buf, buf_size, min_size)) {
117 return false;
118 }
[email protected]e3c404b2008-12-23 01:07:32119 read_buffer_ = *buf;
[email protected]5203e6002009-07-29 03:42:00120 // TODO(willchan): Remove after debugging bug 16371.
121 CHECK(read_buffer_->data());
[email protected]e3c404b2008-12-23 01:07:32122 read_buffer_size_ = *buf_size;
[email protected]f0a51fb52009-03-05 12:46:38123 DCHECK(read_buffer_size_ >= kMaxBytesToSniff * 2);
[email protected]e3c404b2008-12-23 01:07:32124 bytes_read_ = 0;
[email protected]67199052009-06-12 21:15:33125 return true;
[email protected]e3c404b2008-12-23 01:07:32126}
127
128bool BufferedResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
[email protected]e3c404b2008-12-23 01:07:32129 if (sniff_content_ || should_buffer_) {
130 if (KeepBuffering(*bytes_read))
131 return true;
132
133 LOG(INFO) << "Finished buffering " << request_->url().spec();
[email protected]e3c404b2008-12-23 01:07:32134 *bytes_read = bytes_read_;
135
136 // Done buffering, send the pending ResponseStarted event.
137 if (!CompleteResponseStarted(request_id, true))
138 return false;
[email protected]35fa6a22009-08-15 00:04:01139 } else if (wait_for_plugins_) {
140 return true;
[email protected]e3c404b2008-12-23 01:07:32141 }
142
[email protected]9dea9e1f2009-01-29 00:30:47143 // Release the reference that we acquired at OnWillRead.
144 read_buffer_ = NULL;
[email protected]e3c404b2008-12-23 01:07:32145 return real_handler_->OnReadCompleted(request_id, bytes_read);
146}
147
148bool BufferedResourceHandler::DelayResponse() {
149 std::string mime_type;
150 request_->GetMimeType(&mime_type);
151
152 std::string content_type_options;
153 request_->GetResponseHeaderByName("x-content-type-options",
154 &content_type_options);
[email protected]306291392009-01-17 19:15:36155
[email protected]423bd5b842009-01-23 17:30:50156 const bool sniffing_blocked =
157 LowerCaseEqualsASCII(content_type_options, "nosniff");
[email protected]e19d7132009-10-16 23:33:57158 const bool not_modified_status =
159 response_->response_head.headers &&
160 response_->response_head.headers->response_code() == 304;
161 const bool we_would_like_to_sniff = not_modified_status ?
162 false : net::ShouldSniffMimeType(request_->url(), mime_type);
[email protected]306291392009-01-17 19:15:36163
164 RecordSnifferMetrics(sniffing_blocked, we_would_like_to_sniff, mime_type);
165
166 if (!sniffing_blocked && we_would_like_to_sniff) {
[email protected]e3c404b2008-12-23 01:07:32167 // We're going to look at the data before deciding what the content type
168 // is. That means we need to delay sending the ResponseStarted message
169 // over the IPC channel.
170 sniff_content_ = true;
171 LOG(INFO) << "To buffer: " << request_->url().spec();
172 return true;
173 }
174
[email protected]e19d7132009-10-16 23:33:57175 if (sniffing_blocked && mime_type.empty() && !not_modified_status) {
[email protected]423bd5b842009-01-23 17:30:50176 // Ugg. The server told us not to sniff the content but didn't give us a
177 // mime type. What's a browser to do? Turns out, we're supposed to treat
178 // the response as "text/plain". This is the most secure option.
179 mime_type.assign("text/plain");
180 response_->response_head.mime_type.assign(mime_type);
181 }
182
[email protected]b4599a12009-09-07 23:09:58183 if (mime_type == "application/rss+xml" ||
184 mime_type == "application/atom+xml") {
185 // Sad face. The server told us that they wanted us to treat the response
186 // as RSS or Atom. Unfortunately, we don't have a built-in feed previewer
187 // like other browsers. We can't just render the content as XML because
188 // web sites let third parties inject arbitrary script into their RSS
189 // feeds. That leaves us with little choice but to practically ignore the
190 // response. In the future, when we have an RSS feed previewer, we can
191 // remove this logic.
192 mime_type.assign("text/plain");
193 response_->response_head.mime_type.assign(mime_type);
194 }
195
[email protected]e3c404b2008-12-23 01:07:32196 if (ShouldBuffer(request_->url(), mime_type)) {
197 // This is a temporary fix for the fact that webkit expects to have
198 // enough data to decode the doctype in order to select the rendering
199 // mode.
200 should_buffer_ = true;
201 LOG(INFO) << "To buffer: " << request_->url().spec();
202 return true;
203 }
[email protected]35fa6a22009-08-15 00:04:01204
[email protected]e19d7132009-10-16 23:33:57205 if (!not_modified_status && ShouldWaitForPlugins()) {
[email protected]35fa6a22009-08-15 00:04:01206 wait_for_plugins_ = true;
207 return true;
208 }
209
[email protected]e3c404b2008-12-23 01:07:32210 return false;
211}
212
213bool BufferedResourceHandler::ShouldBuffer(const GURL& url,
214 const std::string& mime_type) {
215 // We are willing to buffer for HTTP and HTTPS.
216 bool sniffable_scheme = url.is_empty() ||
[email protected]dcf7d352009-02-26 01:56:02217 url.SchemeIs(chrome::kHttpScheme) ||
218 url.SchemeIs(chrome::kHttpsScheme);
[email protected]e3c404b2008-12-23 01:07:32219 if (!sniffable_scheme)
220 return false;
221
222 // Today, the only reason to buffer the request is to fix the doctype decoding
223 // performed by webkit: if there is not enough data it will go to quirks mode.
224 // We only expect the doctype check to apply to html documents.
225 return mime_type == "text/html";
226}
227
[email protected]35fa6a22009-08-15 00:04:01228bool BufferedResourceHandler::DidBufferEnough(int bytes_read) {
229 const int kRequiredLength = 256;
230
231 return bytes_read >= kRequiredLength;
232}
233
[email protected]e3c404b2008-12-23 01:07:32234bool BufferedResourceHandler::KeepBuffering(int bytes_read) {
235 DCHECK(read_buffer_);
[email protected]9dea9e1f2009-01-29 00:30:47236 if (my_buffer_) {
237 // We are using our own buffer to read, update the main buffer.
238 CHECK(bytes_read + bytes_read_ < read_buffer_size_);
239 memcpy(read_buffer_->data() + bytes_read_, my_buffer_->data(), bytes_read);
240 my_buffer_ = NULL;
241 }
[email protected]e3c404b2008-12-23 01:07:32242 bytes_read_ += bytes_read;
243 finished_ = (bytes_read == 0);
244
245 if (sniff_content_) {
246 std::string type_hint, new_type;
247 request_->GetMimeType(&type_hint);
248
[email protected]9dea9e1f2009-01-29 00:30:47249 if (!net::SniffMimeType(read_buffer_->data(), bytes_read_,
250 request_->url(), type_hint, &new_type)) {
[email protected]e3c404b2008-12-23 01:07:32251 // SniffMimeType() returns false if there is not enough data to determine
252 // the mime type. However, even if it returns false, it returns a new type
253 // that is probably better than the current one.
[email protected]9dea9e1f2009-01-29 00:30:47254 DCHECK(bytes_read_ < kMaxBytesToSniff);
[email protected]e3c404b2008-12-23 01:07:32255 if (!finished_) {
256 buffering_ = true;
257 return true;
258 }
259 }
260 sniff_content_ = false;
261 response_->response_head.mime_type.assign(new_type);
262
263 // We just sniffed the mime type, maybe there is a doctype to process.
[email protected]35fa6a22009-08-15 00:04:01264 if (ShouldBuffer(request_->url(), new_type)) {
[email protected]e3c404b2008-12-23 01:07:32265 should_buffer_ = true;
[email protected]35fa6a22009-08-15 00:04:01266 } else if (ShouldWaitForPlugins()) {
267 wait_for_plugins_ = true;
268 }
[email protected]e3c404b2008-12-23 01:07:32269 }
270
[email protected]35fa6a22009-08-15 00:04:01271 if (should_buffer_) {
272 if (!finished_ && !DidBufferEnough(bytes_read_)) {
[email protected]e3c404b2008-12-23 01:07:32273 buffering_ = true;
274 return true;
275 }
[email protected]35fa6a22009-08-15 00:04:01276
277 should_buffer_ = false;
278 if (ShouldWaitForPlugins())
279 wait_for_plugins_ = true;
[email protected]e3c404b2008-12-23 01:07:32280 }
[email protected]35fa6a22009-08-15 00:04:01281
[email protected]e3c404b2008-12-23 01:07:32282 buffering_ = false;
[email protected]35fa6a22009-08-15 00:04:01283
284 if (wait_for_plugins_)
285 return true;
286
[email protected]e3c404b2008-12-23 01:07:32287 return false;
288}
289
290bool BufferedResourceHandler::CompleteResponseStarted(int request_id,
291 bool in_complete) {
292 // Check to see if we should forward the data from this request to the
293 // download thread.
294 // TODO(paulg): Only download if the context from the renderer allows it.
[email protected]347867b72009-09-02 00:35:58295 ResourceDispatcherHostRequestInfo* info =
296 ResourceDispatcherHost::InfoForRequest(request_);
[email protected]a755e1072009-10-23 16:58:37297 std::string mime_type;
298 request_->GetMimeType(&mime_type);
299
300 // Check if this is an X.509 certificate, if yes, let it be handled
301 // by X509UserCertResourceHandler.
302 if (mime_type == "application/x-x509-user-cert") {
303
304 // This is entirely similar to how DownloadThrottlingResourceHandler
305 // works except we are doing it for an X.509 client certificates.
306
307 if (response_->response_head.headers && // Can be NULL if FTP.
308 response_->response_head.headers->response_code() / 100 != 2) {
309 // The response code indicates that this is an error page, but we are
310 // expecting an X.509 user certificate. We follow Firefox here and show
311 // our own error page instead of handling the error page as a
312 // certificate.
313 // TODO(abarth): We should abstract the response_code test, but this kind
314 // of check is scattered throughout our codebase.
315 request_->SimulateError(net::ERR_FILE_NOT_FOUND);
316 return false;
317 }
318
319 scoped_refptr<X509UserCertResourceHandler> x509_cert_handler =
320 new X509UserCertResourceHandler(host_, request_);
321
322 if (bytes_read_) {
323 // A Read has already occured and we need to copy the data into the
324 // EventHandler.
325 net::IOBuffer* buf = NULL;
326 int buf_len = 0;
327 x509_cert_handler->OnWillRead(request_id, &buf, &buf_len, bytes_read_);
328 CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0));
329 memcpy(buf->data(), read_buffer_->data(), bytes_read_);
330 }
331
332 // Inform the renderer that this will be handled entirely by the browser.
333 real_handler_->OnResponseStarted(info->request_id(), response_);
334 URLRequestStatus status(URLRequestStatus::HANDLED_EXTERNALLY, 0);
335 real_handler_->OnResponseCompleted(info->request_id(), status,
336 std::string());
337
338 // This is handled entirely within the browser, so just reset the handler.
339 real_handler_ = x509_cert_handler;
340 }
[email protected]e3c404b2008-12-23 01:07:32341
[email protected]347867b72009-09-02 00:35:58342 if (info->allow_download() && ShouldDownload(NULL)) {
[email protected]e3c404b2008-12-23 01:07:32343 if (response_->response_head.headers && // Can be NULL if FTP.
344 response_->response_head.headers->response_code() / 100 != 2) {
345 // The response code indicates that this is an error page, but we don't
346 // know how to display the content. We follow Firefox here and show our
347 // own error page instead of triggering a download.
348 // TODO(abarth): We should abstract the response_code test, but this kind
349 // of check is scattered throughout our codebase.
[email protected]c4891b32009-03-08 07:41:31350 request_->SimulateError(net::ERR_FILE_NOT_FOUND);
[email protected]e3c404b2008-12-23 01:07:32351 return false;
352 }
353
[email protected]347867b72009-09-02 00:35:58354 info->set_is_download(true);
[email protected]e3c404b2008-12-23 01:07:32355
356 scoped_refptr<DownloadThrottlingResourceHandler> download_handler =
357 new DownloadThrottlingResourceHandler(host_,
[email protected]a755e1072009-10-23 16:58:37358 request_,
359 request_->url(),
360 info->child_id(),
361 info->route_id(),
362 request_id,
363 in_complete);
[email protected]e3c404b2008-12-23 01:07:32364 if (bytes_read_) {
[email protected]a755e1072009-10-23 16:58:37365 // A Read has already occurred and we need to copy the data into the
[email protected]e3c404b2008-12-23 01:07:32366 // EventHandler.
[email protected]9dea9e1f2009-01-29 00:30:47367 net::IOBuffer* buf = NULL;
[email protected]e3c404b2008-12-23 01:07:32368 int buf_len = 0;
369 download_handler->OnWillRead(request_id, &buf, &buf_len, bytes_read_);
370 CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0));
[email protected]9dea9e1f2009-01-29 00:30:47371 memcpy(buf->data(), read_buffer_->data(), bytes_read_);
[email protected]e3c404b2008-12-23 01:07:32372 }
[email protected]3c9481d2009-02-24 21:25:53373
374 // Send the renderer a response that indicates that the request will be
375 // handled by an external source (the browser's DownloadManager).
[email protected]347867b72009-09-02 00:35:58376 real_handler_->OnResponseStarted(info->request_id(), response_);
[email protected]3c9481d2009-02-24 21:25:53377 URLRequestStatus status(URLRequestStatus::HANDLED_EXTERNALLY, 0);
[email protected]347867b72009-09-02 00:35:58378 real_handler_->OnResponseCompleted(info->request_id(), status,
[email protected]c4891b32009-03-08 07:41:31379 std::string());
[email protected]3c9481d2009-02-24 21:25:53380
381 // Ditch the old async handler that talks to the renderer for the new
382 // download handler that talks to the DownloadManager.
[email protected]e3c404b2008-12-23 01:07:32383 real_handler_ = download_handler;
384 }
385 return real_handler_->OnResponseStarted(request_id, response_);
386}
387
[email protected]35fa6a22009-08-15 00:04:01388bool BufferedResourceHandler::ShouldWaitForPlugins() {
389 bool need_plugin_list;
390 if (!ShouldDownload(&need_plugin_list) || !need_plugin_list)
391 return false;
[email protected]e3c404b2008-12-23 01:07:32392
[email protected]35fa6a22009-08-15 00:04:01393 // We don't want to keep buffering as our buffer will fill up.
[email protected]347867b72009-09-02 00:35:58394 ResourceDispatcherHostRequestInfo* info =
395 ResourceDispatcherHost::InfoForRequest(request_);
396 host_->PauseRequest(info->child_id(), info->request_id(), true);
[email protected]35fa6a22009-08-15 00:04:01397
398 // Schedule plugin loading on the file thread.
[email protected]f7a015e2009-08-15 02:50:19399 // Note: it's possible that the only reference to this object is the task. If
400 // If the task executes on the file thread, and before it returns, the task it
401 // posts to the IO thread runs, then this object will get destructed on the
402 // file thread. This breaks assumptions in other message handlers (i.e. when
403 // unregistering with NotificationService in the destructor).
404 AddRef();
[email protected]35fa6a22009-08-15 00:04:01405 ChromeThread::GetMessageLoop(ChromeThread::FILE)->PostTask(FROM_HERE,
[email protected]f7a015e2009-08-15 02:50:19406 NewRunnableFunction(&BufferedResourceHandler::LoadPlugins,
407 this, host_->ui_loop()));
[email protected]35fa6a22009-08-15 00:04:01408 return true;
409}
410
411// This test mirrors the decision that WebKit makes in
412// WebFrameLoaderClient::dispatchDecidePolicyForMIMEType.
413bool BufferedResourceHandler::ShouldDownload(bool* need_plugin_list) {
414 if (need_plugin_list)
415 *need_plugin_list = false;
416 std::string type = StringToLowerASCII(response_->response_head.mime_type);
417 std::string disposition;
418 request_->GetResponseHeaderByName("content-disposition", &disposition);
419 disposition = StringToLowerASCII(disposition);
420
421 // First, examine content-disposition.
422 if (!disposition.empty()) {
423 bool should_download = true;
424
425 // Some broken sites just send ...
426 // Content-Disposition: ; filename="file"
427 // ... screen those out here.
428 if (disposition[0] == ';')
429 should_download = false;
430
431 if (disposition.compare(0, 6, "inline") == 0)
432 should_download = false;
433
434 // Some broken sites just send ...
435 // Content-Disposition: filename="file"
436 // ... without a disposition token... Screen those out.
437 if (disposition.compare(0, 8, "filename") == 0)
438 should_download = false;
439
440 // Also in use is Content-Disposition: name="file"
441 if (disposition.compare(0, 4, "name") == 0)
442 should_download = false;
443
444 // We have a content-disposition of "attachment" or unknown.
445 // RFC 2183, section 2.8 says that an unknown disposition
446 // value should be treated as "attachment".
447 if (should_download)
448 return true;
449 }
450
451 // MIME type checking.
452 if (net::IsSupportedMimeType(type))
453 return false;
454
455 if (need_plugin_list) {
456 if (!NPAPI::PluginList::Singleton()->PluginsLoaded()) {
457 *need_plugin_list = true;
458 return true;
459 }
460 } else {
461 DCHECK(NPAPI::PluginList::Singleton()->PluginsLoaded());
462 }
463
464 // Finally, check the plugin list.
465 WebPluginInfo info;
466 bool allow_wildcard = false;
467 return !NPAPI::PluginList::Singleton()->GetPluginInfo(
[email protected]610c0892009-09-08 19:46:18468 GURL(), type, allow_wildcard, &info, NULL);
[email protected]35fa6a22009-08-15 00:04:01469}
470
[email protected]f7a015e2009-08-15 02:50:19471void BufferedResourceHandler::LoadPlugins(BufferedResourceHandler* handler,
472 MessageLoop* main_message_loop) {
[email protected]35fa6a22009-08-15 00:04:01473 std::vector<WebPluginInfo> plugins;
474 NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
[email protected]f7a015e2009-08-15 02:50:19475
476 // Note, we want to get to the IO thread now, but the file thread outlives it
477 // so we can't post a task to it directly as it might be in the middle of
478 // destruction. So hop through the main thread, where the destruction of the
479 // IO thread happens and hence no race conditions exist.
480 main_message_loop->PostTask(FROM_HERE,
481 NewRunnableFunction(&BufferedResourceHandler::NotifyPluginsLoaded,
482 handler));
483}
484
485void BufferedResourceHandler::NotifyPluginsLoaded(
486 BufferedResourceHandler* handler) {
487 g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
488 NewRunnableMethod(handler, &BufferedResourceHandler::OnPluginsLoaded));
[email protected]35fa6a22009-08-15 00:04:01489}
490
491void BufferedResourceHandler::OnPluginsLoaded() {
[email protected]35fa6a22009-08-15 00:04:01492 wait_for_plugins_ = false;
[email protected]443b84b22009-08-17 19:18:45493 if (request_) {
[email protected]347867b72009-09-02 00:35:58494 ResourceDispatcherHostRequestInfo* info =
495 ResourceDispatcherHost::InfoForRequest(request_);
496 host_->PauseRequest(info->child_id(), info->request_id(), false);
497 if (!CompleteResponseStarted(info->request_id(), false))
498 host_->CancelRequest(info->child_id(), info->request_id(), false);
[email protected]443b84b22009-08-17 19:18:45499 }
500 Release();
[email protected]e3c404b2008-12-23 01:07:32501}