| 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(next_handler.Pass()), | 83 : LayeredResourceHandler(request, next_handler.Pass()), |
| 84 state_(STATE_STARTING), | 84 state_(STATE_STARTING), |
| 85 host_(host), | 85 host_(host), |
| 86 request_(request), | |
| 87 read_buffer_size_(0), | 86 read_buffer_size_(0), |
| 88 bytes_read_(0), | 87 bytes_read_(0), |
| 89 must_download_(false), | 88 must_download_(false), |
| 90 must_download_is_set_(false), | 89 must_download_is_set_(false), |
| 91 weak_ptr_factory_(this) { | 90 weak_ptr_factory_(this) { |
| 92 } | 91 } |
| 93 | 92 |
| 94 BufferedResourceHandler::~BufferedResourceHandler() { | 93 BufferedResourceHandler::~BufferedResourceHandler() { |
| 95 } | 94 } |
| 96 | 95 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 140 response_->head.mime_type.assign("text/plain"); | 139 response_->head.mime_type.assign("text/plain"); |
| 141 } | 140 } |
| 142 } | 141 } |
| 143 | 142 |
| 144 state_ = STATE_PROCESSING; | 143 state_ = STATE_PROCESSING; |
| 145 return ProcessResponse(defer); | 144 return ProcessResponse(defer); |
| 146 } | 145 } |
| 147 | 146 |
| 148 // We'll let the original event handler provide a buffer, and reuse it for | 147 // We'll let the original event handler provide a buffer, and reuse it for |
| 149 // subsequent reads until we're done buffering. | 148 // subsequent reads until we're done buffering. |
| 150 bool BufferedResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf, | 149 bool BufferedResourceHandler::OnWillRead(int request_id, |
| 151 int* buf_size, int min_size) { | 150 scoped_refptr<net::IOBuffer>* buf, |
| 151 int* buf_size, |
| 152 int min_size) { |
| 152 if (state_ == STATE_STREAMING) | 153 if (state_ == STATE_STREAMING) |
| 153 return next_handler_->OnWillRead(request_id, buf, buf_size, min_size); | 154 return next_handler_->OnWillRead(request_id, buf, buf_size, min_size); |
| 154 | 155 |
| 155 DCHECK_EQ(-1, min_size); | 156 DCHECK_EQ(-1, min_size); |
| 156 | 157 |
| 157 if (read_buffer_.get()) { | 158 if (read_buffer_.get()) { |
| 158 CHECK_LT(bytes_read_, read_buffer_size_); | 159 CHECK_LT(bytes_read_, read_buffer_size_); |
| 159 *buf = new DependentIOBuffer(read_buffer_.get(), bytes_read_); | 160 *buf = new DependentIOBuffer(read_buffer_.get(), bytes_read_); |
| 160 *buf_size = read_buffer_size_ - bytes_read_; | 161 *buf_size = read_buffer_size_ - bytes_read_; |
| 161 } else { | 162 } else { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 if (!(response_->head.headers.get() && | 234 if (!(response_->head.headers.get() && |
| 234 response_->head.headers->response_code() == 304)) { | 235 response_->head.headers->response_code() == 304)) { |
| 235 if (!SelectNextHandler(defer)) | 236 if (!SelectNextHandler(defer)) |
| 236 return false; | 237 return false; |
| 237 if (*defer) | 238 if (*defer) |
| 238 return true; | 239 return true; |
| 239 } | 240 } |
| 240 | 241 |
| 241 state_ = STATE_REPLAYING; | 242 state_ = STATE_REPLAYING; |
| 242 | 243 |
| 243 int request_id = ResourceRequestInfo::ForRequest(request_)->GetRequestID(); | 244 if (!next_handler_->OnResponseStarted(GetRequestID(), response_.get(), defer)) |
| 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 = ResourceRequestInfoImpl::ForRequest(request_); | 304 ResourceRequestInfoImpl* info = GetRequestInfo(); |
| 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 = ResourceRequestInfo::ForRequest(request_)->GetRequestID(); | 369 int request_id = 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 int request_id = ResourceRequestInfo::ForRequest(request_)->GetRequestID(); | 392 bool result = next_handler_->OnReadCompleted(GetRequestID(), bytes_read_, |
| 393 bool result = next_handler_->OnReadCompleted(request_id, bytes_read_, defer); | 393 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 = ResourceRequestInfoImpl::ForRequest(request_); | 437 ResourceRequestInfoImpl* info = GetRequestInfo(); |
| 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 net::IOBuffer* buf = NULL; | 451 scoped_refptr<net::IOBuffer> buf; |
| 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 |