| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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 "components/html_viewer/web_url_loader_impl.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 #include <stdint.h> | |
| 9 #include <utility> | |
| 10 | |
| 11 #include "base/bind.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/numerics/safe_conversions.h" | |
| 14 #include "base/strings/string_util.h" | |
| 15 #include "base/thread_task_runner_handle.h" | |
| 16 #include "components/html_viewer/blink_url_request_type_converters.h" | |
| 17 #include "mojo/common/common_type_converters.h" | |
| 18 #include "mojo/common/data_pipe_utils.h" | |
| 19 #include "mojo/common/url_type_converters.h" | |
| 20 #include "mojo/services/network/public/interfaces/url_loader_factory.mojom.h" | |
| 21 #include "net/base/net_errors.h" | |
| 22 #include "third_party/WebKit/public/platform/WebURLError.h" | |
| 23 #include "third_party/WebKit/public/platform/WebURLLoadTiming.h" | |
| 24 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h" | |
| 25 #include "third_party/WebKit/public/platform/WebURLResponse.h" | |
| 26 | |
| 27 using blink::WebString; | |
| 28 using mojo::URLResponsePtr; | |
| 29 | |
| 30 namespace html_viewer { | |
| 31 namespace { | |
| 32 | |
| 33 blink::WebURLResponse::HTTPVersion StatusLineToHTTPVersion( | |
| 34 const mojo::String& status_line) { | |
| 35 if (status_line.is_null()) | |
| 36 return blink::WebURLResponse::HTTPVersion_0_9; | |
| 37 | |
| 38 if (base::StartsWith(status_line.get(), "HTTP/1.0", | |
| 39 base::CompareCase::SENSITIVE)) | |
| 40 return blink::WebURLResponse::HTTPVersion_1_0; | |
| 41 | |
| 42 if (base::StartsWith(status_line.get(), "HTTP/1.1", | |
| 43 base::CompareCase::SENSITIVE)) | |
| 44 return blink::WebURLResponse::HTTPVersion_1_1; | |
| 45 | |
| 46 return blink::WebURLResponse::HTTPVersionUnknown; | |
| 47 } | |
| 48 | |
| 49 blink::WebURLResponse ToWebURLResponse(const URLResponsePtr& url_response) { | |
| 50 blink::WebURLResponse result; | |
| 51 result.initialize(); | |
| 52 result.setURL(GURL(url_response->url.get())); | |
| 53 result.setMIMEType(blink::WebString::fromUTF8(url_response->mime_type)); | |
| 54 result.setTextEncodingName(blink::WebString::fromUTF8(url_response->charset)); | |
| 55 result.setHTTPVersion(StatusLineToHTTPVersion(url_response->status_line)); | |
| 56 result.setHTTPStatusCode(url_response->status_code); | |
| 57 result.setExpectedContentLength(-1); // Not available. | |
| 58 | |
| 59 // TODO(darin): Initialize timing properly. | |
| 60 blink::WebURLLoadTiming timing; | |
| 61 timing.initialize(); | |
| 62 result.setLoadTiming(timing); | |
| 63 | |
| 64 for (size_t i = 0; i < url_response->headers.size(); ++i) { | |
| 65 result.setHTTPHeaderField( | |
| 66 blink::WebString::fromUTF8(url_response->headers[i]->name), | |
| 67 blink::WebString::fromUTF8(url_response->headers[i]->value)); | |
| 68 } | |
| 69 | |
| 70 return result; | |
| 71 } | |
| 72 | |
| 73 } // namespace | |
| 74 | |
| 75 WebURLRequestExtraData::WebURLRequestExtraData() { | |
| 76 } | |
| 77 | |
| 78 WebURLRequestExtraData::~WebURLRequestExtraData() { | |
| 79 } | |
| 80 | |
| 81 WebURLLoaderImpl::WebURLLoaderImpl(mojo::URLLoaderFactory* url_loader_factory, | |
| 82 MockWebBlobRegistryImpl* web_blob_registry) | |
| 83 : client_(NULL), | |
| 84 web_blob_registry_(web_blob_registry), | |
| 85 referrer_policy_(blink::WebReferrerPolicyDefault), | |
| 86 weak_factory_(this) { | |
| 87 url_loader_factory->CreateURLLoader(GetProxy(&url_loader_)); | |
| 88 } | |
| 89 | |
| 90 WebURLLoaderImpl::~WebURLLoaderImpl() { | |
| 91 } | |
| 92 | |
| 93 void WebURLLoaderImpl::loadSynchronously( | |
| 94 const blink::WebURLRequest& request, | |
| 95 blink::WebURLResponse& response, | |
| 96 blink::WebURLError& error, | |
| 97 blink::WebData& data) { | |
| 98 mojo::URLRequestPtr url_request = mojo::URLRequest::From(request); | |
| 99 url_request->auto_follow_redirects = true; | |
| 100 URLResponsePtr url_response; | |
| 101 url_loader_->Start(std::move(url_request), | |
| 102 [&url_response](URLResponsePtr url_response_result) { | |
| 103 url_response = std::move(url_response_result); | |
| 104 }); | |
| 105 url_loader_.WaitForIncomingResponse(); | |
| 106 if (url_response->error) { | |
| 107 error.domain = WebString::fromUTF8(net::kErrorDomain); | |
| 108 error.reason = url_response->error->code; | |
| 109 error.unreachableURL = GURL(url_response->url.get()); | |
| 110 return; | |
| 111 } | |
| 112 | |
| 113 response = ToWebURLResponse(url_response); | |
| 114 std::string body; | |
| 115 mojo::common::BlockingCopyToString(std::move(url_response->body), &body); | |
| 116 data.assign(body.data(), body.length()); | |
| 117 } | |
| 118 | |
| 119 void WebURLLoaderImpl::loadAsynchronously(const blink::WebURLRequest& request, | |
| 120 blink::WebURLLoaderClient* client) { | |
| 121 client_ = client; | |
| 122 url_ = request.url(); | |
| 123 | |
| 124 mojo::URLRequestPtr url_request = mojo::URLRequest::From(request); | |
| 125 url_request->auto_follow_redirects = false; | |
| 126 referrer_policy_ = request.referrerPolicy(); | |
| 127 | |
| 128 if (request.extraData()) { | |
| 129 WebURLRequestExtraData* extra_data = | |
| 130 static_cast<WebURLRequestExtraData*>(request.extraData()); | |
| 131 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 132 FROM_HERE, | |
| 133 base::Bind(&WebURLLoaderImpl::OnReceivedResponse, | |
| 134 weak_factory_.GetWeakPtr(), | |
| 135 request, | |
| 136 base::Passed(&extra_data->synthetic_response))); | |
| 137 return; | |
| 138 } | |
| 139 | |
| 140 blink::WebString uuid; | |
| 141 if (web_blob_registry_->GetUUIDForURL(url_, &uuid)) { | |
| 142 blink::WebVector<blink::WebBlobData::Item*> items; | |
| 143 if (web_blob_registry_->GetBlobItems(uuid, &items)) { | |
| 144 // The blob data exists in our service, and we don't want to create a | |
| 145 // data pipe just to do a funny dance where at the end, we stuff data | |
| 146 // from memory into data pipes so we can read back the data. | |
| 147 OnReceiveWebBlobData(request, items); | |
| 148 return; | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 url_loader_->Start(std::move(url_request), | |
| 153 base::Bind(&WebURLLoaderImpl::OnReceivedResponse, | |
| 154 weak_factory_.GetWeakPtr(), request)); | |
| 155 } | |
| 156 | |
| 157 void WebURLLoaderImpl::cancel() { | |
| 158 url_loader_.reset(); | |
| 159 response_body_stream_.reset(); | |
| 160 | |
| 161 URLResponsePtr failed_response(mojo::URLResponse::New()); | |
| 162 failed_response->url = mojo::String::From(url_); | |
| 163 failed_response->error = mojo::NetworkError::New(); | |
| 164 failed_response->error->code = net::ERR_ABORTED; | |
| 165 | |
| 166 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 167 FROM_HERE, | |
| 168 base::Bind(&WebURLLoaderImpl::OnReceivedResponse, | |
| 169 weak_factory_.GetWeakPtr(), | |
| 170 blink::WebURLRequest(), | |
| 171 base::Passed(&failed_response))); | |
| 172 } | |
| 173 | |
| 174 void WebURLLoaderImpl::setDefersLoading(bool defers_loading) { | |
| 175 NOTIMPLEMENTED(); | |
| 176 } | |
| 177 | |
| 178 void WebURLLoaderImpl::OnReceivedResponse(const blink::WebURLRequest& request, | |
| 179 URLResponsePtr url_response) { | |
| 180 url_ = GURL(url_response->url.get()); | |
| 181 | |
| 182 if (url_response->error) { | |
| 183 OnReceivedError(std::move(url_response)); | |
| 184 } else if (url_response->redirect_url) { | |
| 185 OnReceivedRedirect(request, std::move(url_response)); | |
| 186 } else { | |
| 187 base::WeakPtr<WebURLLoaderImpl> self(weak_factory_.GetWeakPtr()); | |
| 188 client_->didReceiveResponse(this, ToWebURLResponse(url_response)); | |
| 189 | |
| 190 // We may have been deleted during didReceiveResponse. | |
| 191 if (!self) | |
| 192 return; | |
| 193 | |
| 194 // Start streaming data | |
| 195 response_body_stream_ = std::move(url_response->body); | |
| 196 ReadMore(); | |
| 197 } | |
| 198 } | |
| 199 | |
| 200 void WebURLLoaderImpl::OnReceivedError(URLResponsePtr url_response) { | |
| 201 blink::WebURLError web_error; | |
| 202 web_error.domain = blink::WebString::fromUTF8(net::kErrorDomain); | |
| 203 web_error.reason = url_response->error->code; | |
| 204 web_error.unreachableURL = GURL(url_response->url.get()); | |
| 205 web_error.staleCopyInCache = false; | |
| 206 web_error.isCancellation = | |
| 207 url_response->error->code == net::ERR_ABORTED ? true : false; | |
| 208 | |
| 209 client_->didFail(this, web_error); | |
| 210 } | |
| 211 | |
| 212 void WebURLLoaderImpl::OnReceivedRedirect(const blink::WebURLRequest& request, | |
| 213 URLResponsePtr url_response) { | |
| 214 // TODO(erg): setFirstPartyForCookies() and setHTTPReferrer() are unset here. | |
| 215 blink::WebURLRequest new_request; | |
| 216 new_request.initialize(); | |
| 217 new_request.setURL(GURL(url_response->redirect_url.get())); | |
| 218 new_request.setDownloadToFile(request.downloadToFile()); | |
| 219 new_request.setRequestContext(request.requestContext()); | |
| 220 new_request.setFrameType(request.frameType()); | |
| 221 new_request.setSkipServiceWorker(request.skipServiceWorker()); | |
| 222 new_request.setFetchRequestMode(request.fetchRequestMode()); | |
| 223 new_request.setFetchCredentialsMode(request.fetchCredentialsMode()); | |
| 224 new_request.setHTTPReferrer( | |
| 225 WebString::fromUTF8(url_response->redirect_referrer), | |
| 226 referrer_policy_); | |
| 227 | |
| 228 std::string old_method = request.httpMethod().utf8(); | |
| 229 new_request.setHTTPMethod( | |
| 230 blink::WebString::fromUTF8(url_response->redirect_method)); | |
| 231 if (url_response->redirect_method == old_method) | |
| 232 new_request.setHTTPBody(request.httpBody()); | |
| 233 | |
| 234 base::WeakPtr<WebURLLoaderImpl> self(weak_factory_.GetWeakPtr()); | |
| 235 client_->willFollowRedirect( | |
| 236 this, new_request, ToWebURLResponse(url_response)); | |
| 237 // TODO(darin): Check if new_request was rejected. | |
| 238 | |
| 239 // We may have been deleted during willFollowRedirect. | |
| 240 if (!self) | |
| 241 return; | |
| 242 | |
| 243 url_loader_->FollowRedirect( | |
| 244 base::Bind(&WebURLLoaderImpl::OnReceivedResponse, | |
| 245 weak_factory_.GetWeakPtr(), | |
| 246 request)); | |
| 247 } | |
| 248 | |
| 249 void WebURLLoaderImpl::OnReceiveWebBlobData( | |
| 250 const blink::WebURLRequest& request, | |
| 251 const blink::WebVector<blink::WebBlobData::Item*>& items) { | |
| 252 blink::WebURLResponse result; | |
| 253 result.initialize(); | |
| 254 result.setURL(url_); | |
| 255 result.setHTTPStatusCode(200); | |
| 256 result.setExpectedContentLength(-1); // Not available. | |
| 257 | |
| 258 base::WeakPtr<WebURLLoaderImpl> self(weak_factory_.GetWeakPtr()); | |
| 259 client_->didReceiveResponse(this, result); | |
| 260 | |
| 261 // We may have been deleted during didReceiveResponse. | |
| 262 if (!self) | |
| 263 return; | |
| 264 | |
| 265 // Send a receive data for each blob item. | |
| 266 for (size_t i = 0; i < items.size(); ++i) { | |
| 267 const int data_size = base::checked_cast<int>(items[i]->data.size()); | |
| 268 client_->didReceiveData(this, items[i]->data.data(), data_size, -1); | |
| 269 } | |
| 270 | |
| 271 // Send a closing finish. | |
| 272 double finish_time = base::Time::Now().ToDoubleT(); | |
| 273 client_->didFinishLoading( | |
| 274 this, finish_time, blink::WebURLLoaderClient::kUnknownEncodedDataLength); | |
| 275 } | |
| 276 | |
| 277 void WebURLLoaderImpl::ReadMore() { | |
| 278 const void* buf; | |
| 279 uint32_t buf_size; | |
| 280 MojoResult rv = BeginReadDataRaw(response_body_stream_.get(), | |
| 281 &buf, | |
| 282 &buf_size, | |
| 283 MOJO_READ_DATA_FLAG_NONE); | |
| 284 if (rv == MOJO_RESULT_OK) { | |
| 285 base::WeakPtr<WebURLLoaderImpl> self(weak_factory_.GetWeakPtr()); | |
| 286 client_->didReceiveData(this, static_cast<const char*>(buf), buf_size, -1); | |
| 287 // We may have been deleted during didReceiveData. | |
| 288 if (!self) | |
| 289 return; | |
| 290 EndReadDataRaw(response_body_stream_.get(), buf_size); | |
| 291 WaitToReadMore(); | |
| 292 } else if (rv == MOJO_RESULT_SHOULD_WAIT) { | |
| 293 WaitToReadMore(); | |
| 294 } else if (rv == MOJO_RESULT_FAILED_PRECONDITION) { | |
| 295 // We reached end-of-file. | |
| 296 double finish_time = base::Time::Now().ToDoubleT(); | |
| 297 client_->didFinishLoading( | |
| 298 this, | |
| 299 finish_time, | |
| 300 blink::WebURLLoaderClient::kUnknownEncodedDataLength); | |
| 301 } else { | |
| 302 // TODO(darin): Oops! | |
| 303 } | |
| 304 } | |
| 305 | |
| 306 void WebURLLoaderImpl::WaitToReadMore() { | |
| 307 handle_watcher_.Start( | |
| 308 response_body_stream_.get(), | |
| 309 MOJO_HANDLE_SIGNAL_READABLE, | |
| 310 MOJO_DEADLINE_INDEFINITE, | |
| 311 base::Bind(&WebURLLoaderImpl::OnResponseBodyStreamReady, | |
| 312 weak_factory_.GetWeakPtr())); | |
| 313 } | |
| 314 | |
| 315 void WebURLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) { | |
| 316 ReadMore(); | |
| 317 } | |
| 318 | |
| 319 void WebURLLoaderImpl::setLoadingTaskRunner( | |
| 320 blink::WebTaskRunner* web_task_runner) { | |
| 321 // TODO(alexclarke): Consider hooking this up. | |
| 322 } | |
| 323 | |
| 324 } // namespace html_viewer | |
| OLD | NEW |