| Index: third_party/WebKit/Source/web/WebAssociatedURLLoaderImpl.cpp
|
| diff --git a/third_party/WebKit/Source/web/WebAssociatedURLLoaderImpl.cpp b/third_party/WebKit/Source/web/WebAssociatedURLLoaderImpl.cpp
|
| deleted file mode 100644
|
| index 8d212a2a6e422f58db1cb6f2e958d21db9c4838b..0000000000000000000000000000000000000000
|
| --- a/third_party/WebKit/Source/web/WebAssociatedURLLoaderImpl.cpp
|
| +++ /dev/null
|
| @@ -1,508 +0,0 @@
|
| -/*
|
| - * Copyright (C) 2010, 2011, 2012 Google Inc. All rights reserved.
|
| - *
|
| - * Redistribution and use in source and binary forms, with or without
|
| - * modification, are permitted provided that the following conditions are
|
| - * met:
|
| - *
|
| - * * Redistributions of source code must retain the above copyright
|
| - * notice, this list of conditions and the following disclaimer.
|
| - * * Redistributions in binary form must reproduce the above
|
| - * copyright notice, this list of conditions and the following disclaimer
|
| - * in the documentation and/or other materials provided with the
|
| - * distribution.
|
| - * * Neither the name of Google Inc. nor the names of its
|
| - * contributors may be used to endorse or promote products derived from
|
| - * this software without specific prior written permission.
|
| - *
|
| - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| - */
|
| -
|
| -#include "web/WebAssociatedURLLoaderImpl.h"
|
| -
|
| -#include <limits.h>
|
| -#include <memory>
|
| -#include "core/dom/ContextLifecycleObserver.h"
|
| -#include "core/dom/TaskRunnerHelper.h"
|
| -#include "core/loader/DocumentThreadableLoader.h"
|
| -#include "core/loader/DocumentThreadableLoaderClient.h"
|
| -#include "core/loader/ThreadableLoadingContext.h"
|
| -#include "platform/Timer.h"
|
| -#include "platform/exported/WrappedResourceRequest.h"
|
| -#include "platform/exported/WrappedResourceResponse.h"
|
| -#include "platform/loader/fetch/CrossOriginAccessControl.h"
|
| -#include "platform/loader/fetch/FetchUtils.h"
|
| -#include "platform/loader/fetch/ResourceError.h"
|
| -#include "platform/network/HTTPParsers.h"
|
| -#include "platform/wtf/HashSet.h"
|
| -#include "platform/wtf/PtrUtil.h"
|
| -#include "platform/wtf/text/WTFString.h"
|
| -#include "public/platform/WebHTTPHeaderVisitor.h"
|
| -#include "public/platform/WebString.h"
|
| -#include "public/platform/WebURLError.h"
|
| -#include "public/platform/WebURLRequest.h"
|
| -#include "public/web/WebAssociatedURLLoaderClient.h"
|
| -#include "public/web/WebDataSource.h"
|
| -#include "web/WebLocalFrameImpl.h"
|
| -
|
| -namespace blink {
|
| -
|
| -namespace {
|
| -
|
| -class HTTPRequestHeaderValidator : public WebHTTPHeaderVisitor {
|
| - WTF_MAKE_NONCOPYABLE(HTTPRequestHeaderValidator);
|
| -
|
| - public:
|
| - HTTPRequestHeaderValidator() : is_safe_(true) {}
|
| - ~HTTPRequestHeaderValidator() override {}
|
| -
|
| - void VisitHeader(const WebString& name, const WebString& value) override;
|
| - bool IsSafe() const { return is_safe_; }
|
| -
|
| - private:
|
| - bool is_safe_;
|
| -};
|
| -
|
| -void HTTPRequestHeaderValidator::VisitHeader(const WebString& name,
|
| - const WebString& value) {
|
| - is_safe_ = is_safe_ && IsValidHTTPToken(name) &&
|
| - !FetchUtils::IsForbiddenHeaderName(name) &&
|
| - IsValidHTTPHeaderValue(value);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -// This class bridges the interface differences between WebCore and WebKit
|
| -// loader clients.
|
| -// It forwards its ThreadableLoaderClient notifications to a
|
| -// WebAssociatedURLLoaderClient.
|
| -class WebAssociatedURLLoaderImpl::ClientAdapter final
|
| - : public DocumentThreadableLoaderClient {
|
| - WTF_MAKE_NONCOPYABLE(ClientAdapter);
|
| -
|
| - public:
|
| - static std::unique_ptr<ClientAdapter> Create(
|
| - WebAssociatedURLLoaderImpl*,
|
| - WebAssociatedURLLoaderClient*,
|
| - const WebAssociatedURLLoaderOptions&,
|
| - RefPtr<WebTaskRunner>);
|
| -
|
| - // ThreadableLoaderClient
|
| - void DidSendData(unsigned long long /*bytesSent*/,
|
| - unsigned long long /*totalBytesToBeSent*/) override;
|
| - void DidReceiveResponse(unsigned long,
|
| - const ResourceResponse&,
|
| - std::unique_ptr<WebDataConsumerHandle>) override;
|
| - void DidDownloadData(int /*dataLength*/) override;
|
| - void DidReceiveData(const char*, unsigned /*dataLength*/) override;
|
| - void DidReceiveCachedMetadata(const char*, int /*dataLength*/) override;
|
| - void DidFinishLoading(unsigned long /*identifier*/,
|
| - double /*finishTime*/) override;
|
| - void DidFail(const ResourceError&) override;
|
| - void DidFailRedirectCheck() override;
|
| -
|
| - // DocumentThreadableLoaderClient
|
| - bool WillFollowRedirect(
|
| - const ResourceRequest& /*newRequest*/,
|
| - const ResourceResponse& /*redirectResponse*/) override;
|
| -
|
| - // Sets an error to be reported back to the client, asychronously.
|
| - void SetDelayedError(const ResourceError&);
|
| -
|
| - // Enables forwarding of error notifications to the
|
| - // WebAssociatedURLLoaderClient. These
|
| - // must be deferred until after the call to
|
| - // WebAssociatedURLLoader::loadAsynchronously() completes.
|
| - void EnableErrorNotifications();
|
| -
|
| - // Stops loading and releases the DocumentThreadableLoader as early as
|
| - // possible.
|
| - WebAssociatedURLLoaderClient* ReleaseClient() {
|
| - WebAssociatedURLLoaderClient* client = client_;
|
| - client_ = nullptr;
|
| - return client;
|
| - }
|
| -
|
| - private:
|
| - ClientAdapter(WebAssociatedURLLoaderImpl*,
|
| - WebAssociatedURLLoaderClient*,
|
| - const WebAssociatedURLLoaderOptions&,
|
| - RefPtr<WebTaskRunner>);
|
| -
|
| - void NotifyError(TimerBase*);
|
| -
|
| - WebAssociatedURLLoaderImpl* loader_;
|
| - WebAssociatedURLLoaderClient* client_;
|
| - WebAssociatedURLLoaderOptions options_;
|
| - WebURLError error_;
|
| -
|
| - TaskRunnerTimer<ClientAdapter> error_timer_;
|
| - bool enable_error_notifications_;
|
| - bool did_fail_;
|
| -};
|
| -
|
| -std::unique_ptr<WebAssociatedURLLoaderImpl::ClientAdapter>
|
| -WebAssociatedURLLoaderImpl::ClientAdapter::Create(
|
| - WebAssociatedURLLoaderImpl* loader,
|
| - WebAssociatedURLLoaderClient* client,
|
| - const WebAssociatedURLLoaderOptions& options,
|
| - RefPtr<WebTaskRunner> task_runner) {
|
| - return WTF::WrapUnique(
|
| - new ClientAdapter(loader, client, options, task_runner));
|
| -}
|
| -
|
| -WebAssociatedURLLoaderImpl::ClientAdapter::ClientAdapter(
|
| - WebAssociatedURLLoaderImpl* loader,
|
| - WebAssociatedURLLoaderClient* client,
|
| - const WebAssociatedURLLoaderOptions& options,
|
| - RefPtr<WebTaskRunner> task_runner)
|
| - : loader_(loader),
|
| - client_(client),
|
| - options_(options),
|
| - error_timer_(std::move(task_runner), this, &ClientAdapter::NotifyError),
|
| - enable_error_notifications_(false),
|
| - did_fail_(false) {
|
| - DCHECK(loader_);
|
| - DCHECK(client_);
|
| -}
|
| -
|
| -bool WebAssociatedURLLoaderImpl::ClientAdapter::WillFollowRedirect(
|
| - const ResourceRequest& new_request,
|
| - const ResourceResponse& redirect_response) {
|
| - if (!client_)
|
| - return true;
|
| -
|
| - WrappedResourceRequest wrapped_new_request(new_request);
|
| - WrappedResourceResponse wrapped_redirect_response(redirect_response);
|
| - return client_->WillFollowRedirect(wrapped_new_request,
|
| - wrapped_redirect_response);
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::ClientAdapter::DidSendData(
|
| - unsigned long long bytes_sent,
|
| - unsigned long long total_bytes_to_be_sent) {
|
| - if (!client_)
|
| - return;
|
| -
|
| - client_->DidSendData(bytes_sent, total_bytes_to_be_sent);
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::ClientAdapter::DidReceiveResponse(
|
| - unsigned long,
|
| - const ResourceResponse& response,
|
| - std::unique_ptr<WebDataConsumerHandle> handle) {
|
| - ALLOW_UNUSED_LOCAL(handle);
|
| - DCHECK(!handle);
|
| - if (!client_)
|
| - return;
|
| -
|
| - if (options_.expose_all_response_headers ||
|
| - options_.cross_origin_request_policy !=
|
| - WebAssociatedURLLoaderOptions::
|
| - kCrossOriginRequestPolicyUseAccessControl) {
|
| - // Use the original ResourceResponse.
|
| - client_->DidReceiveResponse(WrappedResourceResponse(response));
|
| - return;
|
| - }
|
| -
|
| - HTTPHeaderSet exposed_headers;
|
| - ExtractCorsExposedHeaderNamesList(response, exposed_headers);
|
| - HTTPHeaderSet blocked_headers;
|
| - for (const auto& header : response.HttpHeaderFields()) {
|
| - if (FetchUtils::IsForbiddenResponseHeaderName(header.key) ||
|
| - (!IsOnAccessControlResponseHeaderWhitelist(header.key) &&
|
| - !exposed_headers.Contains(header.key)))
|
| - blocked_headers.insert(header.key);
|
| - }
|
| -
|
| - if (blocked_headers.IsEmpty()) {
|
| - // Use the original ResourceResponse.
|
| - client_->DidReceiveResponse(WrappedResourceResponse(response));
|
| - return;
|
| - }
|
| -
|
| - // If there are blocked headers, copy the response so we can remove them.
|
| - WebURLResponse validated_response = WrappedResourceResponse(response);
|
| - for (const auto& header : blocked_headers)
|
| - validated_response.ClearHTTPHeaderField(header);
|
| - client_->DidReceiveResponse(validated_response);
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::ClientAdapter::DidDownloadData(
|
| - int data_length) {
|
| - if (!client_)
|
| - return;
|
| -
|
| - client_->DidDownloadData(data_length);
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::ClientAdapter::DidReceiveData(
|
| - const char* data,
|
| - unsigned data_length) {
|
| - if (!client_)
|
| - return;
|
| -
|
| - CHECK_LE(data_length, static_cast<unsigned>(std::numeric_limits<int>::max()));
|
| -
|
| - client_->DidReceiveData(data, data_length);
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::ClientAdapter::DidReceiveCachedMetadata(
|
| - const char* data,
|
| - int data_length) {
|
| - if (!client_)
|
| - return;
|
| -
|
| - client_->DidReceiveCachedMetadata(data, data_length);
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::ClientAdapter::DidFinishLoading(
|
| - unsigned long identifier,
|
| - double finish_time) {
|
| - if (!client_)
|
| - return;
|
| -
|
| - loader_->ClientAdapterDone();
|
| -
|
| - ReleaseClient()->DidFinishLoading(finish_time);
|
| - // |this| may be dead here.
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::ClientAdapter::DidFail(
|
| - const ResourceError& error) {
|
| - if (!client_)
|
| - return;
|
| -
|
| - loader_->ClientAdapterDone();
|
| -
|
| - did_fail_ = true;
|
| - error_ = WebURLError(error);
|
| - if (enable_error_notifications_)
|
| - NotifyError(&error_timer_);
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::ClientAdapter::DidFailRedirectCheck() {
|
| - DidFail(ResourceError());
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::ClientAdapter::EnableErrorNotifications() {
|
| - enable_error_notifications_ = true;
|
| - // If an error has already been received, start a timer to report it to the
|
| - // client after WebAssociatedURLLoader::loadAsynchronously has returned to the
|
| - // caller.
|
| - if (did_fail_)
|
| - error_timer_.StartOneShot(0, BLINK_FROM_HERE);
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::ClientAdapter::NotifyError(TimerBase* timer) {
|
| - DCHECK_EQ(timer, &error_timer_);
|
| -
|
| - if (client_)
|
| - ReleaseClient()->DidFail(error_);
|
| - // |this| may be dead here.
|
| -}
|
| -
|
| -class WebAssociatedURLLoaderImpl::Observer final
|
| - : public GarbageCollected<Observer>,
|
| - public ContextLifecycleObserver {
|
| - USING_GARBAGE_COLLECTED_MIXIN(Observer);
|
| -
|
| - public:
|
| - Observer(WebAssociatedURLLoaderImpl* parent, Document* document)
|
| - : ContextLifecycleObserver(document), parent_(parent) {}
|
| -
|
| - void Dispose() {
|
| - parent_ = nullptr;
|
| - ClearContext();
|
| - }
|
| -
|
| - void ContextDestroyed(ExecutionContext*) override {
|
| - if (parent_)
|
| - parent_->DocumentDestroyed();
|
| - }
|
| -
|
| - DEFINE_INLINE_VIRTUAL_TRACE() { ContextLifecycleObserver::Trace(visitor); }
|
| -
|
| - WebAssociatedURLLoaderImpl* parent_;
|
| -};
|
| -
|
| -WebAssociatedURLLoaderImpl::WebAssociatedURLLoaderImpl(
|
| - WebLocalFrameImpl* frame_impl,
|
| - const WebAssociatedURLLoaderOptions& options)
|
| - : client_(nullptr),
|
| - options_(options),
|
| - observer_(new Observer(this, frame_impl->GetFrame()->GetDocument())) {}
|
| -
|
| -WebAssociatedURLLoaderImpl::~WebAssociatedURLLoaderImpl() {
|
| - Cancel();
|
| -}
|
| -
|
| -#define STATIC_ASSERT_ENUM(a, b) \
|
| - static_assert(static_cast<int>(a) == static_cast<int>(b), \
|
| - "mismatching enum: " #a)
|
| -
|
| -STATIC_ASSERT_ENUM(WebAssociatedURLLoaderOptions::kCrossOriginRequestPolicyDeny,
|
| - kDenyCrossOriginRequests);
|
| -STATIC_ASSERT_ENUM(
|
| - WebAssociatedURLLoaderOptions::kCrossOriginRequestPolicyUseAccessControl,
|
| - kUseAccessControl);
|
| -STATIC_ASSERT_ENUM(
|
| - WebAssociatedURLLoaderOptions::kCrossOriginRequestPolicyAllow,
|
| - kAllowCrossOriginRequests);
|
| -
|
| -STATIC_ASSERT_ENUM(WebAssociatedURLLoaderOptions::kConsiderPreflight,
|
| - kConsiderPreflight);
|
| -STATIC_ASSERT_ENUM(WebAssociatedURLLoaderOptions::kForcePreflight,
|
| - kForcePreflight);
|
| -STATIC_ASSERT_ENUM(WebAssociatedURLLoaderOptions::kPreventPreflight,
|
| - kPreventPreflight);
|
| -
|
| -void WebAssociatedURLLoaderImpl::LoadAsynchronously(
|
| - const WebURLRequest& request,
|
| - WebAssociatedURLLoaderClient* client) {
|
| - DCHECK(!client_);
|
| - DCHECK(!loader_);
|
| - DCHECK(!client_adapter_);
|
| -
|
| - DCHECK(client);
|
| -
|
| - bool allow_load = true;
|
| - WebURLRequest new_request(request);
|
| - if (options_.untrusted_http) {
|
| - WebString method = new_request.HttpMethod();
|
| - allow_load = observer_ && IsValidHTTPToken(method) &&
|
| - FetchUtils::IsUsefulMethod(method);
|
| - if (allow_load) {
|
| - new_request.SetHTTPMethod(FetchUtils::NormalizeMethod(method));
|
| - HTTPRequestHeaderValidator validator;
|
| - new_request.VisitHTTPHeaderFields(&validator);
|
| - allow_load = validator.IsSafe();
|
| - }
|
| - }
|
| -
|
| - RefPtr<WebTaskRunner> task_runner = TaskRunnerHelper::Get(
|
| - TaskType::kUnspecedLoading,
|
| - observer_ ? ToDocument(observer_->LifecycleContext()) : nullptr);
|
| - client_ = client;
|
| - client_adapter_ =
|
| - ClientAdapter::Create(this, client, options_, std::move(task_runner));
|
| -
|
| - if (allow_load) {
|
| - ThreadableLoaderOptions options;
|
| - options.preflight_policy =
|
| - static_cast<PreflightPolicy>(options_.preflight_policy);
|
| - options.cross_origin_request_policy = static_cast<CrossOriginRequestPolicy>(
|
| - options_.cross_origin_request_policy);
|
| -
|
| - ResourceLoaderOptions resource_loader_options;
|
| - resource_loader_options.allow_credentials =
|
| - options_.allow_credentials ? kAllowStoredCredentials
|
| - : kDoNotAllowStoredCredentials;
|
| - resource_loader_options.data_buffering_policy = kDoNotBufferData;
|
| -
|
| - const ResourceRequest& webcore_request = new_request.ToResourceRequest();
|
| - if (webcore_request.GetRequestContext() ==
|
| - WebURLRequest::kRequestContextUnspecified) {
|
| - // FIXME: We load URLs without setting a TargetType (and therefore a
|
| - // request context) in several places in content/
|
| - // (P2PPortAllocatorSession::AllocateLegacyRelaySession, for example).
|
| - // Remove this once those places are patched up.
|
| - new_request.SetRequestContext(WebURLRequest::kRequestContextInternal);
|
| - }
|
| -
|
| - Document* document = ToDocument(observer_->LifecycleContext());
|
| - DCHECK(document);
|
| - loader_ = DocumentThreadableLoader::Create(
|
| - *ThreadableLoadingContext::Create(*document), client_adapter_.get(),
|
| - options, resource_loader_options);
|
| - loader_->Start(webcore_request);
|
| - }
|
| -
|
| - if (!loader_) {
|
| - // FIXME: return meaningful error codes.
|
| - client_adapter_->DidFail(ResourceError());
|
| - }
|
| - client_adapter_->EnableErrorNotifications();
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::Cancel() {
|
| - DisposeObserver();
|
| - CancelLoader();
|
| - ReleaseClient();
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::ClientAdapterDone() {
|
| - DisposeObserver();
|
| - ReleaseClient();
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::CancelLoader() {
|
| - if (!client_adapter_)
|
| - return;
|
| -
|
| - // Prevent invocation of the WebAssociatedURLLoaderClient methods.
|
| - client_adapter_->ReleaseClient();
|
| -
|
| - if (loader_) {
|
| - loader_->Cancel();
|
| - loader_ = nullptr;
|
| - }
|
| - client_adapter_.reset();
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::SetDefersLoading(bool defers_loading) {
|
| - if (loader_)
|
| - loader_->SetDefersLoading(defers_loading);
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::SetLoadingTaskRunner(blink::WebTaskRunner*) {
|
| - // TODO(alexclarke): Maybe support this one day if it proves worthwhile.
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::DocumentDestroyed() {
|
| - DisposeObserver();
|
| - CancelLoader();
|
| -
|
| - if (!client_)
|
| - return;
|
| -
|
| - ReleaseClient()->DidFail(ResourceError());
|
| - // |this| may be dead here.
|
| -}
|
| -
|
| -void WebAssociatedURLLoaderImpl::DisposeObserver() {
|
| - if (!observer_)
|
| - return;
|
| -
|
| - // TODO(tyoshino): Remove this assert once Document is fixed so that
|
| - // contextDestroyed() is invoked for all kinds of Documents.
|
| - //
|
| - // Currently, the method of detecting Document destruction implemented here
|
| - // doesn't work for all kinds of Documents. In case we reached here after
|
| - // the Oilpan is destroyed, we just crash the renderer process to prevent
|
| - // UaF.
|
| - //
|
| - // We could consider just skipping the rest of code in case
|
| - // ThreadState::current() is null. However, the fact we reached here
|
| - // without cancelling the loader means that it's possible there're some
|
| - // non-Blink non-on-heap objects still facing on-heap Blink objects. E.g.
|
| - // there could be a WebURLLoader instance behind the
|
| - // DocumentThreadableLoader instance. So, for safety, we chose to just
|
| - // crash here.
|
| - CHECK(ThreadState::Current());
|
| -
|
| - observer_->Dispose();
|
| - observer_ = nullptr;
|
| -}
|
| -
|
| -} // namespace blink
|
|
|