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 |