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 |