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