| Index: third_party/WebKit/Source/web/AssociatedURLLoader.cpp
|
| diff --git a/third_party/WebKit/Source/web/AssociatedURLLoader.cpp b/third_party/WebKit/Source/web/AssociatedURLLoader.cpp
|
| deleted file mode 100644
|
| index afa383855651aee3731f832689eca4e79507cc34..0000000000000000000000000000000000000000
|
| --- a/third_party/WebKit/Source/web/AssociatedURLLoader.cpp
|
| +++ /dev/null
|
| @@ -1,489 +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/AssociatedURLLoader.h"
|
| -
|
| -#include "core/dom/ContextLifecycleObserver.h"
|
| -#include "core/fetch/CrossOriginAccessControl.h"
|
| -#include "core/fetch/FetchUtils.h"
|
| -#include "core/loader/DocumentThreadableLoader.h"
|
| -#include "core/loader/DocumentThreadableLoaderClient.h"
|
| -#include "platform/Timer.h"
|
| -#include "platform/exported/WrappedResourceRequest.h"
|
| -#include "platform/exported/WrappedResourceResponse.h"
|
| -#include "platform/network/HTTPParsers.h"
|
| -#include "platform/network/ResourceError.h"
|
| -#include "public/platform/WebHTTPHeaderVisitor.h"
|
| -#include "public/platform/WebString.h"
|
| -#include "public/platform/WebURLError.h"
|
| -#include "public/platform/WebURLLoaderClient.h"
|
| -#include "public/platform/WebURLRequest.h"
|
| -#include "public/web/WebDataSource.h"
|
| -#include "web/WebLocalFrameImpl.h"
|
| -#include "wtf/HashSet.h"
|
| -#include "wtf/PtrUtil.h"
|
| -#include "wtf/text/WTFString.h"
|
| -#include <limits.h>
|
| -#include <memory>
|
| -
|
| -namespace blink {
|
| -
|
| -namespace {
|
| -
|
| -class HTTPRequestHeaderValidator : public WebHTTPHeaderVisitor {
|
| - WTF_MAKE_NONCOPYABLE(HTTPRequestHeaderValidator);
|
| -
|
| - public:
|
| - HTTPRequestHeaderValidator() : m_isSafe(true) {}
|
| - ~HTTPRequestHeaderValidator() override {}
|
| -
|
| - void visitHeader(const WebString& name, const WebString& value) override;
|
| - bool isSafe() const { return m_isSafe; }
|
| -
|
| - private:
|
| - bool m_isSafe;
|
| -};
|
| -
|
| -void HTTPRequestHeaderValidator::visitHeader(const WebString& name,
|
| - const WebString& value) {
|
| - m_isSafe = m_isSafe && 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 WebURLLoaderClient.
|
| -class AssociatedURLLoader::ClientAdapter final
|
| - : public DocumentThreadableLoaderClient {
|
| - WTF_MAKE_NONCOPYABLE(ClientAdapter);
|
| -
|
| - public:
|
| - static std::unique_ptr<ClientAdapter> create(AssociatedURLLoader*,
|
| - WebURLLoaderClient*,
|
| - const WebURLLoaderOptions&);
|
| -
|
| - // 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 WebURLLoaderClient. These
|
| - // must be deferred until after the call to
|
| - // AssociatedURLLoader::loadAsynchronously() completes.
|
| - void enableErrorNotifications();
|
| -
|
| - // Stops loading and releases the DocumentThreadableLoader as early as
|
| - // possible.
|
| - WebURLLoaderClient* releaseClient() {
|
| - WebURLLoaderClient* client = m_client;
|
| - m_client = nullptr;
|
| - return client;
|
| - }
|
| -
|
| - private:
|
| - ClientAdapter(AssociatedURLLoader*,
|
| - WebURLLoaderClient*,
|
| - const WebURLLoaderOptions&);
|
| -
|
| - void notifyError(TimerBase*);
|
| -
|
| - AssociatedURLLoader* m_loader;
|
| - WebURLLoaderClient* m_client;
|
| - WebURLLoaderOptions m_options;
|
| - WebURLError m_error;
|
| -
|
| - Timer<ClientAdapter> m_errorTimer;
|
| - bool m_enableErrorNotifications;
|
| - bool m_didFail;
|
| -};
|
| -
|
| -std::unique_ptr<AssociatedURLLoader::ClientAdapter>
|
| -AssociatedURLLoader::ClientAdapter::create(AssociatedURLLoader* loader,
|
| - WebURLLoaderClient* client,
|
| - const WebURLLoaderOptions& options) {
|
| - return wrapUnique(new ClientAdapter(loader, client, options));
|
| -}
|
| -
|
| -AssociatedURLLoader::ClientAdapter::ClientAdapter(
|
| - AssociatedURLLoader* loader,
|
| - WebURLLoaderClient* client,
|
| - const WebURLLoaderOptions& options)
|
| - : m_loader(loader),
|
| - m_client(client),
|
| - m_options(options),
|
| - m_errorTimer(this, &ClientAdapter::notifyError),
|
| - m_enableErrorNotifications(false),
|
| - m_didFail(false) {
|
| - DCHECK(m_loader);
|
| - DCHECK(m_client);
|
| -}
|
| -
|
| -bool AssociatedURLLoader::ClientAdapter::willFollowRedirect(
|
| - const ResourceRequest& newRequest,
|
| - const ResourceResponse& redirectResponse) {
|
| - if (!m_client)
|
| - return true;
|
| -
|
| - WrappedResourceRequest wrappedNewRequest(newRequest);
|
| - WrappedResourceResponse wrappedRedirectResponse(redirectResponse);
|
| - return m_client->willFollowRedirect(m_loader, wrappedNewRequest,
|
| - wrappedRedirectResponse);
|
| -}
|
| -
|
| -void AssociatedURLLoader::ClientAdapter::didSendData(
|
| - unsigned long long bytesSent,
|
| - unsigned long long totalBytesToBeSent) {
|
| - if (!m_client)
|
| - return;
|
| -
|
| - m_client->didSendData(m_loader, bytesSent, totalBytesToBeSent);
|
| -}
|
| -
|
| -void AssociatedURLLoader::ClientAdapter::didReceiveResponse(
|
| - unsigned long,
|
| - const ResourceResponse& response,
|
| - std::unique_ptr<WebDataConsumerHandle> handle) {
|
| - DCHECK(!handle);
|
| - if (!m_client)
|
| - return;
|
| -
|
| - if (m_options.exposeAllResponseHeaders ||
|
| - m_options.crossOriginRequestPolicy !=
|
| - WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl) {
|
| - // Use the original ResourceResponse.
|
| - m_client->didReceiveResponse(m_loader, WrappedResourceResponse(response));
|
| - return;
|
| - }
|
| -
|
| - HTTPHeaderSet exposedHeaders;
|
| - extractCorsExposedHeaderNamesList(response, exposedHeaders);
|
| - HTTPHeaderSet blockedHeaders;
|
| - for (const auto& header : response.httpHeaderFields()) {
|
| - if (FetchUtils::isForbiddenResponseHeaderName(header.key) ||
|
| - (!isOnAccessControlResponseHeaderWhitelist(header.key) &&
|
| - !exposedHeaders.contains(header.key)))
|
| - blockedHeaders.add(header.key);
|
| - }
|
| -
|
| - if (blockedHeaders.isEmpty()) {
|
| - // Use the original ResourceResponse.
|
| - m_client->didReceiveResponse(m_loader, WrappedResourceResponse(response));
|
| - return;
|
| - }
|
| -
|
| - // If there are blocked headers, copy the response so we can remove them.
|
| - WebURLResponse validatedResponse = WrappedResourceResponse(response);
|
| - for (const auto& header : blockedHeaders)
|
| - validatedResponse.clearHTTPHeaderField(header);
|
| - m_client->didReceiveResponse(m_loader, validatedResponse);
|
| -}
|
| -
|
| -void AssociatedURLLoader::ClientAdapter::didDownloadData(int dataLength) {
|
| - if (!m_client)
|
| - return;
|
| -
|
| - m_client->didDownloadData(m_loader, dataLength, -1);
|
| -}
|
| -
|
| -void AssociatedURLLoader::ClientAdapter::didReceiveData(const char* data,
|
| - unsigned dataLength) {
|
| - if (!m_client)
|
| - return;
|
| -
|
| - CHECK_LE(dataLength, static_cast<unsigned>(std::numeric_limits<int>::max()));
|
| -
|
| - m_client->didReceiveData(m_loader, data, dataLength, -1, dataLength);
|
| -}
|
| -
|
| -void AssociatedURLLoader::ClientAdapter::didReceiveCachedMetadata(
|
| - const char* data,
|
| - int dataLength) {
|
| - if (!m_client)
|
| - return;
|
| -
|
| - m_client->didReceiveCachedMetadata(m_loader, data, dataLength);
|
| -}
|
| -
|
| -void AssociatedURLLoader::ClientAdapter::didFinishLoading(
|
| - unsigned long identifier,
|
| - double finishTime) {
|
| - if (!m_client)
|
| - return;
|
| -
|
| - m_loader->clientAdapterDone();
|
| -
|
| - releaseClient()->didFinishLoading(
|
| - m_loader, finishTime, WebURLLoaderClient::kUnknownEncodedDataLength);
|
| - // |this| may be dead here.
|
| -}
|
| -
|
| -void AssociatedURLLoader::ClientAdapter::didFail(const ResourceError& error) {
|
| - if (!m_client)
|
| - return;
|
| -
|
| - m_loader->clientAdapterDone();
|
| -
|
| - m_didFail = true;
|
| - m_error = WebURLError(error);
|
| - if (m_enableErrorNotifications)
|
| - notifyError(&m_errorTimer);
|
| -}
|
| -
|
| -void AssociatedURLLoader::ClientAdapter::didFailRedirectCheck() {
|
| - didFail(ResourceError());
|
| -}
|
| -
|
| -void AssociatedURLLoader::ClientAdapter::enableErrorNotifications() {
|
| - m_enableErrorNotifications = true;
|
| - // If an error has already been received, start a timer to report it to the
|
| - // client after AssociatedURLLoader::loadAsynchronously has returned to the
|
| - // caller.
|
| - if (m_didFail)
|
| - m_errorTimer.startOneShot(0, BLINK_FROM_HERE);
|
| -}
|
| -
|
| -void AssociatedURLLoader::ClientAdapter::notifyError(TimerBase* timer) {
|
| - DCHECK_EQ(timer, &m_errorTimer);
|
| -
|
| - if (m_client)
|
| - releaseClient()->didFail(m_loader, m_error);
|
| - // |this| may be dead here.
|
| -}
|
| -
|
| -class AssociatedURLLoader::Observer final : public GarbageCollected<Observer>,
|
| - public ContextLifecycleObserver {
|
| - USING_GARBAGE_COLLECTED_MIXIN(Observer);
|
| -
|
| - public:
|
| - Observer(AssociatedURLLoader* parent, Document* document)
|
| - : ContextLifecycleObserver(document), m_parent(parent) {}
|
| -
|
| - void dispose() {
|
| - m_parent = nullptr;
|
| - clearContext();
|
| - }
|
| -
|
| - void contextDestroyed() override {
|
| - if (m_parent)
|
| - m_parent->documentDestroyed();
|
| - }
|
| -
|
| - DEFINE_INLINE_VIRTUAL_TRACE() { ContextLifecycleObserver::trace(visitor); }
|
| -
|
| - AssociatedURLLoader* m_parent;
|
| -};
|
| -
|
| -AssociatedURLLoader::AssociatedURLLoader(WebLocalFrameImpl* frameImpl,
|
| - const WebURLLoaderOptions& options)
|
| - : m_client(nullptr),
|
| - m_options(options),
|
| - m_observer(new Observer(this, frameImpl->frame()->document())) {}
|
| -
|
| -AssociatedURLLoader::~AssociatedURLLoader() {
|
| - cancel();
|
| -}
|
| -
|
| -#define STATIC_ASSERT_ENUM(a, b) \
|
| - static_assert(static_cast<int>(a) == static_cast<int>(b), \
|
| - "mismatching enum: " #a)
|
| -
|
| -STATIC_ASSERT_ENUM(WebURLLoaderOptions::CrossOriginRequestPolicyDeny,
|
| - DenyCrossOriginRequests);
|
| -STATIC_ASSERT_ENUM(
|
| - WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl,
|
| - UseAccessControl);
|
| -STATIC_ASSERT_ENUM(WebURLLoaderOptions::CrossOriginRequestPolicyAllow,
|
| - AllowCrossOriginRequests);
|
| -
|
| -STATIC_ASSERT_ENUM(WebURLLoaderOptions::ConsiderPreflight, ConsiderPreflight);
|
| -STATIC_ASSERT_ENUM(WebURLLoaderOptions::ForcePreflight, ForcePreflight);
|
| -STATIC_ASSERT_ENUM(WebURLLoaderOptions::PreventPreflight, PreventPreflight);
|
| -
|
| -void AssociatedURLLoader::loadSynchronously(const WebURLRequest& request,
|
| - WebURLResponse& response,
|
| - WebURLError& error,
|
| - WebData& data,
|
| - int64_t& encodedDataLength) {
|
| - DCHECK(0); // Synchronous loading is not supported.
|
| -}
|
| -
|
| -void AssociatedURLLoader::loadAsynchronously(const WebURLRequest& request,
|
| - WebURLLoaderClient* client) {
|
| - DCHECK(!m_client);
|
| - DCHECK(!m_loader);
|
| - DCHECK(!m_clientAdapter);
|
| -
|
| - DCHECK(client);
|
| -
|
| - bool allowLoad = true;
|
| - WebURLRequest newRequest(request);
|
| - if (m_options.untrustedHTTP) {
|
| - WebString method = newRequest.httpMethod();
|
| - allowLoad = m_observer && isValidHTTPToken(method) &&
|
| - FetchUtils::isUsefulMethod(method);
|
| - if (allowLoad) {
|
| - newRequest.setHTTPMethod(FetchUtils::normalizeMethod(method));
|
| - HTTPRequestHeaderValidator validator;
|
| - newRequest.visitHTTPHeaderFields(&validator);
|
| - allowLoad = validator.isSafe();
|
| - }
|
| - }
|
| -
|
| - m_client = client;
|
| - m_clientAdapter = ClientAdapter::create(this, client, m_options);
|
| -
|
| - if (allowLoad) {
|
| - ThreadableLoaderOptions options;
|
| - options.preflightPolicy =
|
| - static_cast<PreflightPolicy>(m_options.preflightPolicy);
|
| - options.crossOriginRequestPolicy = static_cast<CrossOriginRequestPolicy>(
|
| - m_options.crossOriginRequestPolicy);
|
| -
|
| - ResourceLoaderOptions resourceLoaderOptions;
|
| - resourceLoaderOptions.allowCredentials = m_options.allowCredentials
|
| - ? AllowStoredCredentials
|
| - : DoNotAllowStoredCredentials;
|
| - resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData;
|
| -
|
| - const ResourceRequest& webcoreRequest = newRequest.toResourceRequest();
|
| - if (webcoreRequest.requestContext() ==
|
| - WebURLRequest::RequestContextUnspecified) {
|
| - // 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.
|
| - newRequest.setRequestContext(WebURLRequest::RequestContextInternal);
|
| - }
|
| -
|
| - Document* document = toDocument(m_observer->lifecycleContext());
|
| - DCHECK(document);
|
| - m_loader = DocumentThreadableLoader::create(
|
| - *document, m_clientAdapter.get(), options, resourceLoaderOptions);
|
| - m_loader->start(webcoreRequest);
|
| - }
|
| -
|
| - if (!m_loader) {
|
| - // FIXME: return meaningful error codes.
|
| - m_clientAdapter->didFail(ResourceError());
|
| - }
|
| - m_clientAdapter->enableErrorNotifications();
|
| -}
|
| -
|
| -void AssociatedURLLoader::cancel() {
|
| - disposeObserver();
|
| - cancelLoader();
|
| - releaseClient();
|
| -}
|
| -
|
| -void AssociatedURLLoader::clientAdapterDone() {
|
| - disposeObserver();
|
| - releaseClient();
|
| -}
|
| -
|
| -void AssociatedURLLoader::cancelLoader() {
|
| - if (!m_clientAdapter)
|
| - return;
|
| -
|
| - // Prevent invocation of the WebURLLoaderClient methods.
|
| - m_clientAdapter->releaseClient();
|
| -
|
| - if (m_loader) {
|
| - m_loader->cancel();
|
| - m_loader = nullptr;
|
| - }
|
| - m_clientAdapter.reset();
|
| -}
|
| -
|
| -void AssociatedURLLoader::setDefersLoading(bool defersLoading) {
|
| - if (m_loader)
|
| - m_loader->setDefersLoading(defersLoading);
|
| -}
|
| -
|
| -void AssociatedURLLoader::setLoadingTaskRunner(blink::WebTaskRunner*) {
|
| - // TODO(alexclarke): Maybe support this one day if it proves worthwhile.
|
| -}
|
| -
|
| -void AssociatedURLLoader::documentDestroyed() {
|
| - disposeObserver();
|
| - cancelLoader();
|
| -
|
| - if (!m_client)
|
| - return;
|
| -
|
| - releaseClient()->didFail(this, ResourceError());
|
| - // |this| may be dead here.
|
| -}
|
| -
|
| -void AssociatedURLLoader::disposeObserver() {
|
| - if (!m_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.
|
| - RELEASE_ASSERT(ThreadState::current());
|
| -
|
| - m_observer->dispose();
|
| - m_observer = nullptr;
|
| -}
|
| -
|
| -} // namespace blink
|
|
|