blob: 3de8bb2ae546c0d7840693ae7f0692f941be0037 [file] [log] [blame]
// Copyright 2017 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.
#ifndef SERVICES_NETWORK_CORS_CORS_URL_LOADER_H_
#define SERVICES_NETWORK_CORS_CORS_URL_LOADER_H_
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/network/cors/preflight_controller.h"
#include "services/network/public/cpp/cors/cors_error_status.h"
#include "services/network/public/cpp/cors/preflight_timing_info.h"
#include "services/network/public/mojom/fetch_api.mojom.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace network {
namespace cors {
class OriginAccessList;
// Wrapper class that adds cross-origin resource sharing capabilities
// (https://fetch.spec.whatwg.org/#http-cors-protocol), delegating requests as
// well as potential preflight requests to the supplied
// |network_loader_factory|. It is owned by the CorsURLLoaderFactory that
// created it.
class COMPONENT_EXPORT(NETWORK_SERVICE) CorsURLLoader
: public mojom::URLLoader,
public mojom::URLLoaderClient {
public:
using DeleteCallback = base::OnceCallback<void(mojom::URLLoader* loader)>;
CorsURLLoader(
mojom::URLLoaderRequest loader_request,
int32_t routing_id,
int32_t request_id,
uint32_t options,
DeleteCallback delete_callback,
const ResourceRequest& resource_request,
mojom::URLLoaderClientPtr client,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
mojom::URLLoaderFactory* network_loader_factory,
const OriginAccessList* origin_access_list,
const OriginAccessList* factory_bound_origin_access_list,
PreflightController* preflight_controller);
~CorsURLLoader() override;
// Starts processing the request. This is expected to be called right after
// the constructor.
void Start();
// mojom::URLLoader overrides:
void FollowRedirect(const std::vector<std::string>& removed_headers,
const net::HttpRequestHeaders& modified_headers,
const base::Optional<GURL>& new_url) override;
void ProceedWithResponse() override;
void SetPriority(net::RequestPriority priority,
int intra_priority_value) override;
void PauseReadingBodyFromNet() override;
void ResumeReadingBodyFromNet() override;
// mojom::URLLoaderClient overrides:
void OnReceiveResponse(const ResourceResponseHead& head) override;
void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
const ResourceResponseHead& head) override;
void OnUploadProgress(int64_t current_position,
int64_t total_size,
base::OnceCallback<void()> callback) override;
void OnReceiveCachedMetadata(mojo_base::BigBuffer data) override;
void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
void OnStartLoadingResponseBody(
mojo::ScopedDataPipeConsumerHandle body) override;
void OnComplete(const URLLoaderCompletionStatus& status) override;
// Public for testing.
//
// Returns the response tainting value
// (https://fetch.spec.whatwg.org/#concept-request-response-tainting) for a
// request and the CORS flag, as specified in
// https://fetch.spec.whatwg.org/#main-fetch.
static network::mojom::FetchResponseType CalculateResponseTainting(
const GURL& url,
mojom::FetchRequestMode request_mode,
const base::Optional<url::Origin>& origin,
bool cors_flag,
bool tainted_origin,
const OriginAccessList* origin_access_list);
private:
void StartRequest();
void StartNetworkRequest(
int net_error,
base::Optional<CorsErrorStatus> status,
base::Optional<PreflightTimingInfo> preflight_timing_info);
// Called when there is a connection error on the upstream pipe used for the
// actual request.
void OnUpstreamConnectionError();
// Handles OnComplete() callback.
void HandleComplete(const URLLoaderCompletionStatus& status);
void OnConnectionError();
void SetCorsFlagIfNeeded();
static base::Optional<std::string> GetHeaderString(
const ResourceResponseHead& response,
const std::string& header_name);
mojo::Binding<mojom::URLLoader> binding_;
// We need to save these for redirect.
const int32_t routing_id_;
const int32_t request_id_;
const uint32_t options_;
DeleteCallback delete_callback_;
// This raw URLLoaderFactory pointer is shared with the CorsURLLoaderFactory
// that created and owns this object.
mojom::URLLoaderFactory* network_loader_factory_;
// For the actual request.
mojom::URLLoaderPtr network_loader_;
mojo::Binding<mojom::URLLoaderClient> network_client_binding_;
ResourceRequest request_;
// To be a URLLoader for the client.
mojom::URLLoaderClientPtr forwarding_client_;
// The last response URL, that is usually the requested URL, but can be
// different if redirects happen.
GURL last_response_url_;
// https://fetch.spec.whatwg.org/#concept-request-response-tainting
// As "response tainting" is subset of "response type", we use
// mojom::FetchResponseType for convenience.
mojom::FetchResponseType response_tainting_ =
mojom::FetchResponseType::kBasic;
// Holds the URL of a redirect if it's currently deferred, waiting for
// forwarding_client_ to call FollowRedirect.
std::unique_ptr<GURL> deferred_redirect_url_;
// Corresponds to the Fetch spec, https://fetch.spec.whatwg.org/.
bool fetch_cors_flag_ = false;
net::RedirectInfo redirect_info_;
// https://fetch.spec.whatwg.org/#concept-request-tainted-origin
bool tainted_ = false;
// https://fetch.spec.whatwg.org/#concept-request-redirect-count
int redirect_count_ = 0;
// We need to save this for redirect.
net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
// Holds timing info if a preflight was made.
std::vector<PreflightTimingInfo> preflight_timing_info_;
// Outlives |this|.
const OriginAccessList* const origin_access_list_;
const OriginAccessList* const factory_bound_origin_access_list_;
PreflightController* preflight_controller_;
// Used to run asynchronous class instance bound callbacks safely.
base::WeakPtrFactory<CorsURLLoader> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(CorsURLLoader);
};
} // namespace cors
} // namespace network
#endif // SERVICES_NETWORK_CORS_CORS_URL_LOADER_H_