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