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

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

Issue 164305: Ensure we don't load plugins on the IO thread (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 4 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) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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 "chrome/browser/renderer_host/buffered_resource_handler.h" 5 #include "chrome/browser/renderer_host/buffered_resource_handler.h"
6 6
7 #include "base/histogram.h" 7 #include "base/histogram.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/string_util.h" 9 #include "base/string_util.h"
10 #include "net/base/mime_sniffer.h" 10 #include "net/base/mime_sniffer.h"
11 #include "net/base/net_errors.h" 11 #include "net/base/net_errors.h"
12 #include "chrome/browser/chrome_thread.h"
12 #include "chrome/browser/renderer_host/download_throttling_resource_handler.h" 13 #include "chrome/browser/renderer_host/download_throttling_resource_handler.h"
13 #include "chrome/browser/renderer_host/resource_dispatcher_host.h" 14 #include "chrome/browser/renderer_host/resource_dispatcher_host.h"
14 #include "chrome/common/url_constants.h" 15 #include "chrome/common/url_constants.h"
15 #include "net/base/mime_sniffer.h" 16 #include "net/base/mime_sniffer.h"
17 #include "net/base/mime_util.h"
16 #include "net/base/io_buffer.h" 18 #include "net/base/io_buffer.h"
17 #include "net/http/http_response_headers.h" 19 #include "net/http/http_response_headers.h"
20 #include "webkit/glue/plugins/plugin_list.h"
18 21
19 namespace { 22 namespace {
20 23
21 const int kMaxBytesToSniff = 512; 24 const int kMaxBytesToSniff = 512;
22 25
23 void RecordSnifferMetrics(bool sniffing_blocked, 26 void RecordSnifferMetrics(bool sniffing_blocked,
24 bool we_would_like_to_sniff, 27 bool we_would_like_to_sniff,
25 const std::string& mime_type) { 28 const std::string& mime_type) {
26 static BooleanHistogram nosniff_usage("nosniff.usage"); 29 static BooleanHistogram nosniff_usage("nosniff.usage");
27 nosniff_usage.SetFlags(kUmaTargetedHistogramFlag); 30 nosniff_usage.SetFlags(kUmaTargetedHistogramFlag);
(...skipping 14 matching lines...) Expand all
42 45
43 BufferedResourceHandler::BufferedResourceHandler(ResourceHandler* handler, 46 BufferedResourceHandler::BufferedResourceHandler(ResourceHandler* handler,
44 ResourceDispatcherHost* host, 47 ResourceDispatcherHost* host,
45 URLRequest* request) 48 URLRequest* request)
46 : real_handler_(handler), 49 : real_handler_(handler),
47 host_(host), 50 host_(host),
48 request_(request), 51 request_(request),
49 bytes_read_(0), 52 bytes_read_(0),
50 sniff_content_(false), 53 sniff_content_(false),
51 should_buffer_(false), 54 should_buffer_(false),
55 wait_for_plugins_(false),
52 buffering_(false), 56 buffering_(false),
53 finished_(false) { 57 finished_(false) {
54 } 58 }
55 59
56 bool BufferedResourceHandler::OnUploadProgress(int request_id, 60 bool BufferedResourceHandler::OnUploadProgress(int request_id,
57 uint64 position, 61 uint64 position,
58 uint64 size) { 62 uint64 size) {
59 return real_handler_->OnUploadProgress(request_id, position, size); 63 return real_handler_->OnUploadProgress(request_id, position, size);
60 } 64 }
61 65
62 bool BufferedResourceHandler::OnRequestRedirected(int request_id, 66 bool BufferedResourceHandler::OnRequestRedirected(int request_id,
63 const GURL& new_url, 67 const GURL& new_url,
64 ResourceResponse* response, 68 ResourceResponse* response,
65 bool* defer) { 69 bool* defer) {
66 return real_handler_->OnRequestRedirected( 70 return real_handler_->OnRequestRedirected(
67 request_id, new_url, response, defer); 71 request_id, new_url, response, defer);
68 } 72 }
69 73
70 bool BufferedResourceHandler::OnResponseStarted(int request_id, 74 bool BufferedResourceHandler::OnResponseStarted(int request_id,
71 ResourceResponse* response) { 75 ResourceResponse* response) {
72 response_ = response; 76 response_ = response;
73 if (!DelayResponse()) 77 if (!DelayResponse())
74 return CompleteResponseStarted(request_id, false); 78 return CompleteResponseStarted(request_id, false);
75 return true; 79 return true;
76 } 80 }
77 81
78
79 bool BufferedResourceHandler::OnResponseCompleted( 82 bool BufferedResourceHandler::OnResponseCompleted(
80 int request_id, 83 int request_id,
81 const URLRequestStatus& status, 84 const URLRequestStatus& status,
82 const std::string& security_info) { 85 const std::string& security_info) {
83 return real_handler_->OnResponseCompleted(request_id, status, security_info); 86 return real_handler_->OnResponseCompleted(request_id, status, security_info);
84 } 87 }
85 88
89 void BufferedResourceHandler::OnRequestClosed() {
90 request_ = NULL;
91 real_handler_->OnRequestClosed();
92 }
93
86 // We'll let the original event handler provide a buffer, and reuse it for 94 // We'll let the original event handler provide a buffer, and reuse it for
87 // subsequent reads until we're done buffering. 95 // subsequent reads until we're done buffering.
88 bool BufferedResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf, 96 bool BufferedResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
89 int* buf_size, int min_size) { 97 int* buf_size, int min_size) {
90 if (buffering_) { 98 if (buffering_) {
91 DCHECK(!my_buffer_.get()); 99 DCHECK(!my_buffer_.get());
92 my_buffer_ = new net::IOBuffer(kMaxBytesToSniff); 100 my_buffer_ = new net::IOBuffer(kMaxBytesToSniff);
93 *buf = my_buffer_.get(); 101 *buf = my_buffer_.get();
94 *buf_size = kMaxBytesToSniff; 102 *buf_size = kMaxBytesToSniff;
95 // TODO(willchan): Remove after debugging bug 16371. 103 // TODO(willchan): Remove after debugging bug 16371.
(...skipping 15 matching lines...) Expand all
111 bytes_read_ = 0; 119 bytes_read_ = 0;
112 return true; 120 return true;
113 } 121 }
114 122
115 bool BufferedResourceHandler::OnReadCompleted(int request_id, int* bytes_read) { 123 bool BufferedResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
116 if (sniff_content_ || should_buffer_) { 124 if (sniff_content_ || should_buffer_) {
117 if (KeepBuffering(*bytes_read)) 125 if (KeepBuffering(*bytes_read))
118 return true; 126 return true;
119 127
120 LOG(INFO) << "Finished buffering " << request_->url().spec(); 128 LOG(INFO) << "Finished buffering " << request_->url().spec();
121 sniff_content_ = should_buffer_ = false;
122 *bytes_read = bytes_read_; 129 *bytes_read = bytes_read_;
123 130
124 // Done buffering, send the pending ResponseStarted event. 131 // Done buffering, send the pending ResponseStarted event.
125 if (!CompleteResponseStarted(request_id, true)) 132 if (!CompleteResponseStarted(request_id, true))
126 return false; 133 return false;
134 } else if (wait_for_plugins_) {
135 return true;
127 } 136 }
128 137
129 // Release the reference that we acquired at OnWillRead. 138 // Release the reference that we acquired at OnWillRead.
130 read_buffer_ = NULL; 139 read_buffer_ = NULL;
131 return real_handler_->OnReadCompleted(request_id, bytes_read); 140 return real_handler_->OnReadCompleted(request_id, bytes_read);
132 } 141 }
133 142
134 bool BufferedResourceHandler::DelayResponse() { 143 bool BufferedResourceHandler::DelayResponse() {
135 std::string mime_type; 144 std::string mime_type;
136 request_->GetMimeType(&mime_type); 145 request_->GetMimeType(&mime_type);
(...skipping 27 matching lines...) Expand all
164 } 173 }
165 174
166 if (ShouldBuffer(request_->url(), mime_type)) { 175 if (ShouldBuffer(request_->url(), mime_type)) {
167 // This is a temporary fix for the fact that webkit expects to have 176 // This is a temporary fix for the fact that webkit expects to have
168 // enough data to decode the doctype in order to select the rendering 177 // enough data to decode the doctype in order to select the rendering
169 // mode. 178 // mode.
170 should_buffer_ = true; 179 should_buffer_ = true;
171 LOG(INFO) << "To buffer: " << request_->url().spec(); 180 LOG(INFO) << "To buffer: " << request_->url().spec();
172 return true; 181 return true;
173 } 182 }
183
184 if (ShouldWaitForPlugins()) {
185 wait_for_plugins_ = true;
186 return true;
187 }
188
174 return false; 189 return false;
175 } 190 }
176 191
177 bool BufferedResourceHandler::ShouldBuffer(const GURL& url, 192 bool BufferedResourceHandler::ShouldBuffer(const GURL& url,
178 const std::string& mime_type) { 193 const std::string& mime_type) {
179 // We are willing to buffer for HTTP and HTTPS. 194 // We are willing to buffer for HTTP and HTTPS.
180 bool sniffable_scheme = url.is_empty() || 195 bool sniffable_scheme = url.is_empty() ||
181 url.SchemeIs(chrome::kHttpScheme) || 196 url.SchemeIs(chrome::kHttpScheme) ||
182 url.SchemeIs(chrome::kHttpsScheme); 197 url.SchemeIs(chrome::kHttpsScheme);
183 if (!sniffable_scheme) 198 if (!sniffable_scheme)
184 return false; 199 return false;
185 200
186 // Today, the only reason to buffer the request is to fix the doctype decoding 201 // Today, the only reason to buffer the request is to fix the doctype decoding
187 // performed by webkit: if there is not enough data it will go to quirks mode. 202 // performed by webkit: if there is not enough data it will go to quirks mode.
188 // We only expect the doctype check to apply to html documents. 203 // We only expect the doctype check to apply to html documents.
189 return mime_type == "text/html"; 204 return mime_type == "text/html";
190 } 205 }
191 206
207 bool BufferedResourceHandler::DidBufferEnough(int bytes_read) {
208 const int kRequiredLength = 256;
209
210 return bytes_read >= kRequiredLength;
211 }
212
192 bool BufferedResourceHandler::KeepBuffering(int bytes_read) { 213 bool BufferedResourceHandler::KeepBuffering(int bytes_read) {
193 DCHECK(read_buffer_); 214 DCHECK(read_buffer_);
194 if (my_buffer_) { 215 if (my_buffer_) {
195 // We are using our own buffer to read, update the main buffer. 216 // We are using our own buffer to read, update the main buffer.
196 CHECK(bytes_read + bytes_read_ < read_buffer_size_); 217 CHECK(bytes_read + bytes_read_ < read_buffer_size_);
197 memcpy(read_buffer_->data() + bytes_read_, my_buffer_->data(), bytes_read); 218 memcpy(read_buffer_->data() + bytes_read_, my_buffer_->data(), bytes_read);
198 my_buffer_ = NULL; 219 my_buffer_ = NULL;
199 } 220 }
200 bytes_read_ += bytes_read; 221 bytes_read_ += bytes_read;
201 finished_ = (bytes_read == 0); 222 finished_ = (bytes_read == 0);
(...skipping 10 matching lines...) Expand all
212 DCHECK(bytes_read_ < kMaxBytesToSniff); 233 DCHECK(bytes_read_ < kMaxBytesToSniff);
213 if (!finished_) { 234 if (!finished_) {
214 buffering_ = true; 235 buffering_ = true;
215 return true; 236 return true;
216 } 237 }
217 } 238 }
218 sniff_content_ = false; 239 sniff_content_ = false;
219 response_->response_head.mime_type.assign(new_type); 240 response_->response_head.mime_type.assign(new_type);
220 241
221 // We just sniffed the mime type, maybe there is a doctype to process. 242 // We just sniffed the mime type, maybe there is a doctype to process.
222 if (ShouldBuffer(request_->url(), new_type)) 243 if (ShouldBuffer(request_->url(), new_type)) {
223 should_buffer_ = true; 244 should_buffer_ = true;
245 } else if (ShouldWaitForPlugins()) {
246 wait_for_plugins_ = true;
247 }
224 } 248 }
225 249
226 if (!finished_ && should_buffer_) { 250 if (should_buffer_) {
227 if (!DidBufferEnough(bytes_read_)) { 251 if (!finished_ && !DidBufferEnough(bytes_read_)) {
228 buffering_ = true; 252 buffering_ = true;
229 return true; 253 return true;
230 } 254 }
255
256 should_buffer_ = false;
257 if (ShouldWaitForPlugins())
258 wait_for_plugins_ = true;
231 } 259 }
260
232 buffering_ = false; 261 buffering_ = false;
262
263 if (wait_for_plugins_)
264 return true;
265
233 return false; 266 return false;
234 } 267 }
235 268
236 bool BufferedResourceHandler::CompleteResponseStarted(int request_id, 269 bool BufferedResourceHandler::CompleteResponseStarted(int request_id,
237 bool in_complete) { 270 bool in_complete) {
238 // Check to see if we should forward the data from this request to the 271 // Check to see if we should forward the data from this request to the
239 // download thread. 272 // download thread.
240 // TODO(paulg): Only download if the context from the renderer allows it. 273 // TODO(paulg): Only download if the context from the renderer allows it.
241 std::string content_disposition;
242 request_->GetResponseHeaderByName("content-disposition",
243 &content_disposition);
244
245 ResourceDispatcherHost::ExtraRequestInfo* info = 274 ResourceDispatcherHost::ExtraRequestInfo* info =
246 ResourceDispatcherHost::ExtraInfoForRequest(request_); 275 ResourceDispatcherHost::ExtraInfoForRequest(request_);
247 276
248 if (info->allow_download && 277 if (info->allow_download && ShouldDownload(NULL)) {
249 host_->ShouldDownload(response_->response_head.mime_type,
250 content_disposition)) {
251 if (response_->response_head.headers && // Can be NULL if FTP. 278 if (response_->response_head.headers && // Can be NULL if FTP.
252 response_->response_head.headers->response_code() / 100 != 2) { 279 response_->response_head.headers->response_code() / 100 != 2) {
253 // The response code indicates that this is an error page, but we don't 280 // The response code indicates that this is an error page, but we don't
254 // know how to display the content. We follow Firefox here and show our 281 // know how to display the content. We follow Firefox here and show our
255 // own error page instead of triggering a download. 282 // own error page instead of triggering a download.
256 // TODO(abarth): We should abstract the response_code test, but this kind 283 // TODO(abarth): We should abstract the response_code test, but this kind
257 // of check is scattered throughout our codebase. 284 // of check is scattered throughout our codebase.
258 request_->SimulateError(net::ERR_FILE_NOT_FOUND); 285 request_->SimulateError(net::ERR_FILE_NOT_FOUND);
259 return false; 286 return false;
260 } 287 }
(...skipping 25 matching lines...) Expand all
286 real_handler_->OnResponseCompleted(info->request_id, status, 313 real_handler_->OnResponseCompleted(info->request_id, status,
287 std::string()); 314 std::string());
288 315
289 // Ditch the old async handler that talks to the renderer for the new 316 // Ditch the old async handler that talks to the renderer for the new
290 // download handler that talks to the DownloadManager. 317 // download handler that talks to the DownloadManager.
291 real_handler_ = download_handler; 318 real_handler_ = download_handler;
292 } 319 }
293 return real_handler_->OnResponseStarted(request_id, response_); 320 return real_handler_->OnResponseStarted(request_id, response_);
294 } 321 }
295 322
296 bool BufferedResourceHandler::DidBufferEnough(int bytes_read) { 323 bool BufferedResourceHandler::ShouldWaitForPlugins() {
297 const int kRequiredLength = 256; 324 bool need_plugin_list;
325 if (!ShouldDownload(&need_plugin_list) || !need_plugin_list)
326 return false;
298 327
299 return bytes_read >= kRequiredLength; 328 // We don't want to keep buffering as our buffer will fill up.
329 ResourceDispatcherHost::ExtraRequestInfo* info =
330 ResourceDispatcherHost::ExtraInfoForRequest(request_);
331 host_->PauseRequest(info->process_id, info->request_id, true);
332
333 // Schedule plugin loading on the file thread.
334 ChromeThread::GetMessageLoop(ChromeThread::FILE)->PostTask(FROM_HERE,
335 NewRunnableMethod(this, &BufferedResourceHandler::LoadPlugins));
336 return true;
300 } 337 }
338
339 // This test mirrors the decision that WebKit makes in
340 // WebFrameLoaderClient::dispatchDecidePolicyForMIMEType.
341 bool BufferedResourceHandler::ShouldDownload(bool* need_plugin_list) {
342 if (need_plugin_list)
343 *need_plugin_list = false;
344 std::string type = StringToLowerASCII(response_->response_head.mime_type);
345 std::string disposition;
346 request_->GetResponseHeaderByName("content-disposition", &disposition);
347 disposition = StringToLowerASCII(disposition);
348
349 // First, examine content-disposition.
350 if (!disposition.empty()) {
351 bool should_download = true;
352
353 // Some broken sites just send ...
354 // Content-Disposition: ; filename="file"
355 // ... screen those out here.
356 if (disposition[0] == ';')
357 should_download = false;
358
359 if (disposition.compare(0, 6, "inline") == 0)
360 should_download = false;
361
362 // Some broken sites just send ...
363 // Content-Disposition: filename="file"
364 // ... without a disposition token... Screen those out.
365 if (disposition.compare(0, 8, "filename") == 0)
366 should_download = false;
367
368 // Also in use is Content-Disposition: name="file"
369 if (disposition.compare(0, 4, "name") == 0)
370 should_download = false;
371
372 // We have a content-disposition of "attachment" or unknown.
373 // RFC 2183, section 2.8 says that an unknown disposition
374 // value should be treated as "attachment".
375 if (should_download)
376 return true;
377 }
378
379 // MIME type checking.
380 if (net::IsSupportedMimeType(type))
381 return false;
382
383 if (need_plugin_list) {
384 if (!NPAPI::PluginList::Singleton()->PluginsLoaded()) {
385 *need_plugin_list = true;
386 return true;
387 }
388 } else {
389 DCHECK(NPAPI::PluginList::Singleton()->PluginsLoaded());
390 }
391
392 // Finally, check the plugin list.
393 WebPluginInfo info;
394 bool allow_wildcard = false;
395 return !NPAPI::PluginList::Singleton()->GetPluginInfo(
396 GURL(), type, "", allow_wildcard, &info, NULL);
397 }
398
399 void BufferedResourceHandler::LoadPlugins() {
400 std::vector<WebPluginInfo> plugins;
401 NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
402 ChromeThread::GetMessageLoop(ChromeThread::IO)->PostTask(FROM_HERE,
403 NewRunnableMethod(this, &BufferedResourceHandler::OnPluginsLoaded));
404 }
405
406 void BufferedResourceHandler::OnPluginsLoaded() {
407 wait_for_plugins_ = false;
408 if (!request_)
409 return;
410
411 ResourceDispatcherHost::ExtraRequestInfo* info =
412 ResourceDispatcherHost::ExtraInfoForRequest(request_);
413 host_->PauseRequest(info->process_id, info->request_id, false);
414 if (!CompleteResponseStarted(info->request_id, false))
415 host_->CancelRequest(info->process_id, info->request_id, false);
416 }
OLDNEW
« no previous file with comments | « chrome/browser/renderer_host/buffered_resource_handler.h ('k') | chrome/browser/renderer_host/resource_dispatcher_host.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698