Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Side by Side Diff: third_party/WebKit/Source/web/WebAssociatedURLLoaderImpl.cpp

Issue 2831833002: Move WebAssociatedURLLoaderImpl.* from web/ -> core/export/. (Closed)
Patch Set: Need to BLINK_EXPORT WebAssociatedURLLoader for compile to work on windows. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2010, 2011, 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "web/WebAssociatedURLLoaderImpl.h"
32
33 #include <limits.h>
34 #include <memory>
35 #include "core/dom/ContextLifecycleObserver.h"
36 #include "core/dom/TaskRunnerHelper.h"
37 #include "core/loader/DocumentThreadableLoader.h"
38 #include "core/loader/DocumentThreadableLoaderClient.h"
39 #include "core/loader/ThreadableLoadingContext.h"
40 #include "platform/Timer.h"
41 #include "platform/exported/WrappedResourceRequest.h"
42 #include "platform/exported/WrappedResourceResponse.h"
43 #include "platform/loader/fetch/CrossOriginAccessControl.h"
44 #include "platform/loader/fetch/FetchUtils.h"
45 #include "platform/loader/fetch/ResourceError.h"
46 #include "platform/network/HTTPParsers.h"
47 #include "platform/wtf/HashSet.h"
48 #include "platform/wtf/PtrUtil.h"
49 #include "platform/wtf/text/WTFString.h"
50 #include "public/platform/WebHTTPHeaderVisitor.h"
51 #include "public/platform/WebString.h"
52 #include "public/platform/WebURLError.h"
53 #include "public/platform/WebURLRequest.h"
54 #include "public/web/WebAssociatedURLLoaderClient.h"
55 #include "public/web/WebDataSource.h"
56 #include "web/WebLocalFrameImpl.h"
57
58 namespace blink {
59
60 namespace {
61
62 class HTTPRequestHeaderValidator : public WebHTTPHeaderVisitor {
63 WTF_MAKE_NONCOPYABLE(HTTPRequestHeaderValidator);
64
65 public:
66 HTTPRequestHeaderValidator() : is_safe_(true) {}
67 ~HTTPRequestHeaderValidator() override {}
68
69 void VisitHeader(const WebString& name, const WebString& value) override;
70 bool IsSafe() const { return is_safe_; }
71
72 private:
73 bool is_safe_;
74 };
75
76 void HTTPRequestHeaderValidator::VisitHeader(const WebString& name,
77 const WebString& value) {
78 is_safe_ = is_safe_ && IsValidHTTPToken(name) &&
79 !FetchUtils::IsForbiddenHeaderName(name) &&
80 IsValidHTTPHeaderValue(value);
81 }
82
83 } // namespace
84
85 // This class bridges the interface differences between WebCore and WebKit
86 // loader clients.
87 // It forwards its ThreadableLoaderClient notifications to a
88 // WebAssociatedURLLoaderClient.
89 class WebAssociatedURLLoaderImpl::ClientAdapter final
90 : public DocumentThreadableLoaderClient {
91 WTF_MAKE_NONCOPYABLE(ClientAdapter);
92
93 public:
94 static std::unique_ptr<ClientAdapter> Create(
95 WebAssociatedURLLoaderImpl*,
96 WebAssociatedURLLoaderClient*,
97 const WebAssociatedURLLoaderOptions&,
98 RefPtr<WebTaskRunner>);
99
100 // ThreadableLoaderClient
101 void DidSendData(unsigned long long /*bytesSent*/,
102 unsigned long long /*totalBytesToBeSent*/) override;
103 void DidReceiveResponse(unsigned long,
104 const ResourceResponse&,
105 std::unique_ptr<WebDataConsumerHandle>) override;
106 void DidDownloadData(int /*dataLength*/) override;
107 void DidReceiveData(const char*, unsigned /*dataLength*/) override;
108 void DidReceiveCachedMetadata(const char*, int /*dataLength*/) override;
109 void DidFinishLoading(unsigned long /*identifier*/,
110 double /*finishTime*/) override;
111 void DidFail(const ResourceError&) override;
112 void DidFailRedirectCheck() override;
113
114 // DocumentThreadableLoaderClient
115 bool WillFollowRedirect(
116 const ResourceRequest& /*newRequest*/,
117 const ResourceResponse& /*redirectResponse*/) override;
118
119 // Sets an error to be reported back to the client, asychronously.
120 void SetDelayedError(const ResourceError&);
121
122 // Enables forwarding of error notifications to the
123 // WebAssociatedURLLoaderClient. These
124 // must be deferred until after the call to
125 // WebAssociatedURLLoader::loadAsynchronously() completes.
126 void EnableErrorNotifications();
127
128 // Stops loading and releases the DocumentThreadableLoader as early as
129 // possible.
130 WebAssociatedURLLoaderClient* ReleaseClient() {
131 WebAssociatedURLLoaderClient* client = client_;
132 client_ = nullptr;
133 return client;
134 }
135
136 private:
137 ClientAdapter(WebAssociatedURLLoaderImpl*,
138 WebAssociatedURLLoaderClient*,
139 const WebAssociatedURLLoaderOptions&,
140 RefPtr<WebTaskRunner>);
141
142 void NotifyError(TimerBase*);
143
144 WebAssociatedURLLoaderImpl* loader_;
145 WebAssociatedURLLoaderClient* client_;
146 WebAssociatedURLLoaderOptions options_;
147 WebURLError error_;
148
149 TaskRunnerTimer<ClientAdapter> error_timer_;
150 bool enable_error_notifications_;
151 bool did_fail_;
152 };
153
154 std::unique_ptr<WebAssociatedURLLoaderImpl::ClientAdapter>
155 WebAssociatedURLLoaderImpl::ClientAdapter::Create(
156 WebAssociatedURLLoaderImpl* loader,
157 WebAssociatedURLLoaderClient* client,
158 const WebAssociatedURLLoaderOptions& options,
159 RefPtr<WebTaskRunner> task_runner) {
160 return WTF::WrapUnique(
161 new ClientAdapter(loader, client, options, task_runner));
162 }
163
164 WebAssociatedURLLoaderImpl::ClientAdapter::ClientAdapter(
165 WebAssociatedURLLoaderImpl* loader,
166 WebAssociatedURLLoaderClient* client,
167 const WebAssociatedURLLoaderOptions& options,
168 RefPtr<WebTaskRunner> task_runner)
169 : loader_(loader),
170 client_(client),
171 options_(options),
172 error_timer_(std::move(task_runner), this, &ClientAdapter::NotifyError),
173 enable_error_notifications_(false),
174 did_fail_(false) {
175 DCHECK(loader_);
176 DCHECK(client_);
177 }
178
179 bool WebAssociatedURLLoaderImpl::ClientAdapter::WillFollowRedirect(
180 const ResourceRequest& new_request,
181 const ResourceResponse& redirect_response) {
182 if (!client_)
183 return true;
184
185 WrappedResourceRequest wrapped_new_request(new_request);
186 WrappedResourceResponse wrapped_redirect_response(redirect_response);
187 return client_->WillFollowRedirect(wrapped_new_request,
188 wrapped_redirect_response);
189 }
190
191 void WebAssociatedURLLoaderImpl::ClientAdapter::DidSendData(
192 unsigned long long bytes_sent,
193 unsigned long long total_bytes_to_be_sent) {
194 if (!client_)
195 return;
196
197 client_->DidSendData(bytes_sent, total_bytes_to_be_sent);
198 }
199
200 void WebAssociatedURLLoaderImpl::ClientAdapter::DidReceiveResponse(
201 unsigned long,
202 const ResourceResponse& response,
203 std::unique_ptr<WebDataConsumerHandle> handle) {
204 ALLOW_UNUSED_LOCAL(handle);
205 DCHECK(!handle);
206 if (!client_)
207 return;
208
209 if (options_.expose_all_response_headers ||
210 options_.cross_origin_request_policy !=
211 WebAssociatedURLLoaderOptions::
212 kCrossOriginRequestPolicyUseAccessControl) {
213 // Use the original ResourceResponse.
214 client_->DidReceiveResponse(WrappedResourceResponse(response));
215 return;
216 }
217
218 HTTPHeaderSet exposed_headers;
219 ExtractCorsExposedHeaderNamesList(response, exposed_headers);
220 HTTPHeaderSet blocked_headers;
221 for (const auto& header : response.HttpHeaderFields()) {
222 if (FetchUtils::IsForbiddenResponseHeaderName(header.key) ||
223 (!IsOnAccessControlResponseHeaderWhitelist(header.key) &&
224 !exposed_headers.Contains(header.key)))
225 blocked_headers.insert(header.key);
226 }
227
228 if (blocked_headers.IsEmpty()) {
229 // Use the original ResourceResponse.
230 client_->DidReceiveResponse(WrappedResourceResponse(response));
231 return;
232 }
233
234 // If there are blocked headers, copy the response so we can remove them.
235 WebURLResponse validated_response = WrappedResourceResponse(response);
236 for (const auto& header : blocked_headers)
237 validated_response.ClearHTTPHeaderField(header);
238 client_->DidReceiveResponse(validated_response);
239 }
240
241 void WebAssociatedURLLoaderImpl::ClientAdapter::DidDownloadData(
242 int data_length) {
243 if (!client_)
244 return;
245
246 client_->DidDownloadData(data_length);
247 }
248
249 void WebAssociatedURLLoaderImpl::ClientAdapter::DidReceiveData(
250 const char* data,
251 unsigned data_length) {
252 if (!client_)
253 return;
254
255 CHECK_LE(data_length, static_cast<unsigned>(std::numeric_limits<int>::max()));
256
257 client_->DidReceiveData(data, data_length);
258 }
259
260 void WebAssociatedURLLoaderImpl::ClientAdapter::DidReceiveCachedMetadata(
261 const char* data,
262 int data_length) {
263 if (!client_)
264 return;
265
266 client_->DidReceiveCachedMetadata(data, data_length);
267 }
268
269 void WebAssociatedURLLoaderImpl::ClientAdapter::DidFinishLoading(
270 unsigned long identifier,
271 double finish_time) {
272 if (!client_)
273 return;
274
275 loader_->ClientAdapterDone();
276
277 ReleaseClient()->DidFinishLoading(finish_time);
278 // |this| may be dead here.
279 }
280
281 void WebAssociatedURLLoaderImpl::ClientAdapter::DidFail(
282 const ResourceError& error) {
283 if (!client_)
284 return;
285
286 loader_->ClientAdapterDone();
287
288 did_fail_ = true;
289 error_ = WebURLError(error);
290 if (enable_error_notifications_)
291 NotifyError(&error_timer_);
292 }
293
294 void WebAssociatedURLLoaderImpl::ClientAdapter::DidFailRedirectCheck() {
295 DidFail(ResourceError());
296 }
297
298 void WebAssociatedURLLoaderImpl::ClientAdapter::EnableErrorNotifications() {
299 enable_error_notifications_ = true;
300 // If an error has already been received, start a timer to report it to the
301 // client after WebAssociatedURLLoader::loadAsynchronously has returned to the
302 // caller.
303 if (did_fail_)
304 error_timer_.StartOneShot(0, BLINK_FROM_HERE);
305 }
306
307 void WebAssociatedURLLoaderImpl::ClientAdapter::NotifyError(TimerBase* timer) {
308 DCHECK_EQ(timer, &error_timer_);
309
310 if (client_)
311 ReleaseClient()->DidFail(error_);
312 // |this| may be dead here.
313 }
314
315 class WebAssociatedURLLoaderImpl::Observer final
316 : public GarbageCollected<Observer>,
317 public ContextLifecycleObserver {
318 USING_GARBAGE_COLLECTED_MIXIN(Observer);
319
320 public:
321 Observer(WebAssociatedURLLoaderImpl* parent, Document* document)
322 : ContextLifecycleObserver(document), parent_(parent) {}
323
324 void Dispose() {
325 parent_ = nullptr;
326 ClearContext();
327 }
328
329 void ContextDestroyed(ExecutionContext*) override {
330 if (parent_)
331 parent_->DocumentDestroyed();
332 }
333
334 DEFINE_INLINE_VIRTUAL_TRACE() { ContextLifecycleObserver::Trace(visitor); }
335
336 WebAssociatedURLLoaderImpl* parent_;
337 };
338
339 WebAssociatedURLLoaderImpl::WebAssociatedURLLoaderImpl(
340 WebLocalFrameImpl* frame_impl,
341 const WebAssociatedURLLoaderOptions& options)
342 : client_(nullptr),
343 options_(options),
344 observer_(new Observer(this, frame_impl->GetFrame()->GetDocument())) {}
345
346 WebAssociatedURLLoaderImpl::~WebAssociatedURLLoaderImpl() {
347 Cancel();
348 }
349
350 #define STATIC_ASSERT_ENUM(a, b) \
351 static_assert(static_cast<int>(a) == static_cast<int>(b), \
352 "mismatching enum: " #a)
353
354 STATIC_ASSERT_ENUM(WebAssociatedURLLoaderOptions::kCrossOriginRequestPolicyDeny,
355 kDenyCrossOriginRequests);
356 STATIC_ASSERT_ENUM(
357 WebAssociatedURLLoaderOptions::kCrossOriginRequestPolicyUseAccessControl,
358 kUseAccessControl);
359 STATIC_ASSERT_ENUM(
360 WebAssociatedURLLoaderOptions::kCrossOriginRequestPolicyAllow,
361 kAllowCrossOriginRequests);
362
363 STATIC_ASSERT_ENUM(WebAssociatedURLLoaderOptions::kConsiderPreflight,
364 kConsiderPreflight);
365 STATIC_ASSERT_ENUM(WebAssociatedURLLoaderOptions::kForcePreflight,
366 kForcePreflight);
367 STATIC_ASSERT_ENUM(WebAssociatedURLLoaderOptions::kPreventPreflight,
368 kPreventPreflight);
369
370 void WebAssociatedURLLoaderImpl::LoadAsynchronously(
371 const WebURLRequest& request,
372 WebAssociatedURLLoaderClient* client) {
373 DCHECK(!client_);
374 DCHECK(!loader_);
375 DCHECK(!client_adapter_);
376
377 DCHECK(client);
378
379 bool allow_load = true;
380 WebURLRequest new_request(request);
381 if (options_.untrusted_http) {
382 WebString method = new_request.HttpMethod();
383 allow_load = observer_ && IsValidHTTPToken(method) &&
384 FetchUtils::IsUsefulMethod(method);
385 if (allow_load) {
386 new_request.SetHTTPMethod(FetchUtils::NormalizeMethod(method));
387 HTTPRequestHeaderValidator validator;
388 new_request.VisitHTTPHeaderFields(&validator);
389 allow_load = validator.IsSafe();
390 }
391 }
392
393 RefPtr<WebTaskRunner> task_runner = TaskRunnerHelper::Get(
394 TaskType::kUnspecedLoading,
395 observer_ ? ToDocument(observer_->LifecycleContext()) : nullptr);
396 client_ = client;
397 client_adapter_ =
398 ClientAdapter::Create(this, client, options_, std::move(task_runner));
399
400 if (allow_load) {
401 ThreadableLoaderOptions options;
402 options.preflight_policy =
403 static_cast<PreflightPolicy>(options_.preflight_policy);
404 options.cross_origin_request_policy = static_cast<CrossOriginRequestPolicy>(
405 options_.cross_origin_request_policy);
406
407 ResourceLoaderOptions resource_loader_options;
408 resource_loader_options.allow_credentials =
409 options_.allow_credentials ? kAllowStoredCredentials
410 : kDoNotAllowStoredCredentials;
411 resource_loader_options.data_buffering_policy = kDoNotBufferData;
412
413 const ResourceRequest& webcore_request = new_request.ToResourceRequest();
414 if (webcore_request.GetRequestContext() ==
415 WebURLRequest::kRequestContextUnspecified) {
416 // FIXME: We load URLs without setting a TargetType (and therefore a
417 // request context) in several places in content/
418 // (P2PPortAllocatorSession::AllocateLegacyRelaySession, for example).
419 // Remove this once those places are patched up.
420 new_request.SetRequestContext(WebURLRequest::kRequestContextInternal);
421 }
422
423 Document* document = ToDocument(observer_->LifecycleContext());
424 DCHECK(document);
425 loader_ = DocumentThreadableLoader::Create(
426 *ThreadableLoadingContext::Create(*document), client_adapter_.get(),
427 options, resource_loader_options);
428 loader_->Start(webcore_request);
429 }
430
431 if (!loader_) {
432 // FIXME: return meaningful error codes.
433 client_adapter_->DidFail(ResourceError());
434 }
435 client_adapter_->EnableErrorNotifications();
436 }
437
438 void WebAssociatedURLLoaderImpl::Cancel() {
439 DisposeObserver();
440 CancelLoader();
441 ReleaseClient();
442 }
443
444 void WebAssociatedURLLoaderImpl::ClientAdapterDone() {
445 DisposeObserver();
446 ReleaseClient();
447 }
448
449 void WebAssociatedURLLoaderImpl::CancelLoader() {
450 if (!client_adapter_)
451 return;
452
453 // Prevent invocation of the WebAssociatedURLLoaderClient methods.
454 client_adapter_->ReleaseClient();
455
456 if (loader_) {
457 loader_->Cancel();
458 loader_ = nullptr;
459 }
460 client_adapter_.reset();
461 }
462
463 void WebAssociatedURLLoaderImpl::SetDefersLoading(bool defers_loading) {
464 if (loader_)
465 loader_->SetDefersLoading(defers_loading);
466 }
467
468 void WebAssociatedURLLoaderImpl::SetLoadingTaskRunner(blink::WebTaskRunner*) {
469 // TODO(alexclarke): Maybe support this one day if it proves worthwhile.
470 }
471
472 void WebAssociatedURLLoaderImpl::DocumentDestroyed() {
473 DisposeObserver();
474 CancelLoader();
475
476 if (!client_)
477 return;
478
479 ReleaseClient()->DidFail(ResourceError());
480 // |this| may be dead here.
481 }
482
483 void WebAssociatedURLLoaderImpl::DisposeObserver() {
484 if (!observer_)
485 return;
486
487 // TODO(tyoshino): Remove this assert once Document is fixed so that
488 // contextDestroyed() is invoked for all kinds of Documents.
489 //
490 // Currently, the method of detecting Document destruction implemented here
491 // doesn't work for all kinds of Documents. In case we reached here after
492 // the Oilpan is destroyed, we just crash the renderer process to prevent
493 // UaF.
494 //
495 // We could consider just skipping the rest of code in case
496 // ThreadState::current() is null. However, the fact we reached here
497 // without cancelling the loader means that it's possible there're some
498 // non-Blink non-on-heap objects still facing on-heap Blink objects. E.g.
499 // there could be a WebURLLoader instance behind the
500 // DocumentThreadableLoader instance. So, for safety, we chose to just
501 // crash here.
502 CHECK(ThreadState::Current());
503
504 observer_->Dispose();
505 observer_ = nullptr;
506 }
507
508 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/web/WebAssociatedURLLoaderImpl.h ('k') | third_party/WebKit/Source/web/WebLocalFrameImpl.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698