OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 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/service_worker/service_worker_url_job_wrapper.h" | 5 #include "content/browser/service_worker/service_worker_url_job_wrapper.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "content/browser/service_worker/service_worker_response_type.h" | 8 #include "content/browser/service_worker/service_worker_response_type.h" |
| 9 #include "content/browser/service_worker/service_worker_version.h" |
| 10 #include "content/common/service_worker/service_worker_utils.h" |
| 11 #include "content/public/browser/browser_thread.h" |
9 #include "content/public/browser/resource_request_info.h" | 12 #include "content/public/browser/resource_request_info.h" |
10 #include "content/public/common/browser_side_navigation_policy.h" | 13 #include "content/public/common/browser_side_navigation_policy.h" |
11 #include "content/public/common/content_switches.h" | 14 #include "content/public/common/content_switches.h" |
| 15 #include "mojo/public/cpp/bindings/strong_associated_binding.h" |
| 16 #include "net/base/io_buffer.h" |
| 17 #include "storage/browser/blob/blob_storage_context.h" |
12 | 18 |
13 namespace content { | 19 namespace content { |
14 | 20 |
| 21 namespace { |
| 22 |
| 23 class URLLoaderImpl : public mojom::URLLoader { |
| 24 public: |
| 25 URLLoaderImpl(const ServiceWorkerResponse& response, |
| 26 blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream, |
| 27 base::WeakPtr<storage::BlobStorageContext> blob_storage_context, |
| 28 mojom::URLLoaderClientPtr url_loader_client) |
| 29 : blob_storage_context_(blob_storage_context), |
| 30 url_loader_client_(std::move(url_loader_client)), |
| 31 weak_factory_(this) { |
| 32 ResourceResponseHead head; |
| 33 // TODO(scottmg): More fields in |head| required? |
| 34 head.headers = new net::HttpResponseHeaders(""); |
| 35 for (const auto& kv : response.headers) |
| 36 head.headers->AddHeader(kv.first + ": " + kv.second); |
| 37 head.url_list_via_service_worker = response.url_list; |
| 38 head.mime_type = "text/html"; // TODO(scottmg): No idea where to get this. |
| 39 head.was_fetched_via_service_worker = true; |
| 40 head.cors_exposed_header_names = response.cors_exposed_header_names; |
| 41 url_loader_client_->OnReceiveResponse( |
| 42 head, base::nullopt /* TODO(scottmg): ssl info */, |
| 43 mojom::DownloadedTempFilePtr()); |
| 44 |
| 45 // Ideally, we would always get a data pipe fom SWFetchDispatcher and use |
| 46 // this case. See: |
| 47 // https://docs.google.com/a/google.com/document/d/1_ROmusFvd8ATwIZa29-P6Ls5
yyLjfld0KvKchVfA84Y/edit?usp=drive_web |
| 48 if (!body_as_stream.is_null() && body_as_stream->stream.is_valid()) { |
| 49 url_loader_client_->OnStartLoadingResponseBody( |
| 50 std::move(body_as_stream->stream)); |
| 51 } else { |
| 52 // TODO(scottmg): This is temporary way to load the blob right here and |
| 53 // turn it into a data pipe to respond with, until we are always able to |
| 54 // take the above path. |
| 55 if (!response.blob_uuid.empty() && blob_storage_context_) { |
| 56 std::unique_ptr<storage::BlobDataHandle> blob_data_handle = |
| 57 blob_storage_context_->GetBlobDataFromUUID(response.blob_uuid); |
| 58 blob_reader_ = blob_data_handle->CreateReader( |
| 59 nullptr /* file system context */, |
| 60 BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE).get()); |
| 61 CHECK(storage::BlobReader::Status::DONE == |
| 62 blob_reader_->CalculateSize(net::CompletionCallback())); |
| 63 blob_reader_->SetReadRange(0, blob_reader_->total_size()); |
| 64 scoped_refptr<net::IOBuffer> buffer( |
| 65 new net::IOBuffer(static_cast<size_t>(blob_reader_->total_size()))); |
| 66 |
| 67 int bytes_read; |
| 68 blob_reader_->Read(buffer.get(), blob_reader_->total_size(), |
| 69 &bytes_read, |
| 70 base::Bind(&URLLoaderImpl::AfterRead, |
| 71 weak_factory_.GetWeakPtr(), buffer)); |
| 72 } |
| 73 } |
| 74 } |
| 75 |
| 76 // mojom::URLLoader: |
| 77 void FollowRedirect() override { NOTIMPLEMENTED(); } |
| 78 |
| 79 void SetPriority(net::RequestPriority priority, |
| 80 int32_t intra_priority_value) override { |
| 81 NOTIMPLEMENTED(); |
| 82 } |
| 83 |
| 84 private: |
| 85 void AfterRead(scoped_refptr<net::IOBuffer> buffer, int bytes) { |
| 86 uint32_t bytes_written = static_cast<uint32_t>(bytes); |
| 87 mojo::WriteDataRaw(data_pipe_.producer_handle.get(), buffer->data(), |
| 88 &bytes_written, MOJO_WRITE_DATA_FLAG_NONE); |
| 89 url_loader_client_->OnStartLoadingResponseBody( |
| 90 std::move(data_pipe_.consumer_handle)); |
| 91 } |
| 92 |
| 93 base::WeakPtr<storage::BlobStorageContext> blob_storage_context_; |
| 94 mojom::URLLoaderClientPtr url_loader_client_; |
| 95 std::unique_ptr<storage::BlobReader> blob_reader_; |
| 96 mojo::DataPipe data_pipe_; |
| 97 |
| 98 base::WeakPtrFactory<URLLoaderImpl> weak_factory_; |
| 99 |
| 100 DISALLOW_COPY_AND_ASSIGN(URLLoaderImpl); |
| 101 }; |
| 102 |
| 103 } // namespace |
| 104 |
| 105 class ServiceWorkerURLJobWrapper::Factory : public mojom::URLLoaderFactory { |
| 106 public: |
| 107 Factory(const ServiceWorkerResponse& response, |
| 108 blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream, |
| 109 base::WeakPtr<storage::BlobStorageContext> blob_storage_context) |
| 110 : response_(response), |
| 111 body_as_stream_(std::move(body_as_stream)), |
| 112 blob_storage_context_(blob_storage_context) {} |
| 113 |
| 114 void CreateLoaderAndStart(mojom::URLLoaderAssociatedRequest request, |
| 115 int32_t routing_id, |
| 116 int32_t request_id, |
| 117 uint32_t options, |
| 118 const ResourceRequest& url_request, |
| 119 mojom::URLLoaderClientPtr client) override { |
| 120 // Note that url_request is ignored here, as we've already processed the |
| 121 // fetch before even creating the factory. |
| 122 // TODO(scottmg): Use options. |
| 123 mojo::MakeStrongAssociatedBinding( |
| 124 base::MakeUnique<URLLoaderImpl>(response_, std::move(body_as_stream_), |
| 125 blob_storage_context_, |
| 126 std::move(client)), |
| 127 std::move(request)); |
| 128 } |
| 129 |
| 130 void SyncLoad(int32_t routing_id, |
| 131 int32_t request_id, |
| 132 const ResourceRequest& url_request, |
| 133 SyncLoadCallback callback) override { |
| 134 NOTREACHED(); |
| 135 } |
| 136 |
| 137 private: |
| 138 ServiceWorkerResponse response_; |
| 139 blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream_; |
| 140 base::WeakPtr<storage::BlobStorageContext> blob_storage_context_; |
| 141 |
| 142 DISALLOW_COPY_AND_ASSIGN(Factory); |
| 143 }; |
| 144 |
15 ServiceWorkerURLJobWrapper::ServiceWorkerURLJobWrapper( | 145 ServiceWorkerURLJobWrapper::ServiceWorkerURLJobWrapper( |
16 base::WeakPtr<ServiceWorkerURLRequestJob> url_request_job) | 146 base::WeakPtr<ServiceWorkerURLRequestJob> url_request_job) |
17 : job_type_(JobType::kURLRequest), | 147 : job_type_(JobType::kURLRequest), |
18 url_request_job_(std::move(url_request_job)), | 148 url_request_job_(std::move(url_request_job)), |
19 weak_factory_(this) {} | 149 weak_factory_(this) {} |
20 | 150 |
21 ServiceWorkerURLJobWrapper::ServiceWorkerURLJobWrapper( | 151 ServiceWorkerURLJobWrapper::ServiceWorkerURLJobWrapper( |
22 LoaderFactoryCallback callback) | 152 LoaderFactoryCallback callback, |
| 153 Delegate* delegate, |
| 154 const ResourceRequest& resource_request, |
| 155 base::WeakPtr<storage::BlobStorageContext> blob_storage_context) |
23 : job_type_(JobType::kURLLoader), | 156 : job_type_(JobType::kURLLoader), |
24 loader_factory_callback_(std::move(callback)), | 157 loader_factory_callback_(std::move(callback)), |
| 158 delegate_(delegate), |
| 159 resource_request_(resource_request), |
| 160 blob_storage_context_(blob_storage_context), |
25 weak_factory_(this) { | 161 weak_factory_(this) { |
26 DCHECK(IsBrowserSideNavigationEnabled() && | 162 DCHECK(IsBrowserSideNavigationEnabled() && |
27 base::CommandLine::ForCurrentProcess()->HasSwitch( | 163 base::CommandLine::ForCurrentProcess()->HasSwitch( |
28 switches::kEnableNetworkService)); | 164 switches::kEnableNetworkService)); |
29 } | 165 } |
30 | 166 |
31 ServiceWorkerURLJobWrapper::~ServiceWorkerURLJobWrapper() {} | 167 ServiceWorkerURLJobWrapper::~ServiceWorkerURLJobWrapper() {} |
32 | 168 |
33 void ServiceWorkerURLJobWrapper::FallbackToNetwork() { | 169 void ServiceWorkerURLJobWrapper::FallbackToNetwork() { |
34 if (job_type_ == JobType::kURLLoader) { | 170 if (job_type_ == JobType::kURLLoader) { |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 bool ServiceWorkerURLJobWrapper::WasCanceled() const { | 241 bool ServiceWorkerURLJobWrapper::WasCanceled() const { |
106 if (job_type_ == JobType::kURLLoader) { | 242 if (job_type_ == JobType::kURLLoader) { |
107 return loader_factory_callback_.is_null(); | 243 return loader_factory_callback_.is_null(); |
108 } else { | 244 } else { |
109 return !url_request_job_; | 245 return !url_request_job_; |
110 } | 246 } |
111 } | 247 } |
112 | 248 |
113 void ServiceWorkerURLJobWrapper::StartRequest() { | 249 void ServiceWorkerURLJobWrapper::StartRequest() { |
114 DCHECK_EQ(FORWARD_TO_SERVICE_WORKER, response_type_); | 250 DCHECK_EQ(FORWARD_TO_SERVICE_WORKER, response_type_); |
115 // TODO(kinuko): Implement. For now we just exercise async fall back path | 251 |
116 // to the network. | 252 ServiceWorkerMetrics::URLRequestJobResult result = |
117 base::ThreadTaskRunnerHandle::Get()->PostTask( | 253 ServiceWorkerMetrics::REQUEST_JOB_ERROR_BAD_DELEGATE; |
118 FROM_HERE, base::Bind(&ServiceWorkerURLJobWrapper::FallbackToNetwork, | 254 ServiceWorkerVersion* active_worker = |
119 weak_factory_.GetWeakPtr())); | 255 delegate_->GetServiceWorkerVersion(&result); |
| 256 |
| 257 fetch_dispatcher_.reset(new ServiceWorkerFetchDispatcher( |
| 258 CreateFetchRequest(resource_request_), active_worker, |
| 259 resource_request_.resource_type, base::nullopt, |
| 260 net::NetLogWithSource() /* TODO(scottmg): net log? */, |
| 261 base::Bind(&ServiceWorkerURLJobWrapper::DidPrepareFetchEvent, |
| 262 weak_factory_.GetWeakPtr(), active_worker), |
| 263 base::Bind(&ServiceWorkerURLJobWrapper::DidDispatchFetchEvent, |
| 264 weak_factory_.GetWeakPtr()))); |
| 265 fetch_dispatcher_->Run(); |
| 266 } |
| 267 |
| 268 std::unique_ptr<ServiceWorkerFetchRequest> |
| 269 ServiceWorkerURLJobWrapper::CreateFetchRequest(const ResourceRequest& request) { |
| 270 std::string blob_uuid; |
| 271 uint64_t blob_size = 0; |
| 272 // TODO(scottmg): Implement passing body as blob to handler. |
| 273 DCHECK(!request.request_body); |
| 274 std::unique_ptr<ServiceWorkerFetchRequest> new_request( |
| 275 new ServiceWorkerFetchRequest()); |
| 276 new_request->mode = request.fetch_request_mode; |
| 277 new_request->is_main_resource_load = |
| 278 ServiceWorkerUtils::IsMainResourceType(request.resource_type); |
| 279 new_request->request_context_type = request.fetch_request_context_type; |
| 280 new_request->frame_type = request.fetch_frame_type; |
| 281 new_request->url = request.url; |
| 282 new_request->method = request.method; |
| 283 new_request->blob_uuid = blob_uuid; |
| 284 new_request->blob_size = blob_size; |
| 285 new_request->credentials_mode = request.fetch_credentials_mode; |
| 286 new_request->redirect_mode = request.fetch_redirect_mode; |
| 287 new_request->is_reload = ui::PageTransitionCoreTypeIs( |
| 288 request.transition_type, ui::PAGE_TRANSITION_RELOAD); |
| 289 new_request->referrer = |
| 290 Referrer(GURL(request.referrer), request.referrer_policy); |
| 291 new_request->fetch_type = ServiceWorkerFetchType::FETCH; |
| 292 return new_request; |
| 293 } |
| 294 |
| 295 void ServiceWorkerURLJobWrapper::DidPrepareFetchEvent( |
| 296 scoped_refptr<ServiceWorkerVersion> version) {} |
| 297 |
| 298 void ServiceWorkerURLJobWrapper::DidDispatchFetchEvent( |
| 299 ServiceWorkerStatusCode status, |
| 300 ServiceWorkerFetchEventResult fetch_result, |
| 301 const ServiceWorkerResponse& response, |
| 302 blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream, |
| 303 const scoped_refptr<ServiceWorkerVersion>& version) { |
| 304 if (fetch_result == SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK) { |
| 305 std::move(loader_factory_callback_).Run(nullptr); |
| 306 return; |
| 307 } |
| 308 DCHECK_EQ(fetch_result, SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE); |
| 309 |
| 310 factory_ = base::MakeUnique<Factory>(response, std::move(body_as_stream), |
| 311 blob_storage_context_); |
| 312 std::move(loader_factory_callback_).Run(factory_.get()); |
120 } | 313 } |
121 | 314 |
122 } // namespace content | 315 } // namespace content |
OLD | NEW |