OLD | NEW |
---|---|
1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2017 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/appcache/appcache_url_loader_job.h" | 5 #include "content/browser/appcache/appcache_url_loader_job.h" |
6 #include "content/browser/appcache/appcache_entry.h" | 6 |
7 #include "base/strings/string_number_conversions.h" | |
8 #include "content/browser/appcache/appcache_histograms.h" | |
9 #include "content/common/net_adapters.h" | |
10 #include "content/public/common/resource_type.h" | |
11 #include "net/http/http_status_code.h" | |
7 | 12 |
8 namespace content { | 13 namespace content { |
9 | 14 |
10 AppCacheURLLoaderJob::~AppCacheURLLoaderJob() {} | 15 AppCacheURLLoaderJob::~AppCacheURLLoaderJob() { |
16 if (storage_.get()) | |
17 storage_->CancelDelegateCallbacks(this); | |
18 } | |
11 | 19 |
12 void AppCacheURLLoaderJob::Kill() {} | 20 void AppCacheURLLoaderJob::Kill() {} |
13 | 21 |
14 bool AppCacheURLLoaderJob::IsStarted() const { | 22 bool AppCacheURLLoaderJob::IsStarted() const { |
15 return false; | 23 return delivery_type_ != AWAITING_DELIVERY_ORDERS; |
16 } | |
17 | |
18 bool AppCacheURLLoaderJob::IsWaiting() const { | |
19 return false; | |
20 } | |
21 | |
22 bool AppCacheURLLoaderJob::IsDeliveringAppCacheResponse() const { | |
23 return false; | |
24 } | |
25 | |
26 bool AppCacheURLLoaderJob::IsDeliveringNetworkResponse() const { | |
27 return false; | |
28 } | |
29 | |
30 bool AppCacheURLLoaderJob::IsDeliveringErrorResponse() const { | |
31 return false; | |
32 } | |
33 | |
34 bool AppCacheURLLoaderJob::IsCacheEntryNotFound() const { | |
35 return false; | |
36 } | 24 } |
37 | 25 |
38 void AppCacheURLLoaderJob::DeliverAppCachedResponse(const GURL& manifest_url, | 26 void AppCacheURLLoaderJob::DeliverAppCachedResponse(const GURL& manifest_url, |
39 int64_t cache_id, | 27 int64_t cache_id, |
40 const AppCacheEntry& entry, | 28 const AppCacheEntry& entry, |
41 bool is_fallback) {} | 29 bool is_fallback) { |
42 | 30 // Should we send out an error response here?. We may not have a client |
43 void AppCacheURLLoaderJob::DeliverNetworkResponse() {} | 31 // connection at this point though. |
michaeln
2017/06/09 21:49:00
probably we should call DeliverErrorResponse() her
ananta
2017/06/09 22:16:52
Done.
| |
44 | 32 if (!storage_.get()) |
45 void AppCacheURLLoaderJob::DeliverErrorResponse() {} | 33 return; |
34 | |
35 delivery_type_ = APPCACHED_DELIVERY; | |
36 | |
37 AppCacheHistograms::AddAppCacheJobStartDelaySample(base::TimeTicks::Now() - | |
38 start_time_tick_); | |
39 | |
40 manifest_url_ = manifest_url; | |
41 cache_id_ = cache_id; | |
42 entry_ = entry; | |
43 is_fallback_ = is_fallback; | |
44 | |
45 // TODO(ananta) | |
46 // Implement the AppCacheServiceImpl::Observer interface or add weak pointer | |
47 // support to it. | |
48 storage_->LoadResponseInfo(manifest_url_, entry_.response_id(), this); | |
49 } | |
50 | |
51 void AppCacheURLLoaderJob::DeliverNetworkResponse() { | |
52 delivery_type_ = NETWORK_DELIVERY; | |
53 | |
54 AppCacheHistograms::AddNetworkJobStartDelaySample(base::TimeTicks::Now() - | |
55 start_time_tick_); | |
56 | |
57 DCHECK(!loader_callback_.is_null()); | |
58 // In network service land, if we are processing a navigation request, we | |
59 // need to inform the loader callback that we are not going to handle this | |
60 // request. The loader callback is valid only for navigation requests. | |
61 std::move(loader_callback_).Run(StartLoaderCallback()); | |
62 } | |
63 | |
64 void AppCacheURLLoaderJob::DeliverErrorResponse() { | |
65 delivery_type_ = ERROR_DELIVERY; | |
66 | |
67 // We expect the URLLoaderClient pointer to be valid at this point. | |
68 DCHECK(client_info_); | |
69 | |
70 // AppCacheURLRequestJob uses ERR_FAILED as the error code here. That seems | |
71 // to map to HTTP_INTERNAL_SERVER_ERROR. | |
72 std::string status("HTTP/1.1 "); | |
73 status.append(base::IntToString(net::HTTP_INTERNAL_SERVER_ERROR)); | |
74 status.append(" "); | |
75 status.append(net::GetHttpReasonPhrase(net::HTTP_INTERNAL_SERVER_ERROR)); | |
76 status.append("\0\0", 2); | |
77 | |
78 ResourceResponseHead response; | |
79 response.headers = new net::HttpResponseHeaders(status); | |
80 client_info_->OnReceiveResponse(response, base::nullopt, nullptr); | |
81 | |
82 NotifyCompleted(net::ERR_FAILED); | |
83 | |
84 AppCacheHistograms::AddErrorJobStartDelaySample(base::TimeTicks::Now() - | |
85 start_time_tick_); | |
86 } | |
46 | 87 |
47 const GURL& AppCacheURLLoaderJob::GetURL() const { | 88 const GURL& AppCacheURLLoaderJob::GetURL() const { |
48 return url_; | 89 return request_.url; |
49 } | 90 } |
50 | 91 |
51 AppCacheURLLoaderJob::AppCacheURLLoaderJob() {} | 92 AppCacheURLLoaderJob* AppCacheURLLoaderJob::AsURLLoaderJob() { |
93 return this; | |
94 } | |
95 | |
96 void AppCacheURLLoaderJob::FollowRedirect() { | |
97 DCHECK(false); | |
98 } | |
99 | |
100 void AppCacheURLLoaderJob::SetPriority(net::RequestPriority priority, | |
101 int32_t intra_priority_value) { | |
102 NOTREACHED() << "We don't support SetPriority()"; | |
103 } | |
104 | |
105 void AppCacheURLLoaderJob::Start(mojom::URLLoaderRequest request, | |
106 mojom::URLLoaderClientPtr client) { | |
107 DCHECK(!binding_.is_bound()); | |
108 binding_.Bind(std::move(request)); | |
109 | |
110 binding_.set_connection_error_handler(base::Bind( | |
111 &AppCacheURLLoaderJob::OnConnectionError, StaticAsWeakPtr(this))); | |
112 | |
113 client_info_ = std::move(client); | |
114 | |
115 // Send the cached AppCacheResponse if any. | |
116 if (info_.get()) | |
117 SendResponseInfo(); | |
118 } | |
119 | |
120 AppCacheURLLoaderJob::AppCacheURLLoaderJob(const ResourceRequest& request, | |
121 AppCacheStorage* storage) | |
122 : request_(request), | |
123 storage_(storage->GetWeakPtr()), | |
124 start_time_tick_(base::TimeTicks::Now()), | |
125 cache_id_(kAppCacheNoCacheId), | |
126 is_fallback_(false), | |
127 binding_(this), | |
128 writable_handle_watcher_(FROM_HERE, | |
129 mojo::SimpleWatcher::ArmingPolicy::MANUAL) {} | |
130 | |
131 void AppCacheURLLoaderJob::OnResponseInfoLoaded( | |
132 AppCacheResponseInfo* response_info, | |
133 int64_t response_id) { | |
134 DCHECK(IsDeliveringAppCacheResponse()); | |
135 | |
136 if (!storage_.get()) { | |
137 NotifyCompleted(net::ERR_FAILED); | |
michaeln
2017/06/09 21:49:00
at this point, we haven't sent headers yet, we can
ananta
2017/06/09 22:16:52
Done.
| |
138 return; | |
139 } | |
140 | |
141 if (response_info) { | |
142 info_ = response_info; | |
143 reader_.reset( | |
144 storage_->CreateResponseReader(manifest_url_, entry_.response_id())); | |
145 | |
146 DCHECK(!loader_callback_.is_null()); | |
147 std::move(loader_callback_) | |
148 .Run(base::Bind(&AppCacheURLLoaderJob::Start, StaticAsWeakPtr(this))); | |
149 | |
150 // TODO(ananta) | |
151 // Handle range requests. | |
152 | |
153 response_body_stream_ = std::move(data_pipe_.producer_handle); | |
154 | |
155 // TODO(ananta) | |
156 // Move the asynchronous reading and mojo pipe handling code to a helper | |
157 // class. That would also need a change to BlobURLLoader. | |
158 | |
159 // Wait for the data pipe to be ready to accept data. | |
160 writable_handle_watcher_.Watch( | |
161 response_body_stream_.get(), MOJO_HANDLE_SIGNAL_WRITABLE, | |
162 base::Bind(&AppCacheURLLoaderJob::OnResponseBodyStreamReady, | |
163 StaticAsWeakPtr(this))); | |
164 | |
165 if (client_info_) | |
166 SendResponseInfo(); | |
167 | |
168 ReadMore(); | |
169 } else { | |
170 // Error case here. We fallback to the network. | |
171 DeliverNetworkResponse(); | |
172 AppCacheHistograms::CountResponseRetrieval( | |
173 false, IsResourceTypeFrame(request_.resource_type), | |
174 manifest_url_.GetOrigin()); | |
175 | |
176 cache_entry_not_found_ = true; | |
177 } | |
178 } | |
179 | |
180 void AppCacheURLLoaderJob::OnReadComplete(int result) { | |
181 DLOG(WARNING) << "AppCache read completed with result: " << result; | |
182 | |
183 bool is_main_resource = IsResourceTypeFrame(request_.resource_type); | |
184 | |
185 if (result == 0) { | |
186 NotifyCompleted(result); | |
187 AppCacheHistograms::CountResponseRetrieval(true, is_main_resource, | |
188 manifest_url_.GetOrigin()); | |
189 return; | |
190 } else if (result < 0) { | |
191 // TODO(ananta) | |
192 // Populate the relevant fields of the ResourceRequestCompletionStatus | |
193 // structure. | |
194 NotifyCompleted(result); | |
195 AppCacheHistograms::CountResponseRetrieval(false, is_main_resource, | |
196 manifest_url_.GetOrigin()); | |
197 return; | |
198 } | |
199 | |
200 uint32_t bytes_written = static_cast<uint32_t>(result); | |
201 response_body_stream_ = pending_write_->Complete(bytes_written); | |
202 pending_write_ = nullptr; | |
203 ReadMore(); | |
204 } | |
205 | |
206 void AppCacheURLLoaderJob::OnConnectionError() { | |
207 if (storage_.get()) | |
208 storage_->CancelDelegateCallbacks(this); | |
209 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); | |
210 } | |
211 | |
212 void AppCacheURLLoaderJob::SendResponseInfo() { | |
213 DCHECK(client_info_); | |
214 | |
215 // If this is null it means the response information was sent to the client. | |
216 if (!data_pipe_.consumer_handle.is_valid()) | |
217 return; | |
218 | |
219 const net::HttpResponseInfo* http_info = info_->http_response_info(); | |
220 | |
221 ResourceResponseHead response_head; | |
222 response_head.headers = http_info->headers; | |
223 | |
224 // TODO(ananta) | |
225 // Copy more fields. | |
226 http_info->headers->GetMimeType(&response_head.mime_type); | |
227 http_info->headers->GetCharset(&response_head.charset); | |
228 | |
229 response_head.request_time = http_info->request_time; | |
230 response_head.response_time = http_info->response_time; | |
231 response_head.content_length = info_->response_data_size(); | |
232 | |
233 client_info_->OnReceiveResponse(response_head, http_info->ssl_info, | |
234 mojom::DownloadedTempFilePtr()); | |
235 | |
236 client_info_->OnStartLoadingResponseBody( | |
237 std::move(data_pipe_.consumer_handle)); | |
238 } | |
239 | |
240 void AppCacheURLLoaderJob::ReadMore() { | |
241 DCHECK(!pending_write_.get()); | |
242 | |
243 uint32_t num_bytes; | |
244 // TODO: we should use the abstractions in MojoAsyncResourceHandler. | |
245 MojoResult result = NetToMojoPendingBuffer::BeginWrite( | |
246 &response_body_stream_, &pending_write_, &num_bytes); | |
247 if (result == MOJO_RESULT_SHOULD_WAIT) { | |
248 // The pipe is full. We need to wait for it to have more space. | |
249 writable_handle_watcher_.ArmOrNotify(); | |
250 return; | |
251 } else if (result != MOJO_RESULT_OK) { | |
252 // The response body stream is in a bad state. Bail. | |
253 // TODO(ananta) | |
254 // Add proper error handling here. | |
255 NotifyCompleted(net::ERR_FAILED); | |
256 writable_handle_watcher_.Cancel(); | |
257 response_body_stream_.reset(); | |
258 return; | |
259 } | |
260 | |
261 CHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()), num_bytes); | |
262 scoped_refptr<NetToMojoIOBuffer> buffer = | |
263 new NetToMojoIOBuffer(pending_write_.get()); | |
264 | |
265 reader_->ReadData( | |
266 buffer.get(), info_->response_data_size(), | |
267 base::Bind(&AppCacheURLLoaderJob::OnReadComplete, StaticAsWeakPtr(this))); | |
268 } | |
269 | |
270 void AppCacheURLLoaderJob::OnResponseBodyStreamReady(MojoResult result) { | |
271 // TODO(ananta) | |
272 // Add proper error handling here. | |
273 if (result != MOJO_RESULT_OK) { | |
274 DCHECK(false); | |
275 NotifyCompleted(net::ERR_FAILED); | |
276 } | |
277 ReadMore(); | |
278 } | |
279 | |
280 void AppCacheURLLoaderJob::NotifyCompleted(int error_code) { | |
281 if (storage_.get()) | |
282 storage_->CancelDelegateCallbacks(this); | |
283 // TODO(ananta) | |
284 // Fill other details in the ResourceRequestCompletionStatus structure. | |
285 ResourceRequestCompletionStatus request_complete_data; | |
286 request_complete_data.error_code = error_code; | |
287 client_info_->OnComplete(request_complete_data); | |
288 } | |
52 | 289 |
53 } // namespace content | 290 } // namespace content |
OLD | NEW |