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 |