proxying_url_loader_factory.cc 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. // Copyright (c) 2019 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "shell/browser/net/proxying_url_loader_factory.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "base/command_line.h"
  8. #include "base/functional/bind.h"
  9. #include "base/functional/callback_helpers.h"
  10. #include "base/strings/string_split.h"
  11. #include "content/public/browser/browser_context.h"
  12. #include "extensions/browser/extension_navigation_ui_data.h"
  13. #include "net/base/completion_repeating_callback.h"
  14. #include "net/base/load_flags.h"
  15. #include "net/http/http_response_headers.h"
  16. #include "net/http/http_status_code.h"
  17. #include "net/http/http_util.h"
  18. #include "net/url_request/redirect_info.h"
  19. #include "services/network/public/cpp/features.h"
  20. #include "services/network/public/mojom/early_hints.mojom.h"
  21. #include "services/network/public/mojom/url_response_head.mojom.h"
  22. #include "shell/browser/net/asar/asar_url_loader.h"
  23. #include "shell/common/options_switches.h"
  24. #include "third_party/abseil-cpp/absl/strings/str_format.h"
  25. #include "url/origin.h"
  26. namespace electron {
  27. ProxyingURLLoaderFactory::InProgressRequest::FollowRedirectParams::
  28. FollowRedirectParams() = default;
  29. ProxyingURLLoaderFactory::InProgressRequest::FollowRedirectParams::
  30. ~FollowRedirectParams() = default;
  31. ProxyingURLLoaderFactory::InProgressRequest::InProgressRequest(
  32. ProxyingURLLoaderFactory* factory,
  33. uint64_t web_request_id,
  34. int32_t frame_routing_id,
  35. int32_t network_service_request_id,
  36. uint32_t options,
  37. const network::ResourceRequest& request,
  38. const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
  39. mojo::PendingReceiver<network::mojom::URLLoader> loader_receiver,
  40. mojo::PendingRemote<network::mojom::URLLoaderClient> client)
  41. : factory_(factory),
  42. request_(request),
  43. original_initiator_(request.request_initiator),
  44. request_id_(web_request_id),
  45. network_service_request_id_(network_service_request_id),
  46. frame_routing_id_(frame_routing_id),
  47. options_(options),
  48. traffic_annotation_(traffic_annotation),
  49. proxied_loader_receiver_(this, std::move(loader_receiver)),
  50. target_client_(std::move(client)),
  51. current_response_(network::mojom::URLResponseHead::New()),
  52. // Always use "extraHeaders" mode to be compatible with old APIs, except
  53. // when the |request_id_| is zero, which is not supported in Chromium and
  54. // only happens in Electron when the request is started from net module.
  55. has_any_extra_headers_listeners_(network_service_request_id != 0) {
  56. // If there is a client error, clean up the request.
  57. target_client_.set_disconnect_handler(base::BindOnce(
  58. &ProxyingURLLoaderFactory::InProgressRequest::OnRequestError,
  59. weak_factory_.GetWeakPtr(),
  60. network::URLLoaderCompletionStatus(net::ERR_ABORTED)));
  61. proxied_loader_receiver_.set_disconnect_handler(base::BindOnce(
  62. &ProxyingURLLoaderFactory::InProgressRequest::OnRequestError,
  63. weak_factory_.GetWeakPtr(),
  64. network::URLLoaderCompletionStatus(net::ERR_ABORTED)));
  65. }
  66. ProxyingURLLoaderFactory::InProgressRequest::InProgressRequest(
  67. ProxyingURLLoaderFactory* factory,
  68. uint64_t request_id,
  69. int32_t frame_routing_id,
  70. const network::ResourceRequest& request)
  71. : factory_(factory),
  72. request_(request),
  73. original_initiator_(request.request_initiator),
  74. request_id_(request_id),
  75. frame_routing_id_(frame_routing_id),
  76. proxied_loader_receiver_(this),
  77. for_cors_preflight_(true),
  78. has_any_extra_headers_listeners_(true) {}
  79. ProxyingURLLoaderFactory::InProgressRequest::~InProgressRequest() {
  80. // This is important to ensure that no outstanding blocking requests continue
  81. // to reference state owned by this object.
  82. if (info_) {
  83. factory_->web_request_api()->OnRequestWillBeDestroyed(&info_.value());
  84. }
  85. if (on_before_send_headers_callback_) {
  86. std::move(on_before_send_headers_callback_)
  87. .Run(net::ERR_ABORTED, std::nullopt);
  88. }
  89. if (on_headers_received_callback_) {
  90. std::move(on_headers_received_callback_)
  91. .Run(net::ERR_ABORTED, std::nullopt, std::nullopt);
  92. }
  93. }
  94. void ProxyingURLLoaderFactory::InProgressRequest::Restart() {
  95. UpdateRequestInfo();
  96. RestartInternal();
  97. }
  98. void ProxyingURLLoaderFactory::InProgressRequest::UpdateRequestInfo() {
  99. // Derive a new WebRequestInfo value any time |Restart()| is called, because
  100. // the details in |request_| may have changed e.g. if we've been redirected.
  101. // |request_initiator| can be modified on redirects, but we keep the original
  102. // for |initiator| in the event. See also
  103. // https://developer.chrome.com/extensions/webRequest#event-onBeforeRequest.
  104. network::ResourceRequest request_for_info = request_;
  105. request_for_info.request_initiator = original_initiator_;
  106. info_.emplace(extensions::WebRequestInfoInitParams(
  107. request_id_, factory_->render_process_id_, frame_routing_id_,
  108. factory_->navigation_ui_data_ ? factory_->navigation_ui_data_->DeepCopy()
  109. : nullptr,
  110. request_for_info, false,
  111. !(options_ & network::mojom::kURLLoadOptionSynchronous),
  112. factory_->IsForServiceWorkerScript(), factory_->navigation_id_));
  113. current_request_uses_header_client_ =
  114. factory_->url_loader_header_client_receiver_.is_bound() &&
  115. (for_cors_preflight_ || network_service_request_id_ != 0) &&
  116. has_any_extra_headers_listeners_;
  117. }
  118. void ProxyingURLLoaderFactory::InProgressRequest::RestartInternal() {
  119. DCHECK_EQ(info_->url, request_.url)
  120. << "UpdateRequestInfo must have been called first";
  121. // If the header client will be used, we start the request immediately, and
  122. // OnBeforeSendHeaders and OnSendHeaders will be handled there. Otherwise,
  123. // send these events before the request starts.
  124. base::RepeatingCallback<void(int)> continuation;
  125. if (current_request_uses_header_client_) {
  126. continuation = base::BindRepeating(
  127. &InProgressRequest::ContinueToStartRequest, weak_factory_.GetWeakPtr());
  128. } else if (for_cors_preflight_) {
  129. // In this case we do nothing because extensions should see nothing.
  130. return;
  131. } else {
  132. continuation =
  133. base::BindRepeating(&InProgressRequest::ContinueToBeforeSendHeaders,
  134. weak_factory_.GetWeakPtr());
  135. }
  136. redirect_url_ = GURL();
  137. int result = factory_->web_request_api()->OnBeforeRequest(
  138. &info_.value(), request_, continuation, &redirect_url_);
  139. if (result == net::ERR_BLOCKED_BY_CLIENT) {
  140. // The request was cancelled synchronously. Dispatch an error notification
  141. // and terminate the request.
  142. network::URLLoaderCompletionStatus status(result);
  143. OnRequestError(status);
  144. return;
  145. }
  146. if (result == net::ERR_IO_PENDING) {
  147. // One or more listeners is blocking, so the request must be paused until
  148. // they respond. |continuation| above will be invoked asynchronously to
  149. // continue or cancel the request.
  150. //
  151. // We pause the receiver here to prevent further client message processing.
  152. if (proxied_client_receiver_.is_bound())
  153. proxied_client_receiver_.Pause();
  154. // Pause the header client, since we want to wait until OnBeforeRequest has
  155. // finished before processing any future events.
  156. if (header_client_receiver_.is_bound())
  157. header_client_receiver_.Pause();
  158. return;
  159. }
  160. DCHECK_EQ(net::OK, result);
  161. continuation.Run(net::OK);
  162. }
  163. void ProxyingURLLoaderFactory::InProgressRequest::FollowRedirect(
  164. const std::vector<std::string>& removed_headers,
  165. const net::HttpRequestHeaders& modified_headers,
  166. const net::HttpRequestHeaders& modified_cors_exempt_headers,
  167. const std::optional<GURL>& new_url) {
  168. if (new_url)
  169. request_.url = new_url.value();
  170. for (const std::string& header : removed_headers)
  171. request_.headers.RemoveHeader(header);
  172. request_.headers.MergeFrom(modified_headers);
  173. // Call this before checking |current_request_uses_header_client_| as it
  174. // calculates it.
  175. UpdateRequestInfo();
  176. if (target_loader_.is_bound()) {
  177. // If header_client_ is used, then we have to call FollowRedirect now as
  178. // that's what triggers the network service calling back to
  179. // OnBeforeSendHeaders(). Otherwise, don't call FollowRedirect now. Wait for
  180. // the onBeforeSendHeaders callback(s) to run as these may modify request
  181. // headers and if so we'll pass these modifications to FollowRedirect.
  182. if (current_request_uses_header_client_) {
  183. target_loader_->FollowRedirect(removed_headers, modified_headers,
  184. modified_cors_exempt_headers, new_url);
  185. } else {
  186. auto params = std::make_unique<FollowRedirectParams>();
  187. params->removed_headers = removed_headers;
  188. params->modified_headers = modified_headers;
  189. params->modified_cors_exempt_headers = modified_cors_exempt_headers;
  190. params->new_url = new_url;
  191. pending_follow_redirect_params_ = std::move(params);
  192. }
  193. }
  194. RestartInternal();
  195. }
  196. void ProxyingURLLoaderFactory::InProgressRequest::SetPriority(
  197. net::RequestPriority priority,
  198. int32_t intra_priority_value) {
  199. if (target_loader_.is_bound())
  200. target_loader_->SetPriority(priority, intra_priority_value);
  201. }
  202. void ProxyingURLLoaderFactory::InProgressRequest::OnReceiveEarlyHints(
  203. network::mojom::EarlyHintsPtr early_hints) {
  204. target_client_->OnReceiveEarlyHints(std::move(early_hints));
  205. }
  206. void ProxyingURLLoaderFactory::InProgressRequest::OnReceiveResponse(
  207. network::mojom::URLResponseHeadPtr head,
  208. mojo::ScopedDataPipeConsumerHandle body,
  209. std::optional<mojo_base::BigBuffer> cached_metadata) {
  210. current_body_ = std::move(body);
  211. current_cached_metadata_ = std::move(cached_metadata);
  212. if (current_request_uses_header_client_) {
  213. // Use the headers we got from OnHeadersReceived as that'll contain
  214. // Set-Cookie if it existed.
  215. auto saved_headers = current_response_->headers;
  216. current_response_ = std::move(head);
  217. current_response_->headers = saved_headers;
  218. ContinueToResponseStarted(net::OK);
  219. } else {
  220. current_response_ = std::move(head);
  221. HandleResponseOrRedirectHeaders(
  222. base::BindOnce(&InProgressRequest::ContinueToResponseStarted,
  223. weak_factory_.GetWeakPtr()));
  224. }
  225. }
  226. void ProxyingURLLoaderFactory::InProgressRequest::OnReceiveRedirect(
  227. const net::RedirectInfo& redirect_info,
  228. network::mojom::URLResponseHeadPtr head) {
  229. // Note: In Electron we don't check IsRedirectSafe.
  230. if (current_request_uses_header_client_) {
  231. // Use the headers we got from OnHeadersReceived as that'll contain
  232. // Set-Cookie if it existed.
  233. auto saved_headers = current_response_->headers;
  234. current_response_ = std::move(head);
  235. // If this redirect is from an HSTS upgrade, OnHeadersReceived will not be
  236. // called before OnReceiveRedirect, so make sure the saved headers exist
  237. // before setting them.
  238. if (saved_headers)
  239. current_response_->headers = saved_headers;
  240. ContinueToBeforeRedirect(redirect_info, net::OK);
  241. } else {
  242. current_response_ = std::move(head);
  243. HandleResponseOrRedirectHeaders(
  244. base::BindOnce(&InProgressRequest::ContinueToBeforeRedirect,
  245. weak_factory_.GetWeakPtr(), redirect_info));
  246. }
  247. }
  248. void ProxyingURLLoaderFactory::InProgressRequest::OnUploadProgress(
  249. int64_t current_position,
  250. int64_t total_size,
  251. OnUploadProgressCallback callback) {
  252. target_client_->OnUploadProgress(current_position, total_size,
  253. std::move(callback));
  254. }
  255. void ProxyingURLLoaderFactory::InProgressRequest::OnTransferSizeUpdated(
  256. int32_t transfer_size_diff) {
  257. target_client_->OnTransferSizeUpdated(transfer_size_diff);
  258. }
  259. void ProxyingURLLoaderFactory::InProgressRequest::OnComplete(
  260. const network::URLLoaderCompletionStatus& status) {
  261. if (status.error_code != net::OK) {
  262. OnRequestError(status);
  263. return;
  264. }
  265. target_client_->OnComplete(status);
  266. factory_->web_request_api()->OnCompleted(&info_.value(), request_,
  267. status.error_code);
  268. // Deletes |this|.
  269. factory_->RemoveRequest(network_service_request_id_, request_id_);
  270. }
  271. bool ProxyingURLLoaderFactory::IsForServiceWorkerScript() const {
  272. return loader_factory_type_ == content::ContentBrowserClient::
  273. URLLoaderFactoryType::kServiceWorkerScript;
  274. }
  275. void ProxyingURLLoaderFactory::InProgressRequest::OnLoaderCreated(
  276. mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) {
  277. // When CORS is involved there may be multiple network::URLLoader associated
  278. // with this InProgressRequest, because CorsURLLoader may create a new
  279. // network::URLLoader for the same request id in redirect handling - see
  280. // CorsURLLoader::FollowRedirect. In such a case the old network::URLLoader
  281. // is going to be detached fairly soon, so we don't need to take care of it.
  282. // We need this explicit reset to avoid a DCHECK failure in mojo::Receiver.
  283. header_client_receiver_.reset();
  284. header_client_receiver_.Bind(std::move(receiver));
  285. if (for_cors_preflight_) {
  286. // In this case we don't have |target_loader_| and
  287. // |proxied_client_receiver_|, and |receiver| is the only connection to the
  288. // network service, so we observe mojo connection errors.
  289. header_client_receiver_.set_disconnect_handler(base::BindOnce(
  290. &ProxyingURLLoaderFactory::InProgressRequest::OnRequestError,
  291. weak_factory_.GetWeakPtr(),
  292. network::URLLoaderCompletionStatus(net::ERR_FAILED)));
  293. }
  294. }
  295. void ProxyingURLLoaderFactory::InProgressRequest::OnBeforeSendHeaders(
  296. const net::HttpRequestHeaders& headers,
  297. OnBeforeSendHeadersCallback callback) {
  298. if (!current_request_uses_header_client_) {
  299. std::move(callback).Run(net::OK, std::nullopt);
  300. return;
  301. }
  302. request_.headers = headers;
  303. on_before_send_headers_callback_ = std::move(callback);
  304. ContinueToBeforeSendHeaders(net::OK);
  305. }
  306. void ProxyingURLLoaderFactory::InProgressRequest::OnHeadersReceived(
  307. const std::string& headers,
  308. const net::IPEndPoint& remote_endpoint,
  309. OnHeadersReceivedCallback callback) {
  310. if (!current_request_uses_header_client_) {
  311. std::move(callback).Run(net::OK, std::nullopt, GURL());
  312. if (for_cors_preflight_) {
  313. // CORS preflight is supported only when "extraHeaders" is specified.
  314. // Deletes |this|.
  315. factory_->RemoveRequest(network_service_request_id_, request_id_);
  316. }
  317. return;
  318. }
  319. on_headers_received_callback_ = std::move(callback);
  320. current_response_ = network::mojom::URLResponseHead::New();
  321. current_response_->headers =
  322. base::MakeRefCounted<net::HttpResponseHeaders>(headers);
  323. current_response_->remote_endpoint = remote_endpoint;
  324. HandleResponseOrRedirectHeaders(
  325. base::BindOnce(&InProgressRequest::ContinueToHandleOverrideHeaders,
  326. weak_factory_.GetWeakPtr()));
  327. }
  328. void ProxyingURLLoaderFactory::InProgressRequest::
  329. HandleBeforeRequestRedirect() {
  330. // The extension requested a redirect. Close the connection with the current
  331. // URLLoader and inform the URLLoaderClient the WebRequest API generated a
  332. // redirect. To load |redirect_url_|, a new URLLoader will be recreated
  333. // after receiving FollowRedirect().
  334. // Forgetting to close the connection with the current URLLoader caused
  335. // bugs. The latter doesn't know anything about the redirect. Continuing
  336. // the load with it gives unexpected results. See
  337. // https://crbug.com/882661#c72.
  338. proxied_client_receiver_.reset();
  339. header_client_receiver_.reset();
  340. target_loader_.reset();
  341. constexpr int kInternalRedirectStatusCode = net::HTTP_TEMPORARY_REDIRECT;
  342. net::RedirectInfo redirect_info;
  343. redirect_info.status_code = kInternalRedirectStatusCode;
  344. redirect_info.new_method = request_.method;
  345. redirect_info.new_url = redirect_url_;
  346. redirect_info.new_site_for_cookies =
  347. net::SiteForCookies::FromUrl(redirect_url_);
  348. auto head = network::mojom::URLResponseHead::New();
  349. std::string headers = absl::StrFormat(
  350. "HTTP/1.1 %i Internal Redirect\n"
  351. "Location: %s\n"
  352. "Non-Authoritative-Reason: WebRequest API\n\n",
  353. kInternalRedirectStatusCode, redirect_url_.spec().c_str());
  354. // Cross-origin requests need to modify the Origin header to 'null'. Since
  355. // CorsURLLoader sets |request_initiator| to the Origin request header in
  356. // NetworkService, we need to modify |request_initiator| here to craft the
  357. // Origin header indirectly.
  358. // Following checks implement the step 10 of "4.4. HTTP-redirect fetch",
  359. // https://fetch.spec.whatwg.org/#http-redirect-fetch
  360. if (request_.request_initiator &&
  361. (!url::Origin::Create(redirect_url_)
  362. .IsSameOriginWith(url::Origin::Create(request_.url)) &&
  363. !request_.request_initiator->IsSameOriginWith(
  364. url::Origin::Create(request_.url)))) {
  365. // Reset the initiator to pretend tainted origin flag of the spec is set.
  366. request_.request_initiator = url::Origin();
  367. }
  368. head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
  369. net::HttpUtil::AssembleRawHeaders(headers));
  370. head->encoded_data_length = 0;
  371. current_response_ = std::move(head);
  372. ContinueToBeforeRedirect(redirect_info, net::OK);
  373. }
  374. void ProxyingURLLoaderFactory::InProgressRequest::ContinueToBeforeSendHeaders(
  375. int error_code) {
  376. if (error_code != net::OK) {
  377. OnRequestError(network::URLLoaderCompletionStatus(error_code));
  378. return;
  379. }
  380. if (!current_request_uses_header_client_ && !redirect_url_.is_empty()) {
  381. if (for_cors_preflight_) {
  382. // CORS preflight doesn't support redirect.
  383. OnRequestError(network::URLLoaderCompletionStatus(net::ERR_FAILED));
  384. return;
  385. }
  386. HandleBeforeRequestRedirect();
  387. return;
  388. }
  389. if (proxied_client_receiver_.is_bound())
  390. proxied_client_receiver_.Resume();
  391. auto continuation = base::BindRepeating(
  392. &InProgressRequest::ContinueToSendHeaders, weak_factory_.GetWeakPtr());
  393. // Note: In Electron onBeforeSendHeaders is called for all protocols.
  394. int result = factory_->web_request_api()->OnBeforeSendHeaders(
  395. &info_.value(), request_, continuation, &request_.headers);
  396. if (result == net::ERR_BLOCKED_BY_CLIENT) {
  397. // The request was cancelled synchronously. Dispatch an error notification
  398. // and terminate the request.
  399. OnRequestError(network::URLLoaderCompletionStatus(result));
  400. return;
  401. }
  402. if (result == net::ERR_IO_PENDING) {
  403. // One or more listeners is blocking, so the request must be paused until
  404. // they respond. |continuation| above will be invoked asynchronously to
  405. // continue or cancel the request.
  406. //
  407. // We pause the receiver here to prevent further client message processing.
  408. if (proxied_client_receiver_.is_bound())
  409. proxied_client_receiver_.Resume();
  410. return;
  411. }
  412. DCHECK_EQ(net::OK, result);
  413. ContinueToSendHeaders(std::set<std::string>(), std::set<std::string>(),
  414. net::OK);
  415. }
  416. void ProxyingURLLoaderFactory::InProgressRequest::ContinueToStartRequest(
  417. int error_code) {
  418. if (error_code != net::OK) {
  419. OnRequestError(network::URLLoaderCompletionStatus(error_code));
  420. return;
  421. }
  422. if (current_request_uses_header_client_ && !redirect_url_.is_empty()) {
  423. HandleBeforeRequestRedirect();
  424. return;
  425. }
  426. if (proxied_client_receiver_.is_bound())
  427. proxied_client_receiver_.Resume();
  428. if (header_client_receiver_.is_bound())
  429. header_client_receiver_.Resume();
  430. if (for_cors_preflight_) {
  431. // For CORS preflight requests, we have already started the request in
  432. // the network service. We did block the request by blocking
  433. // |header_client_receiver_|, which we unblocked right above.
  434. return;
  435. }
  436. if (!target_loader_.is_bound() && factory_->target_factory_.is_bound()) {
  437. // No extensions have cancelled us up to this point, so it's now OK to
  438. // initiate the real network request.
  439. uint32_t options = options_;
  440. // Even if this request does not use the header client, future redirects
  441. // might, so we need to set the option on the loader.
  442. if (has_any_extra_headers_listeners_)
  443. options |= network::mojom::kURLLoadOptionUseHeaderClient;
  444. factory_->target_factory_->CreateLoaderAndStart(
  445. target_loader_.BindNewPipeAndPassReceiver(),
  446. network_service_request_id_, options, request_,
  447. proxied_client_receiver_.BindNewPipeAndPassRemote(),
  448. traffic_annotation_);
  449. }
  450. // From here the lifecycle of this request is driven by subsequent events on
  451. // either |proxied_loader_receiver_|, |proxied_client_receiver_|, or
  452. // |header_client_receiver_|.
  453. }
  454. void ProxyingURLLoaderFactory::InProgressRequest::ContinueToSendHeaders(
  455. const std::set<std::string>& removed_headers,
  456. const std::set<std::string>& set_headers,
  457. int error_code) {
  458. if (error_code != net::OK) {
  459. OnRequestError(network::URLLoaderCompletionStatus(error_code));
  460. return;
  461. }
  462. if (current_request_uses_header_client_) {
  463. DCHECK(on_before_send_headers_callback_);
  464. std::move(on_before_send_headers_callback_)
  465. .Run(error_code, request_.headers);
  466. } else if (pending_follow_redirect_params_) {
  467. pending_follow_redirect_params_->removed_headers.insert(
  468. pending_follow_redirect_params_->removed_headers.end(),
  469. removed_headers.begin(), removed_headers.end());
  470. for (auto& set_header : set_headers) {
  471. auto header = request_.headers.GetHeader(set_header);
  472. if (header) {
  473. pending_follow_redirect_params_->modified_headers.SetHeader(
  474. set_header, header.value());
  475. } else {
  476. NOTREACHED();
  477. }
  478. }
  479. if (target_loader_.is_bound()) {
  480. target_loader_->FollowRedirect(
  481. pending_follow_redirect_params_->removed_headers,
  482. pending_follow_redirect_params_->modified_headers,
  483. pending_follow_redirect_params_->modified_cors_exempt_headers,
  484. pending_follow_redirect_params_->new_url);
  485. }
  486. pending_follow_redirect_params_.reset();
  487. }
  488. if (proxied_client_receiver_.is_bound())
  489. proxied_client_receiver_.Resume();
  490. // Note: In Electron onSendHeaders is called for all protocols.
  491. factory_->web_request_api()->OnSendHeaders(&info_.value(), request_,
  492. request_.headers);
  493. if (!current_request_uses_header_client_)
  494. ContinueToStartRequest(net::OK);
  495. }
  496. void ProxyingURLLoaderFactory::InProgressRequest::
  497. ContinueToHandleOverrideHeaders(int error_code) {
  498. if (error_code != net::OK) {
  499. OnRequestError(network::URLLoaderCompletionStatus(error_code));
  500. return;
  501. }
  502. DCHECK(on_headers_received_callback_);
  503. std::optional<std::string> headers;
  504. if (override_headers_) {
  505. headers = override_headers_->raw_headers();
  506. if (current_request_uses_header_client_) {
  507. // Make sure to update current_response_, since when OnReceiveResponse
  508. // is called we will not use its headers as it might be missing the
  509. // Set-Cookie line (as that gets stripped over IPC).
  510. current_response_->headers = override_headers_;
  511. }
  512. }
  513. if (for_cors_preflight_ && !redirect_url_.is_empty()) {
  514. OnRequestError(network::URLLoaderCompletionStatus(net::ERR_FAILED));
  515. return;
  516. }
  517. std::move(on_headers_received_callback_).Run(net::OK, headers, redirect_url_);
  518. override_headers_ = nullptr;
  519. if (for_cors_preflight_) {
  520. // If this is for CORS preflight, there is no associated client.
  521. info_->AddResponseInfoFromResourceResponse(*current_response_);
  522. // Do not finish proxied preflight requests that require proxy auth.
  523. // The request is not finished yet, give control back to network service
  524. // which will start authentication process.
  525. if (info_->response_code == net::HTTP_PROXY_AUTHENTICATION_REQUIRED)
  526. return;
  527. // We notify the completion here, and delete |this|.
  528. factory_->web_request_api()->OnResponseStarted(&info_.value(), request_);
  529. factory_->web_request_api()->OnCompleted(&info_.value(), request_, net::OK);
  530. factory_->RemoveRequest(network_service_request_id_, request_id_);
  531. return;
  532. }
  533. if (proxied_client_receiver_.is_bound())
  534. proxied_client_receiver_.Resume();
  535. }
  536. void ProxyingURLLoaderFactory::InProgressRequest::ContinueToResponseStarted(
  537. int error_code) {
  538. DCHECK(!for_cors_preflight_);
  539. if (error_code != net::OK) {
  540. OnRequestError(network::URLLoaderCompletionStatus(error_code));
  541. return;
  542. }
  543. DCHECK(!current_request_uses_header_client_ || !override_headers_);
  544. if (override_headers_)
  545. current_response_->headers = override_headers_;
  546. std::string redirect_location;
  547. if (override_headers_ && override_headers_->IsRedirect(&redirect_location)) {
  548. // The response headers may have been overridden by an |onHeadersReceived|
  549. // handler and may have been changed to a redirect. We handle that here
  550. // instead of acting like regular request completion.
  551. //
  552. // Note that we can't actually change how the Network Service handles the
  553. // original request at this point, so our "redirect" is really just
  554. // generating an artificial |onBeforeRedirect| event and starting a new
  555. // request to the Network Service. Our client shouldn't know the difference.
  556. GURL new_url(redirect_location);
  557. net::RedirectInfo redirect_info;
  558. redirect_info.status_code = override_headers_->response_code();
  559. redirect_info.new_method = request_.method;
  560. redirect_info.new_url = new_url;
  561. redirect_info.new_site_for_cookies = net::SiteForCookies::FromUrl(new_url);
  562. // These will get re-bound if a new request is initiated by
  563. // |FollowRedirect()|.
  564. proxied_client_receiver_.reset();
  565. header_client_receiver_.reset();
  566. target_loader_.reset();
  567. ContinueToBeforeRedirect(redirect_info, net::OK);
  568. return;
  569. }
  570. info_->AddResponseInfoFromResourceResponse(*current_response_);
  571. proxied_client_receiver_.Resume();
  572. factory_->web_request_api()->OnResponseStarted(&info_.value(), request_);
  573. target_client_->OnReceiveResponse(current_response_.Clone(),
  574. std::move(current_body_),
  575. std::move(current_cached_metadata_));
  576. }
  577. void ProxyingURLLoaderFactory::InProgressRequest::ContinueToBeforeRedirect(
  578. const net::RedirectInfo& redirect_info,
  579. int error_code) {
  580. if (error_code != net::OK) {
  581. OnRequestError(network::URLLoaderCompletionStatus(error_code));
  582. return;
  583. }
  584. info_->AddResponseInfoFromResourceResponse(*current_response_);
  585. if (proxied_client_receiver_.is_bound())
  586. proxied_client_receiver_.Resume();
  587. factory_->web_request_api()->OnBeforeRedirect(&info_.value(), request_,
  588. redirect_info.new_url);
  589. target_client_->OnReceiveRedirect(redirect_info, current_response_.Clone());
  590. request_.url = redirect_info.new_url;
  591. request_.method = redirect_info.new_method;
  592. request_.site_for_cookies = redirect_info.new_site_for_cookies;
  593. request_.referrer = GURL(redirect_info.new_referrer);
  594. request_.referrer_policy = redirect_info.new_referrer_policy;
  595. // The request method can be changed to "GET". In this case we need to
  596. // reset the request body manually.
  597. if (request_.method == net::HttpRequestHeaders::kGetMethod)
  598. request_.request_body = nullptr;
  599. }
  600. void ProxyingURLLoaderFactory::InProgressRequest::
  601. HandleResponseOrRedirectHeaders(net::CompletionOnceCallback continuation) {
  602. override_headers_ = nullptr;
  603. redirect_url_ = GURL();
  604. info_->AddResponseInfoFromResourceResponse(*current_response_);
  605. auto callback_pair = base::SplitOnceCallback(std::move(continuation));
  606. DCHECK(info_.has_value());
  607. int result = factory_->web_request_api()->OnHeadersReceived(
  608. &info_.value(), request_, std::move(callback_pair.first),
  609. current_response_->headers.get(), &override_headers_, &redirect_url_);
  610. if (result == net::ERR_BLOCKED_BY_CLIENT) {
  611. OnRequestError(network::URLLoaderCompletionStatus(result));
  612. return;
  613. }
  614. if (result == net::ERR_IO_PENDING) {
  615. // One or more listeners is blocking, so the request must be paused until
  616. // they respond. |continuation| above will be invoked asynchronously to
  617. // continue or cancel the request.
  618. //
  619. // We pause the receiver here to prevent further client message processing.
  620. if (proxied_client_receiver_.is_bound())
  621. proxied_client_receiver_.Pause();
  622. return;
  623. }
  624. DCHECK_EQ(net::OK, result);
  625. std::move(callback_pair.second).Run(net::OK);
  626. }
  627. void ProxyingURLLoaderFactory::InProgressRequest::OnRequestError(
  628. const network::URLLoaderCompletionStatus& status) {
  629. if (target_client_)
  630. target_client_->OnComplete(status);
  631. factory_->web_request_api()->OnErrorOccurred(&info_.value(), request_,
  632. status.error_code);
  633. // Deletes |this|.
  634. factory_->RemoveRequest(network_service_request_id_, request_id_);
  635. }
  636. ProxyingURLLoaderFactory::ProxyingURLLoaderFactory(
  637. WebRequestAPI* web_request_api,
  638. const HandlersMap& intercepted_handlers,
  639. int render_process_id,
  640. int frame_routing_id,
  641. uint64_t* request_id_generator,
  642. std::unique_ptr<extensions::ExtensionNavigationUIData> navigation_ui_data,
  643. std::optional<int64_t> navigation_id,
  644. mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_request,
  645. mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory_remote,
  646. mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient>
  647. header_client_receiver,
  648. content::ContentBrowserClient::URLLoaderFactoryType loader_factory_type)
  649. : web_request_api_(web_request_api),
  650. intercepted_handlers_(intercepted_handlers),
  651. render_process_id_(render_process_id),
  652. frame_routing_id_(frame_routing_id),
  653. request_id_generator_(request_id_generator),
  654. navigation_ui_data_(std::move(navigation_ui_data)),
  655. navigation_id_(std::move(navigation_id)),
  656. loader_factory_type_(loader_factory_type) {
  657. target_factory_.Bind(std::move(target_factory_remote));
  658. target_factory_.set_disconnect_handler(base::BindOnce(
  659. &ProxyingURLLoaderFactory::OnTargetFactoryError, base::Unretained(this)));
  660. proxy_receivers_.Add(this, std::move(loader_request));
  661. proxy_receivers_.set_disconnect_handler(base::BindRepeating(
  662. &ProxyingURLLoaderFactory::OnProxyBindingError, base::Unretained(this)));
  663. if (header_client_receiver)
  664. url_loader_header_client_receiver_.Bind(std::move(header_client_receiver));
  665. ignore_connections_limit_domains_ = base::SplitString(
  666. base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
  667. switches::kIgnoreConnectionsLimit),
  668. ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  669. }
  670. bool ProxyingURLLoaderFactory::ShouldIgnoreConnectionsLimit(
  671. const network::ResourceRequest& request) {
  672. for (const auto& domain : ignore_connections_limit_domains_) {
  673. if (request.url.DomainIs(domain)) {
  674. return true;
  675. }
  676. }
  677. return false;
  678. }
  679. void ProxyingURLLoaderFactory::CreateLoaderAndStart(
  680. mojo::PendingReceiver<network::mojom::URLLoader> loader,
  681. int32_t request_id,
  682. uint32_t options,
  683. const network::ResourceRequest& original_request,
  684. mojo::PendingRemote<network::mojom::URLLoaderClient> client,
  685. const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
  686. // Take a copy so we can mutate the request.
  687. network::ResourceRequest request = original_request;
  688. if (ShouldIgnoreConnectionsLimit(request)) {
  689. request.priority = net::RequestPriority::MAXIMUM_PRIORITY;
  690. request.load_flags |= net::LOAD_IGNORE_LIMITS;
  691. }
  692. // Check if user has intercepted this scheme.
  693. bool bypass_custom_protocol_handlers =
  694. options & kBypassCustomProtocolHandlers;
  695. if (!bypass_custom_protocol_handlers) {
  696. auto it = intercepted_handlers_->find(request.url.scheme_piece());
  697. if (it != intercepted_handlers_->end()) {
  698. mojo::PendingRemote<network::mojom::URLLoaderFactory> loader_remote;
  699. this->Clone(loader_remote.InitWithNewPipeAndPassReceiver());
  700. // <scheme, <type, handler>>
  701. it->second.second.Run(
  702. request,
  703. base::BindOnce(&ElectronURLLoaderFactory::StartLoading,
  704. std::move(loader), request_id, options, request,
  705. std::move(client), traffic_annotation,
  706. std::move(loader_remote), it->second.first));
  707. return;
  708. }
  709. }
  710. // The loader of ServiceWorker forbids loading scripts from file:// URLs, and
  711. // Chromium does not provide a way to override this behavior. So in order to
  712. // make ServiceWorker work with file:// URLs, we have to intercept its
  713. // requests here.
  714. if (IsForServiceWorkerScript() && request.url.SchemeIsFile()) {
  715. asar::CreateAsarURLLoader(
  716. request, std::move(loader), std::move(client),
  717. base::MakeRefCounted<net::HttpResponseHeaders>(""));
  718. return;
  719. }
  720. if (!web_request_api()->HasListener()) {
  721. // Pass-through to the original factory.
  722. target_factory_->CreateLoaderAndStart(std::move(loader), request_id,
  723. options, request, std::move(client),
  724. traffic_annotation);
  725. return;
  726. }
  727. // The request ID doesn't really matter. It just needs to be unique
  728. // per-BrowserContext so extensions can make sense of it. Note that
  729. // |network_service_request_id_| by contrast is not necessarily unique, so we
  730. // don't use it for identity here.
  731. const uint64_t web_request_id = ++(*request_id_generator_);
  732. // Notes: Chromium assumes that requests with zero-ID would never use the
  733. // "extraHeaders" code path, however in Electron requests started from
  734. // the net module would have zero-ID because they do not have renderer process
  735. // associated.
  736. if (request_id)
  737. network_request_id_to_web_request_id_.emplace(request_id, web_request_id);
  738. auto result = requests_.emplace(
  739. web_request_id,
  740. std::make_unique<InProgressRequest>(
  741. this, web_request_id, frame_routing_id_, request_id, options, request,
  742. traffic_annotation, std::move(loader), std::move(client)));
  743. result.first->second->Restart();
  744. }
  745. void ProxyingURLLoaderFactory::Clone(
  746. mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver) {
  747. proxy_receivers_.Add(this, std::move(loader_receiver));
  748. }
  749. void ProxyingURLLoaderFactory::OnLoaderCreated(
  750. int32_t request_id,
  751. mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) {
  752. auto it = network_request_id_to_web_request_id_.find(request_id);
  753. if (it == network_request_id_to_web_request_id_.end())
  754. return;
  755. auto request_it = requests_.find(it->second);
  756. DCHECK(request_it != requests_.end());
  757. request_it->second->OnLoaderCreated(std::move(receiver));
  758. }
  759. void ProxyingURLLoaderFactory::OnLoaderForCorsPreflightCreated(
  760. const network::ResourceRequest& request,
  761. mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) {
  762. // Please note that the URLLoader is now starting, without waiting for
  763. // additional signals from here. The URLLoader will be blocked before
  764. // sending HTTP request headers (TrustedHeaderClient.OnBeforeSendHeaders),
  765. // but the connection set up will be done before that. This is acceptable from
  766. // Web Request API because the extension has already allowed to set up
  767. // a connection to the same URL (i.e., the actual request), and distinguishing
  768. // two connections for the actual request and the preflight request before
  769. // sending request headers is very difficult.
  770. const uint64_t web_request_id = ++(*request_id_generator_);
  771. auto result = requests_.insert(std::make_pair(
  772. web_request_id, std::make_unique<InProgressRequest>(
  773. this, web_request_id, frame_routing_id_, request)));
  774. result.first->second->OnLoaderCreated(std::move(receiver));
  775. result.first->second->Restart();
  776. }
  777. ProxyingURLLoaderFactory::~ProxyingURLLoaderFactory() = default;
  778. void ProxyingURLLoaderFactory::OnTargetFactoryError() {
  779. target_factory_.reset();
  780. proxy_receivers_.Clear();
  781. MaybeDeleteThis();
  782. }
  783. void ProxyingURLLoaderFactory::OnProxyBindingError() {
  784. if (proxy_receivers_.empty())
  785. target_factory_.reset();
  786. MaybeDeleteThis();
  787. }
  788. void ProxyingURLLoaderFactory::RemoveRequest(int32_t network_service_request_id,
  789. uint64_t request_id) {
  790. network_request_id_to_web_request_id_.erase(network_service_request_id);
  791. requests_.erase(request_id);
  792. MaybeDeleteThis();
  793. }
  794. void ProxyingURLLoaderFactory::MaybeDeleteThis() {
  795. // Even if all URLLoaderFactory pipes connected to this object have been
  796. // closed it has to stay alive until all active requests have completed.
  797. if (target_factory_.is_bound() || !requests_.empty() ||
  798. !proxy_receivers_.empty())
  799. return;
  800. delete this;
  801. }
  802. } // namespace electron