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/mime_sniffing_resource_handler.h" | 5 #include "content/browser/loader/mime_sniffing_resource_handler.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/location.h" | 11 #include "base/location.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/metrics/histogram_macros.h" | 13 #include "base/metrics/histogram_macros.h" |
14 #include "base/single_thread_task_runner.h" | 14 #include "base/single_thread_task_runner.h" |
15 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
16 #include "base/threading/thread_task_runner_handle.h" | 16 #include "base/threading/thread_task_runner_handle.h" |
17 #include "components/mime_util/mime_util.h" | 17 #include "components/mime_util/mime_util.h" |
18 #include "content/browser/download/download_resource_handler.h" | 18 #include "content/browser/download/download_resource_handler.h" |
19 #include "content/browser/download/download_stats.h" | 19 #include "content/browser/download/download_stats.h" |
20 #include "content/browser/loader/intercepting_resource_handler.h" | 20 #include "content/browser/loader/intercepting_resource_handler.h" |
21 #include "content/browser/loader/resource_dispatcher_host_impl.h" | 21 #include "content/browser/loader/resource_dispatcher_host_impl.h" |
22 #include "content/browser/loader/resource_request_info_impl.h" | 22 #include "content/browser/loader/resource_request_info_impl.h" |
23 #include "content/browser/loader/stream_resource_handler.h" | 23 #include "content/browser/loader/stream_resource_handler.h" |
24 #include "content/public/browser/content_browser_client.h" | 24 #include "content/public/browser/content_browser_client.h" |
25 #include "content/public/browser/download_item.h" | 25 #include "content/public/browser/download_item.h" |
26 #include "content/public/browser/download_save_info.h" | 26 #include "content/public/browser/download_save_info.h" |
27 #include "content/public/browser/download_url_parameters.h" | 27 #include "content/public/browser/download_url_parameters.h" |
28 #include "content/public/browser/plugin_service.h" | 28 #include "content/public/browser/plugin_service.h" |
29 #include "content/public/browser/resource_context.h" | 29 #include "content/public/browser/resource_context.h" |
| 30 #include "content/public/browser/resource_controller.h" |
30 #include "content/public/browser/resource_dispatcher_host_delegate.h" | 31 #include "content/public/browser/resource_dispatcher_host_delegate.h" |
31 #include "content/public/common/resource_response.h" | 32 #include "content/public/common/resource_response.h" |
32 #include "content/public/common/webplugininfo.h" | 33 #include "content/public/common/webplugininfo.h" |
33 #include "net/base/io_buffer.h" | 34 #include "net/base/io_buffer.h" |
34 #include "net/base/mime_sniffer.h" | 35 #include "net/base/mime_sniffer.h" |
35 #include "net/base/mime_util.h" | 36 #include "net/base/mime_util.h" |
36 #include "net/http/http_content_disposition.h" | 37 #include "net/http/http_content_disposition.h" |
37 #include "net/http/http_response_headers.h" | 38 #include "net/http/http_response_headers.h" |
38 #include "net/url_request/url_request.h" | 39 #include "net/url_request/url_request.h" |
39 #include "ppapi/features/features.h" | 40 #include "ppapi/features/features.h" |
(...skipping 18 matching lines...) Expand all Loading... |
58 : net::WrappedIOBuffer(buf->data() + offset), buf_(buf) {} | 59 : net::WrappedIOBuffer(buf->data() + offset), buf_(buf) {} |
59 | 60 |
60 private: | 61 private: |
61 ~DependentIOBuffer() override {} | 62 ~DependentIOBuffer() override {} |
62 | 63 |
63 scoped_refptr<net::IOBuffer> buf_; | 64 scoped_refptr<net::IOBuffer> buf_; |
64 }; | 65 }; |
65 | 66 |
66 } // namespace | 67 } // namespace |
67 | 68 |
| 69 class MimeSniffingResourceHandler::Controller : public ResourceController { |
| 70 public: |
| 71 explicit Controller(MimeSniffingResourceHandler* mime_handler) |
| 72 : mime_handler_(mime_handler) {} |
| 73 |
| 74 void Resume() override { |
| 75 DCHECK(!used_); |
| 76 used_ = true; |
| 77 mime_handler_->ResumeInternal(); |
| 78 } |
| 79 |
| 80 void Cancel() override { |
| 81 DCHECK(!used_); |
| 82 used_ = true; |
| 83 mime_handler_->Cancel(); |
| 84 } |
| 85 |
| 86 void CancelAndIgnore() override { |
| 87 DCHECK(!used_); |
| 88 used_ = true; |
| 89 mime_handler_->CancelAndIgnore(); |
| 90 } |
| 91 |
| 92 void CancelWithError(int error_code) override { |
| 93 DCHECK(!used_); |
| 94 used_ = true; |
| 95 mime_handler_->CancelWithError(error_code); |
| 96 } |
| 97 |
| 98 private: |
| 99 MimeSniffingResourceHandler* mime_handler_; |
| 100 bool used_ = false; |
| 101 |
| 102 DISALLOW_COPY_AND_ASSIGN(Controller); |
| 103 }; |
| 104 |
68 MimeSniffingResourceHandler::MimeSniffingResourceHandler( | 105 MimeSniffingResourceHandler::MimeSniffingResourceHandler( |
69 std::unique_ptr<ResourceHandler> next_handler, | 106 std::unique_ptr<ResourceHandler> next_handler, |
70 ResourceDispatcherHostImpl* host, | 107 ResourceDispatcherHostImpl* host, |
71 PluginService* plugin_service, | 108 PluginService* plugin_service, |
72 InterceptingResourceHandler* intercepting_handler, | 109 InterceptingResourceHandler* intercepting_handler, |
73 net::URLRequest* request, | 110 net::URLRequest* request, |
74 RequestContextType request_context_type) | 111 RequestContextType request_context_type) |
75 : LayeredResourceHandler(request, std::move(next_handler)), | 112 : LayeredResourceHandler(request, std::move(next_handler)), |
76 state_(STATE_STARTING), | 113 state_(STATE_STARTING), |
77 host_(host), | 114 host_(host), |
78 #if BUILDFLAG(ENABLE_PLUGINS) | 115 #if BUILDFLAG(ENABLE_PLUGINS) |
79 plugin_service_(plugin_service), | 116 plugin_service_(plugin_service), |
80 #endif | 117 #endif |
81 must_download_(false), | 118 must_download_(false), |
82 must_download_is_set_(false), | 119 must_download_is_set_(false), |
83 read_buffer_size_(0), | 120 read_buffer_size_(0), |
84 bytes_read_(0), | 121 bytes_read_(0), |
85 intercepting_handler_(intercepting_handler), | 122 intercepting_handler_(intercepting_handler), |
86 request_context_type_(request_context_type), | 123 request_context_type_(request_context_type), |
87 weak_ptr_factory_(this) { | 124 weak_ptr_factory_(this) { |
88 } | 125 } |
89 | 126 |
90 MimeSniffingResourceHandler::~MimeSniffingResourceHandler() {} | 127 MimeSniffingResourceHandler::~MimeSniffingResourceHandler() {} |
91 | 128 |
92 void MimeSniffingResourceHandler::SetController( | 129 void MimeSniffingResourceHandler::OnWillStart( |
93 ResourceController* controller) { | 130 const GURL& url, |
94 ResourceHandler::SetController(controller); | 131 std::unique_ptr<ResourceController> controller) { |
| 132 DCHECK(!has_controller()); |
95 | 133 |
96 // Downstream handlers see the MimeSniffingResourceHandler as their | |
97 // ResourceController, which allows it to consume part or all of the resource | |
98 // response, and then later replay it to downstream handler. | |
99 DCHECK(next_handler_.get()); | |
100 next_handler_->SetController(this); | |
101 } | |
102 | |
103 bool MimeSniffingResourceHandler::OnWillStart(const GURL& url, bool* defer) { | |
104 const char* accept_value = nullptr; | 134 const char* accept_value = nullptr; |
105 switch (GetRequestInfo()->GetResourceType()) { | 135 switch (GetRequestInfo()->GetResourceType()) { |
106 case RESOURCE_TYPE_MAIN_FRAME: | 136 case RESOURCE_TYPE_MAIN_FRAME: |
107 case RESOURCE_TYPE_SUB_FRAME: | 137 case RESOURCE_TYPE_SUB_FRAME: |
108 accept_value = kFrameAcceptHeader; | 138 accept_value = kFrameAcceptHeader; |
109 break; | 139 break; |
110 case RESOURCE_TYPE_STYLESHEET: | 140 case RESOURCE_TYPE_STYLESHEET: |
111 accept_value = kStylesheetAcceptHeader; | 141 accept_value = kStylesheetAcceptHeader; |
112 break; | 142 break; |
113 case RESOURCE_TYPE_FAVICON: | 143 case RESOURCE_TYPE_FAVICON: |
(...skipping 16 matching lines...) Expand all Loading... |
130 accept_value = kDefaultAcceptHeader; | 160 accept_value = kDefaultAcceptHeader; |
131 break; | 161 break; |
132 case RESOURCE_TYPE_LAST_TYPE: | 162 case RESOURCE_TYPE_LAST_TYPE: |
133 NOTREACHED(); | 163 NOTREACHED(); |
134 break; | 164 break; |
135 } | 165 } |
136 | 166 |
137 // The false parameter prevents overwriting an existing accept header value, | 167 // The false parameter prevents overwriting an existing accept header value, |
138 // which is needed because JS can manually set an accept header on an XHR. | 168 // which is needed because JS can manually set an accept header on an XHR. |
139 request()->SetExtraRequestHeaderByName(kAcceptHeader, accept_value, false); | 169 request()->SetExtraRequestHeaderByName(kAcceptHeader, accept_value, false); |
140 return next_handler_->OnWillStart(url, defer); | 170 next_handler_->OnWillStart(url, std::move(controller)); |
141 } | 171 } |
142 | 172 |
143 bool MimeSniffingResourceHandler::OnResponseStarted(ResourceResponse* response, | 173 void MimeSniffingResourceHandler::OnResponseStarted( |
144 bool* defer) { | 174 ResourceResponse* response, |
| 175 std::unique_ptr<ResourceController> controller) { |
145 DCHECK_EQ(STATE_STARTING, state_); | 176 DCHECK_EQ(STATE_STARTING, state_); |
| 177 DCHECK(!has_controller()); |
| 178 |
146 response_ = response; | 179 response_ = response; |
147 | 180 |
148 state_ = STATE_BUFFERING; | 181 state_ = STATE_BUFFERING; |
149 // A 304 response should not contain a Content-Type header (RFC 7232 section | 182 // A 304 response should not contain a Content-Type header (RFC 7232 section |
150 // 4.1). The following code may incorrectly attempt to add a Content-Type to | 183 // 4.1). The following code may incorrectly attempt to add a Content-Type to |
151 // the response, and so must be skipped for 304 responses. | 184 // the response, and so must be skipped for 304 responses. |
152 if (!(response_->head.headers.get() && | 185 if (!(response_->head.headers.get() && |
153 response_->head.headers->response_code() == 304)) { | 186 response_->head.headers->response_code() == 304)) { |
154 if (ShouldSniffContent()) | 187 if (ShouldSniffContent()) { |
155 return true; | 188 controller->Resume(); |
| 189 return; |
| 190 } |
156 | 191 |
157 if (response_->head.mime_type.empty()) { | 192 if (response_->head.mime_type.empty()) { |
158 // Ugg. The server told us not to sniff the content but didn't give us a | 193 // Ugg. The server told us not to sniff the content but didn't give us a |
159 // mime type. What's a browser to do? Turns out, we're supposed to | 194 // mime type. What's a browser to do? Turns out, we're supposed to |
160 // treat the response as "text/plain". This is the most secure option. | 195 // treat the response as "text/plain". This is the most secure option. |
161 response_->head.mime_type.assign("text/plain"); | 196 response_->head.mime_type.assign("text/plain"); |
162 } | 197 } |
163 | 198 |
164 // Treat feed types as text/plain. | 199 // Treat feed types as text/plain. |
165 if (response_->head.mime_type == "application/rss+xml" || | 200 if (response_->head.mime_type == "application/rss+xml" || |
166 response_->head.mime_type == "application/atom+xml") { | 201 response_->head.mime_type == "application/atom+xml") { |
167 response_->head.mime_type.assign("text/plain"); | 202 response_->head.mime_type.assign("text/plain"); |
168 } | 203 } |
169 } | 204 } |
170 | 205 |
171 return ProcessState(defer); | 206 set_controller(std::move(controller)); |
| 207 AdvanceState(); |
172 } | 208 } |
173 | 209 |
174 bool MimeSniffingResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, | 210 bool MimeSniffingResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, |
175 int* buf_size, | 211 int* buf_size, |
176 int min_size) { | 212 int min_size) { |
177 if (state_ == STATE_STREAMING) | 213 if (state_ == STATE_STREAMING) |
178 return next_handler_->OnWillRead(buf, buf_size, min_size); | 214 return next_handler_->OnWillRead(buf, buf_size, min_size); |
179 | 215 |
180 DCHECK_EQ(-1, min_size); | 216 DCHECK_EQ(-1, min_size); |
181 | 217 |
182 if (read_buffer_.get()) { | 218 if (read_buffer_.get()) { |
183 CHECK_LT(bytes_read_, read_buffer_size_); | 219 CHECK_LT(bytes_read_, read_buffer_size_); |
184 *buf = new DependentIOBuffer(read_buffer_.get(), bytes_read_); | 220 *buf = new DependentIOBuffer(read_buffer_.get(), bytes_read_); |
185 *buf_size = read_buffer_size_ - bytes_read_; | 221 *buf_size = read_buffer_size_ - bytes_read_; |
186 } else { | 222 } else { |
187 if (!next_handler_->OnWillRead(buf, buf_size, min_size)) | 223 if (!next_handler_->OnWillRead(buf, buf_size, min_size)) |
188 return false; | 224 return false; |
189 | 225 |
190 read_buffer_ = *buf; | 226 read_buffer_ = *buf; |
191 read_buffer_size_ = *buf_size; | 227 read_buffer_size_ = *buf_size; |
192 DCHECK_GE(read_buffer_size_, net::kMaxBytesToSniff * 2); | 228 DCHECK_GE(read_buffer_size_, net::kMaxBytesToSniff * 2); |
193 } | 229 } |
194 return true; | 230 return true; |
195 } | 231 } |
196 | 232 |
197 bool MimeSniffingResourceHandler::OnReadCompleted(int bytes_read, bool* defer) { | 233 void MimeSniffingResourceHandler::OnReadCompleted( |
198 if (state_ == STATE_STREAMING) | 234 int bytes_read, |
199 return next_handler_->OnReadCompleted(bytes_read, defer); | 235 std::unique_ptr<ResourceController> controller) { |
| 236 DCHECK(!has_controller()); |
| 237 |
| 238 if (state_ == STATE_STREAMING) { |
| 239 next_handler_->OnReadCompleted(bytes_read, std::move(controller)); |
| 240 return; |
| 241 } |
200 | 242 |
201 DCHECK_EQ(state_, STATE_BUFFERING); | 243 DCHECK_EQ(state_, STATE_BUFFERING); |
202 bytes_read_ += bytes_read; | 244 bytes_read_ += bytes_read; |
203 | 245 |
204 const std::string& type_hint = response_->head.mime_type; | 246 const std::string& type_hint = response_->head.mime_type; |
205 | 247 |
206 std::string new_type; | 248 std::string new_type; |
207 bool made_final_decision = | 249 bool made_final_decision = |
208 net::SniffMimeType(read_buffer_->data(), bytes_read_, request()->url(), | 250 net::SniffMimeType(read_buffer_->data(), bytes_read_, request()->url(), |
209 type_hint, &new_type); | 251 type_hint, &new_type); |
210 | 252 |
211 // SniffMimeType() returns false if there is not enough data to determine | 253 // SniffMimeType() returns false if there is not enough data to determine |
212 // the mime type. However, even if it returns false, it returns a new type | 254 // the mime type. However, even if it returns false, it returns a new type |
213 // that is probably better than the current one. | 255 // that is probably better than the current one. |
214 response_->head.mime_type.assign(new_type); | 256 response_->head.mime_type.assign(new_type); |
215 | 257 |
216 if (!made_final_decision && (bytes_read > 0)) | 258 if (!made_final_decision && (bytes_read > 0)) { |
217 return true; | 259 controller->Resume(); |
| 260 return; |
| 261 } |
218 | 262 |
219 return ProcessState(defer); | 263 set_controller(std::move(controller)); |
| 264 AdvanceState(); |
220 } | 265 } |
221 | 266 |
222 void MimeSniffingResourceHandler::OnResponseCompleted( | 267 void MimeSniffingResourceHandler::OnResponseCompleted( |
223 const net::URLRequestStatus& status, | 268 const net::URLRequestStatus& status, |
224 bool* defer) { | 269 std::unique_ptr<ResourceController> resource_controller) { |
225 // Upon completion, act like a pass-through handler in case the downstream | 270 // Upon completion, act like a pass-through handler in case the downstream |
226 // handler defers OnResponseCompleted. | 271 // handler defers OnResponseCompleted. |
227 state_ = STATE_STREAMING; | 272 state_ = STATE_STREAMING; |
228 | 273 |
229 next_handler_->OnResponseCompleted(status, defer); | 274 next_handler_->OnResponseCompleted(status, std::move(resource_controller)); |
230 } | 275 } |
231 | 276 |
232 void MimeSniffingResourceHandler::Resume() { | 277 void MimeSniffingResourceHandler::ResumeInternal() { |
233 // If no information is currently being transmitted to downstream handlers, | 278 // If no information is currently being transmitted to downstream handlers, |
234 // they should not attempt to resume the request. | 279 // they should not attempt to resume the request. |
235 if (state_ == STATE_BUFFERING) { | 280 if (state_ == STATE_BUFFERING) { |
236 NOTREACHED(); | 281 NOTREACHED(); |
237 return; | 282 return; |
238 } | 283 } |
239 | 284 |
240 // If the BufferingHandler is acting as a pass-through handler, just ask the | 285 // If the BufferingHandler is acting as a pass-through handler, just ask the |
241 // upwards ResourceController to resume the request. | 286 // upwards ResourceController to resume the request. |
242 if (state_ == STATE_STARTING || state_ == STATE_STREAMING) { | 287 if (state_ == STATE_STARTING || state_ == STATE_STREAMING) { |
243 controller()->Resume(); | 288 Resume(); |
244 return; | 289 return; |
245 } | 290 } |
246 | 291 |
247 // Otherwise proceed with the replay of the response. If it is successful, | 292 // Otherwise proceed with the replay of the response. If it is successful, |
248 // it will resume the request. | 293 // it will resume the request. |
249 AdvanceState(); | 294 AdvanceState(); |
250 } | 295 } |
251 | 296 |
252 void MimeSniffingResourceHandler::Cancel() { | |
253 controller()->Cancel(); | |
254 } | |
255 | |
256 void MimeSniffingResourceHandler::CancelAndIgnore() { | |
257 controller()->CancelAndIgnore(); | |
258 } | |
259 | |
260 void MimeSniffingResourceHandler::CancelWithError(int error_code) { | |
261 controller()->CancelWithError(error_code); | |
262 } | |
263 | |
264 void MimeSniffingResourceHandler::AdvanceState() { | 297 void MimeSniffingResourceHandler::AdvanceState() { |
265 bool defer = false; | 298 switch (state_) { |
266 if (!ProcessState(&defer)) { | 299 case STATE_BUFFERING: |
267 Cancel(); | 300 MaybeIntercept(); |
268 } else if (!defer) { | 301 break; |
269 DCHECK_EQ(STATE_STREAMING, state_); | 302 case STATE_INTERCEPTION_CHECK_DONE: |
270 controller()->Resume(); | 303 ReplayResponseReceived(); |
| 304 break; |
| 305 case STATE_REPLAYING_RESPONSE_RECEIVED: |
| 306 ReplayReadCompleted(); |
| 307 break; |
| 308 default: |
| 309 NOTREACHED(); |
| 310 break; |
271 } | 311 } |
272 } | 312 } |
273 | 313 |
274 bool MimeSniffingResourceHandler::ProcessState(bool* defer) { | 314 void MimeSniffingResourceHandler::MaybeIntercept() { |
275 bool return_value = true; | |
276 while (!*defer && return_value && state_ != STATE_STREAMING) { | |
277 switch (state_) { | |
278 case STATE_BUFFERING: | |
279 return_value = MaybeIntercept(defer); | |
280 break; | |
281 case STATE_INTERCEPTION_CHECK_DONE: | |
282 return_value = ReplayResponseReceived(defer); | |
283 break; | |
284 case STATE_REPLAYING_RESPONSE_RECEIVED: | |
285 return_value = ReplayReadCompleted(defer); | |
286 break; | |
287 default: | |
288 NOTREACHED(); | |
289 break; | |
290 } | |
291 } | |
292 return return_value; | |
293 } | |
294 | |
295 bool MimeSniffingResourceHandler::MaybeIntercept(bool* defer) { | |
296 DCHECK_EQ(STATE_BUFFERING, state_); | 315 DCHECK_EQ(STATE_BUFFERING, state_); |
297 // If a request that can be intercepted failed the check for interception | 316 // If a request that can be intercepted failed the check for interception |
298 // step, it should be canceled. | 317 // step, it should be canceled. |
299 if (!MaybeStartInterception(defer)) | 318 if (!MaybeStartInterception()) |
300 return false; | 319 return; |
301 | 320 |
302 if (!*defer) | 321 state_ = STATE_INTERCEPTION_CHECK_DONE; |
303 state_ = STATE_INTERCEPTION_CHECK_DONE; | 322 ResumeInternal(); |
304 | |
305 return true; | |
306 } | 323 } |
307 | 324 |
308 bool MimeSniffingResourceHandler::ReplayResponseReceived(bool* defer) { | 325 void MimeSniffingResourceHandler::ReplayResponseReceived() { |
309 DCHECK_EQ(STATE_INTERCEPTION_CHECK_DONE, state_); | 326 DCHECK_EQ(STATE_INTERCEPTION_CHECK_DONE, state_); |
310 state_ = STATE_REPLAYING_RESPONSE_RECEIVED; | 327 state_ = STATE_REPLAYING_RESPONSE_RECEIVED; |
311 return next_handler_->OnResponseStarted(response_.get(), defer); | 328 next_handler_->OnResponseStarted(response_.get(), |
| 329 base::MakeUnique<Controller>(this)); |
312 } | 330 } |
313 | 331 |
314 bool MimeSniffingResourceHandler::ReplayReadCompleted(bool* defer) { | 332 void MimeSniffingResourceHandler::ReplayReadCompleted() { |
315 DCHECK_EQ(STATE_REPLAYING_RESPONSE_RECEIVED, state_); | 333 DCHECK_EQ(STATE_REPLAYING_RESPONSE_RECEIVED, state_); |
316 | 334 |
317 state_ = STATE_STREAMING; | 335 state_ = STATE_STREAMING; |
318 | 336 |
319 if (!read_buffer_.get()) | 337 if (!read_buffer_.get()) { |
320 return true; | 338 ResumeInternal(); |
| 339 return; |
| 340 } |
321 | 341 |
322 bool result = next_handler_->OnReadCompleted(bytes_read_, defer); | 342 int bytes_read = bytes_read_; |
323 | 343 |
324 read_buffer_ = nullptr; | 344 read_buffer_ = nullptr; |
325 read_buffer_size_ = 0; | 345 read_buffer_size_ = 0; |
326 bytes_read_ = 0; | 346 bytes_read_ = 0; |
327 | 347 |
328 return result; | 348 next_handler_->OnReadCompleted(bytes_read, |
| 349 base::MakeUnique<Controller>(this)); |
329 } | 350 } |
330 | 351 |
331 bool MimeSniffingResourceHandler::ShouldSniffContent() { | 352 bool MimeSniffingResourceHandler::ShouldSniffContent() { |
332 if (request_context_type_ == REQUEST_CONTEXT_TYPE_FETCH) { | 353 if (request_context_type_ == REQUEST_CONTEXT_TYPE_FETCH) { |
333 // MIME sniffing should be disabled for a request initiated by fetch(). | 354 // MIME sniffing should be disabled for a request initiated by fetch(). |
334 return false; | 355 return false; |
335 } | 356 } |
336 | 357 |
337 const std::string& mime_type = response_->head.mime_type; | 358 const std::string& mime_type = response_->head.mime_type; |
338 | 359 |
(...skipping 10 matching lines...) Expand all Loading... |
349 // We're going to look at the data before deciding what the content type | 370 // We're going to look at the data before deciding what the content type |
350 // is. That means we need to delay sending the ResponseStarted message | 371 // is. That means we need to delay sending the ResponseStarted message |
351 // over the IPC channel. | 372 // over the IPC channel. |
352 VLOG(1) << "To buffer: " << request()->url().spec(); | 373 VLOG(1) << "To buffer: " << request()->url().spec(); |
353 return true; | 374 return true; |
354 } | 375 } |
355 | 376 |
356 return false; | 377 return false; |
357 } | 378 } |
358 | 379 |
359 bool MimeSniffingResourceHandler::MaybeStartInterception(bool* defer) { | 380 bool MimeSniffingResourceHandler::MaybeStartInterception() { |
360 if (!CanBeIntercepted()) | 381 if (!CanBeIntercepted()) |
361 return true; | 382 return true; |
362 | 383 |
363 DCHECK(!response_->head.mime_type.empty()); | 384 DCHECK(!response_->head.mime_type.empty()); |
364 | 385 |
365 ResourceRequestInfoImpl* info = GetRequestInfo(); | 386 ResourceRequestInfoImpl* info = GetRequestInfo(); |
366 const std::string& mime_type = response_->head.mime_type; | 387 const std::string& mime_type = response_->head.mime_type; |
367 | 388 |
368 // https://crbug.com/568184 - Temporary hack to track servers that aren't | 389 // https://crbug.com/568184 - Temporary hack to track servers that aren't |
369 // setting Content-Disposition when sending x-x509-user-cert and expecting | 390 // setting Content-Disposition when sending x-x509-user-cert and expecting |
370 // the browser to automatically install certificates; this is being | 391 // the browser to automatically install certificates; this is being |
371 // deprecated and will be removed upon full <keygen> removal. | 392 // deprecated and will be removed upon full <keygen> removal. |
372 if (mime_type == "application/x-x509-user-cert" && response_->head.headers) { | 393 if (mime_type == "application/x-x509-user-cert" && response_->head.headers) { |
373 UMA_HISTOGRAM_BOOLEAN( | 394 UMA_HISTOGRAM_BOOLEAN( |
374 "UserCert.ContentDisposition", | 395 "UserCert.ContentDisposition", |
375 response_->head.headers->HasHeader("Content-Disposition")); | 396 response_->head.headers->HasHeader("Content-Disposition")); |
376 } | 397 } |
377 | 398 |
378 // Allow requests for object/embed tags to be intercepted as streams. | 399 // Allow requests for object/embed tags to be intercepted as streams. |
379 if (info->GetResourceType() == content::RESOURCE_TYPE_OBJECT) { | 400 if (info->GetResourceType() == content::RESOURCE_TYPE_OBJECT) { |
380 DCHECK(!info->allow_download()); | 401 DCHECK(!info->allow_download()); |
381 | 402 |
382 bool handled_by_plugin; | 403 bool handled_by_plugin; |
383 if (!CheckForPluginHandler(defer, &handled_by_plugin)) | 404 if (!CheckForPluginHandler(&handled_by_plugin)) |
384 return false; | 405 return false; |
385 if (handled_by_plugin || *defer) | 406 if (handled_by_plugin) |
386 return true; | 407 return true; |
387 } | 408 } |
388 | 409 |
389 if (!info->allow_download()) | 410 if (!info->allow_download()) |
390 return true; | 411 return true; |
391 | 412 |
392 // info->allow_download() == true implies | 413 // info->allow_download() == true implies |
393 // info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME or | 414 // info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME or |
394 // info->GetResourceType() == RESOURCE_TYPE_SUB_FRAME. | 415 // info->GetResourceType() == RESOURCE_TYPE_SUB_FRAME. |
395 DCHECK(info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME || | 416 DCHECK(info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME || |
396 info->GetResourceType() == RESOURCE_TYPE_SUB_FRAME); | 417 info->GetResourceType() == RESOURCE_TYPE_SUB_FRAME); |
397 | 418 |
398 bool must_download = MustDownload(); | 419 bool must_download = MustDownload(); |
399 if (!must_download) { | 420 if (!must_download) { |
400 if (mime_util::IsSupportedMimeType(mime_type)) | 421 if (mime_util::IsSupportedMimeType(mime_type)) |
401 return true; | 422 return true; |
402 | 423 |
403 bool handled_by_plugin; | 424 bool handled_by_plugin; |
404 if (!CheckForPluginHandler(defer, &handled_by_plugin)) | 425 if (!CheckForPluginHandler(&handled_by_plugin)) |
405 return false; | 426 return false; |
406 if (handled_by_plugin || *defer) | 427 if (handled_by_plugin) |
407 return true; | 428 return true; |
408 } | 429 } |
409 | 430 |
410 // This request is a download. | 431 // This request is a download. |
411 | 432 |
412 if (!CheckResponseIsNotProvisional()) | 433 if (!CheckResponseIsNotProvisional()) |
413 return false; | 434 return false; |
414 | 435 |
415 info->set_is_download(true); | 436 info->set_is_download(true); |
416 std::unique_ptr<ResourceHandler> handler( | 437 std::unique_ptr<ResourceHandler> handler( |
417 host_->CreateResourceHandlerForDownload(request(), | 438 host_->CreateResourceHandlerForDownload(request(), |
418 true, // is_content_initiated | 439 true, // is_content_initiated |
419 must_download, | 440 must_download, |
420 false /* is_new_request */)); | 441 false /* is_new_request */)); |
421 intercepting_handler_->UseNewHandler(std::move(handler), std::string()); | 442 intercepting_handler_->UseNewHandler(std::move(handler), std::string()); |
422 return true; | 443 return true; |
423 } | 444 } |
424 | 445 |
425 bool MimeSniffingResourceHandler::CheckForPluginHandler( | 446 bool MimeSniffingResourceHandler::CheckForPluginHandler( |
426 bool* defer, | |
427 bool* handled_by_plugin) { | 447 bool* handled_by_plugin) { |
428 *handled_by_plugin = false; | 448 *handled_by_plugin = false; |
429 #if BUILDFLAG(ENABLE_PLUGINS) | 449 #if BUILDFLAG(ENABLE_PLUGINS) |
430 ResourceRequestInfoImpl* info = GetRequestInfo(); | 450 ResourceRequestInfoImpl* info = GetRequestInfo(); |
431 bool allow_wildcard = false; | 451 bool allow_wildcard = false; |
432 bool stale; | 452 bool stale; |
433 WebPluginInfo plugin; | 453 WebPluginInfo plugin; |
434 bool has_plugin = plugin_service_->GetPluginInfo( | 454 bool has_plugin = plugin_service_->GetPluginInfo( |
435 info->GetChildID(), info->GetRenderFrameID(), info->GetContext(), | 455 info->GetChildID(), info->GetRenderFrameID(), info->GetContext(), |
436 request()->url(), url::Origin(), response_->head.mime_type, | 456 request()->url(), url::Origin(), response_->head.mime_type, |
437 allow_wildcard, &stale, &plugin, NULL); | 457 allow_wildcard, &stale, &plugin, NULL); |
438 | 458 |
439 if (stale) { | 459 if (stale) { |
440 // Refresh the plugins asynchronously. | 460 // Refresh the plugins asynchronously. |
441 plugin_service_->GetPlugins( | 461 plugin_service_->GetPlugins( |
442 base::Bind(&MimeSniffingResourceHandler::OnPluginsLoaded, | 462 base::Bind(&MimeSniffingResourceHandler::OnPluginsLoaded, |
443 weak_ptr_factory_.GetWeakPtr())); | 463 weak_ptr_factory_.GetWeakPtr())); |
444 request()->LogBlockedBy("MimeSniffingResourceHandler"); | 464 request()->LogBlockedBy("MimeSniffingResourceHandler"); |
445 *defer = true; | 465 // Will complete asynchronously. |
446 return true; | 466 return false; |
447 } | 467 } |
448 | 468 |
449 if (has_plugin && plugin.type != WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN) { | 469 if (has_plugin && plugin.type != WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN) { |
450 *handled_by_plugin = true; | 470 *handled_by_plugin = true; |
451 return true; | 471 return true; |
452 } | 472 } |
453 | 473 |
454 // Attempt to intercept the request as a stream. | 474 // Attempt to intercept the request as a stream. |
455 base::FilePath plugin_path; | 475 base::FilePath plugin_path; |
456 if (has_plugin) | 476 if (has_plugin) |
457 plugin_path = plugin.path; | 477 plugin_path = plugin.path; |
458 std::string payload; | 478 std::string payload; |
459 std::unique_ptr<ResourceHandler> handler(host_->MaybeInterceptAsStream( | 479 std::unique_ptr<ResourceHandler> handler(host_->MaybeInterceptAsStream( |
460 plugin_path, request(), response_.get(), &payload)); | 480 plugin_path, request(), response_.get(), &payload)); |
461 if (handler) { | 481 if (handler) { |
462 if (!CheckResponseIsNotProvisional()) | 482 if (!CheckResponseIsNotProvisional()) { |
| 483 Cancel(); |
463 return false; | 484 return false; |
| 485 } |
464 *handled_by_plugin = true; | 486 *handled_by_plugin = true; |
465 intercepting_handler_->UseNewHandler(std::move(handler), payload); | 487 intercepting_handler_->UseNewHandler(std::move(handler), payload); |
466 } | 488 } |
467 #endif | 489 #endif |
468 return true; | 490 return true; |
469 } | 491 } |
470 | 492 |
471 bool MimeSniffingResourceHandler::CanBeIntercepted() { | 493 bool MimeSniffingResourceHandler::CanBeIntercepted() { |
472 if (response_->head.headers.get() && | 494 if (response_->head.headers.get() && |
473 response_->head.headers->response_code() == 304) { | 495 response_->head.headers->response_code() == 304) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
517 | 539 |
518 void MimeSniffingResourceHandler::OnPluginsLoaded( | 540 void MimeSniffingResourceHandler::OnPluginsLoaded( |
519 const std::vector<WebPluginInfo>& plugins) { | 541 const std::vector<WebPluginInfo>& plugins) { |
520 // No longer blocking on the plugins being loaded. | 542 // No longer blocking on the plugins being loaded. |
521 request()->LogUnblocked(); | 543 request()->LogUnblocked(); |
522 if (state_ == STATE_BUFFERING) | 544 if (state_ == STATE_BUFFERING) |
523 AdvanceState(); | 545 AdvanceState(); |
524 } | 546 } |
525 | 547 |
526 } // namespace content | 548 } // namespace content |
OLD | NEW |