| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/service_worker/service_worker_write_to_cache_job.h" | 5 #include "content/browser/service_worker/service_worker_write_to_cache_job.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback.h" | 8 #include "base/callback.h" |
| 9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
| 10 #include "base/thread_task_runner_handle.h" | |
| 11 #include "base/trace_event/trace_event.h" | 10 #include "base/trace_event/trace_event.h" |
| 12 #include "content/browser/service_worker/service_worker_cache_writer.h" | 11 #include "content/browser/service_worker/service_worker_cache_writer.h" |
| 13 #include "content/browser/service_worker/service_worker_context_core.h" | 12 #include "content/browser/service_worker/service_worker_context_core.h" |
| 14 #include "content/browser/service_worker/service_worker_disk_cache.h" | 13 #include "content/browser/service_worker/service_worker_disk_cache.h" |
| 15 #include "content/browser/service_worker/service_worker_metrics.h" | 14 #include "content/browser/service_worker/service_worker_metrics.h" |
| 16 #include "content/common/service_worker/service_worker_types.h" | 15 #include "content/common/service_worker/service_worker_types.h" |
| 17 #include "content/common/service_worker/service_worker_utils.h" | 16 #include "content/common/service_worker/service_worker_utils.h" |
| 18 #include "net/base/io_buffer.h" | 17 #include "net/base/io_buffer.h" |
| 19 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
| 20 #include "net/http/http_network_session.h" | 19 #include "net/http/http_network_session.h" |
| (...skipping 20 matching lines...) Expand all Loading... |
| 41 "The script resource is behind a redirect, which is disallowed."; | 40 "The script resource is behind a redirect, which is disallowed."; |
| 42 const char kServiceWorkerAllowed[] = "Service-Worker-Allowed"; | 41 const char kServiceWorkerAllowed[] = "Service-Worker-Allowed"; |
| 43 | 42 |
| 44 // The net error code used when the job fails the update attempt because the new | 43 // The net error code used when the job fails the update attempt because the new |
| 45 // script is byte-by-byte identical to the incumbent script. This error is shown | 44 // script is byte-by-byte identical to the incumbent script. This error is shown |
| 46 // in DevTools and in netlog, so we want something obscure enough that it won't | 45 // in DevTools and in netlog, so we want something obscure enough that it won't |
| 47 // conflict with a legitimate network error, and not too alarming if seen by | 46 // conflict with a legitimate network error, and not too alarming if seen by |
| 48 // developers. | 47 // developers. |
| 49 // TODO(falken): Redesign this class so we don't have to fail at the network | 48 // TODO(falken): Redesign this class so we don't have to fail at the network |
| 50 // stack layer just to cancel the update. | 49 // stack layer just to cancel the update. |
| 51 const net::Error kIdenticalScriptError = net::ERR_FILE_EXISTS; | 50 const int kIdenticalScriptError = net::ERR_FILE_EXISTS; |
| 52 | 51 |
| 53 } // namespace | 52 } // namespace |
| 54 | 53 |
| 55 ServiceWorkerWriteToCacheJob::ServiceWorkerWriteToCacheJob( | 54 ServiceWorkerWriteToCacheJob::ServiceWorkerWriteToCacheJob( |
| 56 net::URLRequest* request, | 55 net::URLRequest* request, |
| 57 net::NetworkDelegate* network_delegate, | 56 net::NetworkDelegate* network_delegate, |
| 58 ResourceType resource_type, | 57 ResourceType resource_type, |
| 59 base::WeakPtr<ServiceWorkerContextCore> context, | 58 base::WeakPtr<ServiceWorkerContextCore> context, |
| 60 ServiceWorkerVersion* version, | 59 ServiceWorkerVersion* version, |
| 61 int extra_load_flags, | 60 int extra_load_flags, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 73 did_notify_finished_(false), | 72 did_notify_finished_(false), |
| 74 weak_factory_(this) { | 73 weak_factory_(this) { |
| 75 InitNetRequest(extra_load_flags); | 74 InitNetRequest(extra_load_flags); |
| 76 } | 75 } |
| 77 | 76 |
| 78 ServiceWorkerWriteToCacheJob::~ServiceWorkerWriteToCacheJob() { | 77 ServiceWorkerWriteToCacheJob::~ServiceWorkerWriteToCacheJob() { |
| 79 DCHECK_EQ(did_notify_started_, did_notify_finished_); | 78 DCHECK_EQ(did_notify_started_, did_notify_finished_); |
| 80 } | 79 } |
| 81 | 80 |
| 82 void ServiceWorkerWriteToCacheJob::Start() { | 81 void ServiceWorkerWriteToCacheJob::Start() { |
| 83 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 84 FROM_HERE, base::Bind(&ServiceWorkerWriteToCacheJob::StartAsync, | |
| 85 weak_factory_.GetWeakPtr())); | |
| 86 } | |
| 87 | |
| 88 void ServiceWorkerWriteToCacheJob::StartAsync() { | |
| 89 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker", | 82 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker", |
| 90 "ServiceWorkerWriteToCacheJob::ExecutingJob", | 83 "ServiceWorkerWriteToCacheJob::ExecutingJob", |
| 91 this, | 84 this, |
| 92 "URL", request_->url().spec()); | 85 "URL", request_->url().spec()); |
| 93 if (!context_) { | 86 if (!context_) { |
| 94 // NotifyStartError is not safe to call synchronously in Start(). | |
| 95 NotifyStartError( | 87 NotifyStartError( |
| 96 net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED)); | 88 net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED)); |
| 97 return; | 89 return; |
| 98 } | 90 } |
| 99 | 91 |
| 100 // These uses of Unretained are safe because this object is the sole owner of | 92 // These uses of Unretained are safe because this object is the sole owner of |
| 101 // |cache_writer_|, which in turn is the sole user of these callbacks. | 93 // |cache_writer_|, which in turn is the sole user of these callbacks. |
| 102 cache_writer_.reset(new ServiceWorkerCacheWriter( | 94 cache_writer_.reset(new ServiceWorkerCacheWriter( |
| 103 base::Bind(&ServiceWorkerWriteToCacheJob::CreateCacheResponseReader, | 95 base::Bind(&ServiceWorkerWriteToCacheJob::CreateCacheResponseReader, |
| 104 base::Unretained(this)), | 96 base::Unretained(this)), |
| 105 base::Bind(&ServiceWorkerWriteToCacheJob::CreateCacheResponseWriter, | 97 base::Bind(&ServiceWorkerWriteToCacheJob::CreateCacheResponseWriter, |
| 106 base::Unretained(this)))); | 98 base::Unretained(this)))); |
| 107 version_->script_cache_map()->NotifyStartedCaching(url_, resource_id_); | 99 version_->script_cache_map()->NotifyStartedCaching(url_, resource_id_); |
| 108 did_notify_started_ = true; | 100 did_notify_started_ = true; |
| 109 StartNetRequest(); | 101 StartNetRequest(); |
| 110 } | 102 } |
| 111 | 103 |
| 112 void ServiceWorkerWriteToCacheJob::Kill() { | 104 void ServiceWorkerWriteToCacheJob::Kill() { |
| 113 if (has_been_killed_) | 105 if (has_been_killed_) |
| 114 return; | 106 return; |
| 115 weak_factory_.InvalidateWeakPtrs(); | 107 weak_factory_.InvalidateWeakPtrs(); |
| 116 has_been_killed_ = true; | 108 has_been_killed_ = true; |
| 117 net_request_.reset(); | 109 net_request_.reset(); |
| 118 if (did_notify_started_) { | 110 if (did_notify_started_) { |
| 119 net::Error error = NotifyFinishedCaching( | 111 NotifyFinishedCaching(net::URLRequestStatus::FromError(net::ERR_ABORTED), |
| 120 net::URLRequestStatus::FromError(net::ERR_ABORTED), kKilledError); | 112 kKilledError); |
| 121 DCHECK_EQ(net::ERR_ABORTED, error); | |
| 122 } | 113 } |
| 123 writer_.reset(); | 114 writer_.reset(); |
| 124 context_.reset(); | 115 context_.reset(); |
| 125 net::URLRequestJob::Kill(); | 116 net::URLRequestJob::Kill(); |
| 126 } | 117 } |
| 127 | 118 |
| 128 net::LoadState ServiceWorkerWriteToCacheJob::GetLoadState() const { | 119 net::LoadState ServiceWorkerWriteToCacheJob::GetLoadState() const { |
| 129 if (writer_ && writer_->IsWritePending()) | 120 if (writer_ && writer_->IsWritePending()) |
| 130 return net::LOAD_STATE_WAITING_FOR_APPCACHE; | 121 return net::LOAD_STATE_WAITING_FOR_APPCACHE; |
| 131 if (net_request_) | 122 if (net_request_) |
| (...skipping 26 matching lines...) Expand all Loading... |
| 158 return http_info()->headers->response_code(); | 149 return http_info()->headers->response_code(); |
| 159 } | 150 } |
| 160 | 151 |
| 161 void ServiceWorkerWriteToCacheJob::SetExtraRequestHeaders( | 152 void ServiceWorkerWriteToCacheJob::SetExtraRequestHeaders( |
| 162 const net::HttpRequestHeaders& headers) { | 153 const net::HttpRequestHeaders& headers) { |
| 163 std::string value; | 154 std::string value; |
| 164 DCHECK(!headers.GetHeader(net::HttpRequestHeaders::kRange, &value)); | 155 DCHECK(!headers.GetHeader(net::HttpRequestHeaders::kRange, &value)); |
| 165 net_request_->SetExtraRequestHeaders(headers); | 156 net_request_->SetExtraRequestHeaders(headers); |
| 166 } | 157 } |
| 167 | 158 |
| 168 int ServiceWorkerWriteToCacheJob::ReadRawData(net::IOBuffer* buf, | 159 bool ServiceWorkerWriteToCacheJob::ReadRawData(net::IOBuffer* buf, |
| 169 int buf_size) { | 160 int buf_size, |
| 170 int bytes_read = 0; | 161 int* bytes_read) { |
| 171 net::URLRequestStatus status = ReadNetData(buf, buf_size, &bytes_read); | 162 net::URLRequestStatus status = ReadNetData(buf, buf_size, bytes_read); |
| 163 SetStatus(status); |
| 172 if (status.is_io_pending()) | 164 if (status.is_io_pending()) |
| 173 return net::ERR_IO_PENDING; | 165 return false; |
| 174 | 166 |
| 175 if (!status.is_success()) { | 167 if (!status.is_success()) { |
| 176 net::Error error = NotifyFinishedCaching(status, kFetchScriptError); | 168 NotifyDoneHelper(status, kFetchScriptError); |
| 177 DCHECK_EQ(status.error(), error); | 169 return false; |
| 178 return error; | |
| 179 } | 170 } |
| 180 | 171 |
| 181 return HandleNetData(bytes_read); | 172 HandleNetData(*bytes_read); |
| 173 status = GetStatus(); |
| 174 |
| 175 // Synchronous EOFs that do not replace the incumbent entry are considered |
| 176 // failures. Since normally the URLRequestJob's status would be set by |
| 177 // ReadNetData or HandleNetData, this code has to manually fix up the status |
| 178 // to match the failure this function is about to return. |
| 179 if (status.status() == net::URLRequestStatus::SUCCESS && *bytes_read == 0 && |
| 180 !cache_writer_->did_replace()) { |
| 181 status = net::URLRequestStatus::FromError(kIdenticalScriptError); |
| 182 } |
| 183 |
| 184 if (!status.is_success()) { |
| 185 NotifyDoneHelper(status, ""); |
| 186 return false; |
| 187 } |
| 188 |
| 189 // Since URLRequestStatus::is_success() means "SUCCESS or IO_PENDING", but the |
| 190 // contract of this function is "return true for synchronous successes only", |
| 191 // it is important to test against SUCCESS explicitly here. |
| 192 return status.status() == net::URLRequestStatus::SUCCESS; |
| 182 } | 193 } |
| 183 | 194 |
| 184 const net::HttpResponseInfo* ServiceWorkerWriteToCacheJob::http_info() const { | 195 const net::HttpResponseInfo* ServiceWorkerWriteToCacheJob::http_info() const { |
| 185 return http_info_.get(); | 196 return http_info_.get(); |
| 186 } | 197 } |
| 187 | 198 |
| 188 void ServiceWorkerWriteToCacheJob::InitNetRequest( | 199 void ServiceWorkerWriteToCacheJob::InitNetRequest( |
| 189 int extra_load_flags) { | 200 int extra_load_flags) { |
| 190 DCHECK(request()); | 201 DCHECK(request()); |
| 191 net_request_ = request()->context()->CreateRequest( | 202 net_request_ = request()->context()->CreateRequest( |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 226 } | 237 } |
| 227 | 238 |
| 228 void ServiceWorkerWriteToCacheJob::OnReceivedRedirect( | 239 void ServiceWorkerWriteToCacheJob::OnReceivedRedirect( |
| 229 net::URLRequest* request, | 240 net::URLRequest* request, |
| 230 const net::RedirectInfo& redirect_info, | 241 const net::RedirectInfo& redirect_info, |
| 231 bool* defer_redirect) { | 242 bool* defer_redirect) { |
| 232 DCHECK_EQ(net_request_.get(), request); | 243 DCHECK_EQ(net_request_.get(), request); |
| 233 TRACE_EVENT0("ServiceWorker", | 244 TRACE_EVENT0("ServiceWorker", |
| 234 "ServiceWorkerWriteToCacheJob::OnReceivedRedirect"); | 245 "ServiceWorkerWriteToCacheJob::OnReceivedRedirect"); |
| 235 // Script resources can't redirect. | 246 // Script resources can't redirect. |
| 236 NotifyStartErrorHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED, | 247 NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED, |
| 237 net::ERR_UNSAFE_REDIRECT), | 248 net::ERR_UNSAFE_REDIRECT), |
| 238 kRedirectError); | 249 kRedirectError); |
| 239 } | 250 } |
| 240 | 251 |
| 241 void ServiceWorkerWriteToCacheJob::OnAuthRequired( | 252 void ServiceWorkerWriteToCacheJob::OnAuthRequired( |
| 242 net::URLRequest* request, | 253 net::URLRequest* request, |
| 243 net::AuthChallengeInfo* auth_info) { | 254 net::AuthChallengeInfo* auth_info) { |
| 244 DCHECK_EQ(net_request_.get(), request); | 255 DCHECK_EQ(net_request_.get(), request); |
| 245 TRACE_EVENT0("ServiceWorker", | 256 TRACE_EVENT0("ServiceWorker", |
| 246 "ServiceWorkerWriteToCacheJob::OnAuthRequired"); | 257 "ServiceWorkerWriteToCacheJob::OnAuthRequired"); |
| 247 // TODO(michaeln): Pass this thru to our jobs client. | 258 // TODO(michaeln): Pass this thru to our jobs client. |
| 248 NotifyStartErrorHelper( | 259 NotifyDoneHelper( |
| 249 net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED), | 260 net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED), |
| 250 kClientAuthenticationError); | 261 kClientAuthenticationError); |
| 251 } | 262 } |
| 252 | 263 |
| 253 void ServiceWorkerWriteToCacheJob::OnCertificateRequested( | 264 void ServiceWorkerWriteToCacheJob::OnCertificateRequested( |
| 254 net::URLRequest* request, | 265 net::URLRequest* request, |
| 255 net::SSLCertRequestInfo* cert_request_info) { | 266 net::SSLCertRequestInfo* cert_request_info) { |
| 256 DCHECK_EQ(net_request_.get(), request); | 267 DCHECK_EQ(net_request_.get(), request); |
| 257 TRACE_EVENT0("ServiceWorker", | 268 TRACE_EVENT0("ServiceWorker", |
| 258 "ServiceWorkerWriteToCacheJob::OnCertificateRequested"); | 269 "ServiceWorkerWriteToCacheJob::OnCertificateRequested"); |
| 259 // TODO(michaeln): Pass this thru to our jobs client. | 270 // TODO(michaeln): Pass this thru to our jobs client. |
| 260 // see NotifyCertificateRequested. | 271 // see NotifyCertificateRequested. |
| 261 NotifyStartErrorHelper( | 272 NotifyDoneHelper( |
| 262 net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED), | 273 net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED), |
| 263 kClientAuthenticationError); | 274 kClientAuthenticationError); |
| 264 } | 275 } |
| 265 | 276 |
| 266 void ServiceWorkerWriteToCacheJob::OnSSLCertificateError( | 277 void ServiceWorkerWriteToCacheJob::OnSSLCertificateError( |
| 267 net::URLRequest* request, | 278 net::URLRequest* request, |
| 268 const net::SSLInfo& ssl_info, | 279 const net::SSLInfo& ssl_info, |
| 269 bool fatal) { | 280 bool fatal) { |
| 270 DCHECK_EQ(net_request_.get(), request); | 281 DCHECK_EQ(net_request_.get(), request); |
| 271 TRACE_EVENT0("ServiceWorker", | 282 TRACE_EVENT0("ServiceWorker", |
| 272 "ServiceWorkerWriteToCacheJob::OnSSLCertificateError"); | 283 "ServiceWorkerWriteToCacheJob::OnSSLCertificateError"); |
| 273 // TODO(michaeln): Pass this thru to our jobs client, | 284 // TODO(michaeln): Pass this thru to our jobs client, |
| 274 // see NotifySSLCertificateError. | 285 // see NotifySSLCertificateError. |
| 275 NotifyStartErrorHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED, | 286 NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED, |
| 276 net::ERR_INSECURE_RESPONSE), | 287 net::ERR_INSECURE_RESPONSE), |
| 277 kSSLError); | 288 kSSLError); |
| 278 } | 289 } |
| 279 | 290 |
| 280 void ServiceWorkerWriteToCacheJob::OnBeforeNetworkStart( | 291 void ServiceWorkerWriteToCacheJob::OnBeforeNetworkStart( |
| 281 net::URLRequest* request, | 292 net::URLRequest* request, |
| 282 bool* defer) { | 293 bool* defer) { |
| 283 DCHECK_EQ(net_request_.get(), request); | 294 DCHECK_EQ(net_request_.get(), request); |
| 284 TRACE_EVENT0("ServiceWorker", | 295 TRACE_EVENT0("ServiceWorker", |
| 285 "ServiceWorkerWriteToCacheJob::OnBeforeNetworkStart"); | 296 "ServiceWorkerWriteToCacheJob::OnBeforeNetworkStart"); |
| 286 NotifyBeforeNetworkStart(defer); | 297 NotifyBeforeNetworkStart(defer); |
| 287 } | 298 } |
| 288 | 299 |
| 289 void ServiceWorkerWriteToCacheJob::OnResponseStarted( | 300 void ServiceWorkerWriteToCacheJob::OnResponseStarted( |
| 290 net::URLRequest* request) { | 301 net::URLRequest* request) { |
| 291 DCHECK_EQ(net_request_.get(), request); | 302 DCHECK_EQ(net_request_.get(), request); |
| 292 if (!request->status().is_success()) { | 303 if (!request->status().is_success()) { |
| 293 NotifyStartErrorHelper(request->status(), kFetchScriptError); | 304 NotifyDoneHelper(request->status(), kFetchScriptError); |
| 294 return; | 305 return; |
| 295 } | 306 } |
| 296 if (request->GetResponseCode() / 100 != 2) { | 307 if (request->GetResponseCode() / 100 != 2) { |
| 297 std::string error_message = | 308 std::string error_message = |
| 298 base::StringPrintf(kBadHTTPResponseError, request->GetResponseCode()); | 309 base::StringPrintf(kBadHTTPResponseError, request->GetResponseCode()); |
| 299 NotifyStartErrorHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED, | 310 NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED, |
| 300 net::ERR_INVALID_RESPONSE), | 311 net::ERR_INVALID_RESPONSE), |
| 301 error_message); | 312 error_message); |
| 302 // TODO(michaeln): Instead of error'ing immediately, send the net | 313 // TODO(michaeln): Instead of error'ing immediately, send the net |
| 303 // response to our consumer, just don't cache it? | 314 // response to our consumer, just don't cache it? |
| 304 return; | 315 return; |
| 305 } | 316 } |
| 306 // OnSSLCertificateError is not called when the HTTPS connection is reused. | 317 // OnSSLCertificateError is not called when the HTTPS connection is reused. |
| 307 // So we check cert_status here. | 318 // So we check cert_status here. |
| 308 if (net::IsCertStatusError(request->ssl_info().cert_status)) { | 319 if (net::IsCertStatusError(request->ssl_info().cert_status)) { |
| 309 const net::HttpNetworkSession::Params* session_params = | 320 const net::HttpNetworkSession::Params* session_params = |
| 310 request->context()->GetNetworkSessionParams(); | 321 request->context()->GetNetworkSessionParams(); |
| 311 if (!session_params || !session_params->ignore_certificate_errors) { | 322 if (!session_params || !session_params->ignore_certificate_errors) { |
| 312 NotifyStartErrorHelper( | 323 NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED, |
| 313 net::URLRequestStatus(net::URLRequestStatus::FAILED, | 324 net::ERR_INSECURE_RESPONSE), |
| 314 net::ERR_INSECURE_RESPONSE), | 325 kSSLError); |
| 315 kSSLError); | |
| 316 return; | 326 return; |
| 317 } | 327 } |
| 318 } | 328 } |
| 319 | 329 |
| 320 if (version_->script_url() == url_) { | 330 if (version_->script_url() == url_) { |
| 321 std::string mime_type; | 331 std::string mime_type; |
| 322 request->GetMimeType(&mime_type); | 332 request->GetMimeType(&mime_type); |
| 323 if (mime_type != "application/x-javascript" && | 333 if (mime_type != "application/x-javascript" && |
| 324 mime_type != "text/javascript" && | 334 mime_type != "text/javascript" && |
| 325 mime_type != "application/javascript") { | 335 mime_type != "application/javascript") { |
| 326 std::string error_message = | 336 std::string error_message = |
| 327 mime_type.empty() | 337 mime_type.empty() |
| 328 ? kNoMIMEError | 338 ? kNoMIMEError |
| 329 : base::StringPrintf(kBadMIMEError, mime_type.c_str()); | 339 : base::StringPrintf(kBadMIMEError, mime_type.c_str()); |
| 330 NotifyStartErrorHelper( | 340 NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED, |
| 331 net::URLRequestStatus(net::URLRequestStatus::FAILED, | 341 net::ERR_INSECURE_RESPONSE), |
| 332 net::ERR_INSECURE_RESPONSE), | 342 error_message); |
| 333 error_message); | |
| 334 return; | 343 return; |
| 335 } | 344 } |
| 336 | 345 |
| 337 if (!CheckPathRestriction(request)) | 346 if (!CheckPathRestriction(request)) |
| 338 return; | 347 return; |
| 339 | 348 |
| 340 version_->SetMainScriptHttpResponseInfo(net_request_->response_info()); | 349 version_->SetMainScriptHttpResponseInfo(net_request_->response_info()); |
| 341 } | 350 } |
| 342 | 351 |
| 343 if (net_request_->response_info().network_accessed) | 352 if (net_request_->response_info().network_accessed) |
| (...skipping 15 matching lines...) Expand all Loading... |
| 359 void ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete(net::Error error) { | 368 void ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete(net::Error error) { |
| 360 DCHECK_NE(net::ERR_IO_PENDING, error); | 369 DCHECK_NE(net::ERR_IO_PENDING, error); |
| 361 if (error != net::OK) { | 370 if (error != net::OK) { |
| 362 NotifyStartError(net::URLRequestStatus::FromError(error)); | 371 NotifyStartError(net::URLRequestStatus::FromError(error)); |
| 363 return; | 372 return; |
| 364 } | 373 } |
| 365 SetStatus(net::URLRequestStatus()); | 374 SetStatus(net::URLRequestStatus()); |
| 366 NotifyHeadersComplete(); | 375 NotifyHeadersComplete(); |
| 367 } | 376 } |
| 368 | 377 |
| 378 void ServiceWorkerWriteToCacheJob::HandleNetData(int bytes_read) { |
| 379 io_buffer_bytes_ = bytes_read; |
| 380 net::Error error = cache_writer_->MaybeWriteData( |
| 381 io_buffer_.get(), bytes_read, |
| 382 base::Bind(&ServiceWorkerWriteToCacheJob::OnWriteDataComplete, |
| 383 weak_factory_.GetWeakPtr())); |
| 384 SetStatus(net::URLRequestStatus::FromError(error)); |
| 385 |
| 386 // In case of ERR_IO_PENDING, this logic is done in OnWriteDataComplete. |
| 387 if (error != net::ERR_IO_PENDING && bytes_read == 0) { |
| 388 NotifyFinishedCaching(net::URLRequestStatus::FromError(error), |
| 389 std::string()); |
| 390 } |
| 391 } |
| 392 |
| 369 void ServiceWorkerWriteToCacheJob::OnWriteDataComplete(net::Error error) { | 393 void ServiceWorkerWriteToCacheJob::OnWriteDataComplete(net::Error error) { |
| 370 SetStatus(net::URLRequestStatus::FromError(error)); | 394 SetStatus(net::URLRequestStatus::FromError(error)); |
| 371 DCHECK_NE(net::ERR_IO_PENDING, error); | 395 DCHECK_NE(net::ERR_IO_PENDING, error); |
| 372 if (io_buffer_bytes_ == 0) | 396 if (io_buffer_bytes_ == 0) { |
| 373 error = NotifyFinishedCaching(net::URLRequestStatus::FromError(error), ""); | 397 NotifyDoneHelper(net::URLRequestStatus::FromError(error), std::string()); |
| 374 ReadRawDataComplete(error == net::OK ? io_buffer_bytes_ : error); | 398 } |
| 399 NotifyReadComplete(error == net::OK ? io_buffer_bytes_ : error); |
| 375 } | 400 } |
| 376 | 401 |
| 377 void ServiceWorkerWriteToCacheJob::OnReadCompleted(net::URLRequest* request, | 402 void ServiceWorkerWriteToCacheJob::OnReadCompleted(net::URLRequest* request, |
| 378 int bytes_read) { | 403 int bytes_read) { |
| 379 DCHECK_EQ(net_request_.get(), request); | 404 DCHECK_EQ(net_request_.get(), request); |
| 380 | |
| 381 int result; | |
| 382 if (bytes_read < 0) { | 405 if (bytes_read < 0) { |
| 383 DCHECK(!request->status().is_success()); | 406 DCHECK(!request->status().is_success()); |
| 384 result = NotifyFinishedCaching(request->status(), kFetchScriptError); | 407 NotifyDoneHelper(request->status(), kFetchScriptError); |
| 385 } else { | 408 return; |
| 386 result = HandleNetData(bytes_read); | |
| 387 } | 409 } |
| 388 | 410 HandleNetData(bytes_read); |
| 389 // ReadRawDataComplete will be called in OnWriteDataComplete, so return early. | 411 // HandleNetData can cause status of this job to change. If the status changes |
| 390 if (result == net::ERR_IO_PENDING) | 412 // to IO_PENDING, that means HandleNetData has pending IO, and |
| 391 return; | 413 // NotifyReadComplete will be called later by the appropriate callback. |
| 392 | 414 if (!GetStatus().is_io_pending()) { |
| 393 ReadRawDataComplete(result); | 415 int result = GetStatus().status() == net::URLRequestStatus::SUCCESS |
| 416 ? bytes_read |
| 417 : GetStatus().error(); |
| 418 // If bytes_read is 0, HandleNetData synchronously completed and this job is |
| 419 // at EOF. |
| 420 if (bytes_read == 0) |
| 421 NotifyDoneHelper(GetStatus(), std::string()); |
| 422 NotifyReadComplete(result); |
| 423 } |
| 394 } | 424 } |
| 395 | 425 |
| 396 bool ServiceWorkerWriteToCacheJob::CheckPathRestriction( | 426 bool ServiceWorkerWriteToCacheJob::CheckPathRestriction( |
| 397 net::URLRequest* request) { | 427 net::URLRequest* request) { |
| 398 std::string service_worker_allowed; | 428 std::string service_worker_allowed; |
| 399 const net::HttpResponseHeaders* headers = request->response_headers(); | 429 const net::HttpResponseHeaders* headers = request->response_headers(); |
| 400 bool has_header = headers->EnumerateHeader(nullptr, kServiceWorkerAllowed, | 430 bool has_header = headers->EnumerateHeader(nullptr, kServiceWorkerAllowed, |
| 401 &service_worker_allowed); | 431 &service_worker_allowed); |
| 402 | 432 |
| 403 std::string error_message; | 433 std::string error_message; |
| 404 if (!ServiceWorkerUtils::IsPathRestrictionSatisfied( | 434 if (!ServiceWorkerUtils::IsPathRestrictionSatisfied( |
| 405 version_->scope(), url_, | 435 version_->scope(), url_, |
| 406 has_header ? &service_worker_allowed : nullptr, &error_message)) { | 436 has_header ? &service_worker_allowed : nullptr, &error_message)) { |
| 407 NotifyStartErrorHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED, | 437 NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED, |
| 408 net::ERR_INSECURE_RESPONSE), | 438 net::ERR_INSECURE_RESPONSE), |
| 409 error_message); | 439 error_message); |
| 410 return false; | 440 return false; |
| 411 } | 441 } |
| 412 return true; | 442 return true; |
| 413 } | 443 } |
| 414 | 444 |
| 415 int ServiceWorkerWriteToCacheJob::HandleNetData(int bytes_read) { | 445 void ServiceWorkerWriteToCacheJob::NotifyDoneHelper( |
| 416 io_buffer_bytes_ = bytes_read; | |
| 417 net::Error error = cache_writer_->MaybeWriteData( | |
| 418 io_buffer_.get(), bytes_read, | |
| 419 base::Bind(&ServiceWorkerWriteToCacheJob::OnWriteDataComplete, | |
| 420 weak_factory_.GetWeakPtr())); | |
| 421 | |
| 422 // In case of ERR_IO_PENDING, this logic is done in OnWriteDataComplete. | |
| 423 if (error != net::ERR_IO_PENDING && bytes_read == 0) { | |
| 424 error = NotifyFinishedCaching(net::URLRequestStatus::FromError(error), | |
| 425 std::string()); | |
| 426 } | |
| 427 return error == net::OK ? bytes_read : error; | |
| 428 } | |
| 429 | |
| 430 void ServiceWorkerWriteToCacheJob::NotifyStartErrorHelper( | |
| 431 const net::URLRequestStatus& status, | 446 const net::URLRequestStatus& status, |
| 432 const std::string& status_message) { | 447 const std::string& status_message) { |
| 433 DCHECK(!status.is_io_pending()); | 448 DCHECK(!status.is_io_pending()); |
| 434 | 449 |
| 435 net::Error error = NotifyFinishedCaching(status, status_message); | 450 // Note that NotifyFinishedCaching has logic in it to detect the special case |
| 436 // The special case mentioned in NotifyFinishedCaching about script being | 451 // mentioned below as well. |
| 437 // identical does not apply here, since the entire body needs to be read | 452 NotifyFinishedCaching(status, status_message); |
| 438 // before this is relevant. | |
| 439 DCHECK_EQ(status.error(), error); | |
| 440 | 453 |
| 441 net::URLRequestStatus reported_status = status; | 454 net::URLRequestStatus reported_status = status; |
| 442 std::string reported_status_message = status_message; | 455 std::string reported_status_message = status_message; |
| 443 | 456 |
| 457 // A strange special case: requests that successfully fetch the entire |
| 458 // ServiceWorker and write it back, but which did not replace the incumbent |
| 459 // script because the new script was identical, are considered to have failed. |
| 460 if (status.is_success() && !cache_writer_->did_replace()) { |
| 461 reported_status = net::URLRequestStatus::FromError(kIdenticalScriptError); |
| 462 reported_status_message = ""; |
| 463 } |
| 464 |
| 444 SetStatus(reported_status); | 465 SetStatus(reported_status); |
| 445 NotifyStartError(reported_status); | 466 NotifyDone(reported_status); |
| 446 } | 467 } |
| 447 | 468 |
| 448 net::Error ServiceWorkerWriteToCacheJob::NotifyFinishedCaching( | 469 void ServiceWorkerWriteToCacheJob::NotifyFinishedCaching( |
| 449 net::URLRequestStatus status, | 470 net::URLRequestStatus status, |
| 450 const std::string& status_message) { | 471 const std::string& status_message) { |
| 451 net::Error result = static_cast<net::Error>(status.error()); | |
| 452 if (did_notify_finished_) | 472 if (did_notify_finished_) |
| 453 return result; | 473 return; |
| 454 | |
| 455 int size = -1; | |
| 456 if (status.is_success()) | |
| 457 size = cache_writer_->bytes_written(); | |
| 458 | 474 |
| 459 // If all the calls to MaybeWriteHeaders/MaybeWriteData succeeded, but the | 475 // If all the calls to MaybeWriteHeaders/MaybeWriteData succeeded, but the |
| 460 // incumbent entry wasn't actually replaced because the new entry was | 476 // incumbent entry wasn't actually replaced because the new entry was |
| 461 // equivalent, the new version didn't actually install because it already | 477 // equivalent, the new version didn't actually install because it already |
| 462 // exists. | 478 // exists. |
| 463 if (status.status() == net::URLRequestStatus::SUCCESS && | 479 if (status.status() == net::URLRequestStatus::SUCCESS && |
| 464 !cache_writer_->did_replace()) { | 480 !cache_writer_->did_replace()) { |
| 465 result = kIdenticalScriptError; | 481 status = net::URLRequestStatus::FromError(kIdenticalScriptError); |
| 466 status = net::URLRequestStatus::FromError(result); | |
| 467 version_->SetStartWorkerStatusCode(SERVICE_WORKER_ERROR_EXISTS); | 482 version_->SetStartWorkerStatusCode(SERVICE_WORKER_ERROR_EXISTS); |
| 468 version_->script_cache_map()->NotifyFinishedCaching(url_, size, status, | |
| 469 std::string()); | |
| 470 } else { | |
| 471 version_->script_cache_map()->NotifyFinishedCaching(url_, size, status, | |
| 472 status_message); | |
| 473 } | 483 } |
| 474 | 484 |
| 485 int size = -1; |
| 486 if (status.is_success()) |
| 487 size = cache_writer_->bytes_written(); |
| 488 |
| 489 version_->script_cache_map()->NotifyFinishedCaching(url_, size, status, |
| 490 status_message); |
| 475 did_notify_finished_ = true; | 491 did_notify_finished_ = true; |
| 476 return result; | |
| 477 } | 492 } |
| 478 | 493 |
| 479 scoped_ptr<ServiceWorkerResponseReader> | 494 scoped_ptr<ServiceWorkerResponseReader> |
| 480 ServiceWorkerWriteToCacheJob::CreateCacheResponseReader() { | 495 ServiceWorkerWriteToCacheJob::CreateCacheResponseReader() { |
| 481 if (incumbent_resource_id_ == kInvalidServiceWorkerResourceId || | 496 if (incumbent_resource_id_ == kInvalidServiceWorkerResourceId || |
| 482 version_->skip_script_comparison()) { | 497 version_->skip_script_comparison()) { |
| 483 return nullptr; | 498 return nullptr; |
| 484 } | 499 } |
| 485 return context_->storage()->CreateResponseReader(incumbent_resource_id_); | 500 return context_->storage()->CreateResponseReader(incumbent_resource_id_); |
| 486 } | 501 } |
| 487 | 502 |
| 488 scoped_ptr<ServiceWorkerResponseWriter> | 503 scoped_ptr<ServiceWorkerResponseWriter> |
| 489 ServiceWorkerWriteToCacheJob::CreateCacheResponseWriter() { | 504 ServiceWorkerWriteToCacheJob::CreateCacheResponseWriter() { |
| 490 return context_->storage()->CreateResponseWriter(resource_id_); | 505 return context_->storage()->CreateResponseWriter(resource_id_); |
| 491 } | 506 } |
| 492 | 507 |
| 493 } // namespace content | 508 } // namespace content |
| OLD | NEW |