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