| Index: headless/public/util/generic_url_request_job.cc
|
| diff --git a/headless/public/util/generic_url_request_job.cc b/headless/public/util/generic_url_request_job.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c7cefc782e8a53c39fcf0bae7f5bb42dcbb87d9a
|
| --- /dev/null
|
| +++ b/headless/public/util/generic_url_request_job.cc
|
| @@ -0,0 +1,185 @@
|
| +// 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 "headless/public/util/generic_url_request_job.h"
|
| +
|
| +#include <string.h>
|
| +#include <algorithm>
|
| +
|
| +#include "base/logging.h"
|
| +#include "headless/public/util/url_request_dispatcher.h"
|
| +#include "net/base/io_buffer.h"
|
| +#include "net/base/net_errors.h"
|
| +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
|
| +#include "net/cookies/cookie_store.h"
|
| +#include "net/http/http_response_headers.h"
|
| +#include "net/url_request/url_request_context.h"
|
| +
|
| +namespace headless {
|
| +namespace {
|
| +
|
| +// True if the request method is "safe" (per section 4.2.1 of RFC 7231).
|
| +bool IsMethodSafe(const std::string& method) {
|
| + return method == "GET" || method == "HEAD" || method == "OPTIONS" ||
|
| + method == "TRACE";
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +GenericURLRequestJob::GenericURLRequestJob(
|
| + net::URLRequest* request,
|
| + net::NetworkDelegate* network_delegate,
|
| + URLRequestDispatcher* url_request_dispatcher,
|
| + std::unique_ptr<URLFetcher> url_fetcher,
|
| + Delegate* delegate)
|
| + : ManagedDispatchURLRequestJob(request,
|
| + network_delegate,
|
| + url_request_dispatcher),
|
| + url_fetcher_(std::move(url_fetcher)),
|
| + delegate_(delegate),
|
| + weak_factory_(this) {}
|
| +
|
| +GenericURLRequestJob::~GenericURLRequestJob() = default;
|
| +
|
| +void GenericURLRequestJob::SetExtraRequestHeaders(
|
| + const net::HttpRequestHeaders& headers) {
|
| + extra_request_headers_ = headers;
|
| +}
|
| +
|
| +void GenericURLRequestJob::Start() {
|
| + auto callback = [this](RewriteResult result, const GURL& url) {
|
| + switch (result) {
|
| + case RewriteResult::kAllow:
|
| + // Note that we use the rewritten url for selecting cookies.
|
| + // Also, rewriting does not affect the request initiator.
|
| + PrepareCookies(url, url::Origin(url));
|
| + break;
|
| + case RewriteResult::kDeny:
|
| + DispatchStartError(net::ERR_FILE_NOT_FOUND);
|
| + break;
|
| + case RewriteResult::kFailure:
|
| + DispatchStartError(net::ERR_UNEXPECTED);
|
| + break;
|
| + default:
|
| + DCHECK(false);
|
| + }
|
| + };
|
| +
|
| + if (!delegate_->BlockOrRewriteRequest(request_->url(), request_->referrer(),
|
| + callback)) {
|
| + PrepareCookies(request()->url(),
|
| + url::Origin(request_->first_party_for_cookies()));
|
| + }
|
| +}
|
| +
|
| +void GenericURLRequestJob::PrepareCookies(const GURL& rewritten_url,
|
| + const url::Origin& site_for_cookies) {
|
| + net::CookieStore* cookie_store = request_->context()->cookie_store();
|
| + net::CookieOptions options;
|
| + options.set_include_httponly();
|
| +
|
| + // See net::URLRequestHttpJob::AddCookieHeaderAndStart().
|
| + url::Origin requested_origin(rewritten_url);
|
| + if (net::registry_controlled_domains::SameDomainOrHost(
|
| + requested_origin, site_for_cookies,
|
| + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) {
|
| + if (net::registry_controlled_domains::SameDomainOrHost(
|
| + requested_origin, request_->initiator(),
|
| + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) {
|
| + options.set_same_site_cookie_mode(
|
| + net::CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
|
| + } else if (IsMethodSafe(request_->method())) {
|
| + options.set_same_site_cookie_mode(
|
| + net::CookieOptions::SameSiteCookieMode::INCLUDE_LAX);
|
| + }
|
| + }
|
| +
|
| + cookie_store->GetCookieListWithOptionsAsync(
|
| + rewritten_url, options,
|
| + base::Bind(&GenericURLRequestJob::OnCookiesAvailable,
|
| + weak_factory_.GetWeakPtr(), rewritten_url));
|
| +}
|
| +
|
| +void GenericURLRequestJob::OnCookiesAvailable(
|
| + const GURL& rewritten_url,
|
| + const net::CookieList& cookie_list) {
|
| + // TODO(alexclarke): Set user agent.
|
| + // Pass cookies, the referrer and any extra headers into the fetch request.
|
| + extra_request_headers_.SetHeader(
|
| + net::HttpRequestHeaders::kCookie,
|
| + net::CookieStore::BuildCookieLine(cookie_list));
|
| +
|
| + extra_request_headers_.SetHeader(net::HttpRequestHeaders::kReferer,
|
| + request_->referrer());
|
| +
|
| + // The resource may have been supplied in the request.
|
| + const HttpResponse* matched_resource =
|
| + delegate_->MaybeMatchResource(rewritten_url, extra_request_headers_);
|
| +
|
| + if (matched_resource) {
|
| + OnFetchCompleteExtractHeaders(
|
| + matched_resource->final_url, matched_resource->http_response_code,
|
| + matched_resource->response_data, matched_resource->response_data_size);
|
| + } else {
|
| + url_fetcher_->StartFetch(rewritten_url, extra_request_headers_, this);
|
| + }
|
| +}
|
| +
|
| +void GenericURLRequestJob::OnStartError(net::Error error) {
|
| + DispatchStartError(error);
|
| +}
|
| +
|
| +void GenericURLRequestJob::OnFetchComplete(
|
| + const GURL& final_url,
|
| + int http_response_code,
|
| + scoped_refptr<net::HttpResponseHeaders> response_headers,
|
| + const char* body,
|
| + size_t body_size) {
|
| + http_response_code_ = http_response_code;
|
| + response_headers_ = response_headers;
|
| + body_ = body;
|
| + body_size_ = body_size;
|
| +
|
| + DispatchHeadersComplete();
|
| +
|
| + std::string mime_type;
|
| + GetMimeType(&mime_type);
|
| +
|
| + delegate_->OnResourceLoadComplete(final_url, mime_type, http_response_code);
|
| +}
|
| +
|
| +int GenericURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size) {
|
| + // TODO(skyostil): Implement ranged fetches.
|
| + // TODO(alexclarke): Add coverage for all the cases below.
|
| + size_t bytes_available = body_size_ - read_offset_;
|
| + size_t bytes_to_copy =
|
| + std::min(static_cast<size_t>(buf_size), bytes_available);
|
| + if (bytes_to_copy) {
|
| + std::memcpy(buf->data(), &body_[read_offset_], bytes_to_copy);
|
| + read_offset_ += bytes_to_copy;
|
| + }
|
| + return bytes_to_copy;
|
| +}
|
| +
|
| +int GenericURLRequestJob::GetResponseCode() const {
|
| + return http_response_code_;
|
| +}
|
| +
|
| +void GenericURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
|
| + info->headers = response_headers_;
|
| +}
|
| +
|
| +bool GenericURLRequestJob::GetMimeType(std::string* mime_type) const {
|
| + if (!response_headers_)
|
| + return false;
|
| + return response_headers_->GetMimeType(mime_type);
|
| +}
|
| +
|
| +bool GenericURLRequestJob::GetCharset(std::string* charset) {
|
| + if (!response_headers_)
|
| + return false;
|
| + return response_headers_->GetCharset(charset);
|
| +}
|
| +
|
| +} // namespace headless
|
|
|