| OLD | NEW |
| 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 "net/base/mime_sniffer.h" | 8 #include "net/base/mime_sniffer.h" |
| 9 #include "chrome/browser/renderer_host/download_throttling_resource_handler.h" | 9 #include "chrome/browser/renderer_host/download_throttling_resource_handler.h" |
| 10 #include "chrome/browser/renderer_host/resource_dispatcher_host.h" | 10 #include "chrome/browser/renderer_host/resource_dispatcher_host.h" |
| 11 #include "net/base/mime_sniffer.h" |
| 12 #include "net/base/io_buffer.h" |
| 11 | 13 |
| 12 namespace { | 14 namespace { |
| 13 | 15 |
| 16 const int kMaxBytesToSniff = 512; |
| 17 |
| 14 void RecordSnifferMetrics(bool sniffing_blocked, | 18 void RecordSnifferMetrics(bool sniffing_blocked, |
| 15 bool we_would_like_to_sniff, | 19 bool we_would_like_to_sniff, |
| 16 const std::string& mime_type) { | 20 const std::string& mime_type) { |
| 17 static BooleanHistogram nosniff_usage(L"nosniff.usage"); | 21 static BooleanHistogram nosniff_usage(L"nosniff.usage"); |
| 18 nosniff_usage.SetFlags(kUmaTargetedHistogramFlag); | 22 nosniff_usage.SetFlags(kUmaTargetedHistogramFlag); |
| 19 nosniff_usage.AddBoolean(sniffing_blocked); | 23 nosniff_usage.AddBoolean(sniffing_blocked); |
| 20 | 24 |
| 21 if (sniffing_blocked) { | 25 if (sniffing_blocked) { |
| 22 static BooleanHistogram nosniff_otherwise(L"nosniff.otherwise"); | 26 static BooleanHistogram nosniff_otherwise(L"nosniff.otherwise"); |
| 23 nosniff_otherwise.SetFlags(kUmaTargetedHistogramFlag); | 27 nosniff_otherwise.SetFlags(kUmaTargetedHistogramFlag); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 64 } | 68 } |
| 65 | 69 |
| 66 | 70 |
| 67 bool BufferedResourceHandler::OnResponseCompleted( | 71 bool BufferedResourceHandler::OnResponseCompleted( |
| 68 int request_id, const URLRequestStatus& status) { | 72 int request_id, const URLRequestStatus& status) { |
| 69 return real_handler_->OnResponseCompleted(request_id, status); | 73 return real_handler_->OnResponseCompleted(request_id, status); |
| 70 } | 74 } |
| 71 | 75 |
| 72 // We'll let the original event handler provide a buffer, and reuse it for | 76 // We'll let the original event handler provide a buffer, and reuse it for |
| 73 // subsequent reads until we're done buffering. | 77 // subsequent reads until we're done buffering. |
| 74 bool BufferedResourceHandler::OnWillRead(int request_id, | 78 bool BufferedResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf, |
| 75 char** buf, int* buf_size, | 79 int* buf_size, int min_size) { |
| 76 int min_size) { | |
| 77 if (buffering_) { | 80 if (buffering_) { |
| 78 *buf = read_buffer_ + bytes_read_; | 81 DCHECK(!my_buffer_.get()); |
| 79 *buf_size = read_buffer_size_ - bytes_read_; | 82 my_buffer_ = new net::IOBuffer(kMaxBytesToSniff); |
| 80 DCHECK(*buf_size > 0); | 83 *buf = my_buffer_.get(); |
| 84 *buf_size = kMaxBytesToSniff; |
| 81 return true; | 85 return true; |
| 82 } | 86 } |
| 83 | 87 |
| 84 if (finished_) | 88 if (finished_) |
| 85 return false; | 89 return false; |
| 86 | 90 |
| 87 bool ret = real_handler_->OnWillRead(request_id, buf, buf_size, min_size); | 91 bool ret = real_handler_->OnWillRead(request_id, buf, buf_size, min_size); |
| 88 read_buffer_ = *buf; | 92 read_buffer_ = *buf; |
| 89 read_buffer_size_ = *buf_size; | 93 read_buffer_size_ = *buf_size; |
| 94 DCHECK(read_buffer_size_ >= kMaxBytesToSniff * 2); |
| 90 bytes_read_ = 0; | 95 bytes_read_ = 0; |
| 91 return ret; | 96 return ret; |
| 92 } | 97 } |
| 93 | 98 |
| 94 bool BufferedResourceHandler::OnReadCompleted(int request_id, int* bytes_read) { | 99 bool BufferedResourceHandler::OnReadCompleted(int request_id, int* bytes_read) { |
| 95 if (sniff_content_ || should_buffer_) { | 100 if (sniff_content_ || should_buffer_) { |
| 96 if (KeepBuffering(*bytes_read)) | 101 if (KeepBuffering(*bytes_read)) |
| 97 return true; | 102 return true; |
| 98 | 103 |
| 99 LOG(INFO) << "Finished buffering " << request_->url().spec(); | 104 LOG(INFO) << "Finished buffering " << request_->url().spec(); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 return false; | 166 return false; |
| 162 | 167 |
| 163 // Today, the only reason to buffer the request is to fix the doctype decoding | 168 // Today, the only reason to buffer the request is to fix the doctype decoding |
| 164 // performed by webkit: if there is not enough data it will go to quirks mode. | 169 // performed by webkit: if there is not enough data it will go to quirks mode. |
| 165 // We only expect the doctype check to apply to html documents. | 170 // We only expect the doctype check to apply to html documents. |
| 166 return mime_type == "text/html"; | 171 return mime_type == "text/html"; |
| 167 } | 172 } |
| 168 | 173 |
| 169 bool BufferedResourceHandler::KeepBuffering(int bytes_read) { | 174 bool BufferedResourceHandler::KeepBuffering(int bytes_read) { |
| 170 DCHECK(read_buffer_); | 175 DCHECK(read_buffer_); |
| 176 if (my_buffer_) { |
| 177 // We are using our own buffer to read, update the main buffer. |
| 178 CHECK(bytes_read + bytes_read_ < read_buffer_size_); |
| 179 memcpy(read_buffer_->data() + bytes_read_, my_buffer_->data(), bytes_read); |
| 180 my_buffer_ = NULL; |
| 181 } |
| 171 bytes_read_ += bytes_read; | 182 bytes_read_ += bytes_read; |
| 172 finished_ = (bytes_read == 0); | 183 finished_ = (bytes_read == 0); |
| 173 | 184 |
| 174 if (sniff_content_) { | 185 if (sniff_content_) { |
| 175 std::string type_hint, new_type; | 186 std::string type_hint, new_type; |
| 176 request_->GetMimeType(&type_hint); | 187 request_->GetMimeType(&type_hint); |
| 177 | 188 |
| 178 if (!net::SniffMimeType(read_buffer_, bytes_read_, request_->url(), | 189 if (!net::SniffMimeType(read_buffer_->data(), bytes_read_, |
| 179 type_hint, &new_type)) { | 190 request_->url(), type_hint, &new_type)) { |
| 180 // SniffMimeType() returns false if there is not enough data to determine | 191 // SniffMimeType() returns false if there is not enough data to determine |
| 181 // the mime type. However, even if it returns false, it returns a new type | 192 // the mime type. However, even if it returns false, it returns a new type |
| 182 // that is probably better than the current one. | 193 // that is probably better than the current one. |
| 183 DCHECK(bytes_read_ < 512 /*kMaxBytesToSniff*/); | 194 DCHECK(bytes_read_ < kMaxBytesToSniff); |
| 184 if (!finished_) { | 195 if (!finished_) { |
| 185 buffering_ = true; | 196 buffering_ = true; |
| 186 return true; | 197 return true; |
| 187 } | 198 } |
| 188 } | 199 } |
| 189 sniff_content_ = false; | 200 sniff_content_ = false; |
| 190 response_->response_head.mime_type.assign(new_type); | 201 response_->response_head.mime_type.assign(new_type); |
| 191 | 202 |
| 192 // We just sniffed the mime type, maybe there is a doctype to process. | 203 // We just sniffed the mime type, maybe there is a doctype to process. |
| 193 if (ShouldBuffer(request_->url(), new_type)) | 204 if (ShouldBuffer(request_->url(), new_type)) |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 new DownloadThrottlingResourceHandler(host_, | 247 new DownloadThrottlingResourceHandler(host_, |
| 237 request_, | 248 request_, |
| 238 request_->url().spec(), | 249 request_->url().spec(), |
| 239 info->render_process_host_id, | 250 info->render_process_host_id, |
| 240 info->render_view_id, | 251 info->render_view_id, |
| 241 request_id, | 252 request_id, |
| 242 in_complete); | 253 in_complete); |
| 243 if (bytes_read_) { | 254 if (bytes_read_) { |
| 244 // a Read has already occurred and we need to copy the data into the | 255 // a Read has already occurred and we need to copy the data into the |
| 245 // EventHandler. | 256 // EventHandler. |
| 246 char *buf = NULL; | 257 net::IOBuffer* buf = NULL; |
| 247 int buf_len = 0; | 258 int buf_len = 0; |
| 248 download_handler->OnWillRead(request_id, &buf, &buf_len, bytes_read_); | 259 download_handler->OnWillRead(request_id, &buf, &buf_len, bytes_read_); |
| 249 CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0)); | 260 CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0)); |
| 250 memcpy(buf, read_buffer_, bytes_read_); | 261 memcpy(buf->data(), read_buffer_->data(), bytes_read_); |
| 251 } | 262 } |
| 252 // Update the renderer with the response headers which will cause it to | 263 // Update the renderer with the response headers which will cause it to |
| 253 // cancel the request. | 264 // cancel the request. |
| 254 // TODO(paulg): Send the renderer a response that indicates that the request | 265 // TODO(paulg): Send the renderer a response that indicates that the request |
| 255 // will be handled by an external source (the browser). | 266 // will be handled by an external source (the browser). |
| 256 real_handler_->OnResponseStarted(info->request_id, response_); | 267 real_handler_->OnResponseStarted(info->request_id, response_); |
| 257 real_handler_ = download_handler; | 268 real_handler_ = download_handler; |
| 258 } | 269 } |
| 259 return real_handler_->OnResponseStarted(request_id, response_); | 270 return real_handler_->OnResponseStarted(request_id, response_); |
| 260 } | 271 } |
| 261 | 272 |
| 262 bool BufferedResourceHandler::DidBufferEnough(int bytes_read) { | 273 bool BufferedResourceHandler::DidBufferEnough(int bytes_read) { |
| 263 const int kRequiredLength = 256; | 274 const int kRequiredLength = 256; |
| 264 | 275 |
| 265 return bytes_read >= kRequiredLength; | 276 return bytes_read >= kRequiredLength; |
| 266 } | 277 } |
| OLD | NEW |