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