Chromium Code Reviews| 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/browser/url_loader_factory_getter.h" | |
| 8 #include "content/common/net_adapters.h" | |
| 9 #include "content/public/common/resource_type.h" | |
| 7 | 10 |
| 8 namespace content { | 11 namespace content { |
| 9 | 12 |
| 10 AppCacheURLLoaderJob::~AppCacheURLLoaderJob() {} | 13 AppCacheURLLoaderJob::~AppCacheURLLoaderJob() {} |
| 11 | 14 |
| 12 void AppCacheURLLoaderJob::Kill() {} | 15 void AppCacheURLLoaderJob::Kill() {} |
| 13 | 16 |
| 14 bool AppCacheURLLoaderJob::IsStarted() const { | 17 bool AppCacheURLLoaderJob::IsStarted() const { |
| 15 return false; | 18 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 } | 19 } |
| 37 | 20 |
| 38 void AppCacheURLLoaderJob::DeliverAppCachedResponse(const GURL& manifest_url, | 21 void AppCacheURLLoaderJob::DeliverAppCachedResponse(const GURL& manifest_url, |
| 39 int64_t cache_id, | 22 int64_t cache_id, |
| 40 const AppCacheEntry& entry, | 23 const AppCacheEntry& entry, |
| 41 bool is_fallback) {} | 24 bool is_fallback) { |
| 42 | 25 delivery_type_ = APPCACHED_DELIVERY; |
| 43 void AppCacheURLLoaderJob::DeliverNetworkResponse() {} | 26 |
| 44 | 27 AppCacheHistograms::AddAppCacheJobStartDelaySample(base::TimeTicks::Now() - |
| 45 void AppCacheURLLoaderJob::DeliverErrorResponse() {} | 28 start_time_tick_); |
| 29 | |
| 30 manifest_url_ = manifest_url; | |
| 31 cache_id_ = cache_id; | |
| 32 entry_ = entry; | |
| 33 is_fallback_ = is_fallback; | |
| 34 | |
| 35 storage_->LoadResponseInfo(manifest_url_, entry_.response_id(), this); | |
|
michaeln
2017/06/09 02:06:18
Unfortunately, the rawptr is a problem
We're goin
ananta
2017/06/09 04:48:19
I added a call to CancelDelegateCallbacks in the d
michaeln
2017/06/09 19:59:53
The other class is actually safe but its not at al
| |
| 36 } | |
| 37 | |
| 38 void AppCacheURLLoaderJob::DeliverNetworkResponse() { | |
| 39 delivery_type_ = NETWORK_DELIVERY; | |
| 40 | |
| 41 AppCacheHistograms::AddNetworkJobStartDelaySample(base::TimeTicks::Now() - | |
| 42 start_time_tick_); | |
| 43 | |
| 44 // In network service land, if we are processing a navigation request, we | |
| 45 // need to inform the loader callback that we are not going to handle this | |
| 46 // request. The loader callback is valid only for navigation requests. | |
| 47 if (!loader_callback_.is_null()) { | |
| 48 std::move(loader_callback_).Run(StartLoaderCallback()); | |
| 49 return; | |
| 50 } | |
| 51 | |
| 52 url_loader_factory_getter_->GetNetworkFactory()->get()->CreateLoaderAndStart( | |
|
michaeln
2017/06/09 01:48:29
We don't yet know if there will be a chain of hand
ananta
2017/06/09 04:48:19
Removed
| |
| 53 mojo::MakeRequest(&url_loader_network_), routing_id_, request_id_, | |
| 54 mojom::kURLLoadOptionSendSSLInfo, request_, std::move(client_info_)); | |
| 55 } | |
| 56 | |
| 57 void AppCacheURLLoaderJob::DeliverErrorResponse() { | |
| 58 delivery_type_ = ERROR_DELIVERY; | |
| 59 | |
| 60 // TODO(ananta) | |
| 61 // Fill up the correct error code here and add support in NotifyError() to | |
| 62 // generate a proper error response. | |
| 63 NotifyCompleted(net::ERR_UNEXPECTED); | |
| 64 | |
| 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 if (url_loader_network_) | |
| 79 url_loader_network_->FollowRedirect(); | |
| 80 } | |
| 81 | |
| 82 void AppCacheURLLoaderJob::SetPriority(net::RequestPriority priority, | |
| 83 int32_t intra_priority_value) { | |
| 84 NOTREACHED() << "We don't support SetPriority()"; | |
| 85 } | |
| 86 | |
| 87 void AppCacheURLLoaderJob::Start(int routing_id, | |
| 88 int request_id, | |
| 89 mojom::URLLoaderRequest request, | |
| 90 mojom::URLLoaderClientPtr client) { | |
| 91 DCHECK(!binding_.is_bound()); | |
| 92 binding_.Bind(std::move(request)); | |
| 93 | |
| 94 binding_.set_connection_error_handler(base::Bind( | |
| 95 &AppCacheURLLoaderJob::OnConnectionError, StaticAsWeakPtr(this))); | |
| 96 | |
| 97 routing_id_ = routing_id; | |
| 98 request_id_ = request_id; | |
| 99 | |
| 100 client_info_ = std::move(client); | |
| 101 | |
| 102 // Send the cached AppCacheResponse if any. | |
| 103 if (info_.get()) | |
| 104 SendResponseInfo(); | |
| 105 } | |
| 106 | |
| 107 void AppCacheURLLoaderJob::SetURLLoaderFactoryGetter( | |
| 108 URLLoaderFactoryGetter* url_loader_factory_getter) { | |
| 109 url_loader_factory_getter_ = url_loader_factory_getter; | |
| 110 } | |
| 111 | |
| 112 AppCacheURLLoaderJob::AppCacheURLLoaderJob(const ResourceRequest& request, | |
| 113 AppCacheStorage* storage) | |
| 114 : request_(request), | |
| 115 storage_(storage), | |
| 116 start_time_tick_(base::TimeTicks::Now()), | |
| 117 cache_id_(kAppCacheNoCacheId), | |
| 118 is_fallback_(false), | |
| 119 buffer_(nullptr), | |
| 120 binding_(this), | |
| 121 routing_id_(-1), | |
| 122 request_id_(-1), | |
| 123 writable_handle_watcher_(FROM_HERE, | |
| 124 mojo::SimpleWatcher::ArmingPolicy::MANUAL) {} | |
| 125 | |
| 126 void AppCacheURLLoaderJob::OnResponseInfoLoaded( | |
| 127 AppCacheResponseInfo* response_info, | |
| 128 int64_t response_id) { | |
| 129 DCHECK(IsDeliveringAppCacheResponse()); | |
| 130 | |
| 131 if (response_info) { | |
| 132 info_ = response_info; | |
| 133 reader_.reset( | |
| 134 storage_->CreateResponseReader(manifest_url_, entry_.response_id())); | |
| 135 | |
| 136 if (!loader_callback_.is_null()) { | |
|
michaeln
2017/06/09 01:48:30
in our current use case, navigation, this is never
ananta
2017/06/09 04:48:19
Replaced with a DCHECK
| |
| 137 std::move(loader_callback_) | |
| 138 .Run(base::Bind(&AppCacheURLLoaderJob::Start, StaticAsWeakPtr(this), | |
| 139 0, 0)); | |
| 140 } | |
| 141 | |
| 142 // TODO(ananta) | |
| 143 // Handle range requests. | |
| 144 | |
| 145 response_body_stream_ = std::move(data_pipe_.producer_handle); | |
| 146 | |
| 147 // Wait for the data pipe to be ready to accept data. | |
| 148 writable_handle_watcher_.Watch( | |
| 149 response_body_stream_.get(), MOJO_HANDLE_SIGNAL_WRITABLE, | |
| 150 base::Bind(&AppCacheURLLoaderJob::OnResponseBodyStreamReady, | |
|
michaeln
2017/06/09 01:48:29
is it possible/expected for OnResponseBodyStreamRe
ananta
2017/06/09 04:48:19
It is on the same thread?. Unless I am missing som
| |
| 151 StaticAsWeakPtr(this))); | |
| 152 | |
| 153 if (client_info_) | |
| 154 SendResponseInfo(); | |
| 155 | |
| 156 ReadMore(); | |
| 157 } else { | |
| 158 // Error case here. We fallback to the network. | |
| 159 // TODO(ananta) | |
| 160 // Should we be invoking the loader callback here to give control to the | |
| 161 // next handler in the chain?. | |
|
michaeln
2017/06/09 01:48:29
The TODO comment seems stale or misplaced, for nav
ananta
2017/06/09 04:48:19
Thanks. Removed the comment.
| |
| 162 DeliverNetworkResponse(); | |
| 163 AppCacheHistograms::CountResponseRetrieval( | |
| 164 false, IsResourceTypeFrame(request_.resource_type), | |
| 165 manifest_url_.GetOrigin()); | |
| 166 | |
| 167 cache_entry_not_found_ = true; | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 void AppCacheURLLoaderJob::OnCacheLoaded(AppCache* cache, int64_t cache_id) { | |
| 172 NOTREACHED() << "Unhandled at the moment."; | |
| 173 } | |
| 174 | |
| 175 void AppCacheURLLoaderJob::OnReadComplete(int result) { | |
| 176 DLOG(WARNING) << "AppCache read completed with result: " << result; | |
| 177 | |
| 178 bool is_main_resource = IsResourceTypeFrame(request_.resource_type); | |
| 179 | |
| 180 if (result == 0) { | |
| 181 NotifyCompleted(result); | |
| 182 AppCacheHistograms::CountResponseRetrieval(true, is_main_resource, | |
| 183 manifest_url_.GetOrigin()); | |
|
michaeln
2017/06/09 01:48:30
you could early return here and avoid the if (resu
ananta
2017/06/09 04:48:19
Done.
| |
| 184 } else if (result < 0) { | |
| 185 // TODO(ananta) | |
| 186 // Populate the relevant fields of the ResourceRequestCompletionStatus | |
| 187 // structure. | |
| 188 NotifyCompleted(result); | |
| 189 AppCacheHistograms::CountResponseRetrieval(false, is_main_resource, | |
| 190 manifest_url_.GetOrigin()); | |
| 191 return; | |
| 192 } | |
| 193 | |
| 194 if (result > 0) { | |
| 195 uint32_t bytes_written = static_cast<uint32_t>(result); | |
| 196 response_body_stream_ = pending_write_->Complete(bytes_written); | |
| 197 pending_write_ = nullptr; | |
| 198 ReadMore(); | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 void AppCacheURLLoaderJob::OnConnectionError() { | |
| 203 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); | |
| 204 } | |
| 205 | |
| 206 void AppCacheURLLoaderJob::SendResponseInfo() { | |
| 207 DCHECK(client_info_); | |
| 208 | |
| 209 // If this is null it means the response information was sent to the client. | |
| 210 if (!data_pipe_.consumer_handle.is_valid()) | |
| 211 return; | |
| 212 | |
| 213 const net::HttpResponseInfo* http_info = info_->http_response_info(); | |
| 214 | |
| 215 ResourceResponseHead response_head; | |
| 216 response_head.headers = http_info->headers; | |
| 217 | |
| 218 // TODO(ananta) | |
| 219 // Copy more fields. | |
| 220 http_info->headers->GetMimeType(&response_head.mime_type); | |
| 221 http_info->headers->GetCharset(&response_head.charset); | |
| 222 | |
| 223 response_head.request_time = http_info->request_time; | |
| 224 response_head.response_time = http_info->response_time; | |
| 225 response_head.content_length = info_->response_data_size(); | |
| 226 | |
| 227 client_info_->OnReceiveResponse(response_head, http_info->ssl_info, | |
| 228 mojom::DownloadedTempFilePtr()); | |
| 229 | |
| 230 client_info_->OnStartLoadingResponseBody( | |
| 231 std::move(data_pipe_.consumer_handle)); | |
| 232 } | |
| 233 | |
| 234 void AppCacheURLLoaderJob::ReadMore() { | |
| 235 DCHECK(!pending_write_.get()); | |
| 236 | |
| 237 uint32_t num_bytes; | |
| 238 // TODO: we should use the abstractions in MojoAsyncResourceHandler. | |
| 239 MojoResult result = NetToMojoPendingBuffer::BeginWrite( | |
| 240 &response_body_stream_, &pending_write_, &num_bytes); | |
| 241 if (result == MOJO_RESULT_SHOULD_WAIT) { | |
| 242 // The pipe is full. We need to wait for it to have more space. | |
| 243 writable_handle_watcher_.ArmOrNotify(); | |
| 244 return; | |
| 245 } else if (result != MOJO_RESULT_OK) { | |
| 246 // The response body stream is in a bad state. Bail. | |
| 247 // TODO: How should this be communicated to our client? | |
|
michaeln
2017/06/09 01:48:29
Probably NotifyComplete(ERR)? As coded will progre
ananta
2017/06/09 04:48:19
Added a call to NotifyCompleted here.
| |
| 248 writable_handle_watcher_.Cancel(); | |
| 249 response_body_stream_.reset(); | |
| 250 return; | |
| 251 } | |
| 252 | |
| 253 CHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()), num_bytes); | |
| 254 buffer_ = nullptr; | |
| 255 buffer_ = new NetToMojoIOBuffer(pending_write_.get()); | |
|
michaeln
2017/06/09 01:48:29
Is the buffer_ data member is needed? It's only ac
ananta
2017/06/09 04:48:19
The buffer_ member should not be needed I think. R
| |
| 256 | |
| 257 reader_->ReadData( | |
| 258 buffer_.get(), info_->response_data_size(), | |
| 259 base::Bind(&AppCacheURLLoaderJob::OnReadComplete, StaticAsWeakPtr(this))); | |
| 260 } | |
| 261 | |
| 262 void AppCacheURLLoaderJob::OnResponseBodyStreamReady(MojoResult result) { | |
| 263 // TODO: Handle a bad |result| value. | |
|
michaeln
2017/06/09 01:48:30
ditto probably NotifyComplete(ERR)
ananta
2017/06/09 04:48:19
Done.
| |
| 264 DCHECK_EQ(result, MOJO_RESULT_OK); | |
| 265 ReadMore(); | |
| 266 } | |
| 267 | |
| 268 void AppCacheURLLoaderJob::NotifyCompleted(int error_code) { | |
| 269 // TODO(ananta) | |
| 270 // Fill other details in the ResourceRequestCompletionStatus structure. | |
| 271 // In case of an error we may need to call OnReceiveResponse on the client. | |
| 272 // That requires HTTP header generation etc. | |
|
michaeln
2017/06/09 01:48:29
I think we only need http header generation and a
ananta
2017/06/09 04:48:19
Thanks. moved this comment to the DeliverErrorResp
| |
| 273 ResourceRequestCompletionStatus request_complete_data; | |
| 274 request_complete_data.error_code = error_code; | |
| 275 client_info_->OnComplete(request_complete_data); | |
| 276 } | |
| 52 | 277 |
| 53 } // namespace content | 278 } // namespace content |
| OLD | NEW |