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
content / browser / loader / navigation_loader_interceptor.h [blame]
// Copyright 2017 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_LOADER_NAVIGATION_LOADER_INTERCEPTOR_H_
#define CONTENT_BROWSER_LOADER_NAVIGATION_LOADER_INTERCEPTOR_H_
#include <optional>
#include "base/functional/callback_forward.h"
#include "content/browser/loader/response_head_update_params.h"
#include "content/browser/navigation_subresource_loader_params.h"
#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "net/base/load_timing_info.h"
#include "net/url_request/redirect_info.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
namespace blink {
class ThrottlingURLLoader;
} // namespace blink
namespace network {
struct ResourceRequest;
} // namespace network
namespace content {
class BrowserContext;
// NavigationLoaderInterceptor is given a chance to create a URLLoader and
// intercept a navigation request before the request is handed off to the
// default URLLoader, e.g. the one from the network service.
// NavigationLoaderInterceptor is a per-request object and kept around during
// the lifetime of a navigation request (including multiple redirect legs).
// All methods are called on the UI thread.
class CONTENT_EXPORT NavigationLoaderInterceptor {
public:
NavigationLoaderInterceptor() = default;
virtual ~NavigationLoaderInterceptor() = default;
// When `LoaderCallback` is called with non-nullopt `Result`:
// - Intercept the navigation request using `single_request_factory` if
// non-null, or otherwise fall back to the default loader factory.
// - Intercept subresource requests using `subresource_loader_params` if
// non-null.
// - Skip all subsequent interceptors.
// When `LoaderCallback` is called with std::nullopt:
// - The navigation/subresource requests are not intercepted.
// - Fall back to the next interceptor if any, or otherwise to the network.
struct CONTENT_EXPORT Result final {
Result(
scoped_refptr<network::SharedURLLoaderFactory> single_request_factory,
SubresourceLoaderParams subresource_loader_params,
ResponseHeadUpdateParams response_head_update_params = {});
~Result();
Result(const Result&) = delete;
Result& operator=(const Result&) = delete;
Result(Result&&);
Result& operator=(Result&&);
// When non-null, `single_request_factory` is used to handle the request.
// When null, the fallback network-service factory is used.
scoped_refptr<network::SharedURLLoaderFactory> single_request_factory;
// Used for subsequent URL requests going forward.
//
// Note that `single_request_factory` can be nullptr while
// `subresource_loader_params` can have non-default values if it does NOT
// want to handle the specific request but wants to handle the subsequent
// resource requests.
SubresourceLoaderParams subresource_loader_params;
// When `single_request_factory` is null, used to update the response params
// in non-intercepted loader via
// `NavigationURLLoaderImpl::head_update_params_`.
ResponseHeadUpdateParams response_head_update_params;
};
using LoaderCallback = base::OnceCallback<void(std::optional<Result>)>;
using FallbackCallback = base::OnceCallback<void(ResponseHeadUpdateParams)>;
// Asks this interceptor to handle this resource load request.
// The interceptor must always invoke `callback`.
//
// The `tentative_resource_request` passed to this function and the resource
// request later passed to the loader factory given to `callback` may not be
// exactly the same, because URLLoaderThrottles may rewrite the request
// between the two calls. However the URL must remain constant between the
// two, as any modifications on the URL done by URLLoaderThrottles must result
// in an (internal) redirect, which must restart the request with a new
// MaybeCreateLoader().
//
// This interceptor might initially elect to handle the request, but later
// decide to fall back to the default behavior. In that case, it can invoke
// `fallback_callback_for_service_worker` to do so. An example of this is when
// a service worker decides to handle the request because it is in-scope, but
// the service worker JavaScript execution does not result in a response
// provided, so fallback to network is required.
//
// `fallback_callback_for_service_worker` is only for service workers to
// fallback to the network after initially electing to intercept the request.
// It must be called after `callback` is called with non-null
// `single_request_factory` and prior to the interceptor making any
// URLLoaderClient calls.
//
// `callback` and `fallback_callback_for_service_worker` must not be invoked
// after the destruction of this interceptor.
//
// TODO(crbug.com/40251638): Possibly remove
// `fallback_callback_for_service_worker` to simplify the ServiceWorker
// interception.
virtual void MaybeCreateLoader(
const network::ResourceRequest& tentative_resource_request,
BrowserContext* browser_context,
LoaderCallback callback,
FallbackCallback fallback_callback_for_service_worker) = 0;
// Returns true if the interceptor creates a loader for the `response_head`
// and `response_body` passed. `request` is the latest request whose request
// URL may include URL fragment. An example of where this is used is
// WebBundles where the URL is used to check if the content must be
// downloaded. The URLLoader remote is returned in the `loader` parameter.
// The mojo::PendingReceiver for the URLLoaderClient is returned in the
// `client_receiver` parameter.
// `status` is the loader completion status, allowing the interceptor to
// handle failed loads differently from successful loads. For requests that
// successfully received a response, this will be a URLLoaderCompletionStatus
// with an error code of `net::OK`. For requests that failed, this will be a
// URLLoaderCompletionStatus with the underlying net error.
// The `url_loader` points to the ThrottlingURLLoader that currently controls
// the request. It can be optionally consumed to get the current
// URLLoaderClient and URLLoader so that the implementation can rebind them to
// intercept the inflight loading if necessary. Note that the `url_loader`
// will be reset after this method is called, which will also drop the
// URLLoader held by `url_loader_` if it is not unbound yet.
// `skip_other_interceptors` is set to true when this interceptor will
// exclusively handle the navigation even after redirections. TODO(horo): This
// flag was introduced to skip service worker after signed exchange redirect.
// Remove this flag when we support service worker and signed exchange
// integration. See crbug.com/894755#c1. Nullptr is not allowed.
virtual bool MaybeCreateLoaderForResponse(
const network::URLLoaderCompletionStatus& status,
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);
};
} // namespace content
#endif // CONTENT_BROWSER_LOADER_NAVIGATION_LOADER_INTERCEPTOR_H_