1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/web_package/signed_exchange_request_handler.h"
6
7 #include <memory>
8
9 #include "base/bind.h"
10 #include "base/feature_list.h"
11 #include "content/browser/loader/single_request_url_loader_factory.h"
12 #include "content/browser/web_package/signed_exchange_devtools_proxy.h"
13 #include "content/browser/web_package/signed_exchange_loader.h"
14 #include "content/browser/web_package/signed_exchange_prefetch_metric_recorder.h"
15 #include "content/browser/web_package/signed_exchange_reporter.h"
16 #include "content/browser/web_package/signed_exchange_utils.h"
17 #include "content/public/common/content_features.h"
18 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
19 #include "net/http/http_response_headers.h"
20 #include "services/network/public/cpp/shared_url_loader_factory.h"
21 #include "services/network/public/mojom/url_loader.mojom.h"
22 #include "services/network/public/mojom/url_response_head.mojom.h"
23 #include "third_party/blink/public/common/loader/throttling_url_loader.h"
24 #include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
25
26 namespace content {
27
28 // static
IsSupportedMimeType(const std::string & mime_type)29 bool SignedExchangeRequestHandler::IsSupportedMimeType(
30 const std::string& mime_type) {
31 return mime_type == "application/signed-exchange";
32 }
33
SignedExchangeRequestHandler(uint32_t url_loader_options,int frame_tree_node_id,const base::UnguessableToken & devtools_navigation_token,scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,URLLoaderThrottlesGetter url_loader_throttles_getter,scoped_refptr<SignedExchangePrefetchMetricRecorder> metric_recorder,std::string accept_langs)34 SignedExchangeRequestHandler::SignedExchangeRequestHandler(
35 uint32_t url_loader_options,
36 int frame_tree_node_id,
37 const base::UnguessableToken& devtools_navigation_token,
38 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
39 URLLoaderThrottlesGetter url_loader_throttles_getter,
40 scoped_refptr<SignedExchangePrefetchMetricRecorder> metric_recorder,
41 std::string accept_langs)
42 : url_loader_options_(url_loader_options),
43 frame_tree_node_id_(frame_tree_node_id),
44 devtools_navigation_token_(devtools_navigation_token),
45 url_loader_factory_(url_loader_factory),
46 url_loader_throttles_getter_(std::move(url_loader_throttles_getter)),
47 metric_recorder_(std::move(metric_recorder)),
48 accept_langs_(std::move(accept_langs)) {}
49
50 SignedExchangeRequestHandler::~SignedExchangeRequestHandler() = default;
51
MaybeCreateLoader(const network::ResourceRequest & tentative_resource_request,BrowserContext * browser_context,LoaderCallback callback,FallbackCallback fallback_callback)52 void SignedExchangeRequestHandler::MaybeCreateLoader(
53 const network::ResourceRequest& tentative_resource_request,
54 BrowserContext* browser_context,
55 LoaderCallback callback,
56 FallbackCallback fallback_callback) {
57 if (!signed_exchange_loader_) {
58 std::move(callback).Run({});
59 return;
60 }
61
62 if (signed_exchange_loader_->fallback_url()) {
63 DCHECK(tentative_resource_request.url.EqualsIgnoringRef(
64 *signed_exchange_loader_->fallback_url()));
65 signed_exchange_loader_ = nullptr;
66 std::move(fallback_callback)
67 .Run(false /* reset_subresource_loader_params */);
68 return;
69 }
70
71 DCHECK(tentative_resource_request.url.EqualsIgnoringRef(
72 *signed_exchange_loader_->inner_request_url()));
73 std::move(callback).Run(base::MakeRefCounted<SingleRequestURLLoaderFactory>(
74 base::BindOnce(&SignedExchangeRequestHandler::StartResponse,
75 weak_factory_.GetWeakPtr())));
76 }
77
MaybeCreateLoaderForResponse(const network::ResourceRequest & request,network::mojom::URLResponseHeadPtr * response_head,mojo::ScopedDataPipeConsumerHandle * response_body,mojo::PendingRemote<network::mojom::URLLoader> * loader,mojo::PendingReceiver<network::mojom::URLLoaderClient> * client_receiver,blink::ThrottlingURLLoader * url_loader,bool * skip_other_interceptors,bool * will_return_unsafe_redirect)78 bool SignedExchangeRequestHandler::MaybeCreateLoaderForResponse(
79 const network::ResourceRequest& request,
80 network::mojom::URLResponseHeadPtr* response_head,
81 mojo::ScopedDataPipeConsumerHandle* response_body,
82 mojo::PendingRemote<network::mojom::URLLoader>* loader,
83 mojo::PendingReceiver<network::mojom::URLLoaderClient>* client_receiver,
84 blink::ThrottlingURLLoader* url_loader,
85 bool* skip_other_interceptors,
86 bool* will_return_unsafe_redirect) {
87 DCHECK(!signed_exchange_loader_);
88
89 // Navigation ResourceRequests always have non-empty |trusted_params|.
90 DCHECK(request.trusted_params);
91
92 if (!signed_exchange_utils::ShouldHandleAsSignedHTTPExchange(
93 request.url, **response_head)) {
94 return false;
95 }
96
97 mojo::PendingRemote<network::mojom::URLLoaderClient> client;
98 *client_receiver = client.InitWithNewPipeAndPassReceiver();
99
100 const net::NetworkIsolationKey& network_isolation_key =
101 request.trusted_params->isolation_info.network_isolation_key();
102 // This lets the SignedExchangeLoader directly returns an artificial redirect
103 // to the downstream client without going through blink::ThrottlingURLLoader,
104 // which means some checks like SafeBrowsing may not see the redirect. Given
105 // that the redirected request will be checked when it's restarted we suppose
106 // this is fine.
107 auto reporter = SignedExchangeReporter::MaybeCreate(
108 request.url, request.referrer.spec(), **response_head,
109 network_isolation_key, frame_tree_node_id_);
110 auto devtools_proxy = std::make_unique<SignedExchangeDevToolsProxy>(
111 request.url, response_head->Clone(), frame_tree_node_id_,
112 devtools_navigation_token_, request.report_raw_headers);
113 signed_exchange_loader_ = std::make_unique<SignedExchangeLoader>(
114 request, std::move(*response_head), std::move(*response_body),
115 std::move(client), url_loader->Unbind(), url_loader_options_,
116 true /* should_redirect_to_fallback */, std::move(devtools_proxy),
117 std::move(reporter), url_loader_factory_, url_loader_throttles_getter_,
118 network_isolation_key, frame_tree_node_id_, metric_recorder_,
119 accept_langs_, false /* keep_entry_for_prefetch_cache */);
120
121 *skip_other_interceptors = true;
122 return true;
123 }
124
StartResponse(const network::ResourceRequest & resource_request,mojo::PendingReceiver<network::mojom::URLLoader> receiver,mojo::PendingRemote<network::mojom::URLLoaderClient> client)125 void SignedExchangeRequestHandler::StartResponse(
126 const network::ResourceRequest& resource_request,
127 mojo::PendingReceiver<network::mojom::URLLoader> receiver,
128 mojo::PendingRemote<network::mojom::URLLoaderClient> client) {
129 signed_exchange_loader_->ConnectToClient(std::move(client));
130 mojo::MakeSelfOwnedReceiver(std::move(signed_exchange_loader_),
131 std::move(receiver));
132 }
133
134 } // namespace content
135