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