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 |