OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/loader/buffered_resource_handler.h" | 5 #include "content/browser/loader/buffered_resource_handler.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 | 73 |
74 scoped_refptr<net::IOBuffer> buf_; | 74 scoped_refptr<net::IOBuffer> buf_; |
75 }; | 75 }; |
76 | 76 |
77 } // namespace | 77 } // namespace |
78 | 78 |
79 BufferedResourceHandler::BufferedResourceHandler( | 79 BufferedResourceHandler::BufferedResourceHandler( |
80 scoped_ptr<ResourceHandler> next_handler, | 80 scoped_ptr<ResourceHandler> next_handler, |
81 ResourceDispatcherHostImpl* host, | 81 ResourceDispatcherHostImpl* host, |
82 net::URLRequest* request) | 82 net::URLRequest* request) |
83 : LayeredResourceHandler(request, next_handler.Pass()), | 83 : LayeredResourceHandler(next_handler.Pass()), |
84 state_(STATE_STARTING), | 84 state_(STATE_STARTING), |
85 host_(host), | 85 host_(host), |
| 86 request_(request), |
86 read_buffer_size_(0), | 87 read_buffer_size_(0), |
87 bytes_read_(0), | 88 bytes_read_(0), |
88 must_download_(false), | 89 must_download_(false), |
89 must_download_is_set_(false), | 90 must_download_is_set_(false), |
90 weak_ptr_factory_(this) { | 91 weak_ptr_factory_(this) { |
91 } | 92 } |
92 | 93 |
93 BufferedResourceHandler::~BufferedResourceHandler() { | 94 BufferedResourceHandler::~BufferedResourceHandler() { |
94 } | 95 } |
95 | 96 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 response_->head.mime_type.assign("text/plain"); | 140 response_->head.mime_type.assign("text/plain"); |
140 } | 141 } |
141 } | 142 } |
142 | 143 |
143 state_ = STATE_PROCESSING; | 144 state_ = STATE_PROCESSING; |
144 return ProcessResponse(defer); | 145 return ProcessResponse(defer); |
145 } | 146 } |
146 | 147 |
147 // We'll let the original event handler provide a buffer, and reuse it for | 148 // We'll let the original event handler provide a buffer, and reuse it for |
148 // subsequent reads until we're done buffering. | 149 // subsequent reads until we're done buffering. |
149 bool BufferedResourceHandler::OnWillRead(int request_id, | 150 bool BufferedResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf, |
150 scoped_refptr<net::IOBuffer>* buf, | 151 int* buf_size, int min_size) { |
151 int* buf_size, | |
152 int min_size) { | |
153 if (state_ == STATE_STREAMING) | 152 if (state_ == STATE_STREAMING) |
154 return next_handler_->OnWillRead(request_id, buf, buf_size, min_size); | 153 return next_handler_->OnWillRead(request_id, buf, buf_size, min_size); |
155 | 154 |
156 DCHECK_EQ(-1, min_size); | 155 DCHECK_EQ(-1, min_size); |
157 | 156 |
158 if (read_buffer_.get()) { | 157 if (read_buffer_.get()) { |
159 CHECK_LT(bytes_read_, read_buffer_size_); | 158 CHECK_LT(bytes_read_, read_buffer_size_); |
160 *buf = new DependentIOBuffer(read_buffer_.get(), bytes_read_); | 159 *buf = new DependentIOBuffer(read_buffer_.get(), bytes_read_); |
161 *buf_size = read_buffer_size_ - bytes_read_; | 160 *buf_size = read_buffer_size_ - bytes_read_; |
162 } else { | 161 } else { |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 if (!(response_->head.headers.get() && | 233 if (!(response_->head.headers.get() && |
235 response_->head.headers->response_code() == 304)) { | 234 response_->head.headers->response_code() == 304)) { |
236 if (!SelectNextHandler(defer)) | 235 if (!SelectNextHandler(defer)) |
237 return false; | 236 return false; |
238 if (*defer) | 237 if (*defer) |
239 return true; | 238 return true; |
240 } | 239 } |
241 | 240 |
242 state_ = STATE_REPLAYING; | 241 state_ = STATE_REPLAYING; |
243 | 242 |
244 if (!next_handler_->OnResponseStarted(GetRequestID(), response_.get(), defer)) | 243 int request_id = ResourceRequestInfo::ForRequest(request_)->GetRequestID(); |
| 244 if (!next_handler_->OnResponseStarted(request_id, response_.get(), defer)) |
245 return false; | 245 return false; |
246 | 246 |
247 if (!read_buffer_.get()) { | 247 if (!read_buffer_.get()) { |
248 state_ = STATE_STREAMING; | 248 state_ = STATE_STREAMING; |
249 return true; | 249 return true; |
250 } | 250 } |
251 | 251 |
252 if (!*defer) | 252 if (!*defer) |
253 return ReplayReadCompleted(defer); | 253 return ReplayReadCompleted(defer); |
254 | 254 |
255 return true; | 255 return true; |
256 } | 256 } |
257 | 257 |
258 bool BufferedResourceHandler::ShouldSniffContent() { | 258 bool BufferedResourceHandler::ShouldSniffContent() { |
259 const std::string& mime_type = response_->head.mime_type; | 259 const std::string& mime_type = response_->head.mime_type; |
260 | 260 |
261 std::string content_type_options; | 261 std::string content_type_options; |
262 request()->GetResponseHeaderByName("x-content-type-options", | 262 request_->GetResponseHeaderByName("x-content-type-options", |
263 &content_type_options); | 263 &content_type_options); |
264 | 264 |
265 bool sniffing_blocked = | 265 bool sniffing_blocked = |
266 LowerCaseEqualsASCII(content_type_options, "nosniff"); | 266 LowerCaseEqualsASCII(content_type_options, "nosniff"); |
267 bool we_would_like_to_sniff = | 267 bool we_would_like_to_sniff = |
268 net::ShouldSniffMimeType(request()->url(), mime_type); | 268 net::ShouldSniffMimeType(request_->url(), mime_type); |
269 | 269 |
270 RecordSnifferMetrics(sniffing_blocked, we_would_like_to_sniff, mime_type); | 270 RecordSnifferMetrics(sniffing_blocked, we_would_like_to_sniff, mime_type); |
271 | 271 |
272 if (!sniffing_blocked && we_would_like_to_sniff) { | 272 if (!sniffing_blocked && we_would_like_to_sniff) { |
273 // We're going to look at the data before deciding what the content type | 273 // We're going to look at the data before deciding what the content type |
274 // is. That means we need to delay sending the ResponseStarted message | 274 // is. That means we need to delay sending the ResponseStarted message |
275 // over the IPC channel. | 275 // over the IPC channel. |
276 VLOG(1) << "To buffer: " << request()->url().spec(); | 276 VLOG(1) << "To buffer: " << request_->url().spec(); |
277 return true; | 277 return true; |
278 } | 278 } |
279 | 279 |
280 return false; | 280 return false; |
281 } | 281 } |
282 | 282 |
283 bool BufferedResourceHandler::DetermineMimeType() { | 283 bool BufferedResourceHandler::DetermineMimeType() { |
284 DCHECK_EQ(STATE_BUFFERING, state_); | 284 DCHECK_EQ(STATE_BUFFERING, state_); |
285 | 285 |
286 const std::string& type_hint = response_->head.mime_type; | 286 const std::string& type_hint = response_->head.mime_type; |
287 | 287 |
288 std::string new_type; | 288 std::string new_type; |
289 bool made_final_decision = | 289 bool made_final_decision = |
290 net::SniffMimeType(read_buffer_->data(), bytes_read_, request()->url(), | 290 net::SniffMimeType(read_buffer_->data(), bytes_read_, request_->url(), |
291 type_hint, &new_type); | 291 type_hint, &new_type); |
292 | 292 |
293 // SniffMimeType() returns false if there is not enough data to determine | 293 // SniffMimeType() returns false if there is not enough data to determine |
294 // the mime type. However, even if it returns false, it returns a new type | 294 // the mime type. However, even if it returns false, it returns a new type |
295 // that is probably better than the current one. | 295 // that is probably better than the current one. |
296 response_->head.mime_type.assign(new_type); | 296 response_->head.mime_type.assign(new_type); |
297 | 297 |
298 return made_final_decision; | 298 return made_final_decision; |
299 } | 299 } |
300 | 300 |
301 bool BufferedResourceHandler::SelectNextHandler(bool* defer) { | 301 bool BufferedResourceHandler::SelectNextHandler(bool* defer) { |
302 DCHECK(!response_->head.mime_type.empty()); | 302 DCHECK(!response_->head.mime_type.empty()); |
303 | 303 |
304 ResourceRequestInfoImpl* info = GetRequestInfo(); | 304 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request_); |
305 const std::string& mime_type = response_->head.mime_type; | 305 const std::string& mime_type = response_->head.mime_type; |
306 | 306 |
307 if (net::IsSupportedCertificateMimeType(mime_type)) { | 307 if (net::IsSupportedCertificateMimeType(mime_type)) { |
308 // Install certificate file. | 308 // Install certificate file. |
309 scoped_ptr<ResourceHandler> handler( | 309 scoped_ptr<ResourceHandler> handler( |
310 new CertificateResourceHandler(request())); | 310 new CertificateResourceHandler(request_)); |
311 return UseAlternateNextHandler(handler.Pass()); | 311 return UseAlternateNextHandler(handler.Pass()); |
312 } | 312 } |
313 | 313 |
314 if (!info->allow_download()) | 314 if (!info->allow_download()) |
315 return true; | 315 return true; |
316 | 316 |
317 bool must_download = MustDownload(); | 317 bool must_download = MustDownload(); |
318 if (!must_download) { | 318 if (!must_download) { |
319 if (net::IsSupportedMimeType(mime_type)) | 319 if (net::IsSupportedMimeType(mime_type)) |
320 return true; | 320 return true; |
321 | 321 |
322 scoped_ptr<ResourceHandler> handler( | 322 scoped_ptr<ResourceHandler> handler( |
323 host_->MaybeInterceptAsStream(request(), response_.get())); | 323 host_->MaybeInterceptAsStream(request_, response_.get())); |
324 if (handler) | 324 if (handler) |
325 return UseAlternateNextHandler(handler.Pass()); | 325 return UseAlternateNextHandler(handler.Pass()); |
326 | 326 |
327 #if defined(ENABLE_PLUGINS) | 327 #if defined(ENABLE_PLUGINS) |
328 bool stale; | 328 bool stale; |
329 bool has_plugin = HasSupportingPlugin(&stale); | 329 bool has_plugin = HasSupportingPlugin(&stale); |
330 if (stale) { | 330 if (stale) { |
331 // Refresh the plugins asynchronously. | 331 // Refresh the plugins asynchronously. |
332 PluginServiceImpl::GetInstance()->GetPlugins( | 332 PluginServiceImpl::GetInstance()->GetPlugins( |
333 base::Bind(&BufferedResourceHandler::OnPluginsLoaded, | 333 base::Bind(&BufferedResourceHandler::OnPluginsLoaded, |
334 weak_ptr_factory_.GetWeakPtr())); | 334 weak_ptr_factory_.GetWeakPtr())); |
335 *defer = true; | 335 *defer = true; |
336 return true; | 336 return true; |
337 } | 337 } |
338 if (has_plugin) | 338 if (has_plugin) |
339 return true; | 339 return true; |
340 #endif | 340 #endif |
341 } | 341 } |
342 | 342 |
343 // Install download handler | 343 // Install download handler |
344 info->set_is_download(true); | 344 info->set_is_download(true); |
345 scoped_ptr<ResourceHandler> handler( | 345 scoped_ptr<ResourceHandler> handler( |
346 host_->CreateResourceHandlerForDownload( | 346 host_->CreateResourceHandlerForDownload( |
347 request(), | 347 request_, |
348 true, // is_content_initiated | 348 true, // is_content_initiated |
349 must_download, | 349 must_download, |
350 content::DownloadItem::kInvalidId, | 350 content::DownloadItem::kInvalidId, |
351 scoped_ptr<DownloadSaveInfo>(new DownloadSaveInfo()), | 351 scoped_ptr<DownloadSaveInfo>(new DownloadSaveInfo()), |
352 DownloadUrlParameters::OnStartedCallback())); | 352 DownloadUrlParameters::OnStartedCallback())); |
353 return UseAlternateNextHandler(handler.Pass()); | 353 return UseAlternateNextHandler(handler.Pass()); |
354 } | 354 } |
355 | 355 |
356 bool BufferedResourceHandler::UseAlternateNextHandler( | 356 bool BufferedResourceHandler::UseAlternateNextHandler( |
357 scoped_ptr<ResourceHandler> new_handler) { | 357 scoped_ptr<ResourceHandler> new_handler) { |
358 if (response_->head.headers.get() && // Can be NULL if FTP. | 358 if (response_->head.headers.get() && // Can be NULL if FTP. |
359 response_->head.headers->response_code() / 100 != 2) { | 359 response_->head.headers->response_code() / 100 != 2) { |
360 // The response code indicates that this is an error page, but we don't | 360 // The response code indicates that this is an error page, but we don't |
361 // know how to display the content. We follow Firefox here and show our | 361 // know how to display the content. We follow Firefox here and show our |
362 // own error page instead of triggering a download. | 362 // own error page instead of triggering a download. |
363 // TODO(abarth): We should abstract the response_code test, but this kind | 363 // TODO(abarth): We should abstract the response_code test, but this kind |
364 // of check is scattered throughout our codebase. | 364 // of check is scattered throughout our codebase. |
365 request()->CancelWithError(net::ERR_FILE_NOT_FOUND); | 365 request_->CancelWithError(net::ERR_FILE_NOT_FOUND); |
366 return false; | 366 return false; |
367 } | 367 } |
368 | 368 |
369 int request_id = GetRequestID(); | 369 int request_id = ResourceRequestInfo::ForRequest(request_)->GetRequestID(); |
370 | 370 |
371 // Inform the original ResourceHandler that this will be handled entirely by | 371 // Inform the original ResourceHandler that this will be handled entirely by |
372 // the new ResourceHandler. | 372 // the new ResourceHandler. |
373 // TODO(darin): We should probably check the return values of these. | 373 // TODO(darin): We should probably check the return values of these. |
374 bool defer_ignored = false; | 374 bool defer_ignored = false; |
375 next_handler_->OnResponseStarted(request_id, response_.get(), &defer_ignored); | 375 next_handler_->OnResponseStarted(request_id, response_.get(), &defer_ignored); |
376 DCHECK(!defer_ignored); | 376 DCHECK(!defer_ignored); |
377 net::URLRequestStatus status(net::URLRequestStatus::CANCELED, | 377 net::URLRequestStatus status(net::URLRequestStatus::CANCELED, |
378 net::ERR_ABORTED); | 378 net::ERR_ABORTED); |
379 next_handler_->OnResponseCompleted(request_id, status, std::string()); | 379 next_handler_->OnResponseCompleted(request_id, status, std::string()); |
380 | 380 |
381 // This is handled entirely within the new ResourceHandler, so just reset the | 381 // This is handled entirely within the new ResourceHandler, so just reset the |
382 // original ResourceHandler. | 382 // original ResourceHandler. |
383 next_handler_ = new_handler.Pass(); | 383 next_handler_ = new_handler.Pass(); |
384 next_handler_->SetController(this); | 384 next_handler_->SetController(this); |
385 | 385 |
386 return CopyReadBufferToNextHandler(request_id); | 386 return CopyReadBufferToNextHandler(request_id); |
387 } | 387 } |
388 | 388 |
389 bool BufferedResourceHandler::ReplayReadCompleted(bool* defer) { | 389 bool BufferedResourceHandler::ReplayReadCompleted(bool* defer) { |
390 DCHECK(read_buffer_.get()); | 390 DCHECK(read_buffer_.get()); |
391 | 391 |
392 bool result = next_handler_->OnReadCompleted(GetRequestID(), bytes_read_, | 392 int request_id = ResourceRequestInfo::ForRequest(request_)->GetRequestID(); |
393 defer); | 393 bool result = next_handler_->OnReadCompleted(request_id, bytes_read_, defer); |
394 | 394 |
395 read_buffer_ = NULL; | 395 read_buffer_ = NULL; |
396 read_buffer_size_ = 0; | 396 read_buffer_size_ = 0; |
397 bytes_read_ = 0; | 397 bytes_read_ = 0; |
398 | 398 |
399 state_ = STATE_STREAMING; | 399 state_ = STATE_STREAMING; |
400 | 400 |
401 return result; | 401 return result; |
402 } | 402 } |
403 | 403 |
404 void BufferedResourceHandler::CallReplayReadCompleted() { | 404 void BufferedResourceHandler::CallReplayReadCompleted() { |
405 bool defer = false; | 405 bool defer = false; |
406 if (!ReplayReadCompleted(&defer)) { | 406 if (!ReplayReadCompleted(&defer)) { |
407 controller()->Cancel(); | 407 controller()->Cancel(); |
408 } else if (!defer) { | 408 } else if (!defer) { |
409 state_ = STATE_STREAMING; | 409 state_ = STATE_STREAMING; |
410 controller()->Resume(); | 410 controller()->Resume(); |
411 } | 411 } |
412 } | 412 } |
413 | 413 |
414 bool BufferedResourceHandler::MustDownload() { | 414 bool BufferedResourceHandler::MustDownload() { |
415 if (must_download_is_set_) | 415 if (must_download_is_set_) |
416 return must_download_; | 416 return must_download_; |
417 | 417 |
418 must_download_is_set_ = true; | 418 must_download_is_set_ = true; |
419 | 419 |
420 std::string disposition; | 420 std::string disposition; |
421 request()->GetResponseHeaderByName("content-disposition", &disposition); | 421 request_->GetResponseHeaderByName("content-disposition", &disposition); |
422 if (!disposition.empty() && | 422 if (!disposition.empty() && |
423 net::HttpContentDisposition(disposition, std::string()).is_attachment()) { | 423 net::HttpContentDisposition(disposition, std::string()).is_attachment()) { |
424 must_download_ = true; | 424 must_download_ = true; |
425 } else if (host_->delegate() && | 425 } else if (host_->delegate() && |
426 host_->delegate()->ShouldForceDownloadResource( | 426 host_->delegate()->ShouldForceDownloadResource( |
427 request()->url(), response_->head.mime_type)) { | 427 request_->url(), response_->head.mime_type)) { |
428 must_download_ = true; | 428 must_download_ = true; |
429 } else { | 429 } else { |
430 must_download_ = false; | 430 must_download_ = false; |
431 } | 431 } |
432 | 432 |
433 return must_download_; | 433 return must_download_; |
434 } | 434 } |
435 | 435 |
436 bool BufferedResourceHandler::HasSupportingPlugin(bool* stale) { | 436 bool BufferedResourceHandler::HasSupportingPlugin(bool* stale) { |
437 ResourceRequestInfoImpl* info = GetRequestInfo(); | 437 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request_); |
438 | 438 |
439 bool allow_wildcard = false; | 439 bool allow_wildcard = false; |
440 WebPluginInfo plugin; | 440 WebPluginInfo plugin; |
441 return PluginServiceImpl::GetInstance()->GetPluginInfo( | 441 return PluginServiceImpl::GetInstance()->GetPluginInfo( |
442 info->GetChildID(), info->GetRouteID(), info->GetContext(), | 442 info->GetChildID(), info->GetRouteID(), info->GetContext(), |
443 request()->url(), GURL(), response_->head.mime_type, allow_wildcard, | 443 request_->url(), GURL(), response_->head.mime_type, allow_wildcard, |
444 stale, &plugin, NULL); | 444 stale, &plugin, NULL); |
445 } | 445 } |
446 | 446 |
447 bool BufferedResourceHandler::CopyReadBufferToNextHandler(int request_id) { | 447 bool BufferedResourceHandler::CopyReadBufferToNextHandler(int request_id) { |
448 if (!bytes_read_) | 448 if (!bytes_read_) |
449 return true; | 449 return true; |
450 | 450 |
451 scoped_refptr<net::IOBuffer> buf; | 451 net::IOBuffer* buf = NULL; |
452 int buf_len = 0; | 452 int buf_len = 0; |
453 if (!next_handler_->OnWillRead(request_id, &buf, &buf_len, bytes_read_)) | 453 if (!next_handler_->OnWillRead(request_id, &buf, &buf_len, bytes_read_)) |
454 return false; | 454 return false; |
455 | 455 |
456 CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0)); | 456 CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0)); |
457 memcpy(buf->data(), read_buffer_->data(), bytes_read_); | 457 memcpy(buf->data(), read_buffer_->data(), bytes_read_); |
458 return true; | 458 return true; |
459 } | 459 } |
460 | 460 |
461 void BufferedResourceHandler::OnPluginsLoaded( | 461 void BufferedResourceHandler::OnPluginsLoaded( |
462 const std::vector<WebPluginInfo>& plugins) { | 462 const std::vector<WebPluginInfo>& plugins) { |
463 bool defer = false; | 463 bool defer = false; |
464 if (!ProcessResponse(&defer)) { | 464 if (!ProcessResponse(&defer)) { |
465 controller()->Cancel(); | 465 controller()->Cancel(); |
466 } else if (!defer) { | 466 } else if (!defer) { |
467 controller()->Resume(); | 467 controller()->Resume(); |
468 } | 468 } |
469 } | 469 } |
470 | 470 |
471 } // namespace content | 471 } // namespace content |
OLD | NEW |