OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "content/browser/service_worker/service_worker_url_loader_job.h" |
| 6 |
| 7 #include "base/command_line.h" |
| 8 #include "content/browser/service_worker/service_worker_fetch_dispatcher.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" |
| 12 #include "content/public/browser/resource_request_info.h" |
| 13 #include "content/public/common/browser_side_navigation_policy.h" |
| 14 #include "content/public/common/content_switches.h" |
| 15 #include "net/base/io_buffer.h" |
| 16 #include "storage/browser/blob/blob_reader.h" |
| 17 #include "storage/browser/blob/blob_storage_context.h" |
| 18 |
| 19 namespace content { |
| 20 |
| 21 ServiceWorkerURLLoaderJob::ServiceWorkerURLLoaderJob( |
| 22 LoaderCallback callback, |
| 23 Delegate* delegate, |
| 24 const ResourceRequest& resource_request, |
| 25 base::WeakPtr<storage::BlobStorageContext> blob_storage_context) |
| 26 : loader_callback_(std::move(callback)), |
| 27 delegate_(delegate), |
| 28 resource_request_(resource_request), |
| 29 blob_storage_context_(blob_storage_context), |
| 30 binding_(this), |
| 31 weak_factory_(this) { |
| 32 DCHECK(IsBrowserSideNavigationEnabled() && |
| 33 base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 34 switches::kEnableNetworkService)); |
| 35 } |
| 36 |
| 37 ServiceWorkerURLLoaderJob::~ServiceWorkerURLLoaderJob() {} |
| 38 |
| 39 void ServiceWorkerURLLoaderJob::FallbackToNetwork() { |
| 40 response_type_ = FALLBACK_TO_NETWORK; |
| 41 // This could be called multiple times in some cases because we simply |
| 42 // call this synchronously here and don't wait for a separate async |
| 43 // StartRequest cue like what URLRequestJob case does. |
| 44 // TODO(kinuko): Make sure this is ok or we need to make this async. |
| 45 if (!loader_callback_.is_null()) |
| 46 std::move(loader_callback_).Run(StartLoaderCallback()); |
| 47 } |
| 48 |
| 49 void ServiceWorkerURLLoaderJob::FallbackToNetworkOrRenderer() { |
| 50 // TODO(kinuko): Implement this. Now we always fallback to network. |
| 51 FallbackToNetwork(); |
| 52 } |
| 53 |
| 54 void ServiceWorkerURLLoaderJob::ForwardToServiceWorker() { |
| 55 response_type_ = FORWARD_TO_SERVICE_WORKER; |
| 56 StartRequest(); |
| 57 } |
| 58 |
| 59 bool ServiceWorkerURLLoaderJob::ShouldFallbackToNetwork() { |
| 60 return response_type_ == FALLBACK_TO_NETWORK; |
| 61 } |
| 62 |
| 63 ui::PageTransition ServiceWorkerURLLoaderJob::GetPageTransition() { |
| 64 NOTIMPLEMENTED(); |
| 65 return ui::PAGE_TRANSITION_LINK; |
| 66 } |
| 67 |
| 68 size_t ServiceWorkerURLLoaderJob::GetURLChainSize() const { |
| 69 NOTIMPLEMENTED(); |
| 70 return 0; |
| 71 } |
| 72 |
| 73 void ServiceWorkerURLLoaderJob::FailDueToLostController() { |
| 74 NOTIMPLEMENTED(); |
| 75 } |
| 76 |
| 77 void ServiceWorkerURLLoaderJob::Cancel() { |
| 78 canceled_ = true; |
| 79 } |
| 80 |
| 81 bool ServiceWorkerURLLoaderJob::WasCanceled() const { |
| 82 return canceled_; |
| 83 } |
| 84 |
| 85 void ServiceWorkerURLLoaderJob::StartRequest() { |
| 86 DCHECK_EQ(FORWARD_TO_SERVICE_WORKER, response_type_); |
| 87 |
| 88 ServiceWorkerMetrics::URLRequestJobResult result = |
| 89 ServiceWorkerMetrics::REQUEST_JOB_ERROR_BAD_DELEGATE; |
| 90 ServiceWorkerVersion* active_worker = |
| 91 delegate_->GetServiceWorkerVersion(&result); |
| 92 |
| 93 fetch_dispatcher_.reset(new ServiceWorkerFetchDispatcher( |
| 94 CreateFetchRequest(resource_request_), active_worker, |
| 95 resource_request_.resource_type, base::nullopt, |
| 96 net::NetLogWithSource() /* TODO(scottmg): net log? */, |
| 97 base::Bind(&ServiceWorkerURLLoaderJob::DidPrepareFetchEvent, |
| 98 weak_factory_.GetWeakPtr(), active_worker), |
| 99 base::Bind(&ServiceWorkerURLLoaderJob::DidDispatchFetchEvent, |
| 100 weak_factory_.GetWeakPtr()))); |
| 101 fetch_dispatcher_->Run(); |
| 102 } |
| 103 |
| 104 std::unique_ptr<ServiceWorkerFetchRequest> |
| 105 ServiceWorkerURLLoaderJob::CreateFetchRequest(const ResourceRequest& request) { |
| 106 std::string blob_uuid; |
| 107 uint64_t blob_size = 0; |
| 108 // TODO(scottmg): Implement passing body as blob to handler. |
| 109 DCHECK(!request.request_body); |
| 110 auto new_request = base::MakeUnique<ServiceWorkerFetchRequest>(); |
| 111 new_request->mode = request.fetch_request_mode; |
| 112 new_request->is_main_resource_load = |
| 113 ServiceWorkerUtils::IsMainResourceType(request.resource_type); |
| 114 new_request->request_context_type = request.fetch_request_context_type; |
| 115 new_request->frame_type = request.fetch_frame_type; |
| 116 new_request->url = request.url; |
| 117 new_request->method = request.method; |
| 118 new_request->blob_uuid = blob_uuid; |
| 119 new_request->blob_size = blob_size; |
| 120 new_request->credentials_mode = request.fetch_credentials_mode; |
| 121 new_request->redirect_mode = request.fetch_redirect_mode; |
| 122 new_request->is_reload = ui::PageTransitionCoreTypeIs( |
| 123 request.transition_type, ui::PAGE_TRANSITION_RELOAD); |
| 124 new_request->referrer = |
| 125 Referrer(GURL(request.referrer), request.referrer_policy); |
| 126 new_request->fetch_type = ServiceWorkerFetchType::FETCH; |
| 127 return new_request; |
| 128 } |
| 129 |
| 130 void ServiceWorkerURLLoaderJob::DidPrepareFetchEvent( |
| 131 scoped_refptr<ServiceWorkerVersion> version) {} |
| 132 |
| 133 void ServiceWorkerURLLoaderJob::DidDispatchFetchEvent( |
| 134 ServiceWorkerStatusCode status, |
| 135 ServiceWorkerFetchEventResult fetch_result, |
| 136 const ServiceWorkerResponse& response, |
| 137 blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream, |
| 138 const scoped_refptr<ServiceWorkerVersion>& version) { |
| 139 if (fetch_result == SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK) { |
| 140 std::move(loader_callback_).Run(StartLoaderCallback()); |
| 141 return; |
| 142 } |
| 143 DCHECK_EQ(fetch_result, SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE); |
| 144 std::move(loader_callback_) |
| 145 .Run(base::Bind(&ServiceWorkerURLLoaderJob::StartResponse, |
| 146 weak_factory_.GetWeakPtr(), response, |
| 147 base::Passed(std::move(body_as_stream)))); |
| 148 } |
| 149 |
| 150 void ServiceWorkerURLLoaderJob::StartResponse( |
| 151 const ServiceWorkerResponse& response, |
| 152 blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream, |
| 153 mojom::URLLoaderRequest request, |
| 154 mojom::URLLoaderClientPtr client) { |
| 155 DCHECK(!binding_.is_bound()); |
| 156 binding_.Bind(std::move(request)); |
| 157 binding_.set_connection_error_handler( |
| 158 base::Bind(&ServiceWorkerURLLoaderJob::Cancel, base::Unretained(this))); |
| 159 url_loader_client_ = std::move(client); |
| 160 |
| 161 ResourceResponseHead head; |
| 162 // TODO(scottmg): More fields in |head| required? |
| 163 head.headers = new net::HttpResponseHeaders(""); |
| 164 for (const auto& kv : response.headers) |
| 165 head.headers->AddHeader(kv.first + ": " + kv.second); |
| 166 head.url_list_via_service_worker = response.url_list; |
| 167 head.mime_type = "text/html"; // TODO(scottmg): No idea where to get this. |
| 168 head.was_fetched_via_service_worker = true; |
| 169 head.cors_exposed_header_names = response.cors_exposed_header_names; |
| 170 url_loader_client_->OnReceiveResponse( |
| 171 head, base::nullopt /* TODO(scottmg): ssl info */, |
| 172 mojom::DownloadedTempFilePtr()); |
| 173 |
| 174 // Ideally, we would always get a data pipe fom SWFetchDispatcher and use |
| 175 // this case. See: |
| 176 // https://docs.google.com/a/google.com/document/d/1_ROmusFvd8ATwIZa29-P6Ls5yy
Ljfld0KvKchVfA84Y/edit?usp=drive_web |
| 177 if (!body_as_stream.is_null() && body_as_stream->stream.is_valid()) { |
| 178 url_loader_client_->OnStartLoadingResponseBody( |
| 179 std::move(body_as_stream->stream)); |
| 180 } else { |
| 181 // TODO(scottmg): This is temporary way to load the blob right here and |
| 182 // turn it into a data pipe to respond with, until we are always able to |
| 183 // take the above path. |
| 184 if (!response.blob_uuid.empty() && blob_storage_context_) { |
| 185 std::unique_ptr<storage::BlobDataHandle> blob_data_handle = |
| 186 blob_storage_context_->GetBlobDataFromUUID(response.blob_uuid); |
| 187 blob_reader_ = blob_data_handle->CreateReader( |
| 188 nullptr /* file system context */, |
| 189 BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE).get()); |
| 190 CHECK(storage::BlobReader::Status::DONE == |
| 191 blob_reader_->CalculateSize(net::CompletionCallback())); |
| 192 blob_reader_->SetReadRange(0, blob_reader_->total_size()); |
| 193 scoped_refptr<net::IOBuffer> buffer( |
| 194 new net::IOBuffer(static_cast<size_t>(blob_reader_->total_size()))); |
| 195 |
| 196 int bytes_read; |
| 197 blob_reader_->Read(buffer.get(), blob_reader_->total_size(), &bytes_read, |
| 198 base::Bind(&ServiceWorkerURLLoaderJob::AfterRead, |
| 199 weak_factory_.GetWeakPtr(), buffer)); |
| 200 } |
| 201 } |
| 202 } |
| 203 |
| 204 void ServiceWorkerURLLoaderJob::AfterRead(scoped_refptr<net::IOBuffer> buffer, |
| 205 int bytes) { |
| 206 uint32_t bytes_written = static_cast<uint32_t>(bytes); |
| 207 mojo::WriteDataRaw(data_pipe_.producer_handle.get(), buffer->data(), |
| 208 &bytes_written, MOJO_WRITE_DATA_FLAG_NONE); |
| 209 url_loader_client_->OnStartLoadingResponseBody( |
| 210 std::move(data_pipe_.consumer_handle)); |
| 211 } |
| 212 |
| 213 void ServiceWorkerURLLoaderJob::FollowRedirect() { |
| 214 NOTIMPLEMENTED(); |
| 215 } |
| 216 |
| 217 void ServiceWorkerURLLoaderJob::SetPriority(net::RequestPriority priority, |
| 218 int32_t intra_priority_value) { |
| 219 NOTIMPLEMENTED(); |
| 220 } |
| 221 |
| 222 } // namespace content |
OLD | NEW |