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