blob: eedd69b65a87605c6a24f46328a4fe4dc15181af [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/fetchers/associated_resource_fetcher_impl.h"
#include <stdint.h>
#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
#include "third_party/WebKit/public/platform/Platform.h"
#include "third_party/WebKit/public/platform/WebHTTPBody.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/platform/WebURLError.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
#include "third_party/WebKit/public/web/WebAssociatedURLLoader.h"
#include "third_party/WebKit/public/web/WebAssociatedURLLoaderClient.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebKit.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
namespace content {
// static
AssociatedResourceFetcher* AssociatedResourceFetcher::Create(const GURL& url) {
return new AssociatedResourceFetcherImpl(url);
}
class AssociatedResourceFetcherImpl::ClientImpl
: public blink::WebAssociatedURLLoaderClient {
public:
explicit ClientImpl(const Callback& callback)
: completed_(false), status_(LOADING), callback_(callback) {}
~ClientImpl() override {}
virtual void Cancel() { OnLoadCompleteInternal(LOAD_FAILED); }
bool completed() const { return completed_; }
private:
enum LoadStatus {
LOADING,
LOAD_FAILED,
LOAD_SUCCEEDED,
};
void OnLoadCompleteInternal(LoadStatus status) {
DCHECK(!completed_);
DCHECK_EQ(status_, LOADING);
completed_ = true;
status_ = status;
if (callback_.is_null())
return;
// Take a reference to the callback as running the callback may lead to our
// destruction.
Callback callback = callback_;
callback.Run(status_ == LOAD_FAILED ? blink::WebURLResponse() : response_,
status_ == LOAD_FAILED ? std::string() : data_);
}
// WebAssociatedURLLoaderClient methods:
void DidReceiveResponse(const blink::WebURLResponse& response) override {
DCHECK(!completed_);
response_ = response;
}
void DidReceiveCachedMetadata(const char* data, int data_length) override {
DCHECK(!completed_);
DCHECK_GT(data_length, 0);
}
void DidReceiveData(const char* data, int data_length) override {
// The WebAssociatedURLLoader will continue after a load failure.
// For example, for an Access Control error.
if (completed_)
return;
DCHECK_GT(data_length, 0);
data_.append(data, data_length);
}
void DidFinishLoading(double finishTime) override {
// The WebAssociatedURLLoader will continue after a load failure.
// For example, for an Access Control error.
if (completed_)
return;
OnLoadCompleteInternal(LOAD_SUCCEEDED);
}
void DidFail(const blink::WebURLError& error) override {
OnLoadCompleteInternal(LOAD_FAILED);
}
private:
// Set to true once the request is complete.
bool completed_;
// Buffer to hold the content from the server.
std::string data_;
// A copy of the original resource response.
blink::WebURLResponse response_;
LoadStatus status_;
// Callback when we're done.
Callback callback_;
DISALLOW_COPY_AND_ASSIGN(ClientImpl);
};
AssociatedResourceFetcherImpl::AssociatedResourceFetcherImpl(const GURL& url)
: request_(url) {}
AssociatedResourceFetcherImpl::~AssociatedResourceFetcherImpl() {
if (!loader_)
return;
DCHECK(client_);
if (!client_->completed())
loader_->Cancel();
}
void AssociatedResourceFetcherImpl::SetServiceWorkerMode(
blink::WebURLRequest::ServiceWorkerMode service_worker_mode) {
DCHECK(!request_.IsNull());
DCHECK(!loader_);
request_.SetServiceWorkerMode(service_worker_mode);
}
void AssociatedResourceFetcherImpl::SetCacheMode(
blink::mojom::FetchCacheMode mode) {
DCHECK(!request_.IsNull());
DCHECK(!loader_);
request_.SetCacheMode(mode);
}
void AssociatedResourceFetcherImpl::SetLoaderOptions(
const blink::WebAssociatedURLLoaderOptions& options) {
DCHECK(!request_.IsNull());
DCHECK(!loader_);
options_ = options;
}
void AssociatedResourceFetcherImpl::Start(
blink::WebLocalFrame* frame,
blink::WebURLRequest::RequestContext request_context,
blink::WebURLRequest::FetchRequestMode fetch_request_mode,
blink::WebURLRequest::FetchCredentialsMode fetch_credentials_mode,
blink::WebURLRequest::FrameType frame_type,
const Callback& callback) {
DCHECK(!loader_);
DCHECK(!client_);
DCHECK(!request_.IsNull());
if (!request_.HttpBody().IsNull())
DCHECK_NE("GET", request_.HttpMethod().Utf8()) << "GETs can't have bodies.";
request_.SetRequestContext(request_context);
request_.SetFrameType(frame_type);
request_.SetSiteForCookies(frame->GetDocument().SiteForCookies());
request_.SetFetchRequestMode(fetch_request_mode);
request_.SetFetchCredentialsMode(fetch_credentials_mode);
client_.reset(new ClientImpl(callback));
loader_.reset(frame->CreateAssociatedURLLoader(options_));
loader_->LoadAsynchronously(request_, client_.get());
// No need to hold on to the request; reset it now.
request_ = blink::WebURLRequest();
}
void AssociatedResourceFetcherImpl::Cancel() {
loader_->Cancel();
client_->Cancel();
}
} // namespace content