1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200

content / browser / web_package / signed_exchange_loader.h [blame]

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_WEB_PACKAGE_SIGNED_EXCHANGE_LOADER_H_
#define CONTENT_BROWSER_WEB_PACKAGE_SIGNED_EXCHANGE_LOADER_H_

#include <memory>
#include <optional>
#include <string>

#include "base/functional/callback.h"
#include "base/unguessable_token.h"
#include "content/browser/web_package/signed_exchange_error.h"
#include "content/common/content_export.h"
#include "content/public/browser/frame_tree_node_id.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/simple_watcher.h"
#include "net/ssl/ssl_info.h"
#include "net/url_request/redirect_info.h"
#include "services/network/public/cpp/net_adapters.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "url/origin.h"

namespace blink {
class URLLoaderThrottle;
}  // namespace blink

namespace net {
class SourceStream;
}  // namespace net

namespace network {
class SharedURLLoaderFactory;
class SourceStreamToDataPipe;
}  // namespace network

namespace content {

class PrefetchedSignedExchangeCacheEntry;
class SignedExchangeDevToolsProxy;
class SignedExchangeHandler;
class SignedExchangeHandlerFactory;
class SignedExchangeReporter;

// SignedExchangeLoader handles an origin-signed HTTP exchange response. It is
// created when a SignedExchangeRequestHandler recieves an origin-signed HTTP
// exchange response, and is owned by the handler until the StartLoaderCallback
// of SignedExchangeRequestHandler::StartResponse is called. After that, it is
// owned by the URLLoader mojo endpoint.
class CONTENT_EXPORT SignedExchangeLoader final
    : public network::mojom::URLLoaderClient,
      public network::mojom::URLLoader {
 public:
  using URLLoaderThrottlesGetter = base::RepeatingCallback<
      std::vector<std::unique_ptr<blink::URLLoaderThrottle>>()>;

  // If |should_redirect_on_failure| is true, verification failure causes a
  // redirect to the fallback URL.
  SignedExchangeLoader(
      const network::ResourceRequest& outer_request,
      network::mojom::URLResponseHeadPtr outer_response_head,
      mojo::ScopedDataPipeConsumerHandle outer_response_body,
      mojo::PendingRemote<network::mojom::URLLoaderClient> forwarding_client,
      network::mojom::URLLoaderClientEndpointsPtr endpoints,
      uint32_t url_loader_options,
      bool should_redirect_on_failure,
      std::unique_ptr<SignedExchangeDevToolsProxy> devtools_proxy,
      std::unique_ptr<SignedExchangeReporter> reporter,
      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
      URLLoaderThrottlesGetter url_loader_throttles_getter,
      FrameTreeNodeId frame_tree_node_id,
      const std::string& accept_langs,
      bool keep_entry_for_prefetch_cache);

  SignedExchangeLoader(const SignedExchangeLoader&) = delete;
  SignedExchangeLoader& operator=(const SignedExchangeLoader&) = delete;

  ~SignedExchangeLoader() override;

  // network::mojom::URLLoaderClient implementation
  // Only OnComplete() is called.
  void OnReceiveEarlyHints(network::mojom::EarlyHintsPtr early_hints) override;
  void OnReceiveResponse(
      network::mojom::URLResponseHeadPtr response_head,
      mojo::ScopedDataPipeConsumerHandle body,
      std::optional<mojo_base::BigBuffer> cached_metadata) override;
  void OnReceiveRedirect(
      const net::RedirectInfo& redirect_info,
      network::mojom::URLResponseHeadPtr response_head) override;
  void OnUploadProgress(int64_t current_position,
                        int64_t total_size,
                        OnUploadProgressCallback ack_callback) override;
  void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
  void OnComplete(const network::URLLoaderCompletionStatus& status) override;

  // network::mojom::URLLoader implementation
  void FollowRedirect(
      const std::vector<std::string>& removed_headers,
      const net::HttpRequestHeaders& modified_headers,
      const net::HttpRequestHeaders& modified_cors_exempt_headers,
      const std::optional<GURL>& new_url) override;
  void SetPriority(net::RequestPriority priority,
                   int intra_priority_value) override;
  void PauseReadingBodyFromNet() override;
  void ResumeReadingBodyFromNet() override;

  void ConnectToClient(
      mojo::PendingRemote<network::mojom::URLLoaderClient> client);

  const std::optional<GURL>& fallback_url() const { return fallback_url_; }

  const std::optional<GURL>& inner_request_url() const {
    return inner_request_url_;
  }

  // Called to get the information about the loaded signed exchange. To call
  // this method, |keep_entry_for_prefetch_cache| constructor argument must be
  // set.
  std::unique_ptr<PrefetchedSignedExchangeCacheEntry>
  TakePrefetchedSignedExchangeCacheEntry();

  // Set nullptr to reset the mocking.
  static void SetSignedExchangeHandlerFactoryForTest(
      SignedExchangeHandlerFactory* factory);

 private:
  // Called from |signed_exchange_handler_| when it finds an origin-signed HTTP
  // exchange.
  void OnHTTPExchangeFound(SignedExchangeLoadResult result,
                           net::Error error,
                           const GURL& request_url,
                           network::mojom::URLResponseHeadPtr resource_response,
                           std::unique_ptr<net::SourceStream> payload_stream);

  void FinishReadingBody(int result);
  void NotifyClientOnCompleteIfReady();
  void ReportLoadResult(SignedExchangeLoadResult result);

  const network::ResourceRequest outer_request_;

  // The outer response of signed HTTP exchange which was received from network.
  network::mojom::URLResponseHeadPtr outer_response_head_;

  // This client is alive until OnHTTPExchangeFound() is called.
  mojo::Remote<network::mojom::URLLoaderClient> forwarding_client_;

  // This |url_loader_| is the remote of the network URL loader.
  mojo::Remote<network::mojom::URLLoader> url_loader_;
  // This receiver connects |this| with the network URL loader.
  mojo::Receiver<network::mojom::URLLoaderClient> url_loader_client_receiver_{
      this};

  // This is pending until connected by ConnectToClient().
  mojo::Remote<network::mojom::URLLoaderClient> client_;

  // This pending receiver is used by ConnectToClient() to connect |client_|.
  mojo::PendingReceiver<network::mojom::URLLoaderClient>
      pending_client_receiver_;

  std::unique_ptr<SignedExchangeReporter> reporter_;

  // `signed_exchange_handler_` borrows reference from `reporter_`, so it needs
  // to be declared last, so that it is destroyed first.
  std::unique_ptr<SignedExchangeHandler> signed_exchange_handler_;
  std::unique_ptr<network::SourceStreamToDataPipe> body_data_pipe_adapter_;

  const uint32_t url_loader_options_;
  const bool should_redirect_on_failure_;

  std::optional<net::SSLInfo> ssl_info_;

  std::optional<GURL> fallback_url_;
  std::optional<GURL> inner_request_url_;

  struct OuterResponseLengthInfo {
    int64_t encoded_data_length;
    int64_t decoded_body_length;
  };
  // Set when URLLoaderClient::OnComplete() is called.
  std::optional<OuterResponseLengthInfo> outer_response_length_info_;

  // Set when |body_data_pipe_adapter_| finishes loading the decoded body.
  std::optional<int> decoded_body_read_result_;

  // Keep the signed exchange info to be stored to
  // PrefetchedSignedExchangeCache.
  std::unique_ptr<PrefetchedSignedExchangeCacheEntry> cache_entry_;

  base::WeakPtrFactory<SignedExchangeLoader> weak_factory_{this};
};

}  // namespace content

#endif  // CONTENT_BROWSER_WEB_PACKAGE_SIGNED_EXCHANGE_LOADER_H_