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 3 // found in the LICENSE file. 4 5 #include "content/browser/loader/buffered_resource_handler.h" 6 7 #include <vector> 8 9 #include "base/bind.h" 10 #include "base/logging.h" 11 #include "base/metrics/histogram.h" 12 #include "base/strings/string_util.h" 13 #include "content/browser/download/download_resource_handler.h" 14 #include "content/browser/download/download_stats.h" 15 #include "content/browser/loader/certificate_resource_handler.h" 16 #include "content/browser/loader/resource_dispatcher_host_impl.h" 17 #include "content/browser/loader/resource_request_info_impl.h" 18 #include "content/browser/loader/stream_resource_handler.h" 19 #include "content/public/browser/content_browser_client.h" 20 #include "content/public/browser/download_item.h" 21 #include "content/public/browser/download_save_info.h" 22 #include "content/public/browser/download_url_parameters.h" 23 #include "content/public/browser/resource_context.h" 24 #include "content/public/browser/resource_dispatcher_host_delegate.h" 25 #include "content/public/common/resource_response.h" 26 #include "content/public/common/webplugininfo.h" 27 #include "net/base/io_buffer.h" 28 #include "net/base/mime_sniffer.h" 29 #include "net/base/mime_util.h" 30 #include "net/base/net_errors.h" 31 #include "net/http/http_content_disposition.h" 32 #include "net/http/http_response_headers.h" 33 34 #if defined(ENABLE_PLUGINS) 35 #include "content/browser/plugin_service_impl.h" 36 #endif 37 38 namespace content { 39 40 namespace { 41 42 void RecordSnifferMetrics(bool sniffing_blocked, 43 bool we_would_like_to_sniff, 44 const std::string& mime_type) { 45 static base::HistogramBase* nosniff_usage(NULL); 46 if (!nosniff_usage) 47 nosniff_usage = base::BooleanHistogram::FactoryGet( 48 "nosniff.usage", base::HistogramBase::kUmaTargetedHistogramFlag); 49 nosniff_usage->AddBoolean(sniffing_blocked); 50 51 if (sniffing_blocked) { 52 static base::HistogramBase* nosniff_otherwise(NULL); 53 if (!nosniff_otherwise) 54 nosniff_otherwise = base::BooleanHistogram::FactoryGet( 55 "nosniff.otherwise", base::HistogramBase::kUmaTargetedHistogramFlag); 56 nosniff_otherwise->AddBoolean(we_would_like_to_sniff); 57 58 static base::HistogramBase* nosniff_empty_mime_type(NULL); 59 if (!nosniff_empty_mime_type) 60 nosniff_empty_mime_type = base::BooleanHistogram::FactoryGet( 61 "nosniff.empty_mime_type", 62 base::HistogramBase::kUmaTargetedHistogramFlag); 63 nosniff_empty_mime_type->AddBoolean(mime_type.empty()); 64 } 65 } 66 67 // Used to write into an existing IOBuffer at a given offset. 68 class DependentIOBuffer : public net::WrappedIOBuffer { 69 public: 70 DependentIOBuffer(net::IOBuffer* buf, int offset) 71 : net::WrappedIOBuffer(buf->data() + offset), 72 buf_(buf) { 73 } 74 75 private: 76 virtual ~DependentIOBuffer() {} 77 78 scoped_refptr<net::IOBuffer> buf_; 79 }; 80 81 } // namespace 82 83 BufferedResourceHandler::BufferedResourceHandler( 84 scoped_ptr<ResourceHandler> next_handler, 85 ResourceDispatcherHostImpl* host, 86 net::URLRequest* request) 87 : LayeredResourceHandler(request, next_handler.Pass()), 88 state_(STATE_STARTING), 89 host_(host), 90 read_buffer_size_(0), 91 bytes_read_(0), 92 must_download_(false), 93 must_download_is_set_(false), 94 weak_ptr_factory_(this) { 95 } 96 97 BufferedResourceHandler::~BufferedResourceHandler() { 98 } 99 100 void BufferedResourceHandler::SetController(ResourceController* controller) { 101 ResourceHandler::SetController(controller); 102 103 // Downstream handlers see us as their ResourceController, which allows us to 104 // consume part or all of the resource response, and then later replay it to 105 // downstream handler. 106 DCHECK(next_handler_.get()); 107 next_handler_->SetController(this); 108 } 109 110 bool BufferedResourceHandler::OnResponseStarted(ResourceResponse* response, 111 bool* defer) { 112 response_ = response; 113 114 // TODO(darin): It is very odd to special-case 304 responses at this level. 115 // We do so only because the code always has, see r24977 and r29355. The 116 // fact that 204 is no longer special-cased this way suggests that 304 need 117 // not be special-cased either. 118 // 119 // The network stack only forwards 304 responses that were not received in 120 // response to a conditional request (i.e., If-Modified-Since). Other 304 121 // responses end up being translated to 200 or whatever the cached response 122 // code happens to be. It should be very rare to see a 304 at this level. 123 124 if (!(response_->head.headers.get() && 125 response_->head.headers->response_code() == 304)) { 126 if (ShouldSniffContent()) { 127 state_ = STATE_BUFFERING; 128 return true; 129 } 130 131 if (response_->head.mime_type.empty()) { 132 // Ugg. The server told us not to sniff the content but didn't give us 133 // a mime type. What's a browser to do? Turns out, we're supposed to 134 // treat the response as "text/plain". This is the most secure option. 135 response_->head.mime_type.assign("text/plain"); 136 } 137 138 // Treat feed types as text/plain. 139 if (response_->head.mime_type == "application/rss+xml" || 140 response_->head.mime_type == "application/atom+xml") { 141 response_->head.mime_type.assign("text/plain"); 142 } 143 } 144 145 state_ = STATE_PROCESSING; 146 return ProcessResponse(defer); 147 } 148 149 // We'll let the original event handler provide a buffer, and reuse it for 150 // subsequent reads until we're done buffering. 151 bool BufferedResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, 152 int* buf_size, 153 int min_size) { 154 if (state_ == STATE_STREAMING) 155 return next_handler_->OnWillRead(buf, buf_size, min_size); 156 157 DCHECK_EQ(-1, min_size); 158 159 if (read_buffer_.get()) { 160 CHECK_LT(bytes_read_, read_buffer_size_); 161 *buf = new DependentIOBuffer(read_buffer_.get(), bytes_read_); 162 *buf_size = read_buffer_size_ - bytes_read_; 163 } else { 164 if (!next_handler_->OnWillRead(buf, buf_size, min_size)) 165 return false; 166 167 read_buffer_ = *buf; 168 read_buffer_size_ = *buf_size; 169 DCHECK_GE(read_buffer_size_, net::kMaxBytesToSniff * 2); 170 } 171 return true; 172 } 173 174 bool BufferedResourceHandler::OnReadCompleted(int bytes_read, bool* defer) { 175 if (state_ == STATE_STREAMING) 176 return next_handler_->OnReadCompleted(bytes_read, defer); 177 178 DCHECK_EQ(state_, STATE_BUFFERING); 179 bytes_read_ += bytes_read; 180 181 if (!DetermineMimeType() && (bytes_read > 0)) 182 return true; // Needs more data, so keep buffering. 183 184 state_ = STATE_PROCESSING; 185 return ProcessResponse(defer); 186 } 187 188 void BufferedResourceHandler::OnResponseCompleted( 189 const net::URLRequestStatus& status, 190 const std::string& security_info, 191 bool* defer) { 192 // Upon completion, act like a pass-through handler in case the downstream 193 // handler defers OnResponseCompleted. 194 state_ = STATE_STREAMING; 195 196 next_handler_->OnResponseCompleted(status, security_info, defer); 197 } 198 199 void BufferedResourceHandler::Resume() { 200 switch (state_) { 201 case STATE_BUFFERING: 202 case STATE_PROCESSING: 203 NOTREACHED(); 204 break; 205 case STATE_REPLAYING: 206 base::MessageLoop::current()->PostTask( 207 FROM_HERE, 208 base::Bind(&BufferedResourceHandler::CallReplayReadCompleted, 209 weak_ptr_factory_.GetWeakPtr())); 210 break; 211 case STATE_STARTING: 212 case STATE_STREAMING: 213 controller()->Resume(); 214 break; 215 } 216 } 217 218 void BufferedResourceHandler::Cancel() { 219 controller()->Cancel(); 220 } 221 222 void BufferedResourceHandler::CancelAndIgnore() { 223 controller()->CancelAndIgnore(); 224 } 225 226 void BufferedResourceHandler::CancelWithError(int error_code) { 227 controller()->CancelWithError(error_code); 228 } 229 230 bool BufferedResourceHandler::ProcessResponse(bool* defer) { 231 DCHECK_EQ(STATE_PROCESSING, state_); 232 233 // TODO(darin): Stop special-casing 304 responses. 234 if (!(response_->head.headers.get() && 235 response_->head.headers->response_code() == 304)) { 236 if (!SelectNextHandler(defer)) 237 return false; 238 if (*defer) 239 return true; 240 } 241 242 state_ = STATE_REPLAYING; 243 244 if (!next_handler_->OnResponseStarted(response_.get(), defer)) 245 return false; 246 247 if (!read_buffer_.get()) { 248 state_ = STATE_STREAMING; 249 return true; 250 } 251 252 if (!*defer) 253 return ReplayReadCompleted(defer); 254 255 return true; 256 } 257 258 bool BufferedResourceHandler::ShouldSniffContent() { 259 const std::string& mime_type = response_->head.mime_type; 260 261 std::string content_type_options; 262 request()->GetResponseHeaderByName("x-content-type-options", 263 &content_type_options); 264 265 bool sniffing_blocked = 266 LowerCaseEqualsASCII(content_type_options, "nosniff"); 267 bool we_would_like_to_sniff = 268 net::ShouldSniffMimeType(request()->url(), mime_type); 269 270 RecordSnifferMetrics(sniffing_blocked, we_would_like_to_sniff, mime_type); 271 272 if (!sniffing_blocked && we_would_like_to_sniff) { 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 275 // over the IPC channel. 276 VLOG(1) << "To buffer: " << request()->url().spec(); 277 return true; 278 } 279 280 return false; 281 } 282 283 bool BufferedResourceHandler::DetermineMimeType() { 284 DCHECK_EQ(STATE_BUFFERING, state_); 285 286 const std::string& type_hint = response_->head.mime_type; 287 288 std::string new_type; 289 bool made_final_decision = 290 net::SniffMimeType(read_buffer_->data(), bytes_read_, request()->url(), 291 type_hint, &new_type); 292 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 295 // that is probably better than the current one. 296 response_->head.mime_type.assign(new_type); 297 298 return made_final_decision; 299 } 300 301 bool BufferedResourceHandler::SelectNextHandler(bool* defer) { 302 DCHECK(!response_->head.mime_type.empty()); 303 304 ResourceRequestInfoImpl* info = GetRequestInfo(); 305 const std::string& mime_type = response_->head.mime_type; 306 307 if (net::IsSupportedCertificateMimeType(mime_type)) { 308 // Install certificate file. 309 info->set_is_download(true); 310 scoped_ptr<ResourceHandler> handler( 311 new CertificateResourceHandler(request())); 312 return UseAlternateNextHandler(handler.Pass(), std::string()); 313 } 314 315 if (!info->allow_download()) 316 return true; 317 318 bool must_download = MustDownload(); 319 if (!must_download) { 320 if (net::IsSupportedMimeType(mime_type)) 321 return true; 322 323 std::string payload; 324 scoped_ptr<ResourceHandler> handler( 325 host_->MaybeInterceptAsStream(request(), response_.get(), &payload)); 326 if (handler) { 327 return UseAlternateNextHandler(handler.Pass(), payload); 328 } 329 330 #if defined(ENABLE_PLUGINS) 331 bool stale; 332 bool has_plugin = HasSupportingPlugin(&stale); 333 if (stale) { 334 // Refresh the plugins asynchronously. 335 PluginServiceImpl::GetInstance()->GetPlugins( 336 base::Bind(&BufferedResourceHandler::OnPluginsLoaded, 337 weak_ptr_factory_.GetWeakPtr())); 338 request()->LogBlockedBy("BufferedResourceHandler"); 339 *defer = true; 340 return true; 341 } 342 if (has_plugin) 343 return true; 344 #endif 345 } 346 347 // Install download handler 348 info->set_is_download(true); 349 scoped_ptr<ResourceHandler> handler( 350 host_->CreateResourceHandlerForDownload( 351 request(), 352 true, // is_content_initiated 353 must_download, 354 DownloadItem::kInvalidId, 355 scoped_ptr<DownloadSaveInfo>(new DownloadSaveInfo()), 356 DownloadUrlParameters::OnStartedCallback())); 357 return UseAlternateNextHandler(handler.Pass(), std::string()); 358 } 359 360 bool BufferedResourceHandler::UseAlternateNextHandler( 361 scoped_ptr<ResourceHandler> new_handler, 362 const std::string& payload_for_old_handler) { 363 if (response_->head.headers.get() && // Can be NULL if FTP. 364 response_->head.headers->response_code() / 100 != 2) { 365 // The response code indicates that this is an error page, but we don't 366 // know how to display the content. We follow Firefox here and show our 367 // own error page instead of triggering a download. 368 // TODO(abarth): We should abstract the response_code test, but this kind 369 // of check is scattered throughout our codebase. 370 request()->CancelWithError(net::ERR_INVALID_RESPONSE); 371 return false; 372 } 373 374 // Inform the original ResourceHandler that this will be handled entirely by 375 // the new ResourceHandler. 376 // TODO(darin): We should probably check the return values of these. 377 bool defer_ignored = false; 378 next_handler_->OnResponseStarted(response_.get(), &defer_ignored); 379 // Although deferring OnResponseStarted is legal, the only downstream handler 380 // which does so is CrossSiteResourceHandler. Cross-site transitions should 381 // not trigger when switching handlers. 382 DCHECK(!defer_ignored); 383 if (payload_for_old_handler.empty()) { 384 net::URLRequestStatus status(net::URLRequestStatus::CANCELED, 385 net::ERR_ABORTED); 386 next_handler_->OnResponseCompleted(status, std::string(), &defer_ignored); 387 DCHECK(!defer_ignored); 388 } else { 389 scoped_refptr<net::IOBuffer> buf; 390 int size = 0; 391 392 next_handler_->OnWillRead(&buf, &size, -1); 393 CHECK_GE(size, static_cast<int>(payload_for_old_handler.length())); 394 395 memcpy(buf->data(), payload_for_old_handler.c_str(), 396 payload_for_old_handler.length()); 397 398 next_handler_->OnReadCompleted(payload_for_old_handler.length(), 399 &defer_ignored); 400 DCHECK(!defer_ignored); 401 402 net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0); 403 next_handler_->OnResponseCompleted(status, std::string(), &defer_ignored); 404 DCHECK(!defer_ignored); 405 } 406 407 // This is handled entirely within the new ResourceHandler, so just reset the 408 // original ResourceHandler. 409 next_handler_ = new_handler.Pass(); 410 next_handler_->SetController(this); 411 412 return CopyReadBufferToNextHandler(); 413 } 414 415 bool BufferedResourceHandler::ReplayReadCompleted(bool* defer) { 416 DCHECK(read_buffer_.get()); 417 418 bool result = next_handler_->OnReadCompleted(bytes_read_, defer); 419 420 read_buffer_ = NULL; 421 read_buffer_size_ = 0; 422 bytes_read_ = 0; 423 424 state_ = STATE_STREAMING; 425 426 return result; 427 } 428 429 void BufferedResourceHandler::CallReplayReadCompleted() { 430 bool defer = false; 431 if (!ReplayReadCompleted(&defer)) { 432 controller()->Cancel(); 433 } else if (!defer) { 434 state_ = STATE_STREAMING; 435 controller()->Resume(); 436 } 437 } 438 439 bool BufferedResourceHandler::MustDownload() { 440 if (must_download_is_set_) 441 return must_download_; 442 443 must_download_is_set_ = true; 444 445 std::string disposition; 446 request()->GetResponseHeaderByName("content-disposition", &disposition); 447 if (!disposition.empty() && 448 net::HttpContentDisposition(disposition, std::string()).is_attachment()) { 449 must_download_ = true; 450 } else if (host_->delegate() && 451 host_->delegate()->ShouldForceDownloadResource( 452 request()->url(), response_->head.mime_type)) { 453 must_download_ = true; 454 } else { 455 must_download_ = false; 456 } 457 458 return must_download_; 459 } 460 461 bool BufferedResourceHandler::HasSupportingPlugin(bool* stale) { 462 #if defined(ENABLE_PLUGINS) 463 ResourceRequestInfoImpl* info = GetRequestInfo(); 464 465 bool allow_wildcard = false; 466 WebPluginInfo plugin; 467 return PluginServiceImpl::GetInstance()->GetPluginInfo( 468 info->GetChildID(), info->GetRenderFrameID(), info->GetContext(), 469 request()->url(), GURL(), response_->head.mime_type, allow_wildcard, 470 stale, &plugin, NULL); 471 #else 472 if (stale) 473 *stale = false; 474 return false; 475 #endif 476 } 477 478 bool BufferedResourceHandler::CopyReadBufferToNextHandler() { 479 if (!read_buffer_.get()) 480 return true; 481 482 scoped_refptr<net::IOBuffer> buf; 483 int buf_len = 0; 484 if (!next_handler_->OnWillRead(&buf, &buf_len, bytes_read_)) 485 return false; 486 487 CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0)); 488 memcpy(buf->data(), read_buffer_->data(), bytes_read_); 489 return true; 490 } 491 492 void BufferedResourceHandler::OnPluginsLoaded( 493 const std::vector<WebPluginInfo>& plugins) { 494 request()->LogUnblocked(); 495 bool defer = false; 496 if (!ProcessResponse(&defer)) { 497 controller()->Cancel(); 498 } else if (!defer) { 499 controller()->Resume(); 500 } 501 } 502 503 } // namespace content 504