* chore: bump chromium in DEPS to 117.0.5899.0 * 4686653: webui: Filter out non-chrome scheme URLs in WebUIConfigMap https://chromium-review.googlesource.com/c/chromium/src/+/4686653 * 4696355: Remove deprecated version of base::CommandLine::CopySwitchesFrom() https://chromium-review.googlesource.com/c/chromium/src/+/4696355 * chore: fixup patch indices * 4603888: Reland "Enable raw_ref check on linux" https://chromium-review.googlesource.com/c/chromium/src/+/4603888 * chore: bump chromium in DEPS to 117.0.5901.0 * chore: update patches * chore: bump chromium in DEPS to 117.0.5903.0 * chore: bump chromium in DEPS to 117.0.5903.2 * chore: bump chromium in DEPS to 117.0.5905.0 * 4706792: Printing: Add debug code for a DispatchBeforePrintEvent() failure https://chromium-review.googlesource.com/c/chromium/src/+/4706792 * 4704786: Refactor libunwind build rules/flags https://chromium-review.googlesource.com/c/chromium/src/+/4704786 * 4701710: [Linux Ui] Set toolkit dark preference based on FDO dark preference https://chromium-review.googlesource.com/c/chromium/src/+/4701710 * chore: fixup patch indices * chore: bump chromium in DEPS to 117.0.5907.0 * chore: bump chromium in DEPS to 117.0.5909.2 * chore: update patches * chore: bump chromium in DEPS to 117.0.5911.0 * chore: update patches * chore: build-what-we-include * fix: set allowFileAccess on devtools extensions correctly Ref: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/4714725 * 4670615: Reland "[iterator-helpers] Shipping iterator helpers" https://chromium-review.googlesource.com/c/v8/v8/+/4670615 --------- Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com> Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>
		
			
				
	
	
		
			940 lines
		
	
	
	
		
			36 KiB
			
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			940 lines
		
	
	
	
		
			36 KiB
			
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright (c) 2019 GitHub, Inc.
 | 
						|
// Use of this source code is governed by the MIT license that can be
 | 
						|
// found in the LICENSE file.
 | 
						|
 | 
						|
#include "shell/browser/net/proxying_url_loader_factory.h"
 | 
						|
 | 
						|
#include <memory>
 | 
						|
#include <utility>
 | 
						|
 | 
						|
#include "base/command_line.h"
 | 
						|
#include "base/functional/bind.h"
 | 
						|
#include "base/functional/callback_helpers.h"
 | 
						|
#include "base/strings/string_split.h"
 | 
						|
#include "base/strings/string_util.h"
 | 
						|
#include "base/strings/stringprintf.h"
 | 
						|
#include "content/public/browser/browser_context.h"
 | 
						|
#include "extensions/browser/extension_navigation_ui_data.h"
 | 
						|
#include "net/base/completion_repeating_callback.h"
 | 
						|
#include "net/base/load_flags.h"
 | 
						|
#include "net/http/http_response_headers.h"
 | 
						|
#include "net/http/http_status_code.h"
 | 
						|
#include "net/http/http_util.h"
 | 
						|
#include "net/url_request/redirect_info.h"
 | 
						|
#include "services/metrics/public/cpp/ukm_source_id.h"
 | 
						|
#include "services/network/public/cpp/features.h"
 | 
						|
#include "services/network/public/mojom/early_hints.mojom.h"
 | 
						|
#include "shell/browser/net/asar/asar_url_loader.h"
 | 
						|
#include "shell/common/options_switches.h"
 | 
						|
#include "url/origin.h"
 | 
						|
 | 
						|
namespace electron {
 | 
						|
 | 
						|
ProxyingURLLoaderFactory::InProgressRequest::FollowRedirectParams::
 | 
						|
    FollowRedirectParams() = default;
 | 
						|
ProxyingURLLoaderFactory::InProgressRequest::FollowRedirectParams::
 | 
						|
    ~FollowRedirectParams() = default;
 | 
						|
 | 
						|
ProxyingURLLoaderFactory::InProgressRequest::InProgressRequest(
 | 
						|
    ProxyingURLLoaderFactory* factory,
 | 
						|
    uint64_t web_request_id,
 | 
						|
    int32_t frame_routing_id,
 | 
						|
    int32_t network_service_request_id,
 | 
						|
    uint32_t options,
 | 
						|
    const network::ResourceRequest& request,
 | 
						|
    const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
 | 
						|
    mojo::PendingReceiver<network::mojom::URLLoader> loader_receiver,
 | 
						|
    mojo::PendingRemote<network::mojom::URLLoaderClient> client)
 | 
						|
    : factory_(factory),
 | 
						|
      request_(request),
 | 
						|
      original_initiator_(request.request_initiator),
 | 
						|
      request_id_(web_request_id),
 | 
						|
      network_service_request_id_(network_service_request_id),
 | 
						|
      frame_routing_id_(frame_routing_id),
 | 
						|
      options_(options),
 | 
						|
      traffic_annotation_(traffic_annotation),
 | 
						|
      proxied_loader_receiver_(this, std::move(loader_receiver)),
 | 
						|
      target_client_(std::move(client)),
 | 
						|
      current_response_(network::mojom::URLResponseHead::New()),
 | 
						|
      // Always use "extraHeaders" mode to be compatible with old APIs, except
 | 
						|
      // when the |request_id_| is zero, which is not supported in Chromium and
 | 
						|
      // only happens in Electron when the request is started from net module.
 | 
						|
      has_any_extra_headers_listeners_(network_service_request_id != 0) {
 | 
						|
  // If there is a client error, clean up the request.
 | 
						|
  target_client_.set_disconnect_handler(base::BindOnce(
 | 
						|
      &ProxyingURLLoaderFactory::InProgressRequest::OnRequestError,
 | 
						|
      weak_factory_.GetWeakPtr(),
 | 
						|
      network::URLLoaderCompletionStatus(net::ERR_ABORTED)));
 | 
						|
  proxied_loader_receiver_.set_disconnect_handler(base::BindOnce(
 | 
						|
      &ProxyingURLLoaderFactory::InProgressRequest::OnRequestError,
 | 
						|
      weak_factory_.GetWeakPtr(),
 | 
						|
      network::URLLoaderCompletionStatus(net::ERR_ABORTED)));
 | 
						|
}
 | 
						|
 | 
						|
ProxyingURLLoaderFactory::InProgressRequest::InProgressRequest(
 | 
						|
    ProxyingURLLoaderFactory* factory,
 | 
						|
    uint64_t request_id,
 | 
						|
    int32_t frame_routing_id,
 | 
						|
    const network::ResourceRequest& request)
 | 
						|
    : factory_(factory),
 | 
						|
      request_(request),
 | 
						|
      original_initiator_(request.request_initiator),
 | 
						|
      request_id_(request_id),
 | 
						|
      frame_routing_id_(frame_routing_id),
 | 
						|
      proxied_loader_receiver_(this),
 | 
						|
      for_cors_preflight_(true),
 | 
						|
      has_any_extra_headers_listeners_(true) {}
 | 
						|
 | 
						|
ProxyingURLLoaderFactory::InProgressRequest::~InProgressRequest() {
 | 
						|
  // This is important to ensure that no outstanding blocking requests continue
 | 
						|
  // to reference state owned by this object.
 | 
						|
  if (info_) {
 | 
						|
    factory_->web_request_api()->OnRequestWillBeDestroyed(&info_.value());
 | 
						|
  }
 | 
						|
  if (on_before_send_headers_callback_) {
 | 
						|
    std::move(on_before_send_headers_callback_)
 | 
						|
        .Run(net::ERR_ABORTED, absl::nullopt);
 | 
						|
  }
 | 
						|
  if (on_headers_received_callback_) {
 | 
						|
    std::move(on_headers_received_callback_)
 | 
						|
        .Run(net::ERR_ABORTED, absl::nullopt, absl::nullopt);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::Restart() {
 | 
						|
  UpdateRequestInfo();
 | 
						|
  RestartInternal();
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::UpdateRequestInfo() {
 | 
						|
  // Derive a new WebRequestInfo value any time |Restart()| is called, because
 | 
						|
  // the details in |request_| may have changed e.g. if we've been redirected.
 | 
						|
  // |request_initiator| can be modified on redirects, but we keep the original
 | 
						|
  // for |initiator| in the event. See also
 | 
						|
  // https://developer.chrome.com/extensions/webRequest#event-onBeforeRequest.
 | 
						|
  network::ResourceRequest request_for_info = request_;
 | 
						|
  request_for_info.request_initiator = original_initiator_;
 | 
						|
  info_.emplace(extensions::WebRequestInfoInitParams(
 | 
						|
      request_id_, factory_->render_process_id_, frame_routing_id_,
 | 
						|
      factory_->navigation_ui_data_ ? factory_->navigation_ui_data_->DeepCopy()
 | 
						|
                                    : nullptr,
 | 
						|
      request_for_info, false,
 | 
						|
      !(options_ & network::mojom::kURLLoadOptionSynchronous),
 | 
						|
      factory_->IsForServiceWorkerScript(), factory_->navigation_id_,
 | 
						|
      ukm::kInvalidSourceIdObj));
 | 
						|
 | 
						|
  current_request_uses_header_client_ =
 | 
						|
      factory_->url_loader_header_client_receiver_.is_bound() &&
 | 
						|
      (for_cors_preflight_ || network_service_request_id_ != 0) &&
 | 
						|
      has_any_extra_headers_listeners_;
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::RestartInternal() {
 | 
						|
  DCHECK_EQ(info_->url, request_.url)
 | 
						|
      << "UpdateRequestInfo must have been called first";
 | 
						|
 | 
						|
  // If the header client will be used, we start the request immediately, and
 | 
						|
  // OnBeforeSendHeaders and OnSendHeaders will be handled there. Otherwise,
 | 
						|
  // send these events before the request starts.
 | 
						|
  base::RepeatingCallback<void(int)> continuation;
 | 
						|
  if (current_request_uses_header_client_) {
 | 
						|
    continuation = base::BindRepeating(
 | 
						|
        &InProgressRequest::ContinueToStartRequest, weak_factory_.GetWeakPtr());
 | 
						|
  } else if (for_cors_preflight_) {
 | 
						|
    // In this case we do nothing because extensions should see nothing.
 | 
						|
    return;
 | 
						|
  } else {
 | 
						|
    continuation =
 | 
						|
        base::BindRepeating(&InProgressRequest::ContinueToBeforeSendHeaders,
 | 
						|
                            weak_factory_.GetWeakPtr());
 | 
						|
  }
 | 
						|
  redirect_url_ = GURL();
 | 
						|
  int result = factory_->web_request_api()->OnBeforeRequest(
 | 
						|
      &info_.value(), request_, continuation, &redirect_url_);
 | 
						|
  if (result == net::ERR_BLOCKED_BY_CLIENT) {
 | 
						|
    // The request was cancelled synchronously. Dispatch an error notification
 | 
						|
    // and terminate the request.
 | 
						|
    network::URLLoaderCompletionStatus status(result);
 | 
						|
    OnRequestError(status);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (result == net::ERR_IO_PENDING) {
 | 
						|
    // One or more listeners is blocking, so the request must be paused until
 | 
						|
    // they respond. |continuation| above will be invoked asynchronously to
 | 
						|
    // continue or cancel the request.
 | 
						|
    //
 | 
						|
    // We pause the receiver here to prevent further client message processing.
 | 
						|
    if (proxied_client_receiver_.is_bound())
 | 
						|
      proxied_client_receiver_.Pause();
 | 
						|
 | 
						|
    // Pause the header client, since we want to wait until OnBeforeRequest has
 | 
						|
    // finished before processing any future events.
 | 
						|
    if (header_client_receiver_.is_bound())
 | 
						|
      header_client_receiver_.Pause();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  DCHECK_EQ(net::OK, result);
 | 
						|
 | 
						|
  continuation.Run(net::OK);
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::FollowRedirect(
 | 
						|
    const std::vector<std::string>& removed_headers,
 | 
						|
    const net::HttpRequestHeaders& modified_headers,
 | 
						|
    const net::HttpRequestHeaders& modified_cors_exempt_headers,
 | 
						|
    const absl::optional<GURL>& new_url) {
 | 
						|
  if (new_url)
 | 
						|
    request_.url = new_url.value();
 | 
						|
 | 
						|
  for (const std::string& header : removed_headers)
 | 
						|
    request_.headers.RemoveHeader(header);
 | 
						|
  request_.headers.MergeFrom(modified_headers);
 | 
						|
 | 
						|
  // Call this before checking |current_request_uses_header_client_| as it
 | 
						|
  // calculates it.
 | 
						|
  UpdateRequestInfo();
 | 
						|
 | 
						|
  if (target_loader_.is_bound()) {
 | 
						|
    // If header_client_ is used, then we have to call FollowRedirect now as
 | 
						|
    // that's what triggers the network service calling back to
 | 
						|
    // OnBeforeSendHeaders(). Otherwise, don't call FollowRedirect now. Wait for
 | 
						|
    // the onBeforeSendHeaders callback(s) to run as these may modify request
 | 
						|
    // headers and if so we'll pass these modifications to FollowRedirect.
 | 
						|
    if (current_request_uses_header_client_) {
 | 
						|
      target_loader_->FollowRedirect(removed_headers, modified_headers,
 | 
						|
                                     modified_cors_exempt_headers, new_url);
 | 
						|
    } else {
 | 
						|
      auto params = std::make_unique<FollowRedirectParams>();
 | 
						|
      params->removed_headers = removed_headers;
 | 
						|
      params->modified_headers = modified_headers;
 | 
						|
      params->modified_cors_exempt_headers = modified_cors_exempt_headers;
 | 
						|
      params->new_url = new_url;
 | 
						|
      pending_follow_redirect_params_ = std::move(params);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  RestartInternal();
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::SetPriority(
 | 
						|
    net::RequestPriority priority,
 | 
						|
    int32_t intra_priority_value) {
 | 
						|
  if (target_loader_.is_bound())
 | 
						|
    target_loader_->SetPriority(priority, intra_priority_value);
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::PauseReadingBodyFromNet() {
 | 
						|
  if (target_loader_.is_bound())
 | 
						|
    target_loader_->PauseReadingBodyFromNet();
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::ResumeReadingBodyFromNet() {
 | 
						|
  if (target_loader_.is_bound())
 | 
						|
    target_loader_->ResumeReadingBodyFromNet();
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::OnReceiveEarlyHints(
 | 
						|
    network::mojom::EarlyHintsPtr early_hints) {
 | 
						|
  target_client_->OnReceiveEarlyHints(std::move(early_hints));
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::OnReceiveResponse(
 | 
						|
    network::mojom::URLResponseHeadPtr head,
 | 
						|
    mojo::ScopedDataPipeConsumerHandle body,
 | 
						|
    absl::optional<mojo_base::BigBuffer> cached_metadata) {
 | 
						|
  current_body_ = std::move(body);
 | 
						|
  current_cached_metadata_ = std::move(cached_metadata);
 | 
						|
  if (current_request_uses_header_client_) {
 | 
						|
    // Use the headers we got from OnHeadersReceived as that'll contain
 | 
						|
    // Set-Cookie if it existed.
 | 
						|
    auto saved_headers = current_response_->headers;
 | 
						|
    current_response_ = std::move(head);
 | 
						|
    current_response_->headers = saved_headers;
 | 
						|
    ContinueToResponseStarted(net::OK);
 | 
						|
  } else {
 | 
						|
    current_response_ = std::move(head);
 | 
						|
    HandleResponseOrRedirectHeaders(
 | 
						|
        base::BindOnce(&InProgressRequest::ContinueToResponseStarted,
 | 
						|
                       weak_factory_.GetWeakPtr()));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::OnReceiveRedirect(
 | 
						|
    const net::RedirectInfo& redirect_info,
 | 
						|
    network::mojom::URLResponseHeadPtr head) {
 | 
						|
  // Note: In Electron we don't check IsRedirectSafe.
 | 
						|
 | 
						|
  if (current_request_uses_header_client_) {
 | 
						|
    // Use the headers we got from OnHeadersReceived as that'll contain
 | 
						|
    // Set-Cookie if it existed.
 | 
						|
    auto saved_headers = current_response_->headers;
 | 
						|
    current_response_ = std::move(head);
 | 
						|
    // If this redirect is from an HSTS upgrade, OnHeadersReceived will not be
 | 
						|
    // called before OnReceiveRedirect, so make sure the saved headers exist
 | 
						|
    // before setting them.
 | 
						|
    if (saved_headers)
 | 
						|
      current_response_->headers = saved_headers;
 | 
						|
    ContinueToBeforeRedirect(redirect_info, net::OK);
 | 
						|
  } else {
 | 
						|
    current_response_ = std::move(head);
 | 
						|
    HandleResponseOrRedirectHeaders(
 | 
						|
        base::BindOnce(&InProgressRequest::ContinueToBeforeRedirect,
 | 
						|
                       weak_factory_.GetWeakPtr(), redirect_info));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::OnUploadProgress(
 | 
						|
    int64_t current_position,
 | 
						|
    int64_t total_size,
 | 
						|
    OnUploadProgressCallback callback) {
 | 
						|
  target_client_->OnUploadProgress(current_position, total_size,
 | 
						|
                                   std::move(callback));
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::OnTransferSizeUpdated(
 | 
						|
    int32_t transfer_size_diff) {
 | 
						|
  target_client_->OnTransferSizeUpdated(transfer_size_diff);
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::OnComplete(
 | 
						|
    const network::URLLoaderCompletionStatus& status) {
 | 
						|
  if (status.error_code != net::OK) {
 | 
						|
    OnRequestError(status);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  target_client_->OnComplete(status);
 | 
						|
  factory_->web_request_api()->OnCompleted(&info_.value(), request_,
 | 
						|
                                           status.error_code);
 | 
						|
 | 
						|
  // Deletes |this|.
 | 
						|
  factory_->RemoveRequest(network_service_request_id_, request_id_);
 | 
						|
}
 | 
						|
 | 
						|
bool ProxyingURLLoaderFactory::IsForServiceWorkerScript() const {
 | 
						|
  return loader_factory_type_ == content::ContentBrowserClient::
 | 
						|
                                     URLLoaderFactoryType::kServiceWorkerScript;
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::OnLoaderCreated(
 | 
						|
    mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) {
 | 
						|
  // When CORS is involved there may be multiple network::URLLoader associated
 | 
						|
  // with this InProgressRequest, because CorsURLLoader may create a new
 | 
						|
  // network::URLLoader for the same request id in redirect handling - see
 | 
						|
  // CorsURLLoader::FollowRedirect. In such a case the old network::URLLoader
 | 
						|
  // is going to be detached fairly soon, so we don't need to take care of it.
 | 
						|
  // We need this explicit reset to avoid a DCHECK failure in mojo::Receiver.
 | 
						|
  header_client_receiver_.reset();
 | 
						|
 | 
						|
  header_client_receiver_.Bind(std::move(receiver));
 | 
						|
  if (for_cors_preflight_) {
 | 
						|
    // In this case we don't have |target_loader_| and
 | 
						|
    // |proxied_client_receiver_|, and |receiver| is the only connection to the
 | 
						|
    // network service, so we observe mojo connection errors.
 | 
						|
    header_client_receiver_.set_disconnect_handler(base::BindOnce(
 | 
						|
        &ProxyingURLLoaderFactory::InProgressRequest::OnRequestError,
 | 
						|
        weak_factory_.GetWeakPtr(),
 | 
						|
        network::URLLoaderCompletionStatus(net::ERR_FAILED)));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::OnBeforeSendHeaders(
 | 
						|
    const net::HttpRequestHeaders& headers,
 | 
						|
    OnBeforeSendHeadersCallback callback) {
 | 
						|
  if (!current_request_uses_header_client_) {
 | 
						|
    std::move(callback).Run(net::OK, absl::nullopt);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  request_.headers = headers;
 | 
						|
  on_before_send_headers_callback_ = std::move(callback);
 | 
						|
  ContinueToBeforeSendHeaders(net::OK);
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::OnHeadersReceived(
 | 
						|
    const std::string& headers,
 | 
						|
    const net::IPEndPoint& remote_endpoint,
 | 
						|
    OnHeadersReceivedCallback callback) {
 | 
						|
  if (!current_request_uses_header_client_) {
 | 
						|
    std::move(callback).Run(net::OK, absl::nullopt, GURL());
 | 
						|
 | 
						|
    if (for_cors_preflight_) {
 | 
						|
      // CORS preflight is supported only when "extraHeaders" is specified.
 | 
						|
      // Deletes |this|.
 | 
						|
      factory_->RemoveRequest(network_service_request_id_, request_id_);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  on_headers_received_callback_ = std::move(callback);
 | 
						|
  current_response_ = network::mojom::URLResponseHead::New();
 | 
						|
  current_response_->headers =
 | 
						|
      base::MakeRefCounted<net::HttpResponseHeaders>(headers);
 | 
						|
  current_response_->remote_endpoint = remote_endpoint;
 | 
						|
  HandleResponseOrRedirectHeaders(
 | 
						|
      base::BindOnce(&InProgressRequest::ContinueToHandleOverrideHeaders,
 | 
						|
                     weak_factory_.GetWeakPtr()));
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::
 | 
						|
    HandleBeforeRequestRedirect() {
 | 
						|
  // The extension requested a redirect. Close the connection with the current
 | 
						|
  // URLLoader and inform the URLLoaderClient the WebRequest API generated a
 | 
						|
  // redirect. To load |redirect_url_|, a new URLLoader will be recreated
 | 
						|
  // after receiving FollowRedirect().
 | 
						|
 | 
						|
  // Forgetting to close the connection with the current URLLoader caused
 | 
						|
  // bugs. The latter doesn't know anything about the redirect. Continuing
 | 
						|
  // the load with it gives unexpected results. See
 | 
						|
  // https://crbug.com/882661#c72.
 | 
						|
  proxied_client_receiver_.reset();
 | 
						|
  header_client_receiver_.reset();
 | 
						|
  target_loader_.reset();
 | 
						|
 | 
						|
  constexpr int kInternalRedirectStatusCode = net::HTTP_TEMPORARY_REDIRECT;
 | 
						|
 | 
						|
  net::RedirectInfo redirect_info;
 | 
						|
  redirect_info.status_code = kInternalRedirectStatusCode;
 | 
						|
  redirect_info.new_method = request_.method;
 | 
						|
  redirect_info.new_url = redirect_url_;
 | 
						|
  redirect_info.new_site_for_cookies =
 | 
						|
      net::SiteForCookies::FromUrl(redirect_url_);
 | 
						|
 | 
						|
  auto head = network::mojom::URLResponseHead::New();
 | 
						|
  std::string headers = base::StringPrintf(
 | 
						|
      "HTTP/1.1 %i Internal Redirect\n"
 | 
						|
      "Location: %s\n"
 | 
						|
      "Non-Authoritative-Reason: WebRequest API\n\n",
 | 
						|
      kInternalRedirectStatusCode, redirect_url_.spec().c_str());
 | 
						|
 | 
						|
  // Cross-origin requests need to modify the Origin header to 'null'. Since
 | 
						|
  // CorsURLLoader sets |request_initiator| to the Origin request header in
 | 
						|
  // NetworkService, we need to modify |request_initiator| here to craft the
 | 
						|
  // Origin header indirectly.
 | 
						|
  // Following checks implement the step 10 of "4.4. HTTP-redirect fetch",
 | 
						|
  // https://fetch.spec.whatwg.org/#http-redirect-fetch
 | 
						|
  if (request_.request_initiator &&
 | 
						|
      (!url::Origin::Create(redirect_url_)
 | 
						|
            .IsSameOriginWith(url::Origin::Create(request_.url)) &&
 | 
						|
       !request_.request_initiator->IsSameOriginWith(
 | 
						|
           url::Origin::Create(request_.url)))) {
 | 
						|
    // Reset the initiator to pretend tainted origin flag of the spec is set.
 | 
						|
    request_.request_initiator = url::Origin();
 | 
						|
  }
 | 
						|
  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
 | 
						|
      net::HttpUtil::AssembleRawHeaders(headers));
 | 
						|
  head->encoded_data_length = 0;
 | 
						|
 | 
						|
  current_response_ = std::move(head);
 | 
						|
  ContinueToBeforeRedirect(redirect_info, net::OK);
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::ContinueToBeforeSendHeaders(
 | 
						|
    int error_code) {
 | 
						|
  if (error_code != net::OK) {
 | 
						|
    OnRequestError(network::URLLoaderCompletionStatus(error_code));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!current_request_uses_header_client_ && !redirect_url_.is_empty()) {
 | 
						|
    if (for_cors_preflight_) {
 | 
						|
      // CORS preflight doesn't support redirect.
 | 
						|
      OnRequestError(network::URLLoaderCompletionStatus(net::ERR_FAILED));
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    HandleBeforeRequestRedirect();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (proxied_client_receiver_.is_bound())
 | 
						|
    proxied_client_receiver_.Resume();
 | 
						|
 | 
						|
  auto continuation = base::BindRepeating(
 | 
						|
      &InProgressRequest::ContinueToSendHeaders, weak_factory_.GetWeakPtr());
 | 
						|
  // Note: In Electron onBeforeSendHeaders is called for all protocols.
 | 
						|
  int result = factory_->web_request_api()->OnBeforeSendHeaders(
 | 
						|
      &info_.value(), request_, continuation, &request_.headers);
 | 
						|
 | 
						|
  if (result == net::ERR_BLOCKED_BY_CLIENT) {
 | 
						|
    // The request was cancelled synchronously. Dispatch an error notification
 | 
						|
    // and terminate the request.
 | 
						|
    OnRequestError(network::URLLoaderCompletionStatus(result));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (result == net::ERR_IO_PENDING) {
 | 
						|
    // One or more listeners is blocking, so the request must be paused until
 | 
						|
    // they respond. |continuation| above will be invoked asynchronously to
 | 
						|
    // continue or cancel the request.
 | 
						|
    //
 | 
						|
    // We pause the receiver here to prevent further client message processing.
 | 
						|
    if (proxied_client_receiver_.is_bound())
 | 
						|
      proxied_client_receiver_.Resume();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  DCHECK_EQ(net::OK, result);
 | 
						|
 | 
						|
  ContinueToSendHeaders(std::set<std::string>(), std::set<std::string>(),
 | 
						|
                        net::OK);
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::ContinueToStartRequest(
 | 
						|
    int error_code) {
 | 
						|
  if (error_code != net::OK) {
 | 
						|
    OnRequestError(network::URLLoaderCompletionStatus(error_code));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (current_request_uses_header_client_ && !redirect_url_.is_empty()) {
 | 
						|
    HandleBeforeRequestRedirect();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (proxied_client_receiver_.is_bound())
 | 
						|
    proxied_client_receiver_.Resume();
 | 
						|
 | 
						|
  if (header_client_receiver_.is_bound())
 | 
						|
    header_client_receiver_.Resume();
 | 
						|
 | 
						|
  if (for_cors_preflight_) {
 | 
						|
    // For CORS preflight requests, we have already started the request in
 | 
						|
    // the network service. We did block the request by blocking
 | 
						|
    // |header_client_receiver_|, which we unblocked right above.
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!target_loader_.is_bound() && factory_->target_factory_.is_bound()) {
 | 
						|
    // No extensions have cancelled us up to this point, so it's now OK to
 | 
						|
    // initiate the real network request.
 | 
						|
    uint32_t options = options_;
 | 
						|
    // Even if this request does not use the header client, future redirects
 | 
						|
    // might, so we need to set the option on the loader.
 | 
						|
    if (has_any_extra_headers_listeners_)
 | 
						|
      options |= network::mojom::kURLLoadOptionUseHeaderClient;
 | 
						|
    factory_->target_factory_->CreateLoaderAndStart(
 | 
						|
        target_loader_.BindNewPipeAndPassReceiver(),
 | 
						|
        network_service_request_id_, options, request_,
 | 
						|
        proxied_client_receiver_.BindNewPipeAndPassRemote(),
 | 
						|
        traffic_annotation_);
 | 
						|
  }
 | 
						|
 | 
						|
  // From here the lifecycle of this request is driven by subsequent events on
 | 
						|
  // either |proxied_loader_receiver_|, |proxied_client_receiver_|, or
 | 
						|
  // |header_client_receiver_|.
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::ContinueToSendHeaders(
 | 
						|
    const std::set<std::string>& removed_headers,
 | 
						|
    const std::set<std::string>& set_headers,
 | 
						|
    int error_code) {
 | 
						|
  if (error_code != net::OK) {
 | 
						|
    OnRequestError(network::URLLoaderCompletionStatus(error_code));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (current_request_uses_header_client_) {
 | 
						|
    DCHECK(on_before_send_headers_callback_);
 | 
						|
    std::move(on_before_send_headers_callback_)
 | 
						|
        .Run(error_code, request_.headers);
 | 
						|
  } else if (pending_follow_redirect_params_) {
 | 
						|
    pending_follow_redirect_params_->removed_headers.insert(
 | 
						|
        pending_follow_redirect_params_->removed_headers.end(),
 | 
						|
        removed_headers.begin(), removed_headers.end());
 | 
						|
 | 
						|
    for (auto& set_header : set_headers) {
 | 
						|
      std::string header_value;
 | 
						|
      if (request_.headers.GetHeader(set_header, &header_value)) {
 | 
						|
        pending_follow_redirect_params_->modified_headers.SetHeader(
 | 
						|
            set_header, header_value);
 | 
						|
      } else {
 | 
						|
        NOTREACHED();
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (target_loader_.is_bound()) {
 | 
						|
      target_loader_->FollowRedirect(
 | 
						|
          pending_follow_redirect_params_->removed_headers,
 | 
						|
          pending_follow_redirect_params_->modified_headers,
 | 
						|
          pending_follow_redirect_params_->modified_cors_exempt_headers,
 | 
						|
          pending_follow_redirect_params_->new_url);
 | 
						|
    }
 | 
						|
 | 
						|
    pending_follow_redirect_params_.reset();
 | 
						|
  }
 | 
						|
 | 
						|
  if (proxied_client_receiver_.is_bound())
 | 
						|
    proxied_client_receiver_.Resume();
 | 
						|
 | 
						|
  // Note: In Electron onSendHeaders is called for all protocols.
 | 
						|
  factory_->web_request_api()->OnSendHeaders(&info_.value(), request_,
 | 
						|
                                             request_.headers);
 | 
						|
 | 
						|
  if (!current_request_uses_header_client_)
 | 
						|
    ContinueToStartRequest(net::OK);
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::
 | 
						|
    ContinueToHandleOverrideHeaders(int error_code) {
 | 
						|
  if (error_code != net::OK) {
 | 
						|
    OnRequestError(network::URLLoaderCompletionStatus(error_code));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  DCHECK(on_headers_received_callback_);
 | 
						|
  absl::optional<std::string> headers;
 | 
						|
  if (override_headers_) {
 | 
						|
    headers = override_headers_->raw_headers();
 | 
						|
    if (current_request_uses_header_client_) {
 | 
						|
      // Make sure to update current_response_,  since when OnReceiveResponse
 | 
						|
      // is called we will not use its headers as it might be missing the
 | 
						|
      // Set-Cookie line (as that gets stripped over IPC).
 | 
						|
      current_response_->headers = override_headers_;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (for_cors_preflight_ && !redirect_url_.is_empty()) {
 | 
						|
    OnRequestError(network::URLLoaderCompletionStatus(net::ERR_FAILED));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  std::move(on_headers_received_callback_).Run(net::OK, headers, redirect_url_);
 | 
						|
  override_headers_ = nullptr;
 | 
						|
 | 
						|
  if (for_cors_preflight_) {
 | 
						|
    // If this is for CORS preflight, there is no associated client.
 | 
						|
    info_->AddResponseInfoFromResourceResponse(*current_response_);
 | 
						|
    // Do not finish proxied preflight requests that require proxy auth.
 | 
						|
    // The request is not finished yet, give control back to network service
 | 
						|
    // which will start authentication process.
 | 
						|
    if (info_->response_code == net::HTTP_PROXY_AUTHENTICATION_REQUIRED)
 | 
						|
      return;
 | 
						|
    // We notify the completion here, and delete |this|.
 | 
						|
    factory_->web_request_api()->OnResponseStarted(&info_.value(), request_);
 | 
						|
    factory_->web_request_api()->OnCompleted(&info_.value(), request_, net::OK);
 | 
						|
 | 
						|
    factory_->RemoveRequest(network_service_request_id_, request_id_);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (proxied_client_receiver_.is_bound())
 | 
						|
    proxied_client_receiver_.Resume();
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::ContinueToResponseStarted(
 | 
						|
    int error_code) {
 | 
						|
  DCHECK(!for_cors_preflight_);
 | 
						|
  if (error_code != net::OK) {
 | 
						|
    OnRequestError(network::URLLoaderCompletionStatus(error_code));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  DCHECK(!current_request_uses_header_client_ || !override_headers_);
 | 
						|
  if (override_headers_)
 | 
						|
    current_response_->headers = override_headers_;
 | 
						|
 | 
						|
  std::string redirect_location;
 | 
						|
  if (override_headers_ && override_headers_->IsRedirect(&redirect_location)) {
 | 
						|
    // The response headers may have been overridden by an |onHeadersReceived|
 | 
						|
    // handler and may have been changed to a redirect. We handle that here
 | 
						|
    // instead of acting like regular request completion.
 | 
						|
    //
 | 
						|
    // Note that we can't actually change how the Network Service handles the
 | 
						|
    // original request at this point, so our "redirect" is really just
 | 
						|
    // generating an artificial |onBeforeRedirect| event and starting a new
 | 
						|
    // request to the Network Service. Our client shouldn't know the difference.
 | 
						|
    GURL new_url(redirect_location);
 | 
						|
 | 
						|
    net::RedirectInfo redirect_info;
 | 
						|
    redirect_info.status_code = override_headers_->response_code();
 | 
						|
    redirect_info.new_method = request_.method;
 | 
						|
    redirect_info.new_url = new_url;
 | 
						|
    redirect_info.new_site_for_cookies = net::SiteForCookies::FromUrl(new_url);
 | 
						|
 | 
						|
    // These will get re-bound if a new request is initiated by
 | 
						|
    // |FollowRedirect()|.
 | 
						|
    proxied_client_receiver_.reset();
 | 
						|
    header_client_receiver_.reset();
 | 
						|
    target_loader_.reset();
 | 
						|
 | 
						|
    ContinueToBeforeRedirect(redirect_info, net::OK);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  info_->AddResponseInfoFromResourceResponse(*current_response_);
 | 
						|
 | 
						|
  proxied_client_receiver_.Resume();
 | 
						|
 | 
						|
  factory_->web_request_api()->OnResponseStarted(&info_.value(), request_);
 | 
						|
  target_client_->OnReceiveResponse(current_response_.Clone(),
 | 
						|
                                    std::move(current_body_),
 | 
						|
                                    std::move(current_cached_metadata_));
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::ContinueToBeforeRedirect(
 | 
						|
    const net::RedirectInfo& redirect_info,
 | 
						|
    int error_code) {
 | 
						|
  if (error_code != net::OK) {
 | 
						|
    OnRequestError(network::URLLoaderCompletionStatus(error_code));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  info_->AddResponseInfoFromResourceResponse(*current_response_);
 | 
						|
 | 
						|
  if (proxied_client_receiver_.is_bound())
 | 
						|
    proxied_client_receiver_.Resume();
 | 
						|
 | 
						|
  factory_->web_request_api()->OnBeforeRedirect(&info_.value(), request_,
 | 
						|
                                                redirect_info.new_url);
 | 
						|
  target_client_->OnReceiveRedirect(redirect_info, current_response_.Clone());
 | 
						|
  request_.url = redirect_info.new_url;
 | 
						|
  request_.method = redirect_info.new_method;
 | 
						|
  request_.site_for_cookies = redirect_info.new_site_for_cookies;
 | 
						|
  request_.referrer = GURL(redirect_info.new_referrer);
 | 
						|
  request_.referrer_policy = redirect_info.new_referrer_policy;
 | 
						|
 | 
						|
  // The request method can be changed to "GET". In this case we need to
 | 
						|
  // reset the request body manually.
 | 
						|
  if (request_.method == net::HttpRequestHeaders::kGetMethod)
 | 
						|
    request_.request_body = nullptr;
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::
 | 
						|
    HandleResponseOrRedirectHeaders(net::CompletionOnceCallback continuation) {
 | 
						|
  override_headers_ = nullptr;
 | 
						|
  redirect_url_ = GURL();
 | 
						|
 | 
						|
  info_->AddResponseInfoFromResourceResponse(*current_response_);
 | 
						|
 | 
						|
  auto callback_pair = base::SplitOnceCallback(std::move(continuation));
 | 
						|
  DCHECK(info_.has_value());
 | 
						|
  int result = factory_->web_request_api()->OnHeadersReceived(
 | 
						|
      &info_.value(), request_, std::move(callback_pair.first),
 | 
						|
      current_response_->headers.get(), &override_headers_, &redirect_url_);
 | 
						|
  if (result == net::ERR_BLOCKED_BY_CLIENT) {
 | 
						|
    OnRequestError(network::URLLoaderCompletionStatus(result));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (result == net::ERR_IO_PENDING) {
 | 
						|
    // One or more listeners is blocking, so the request must be paused until
 | 
						|
    // they respond. |continuation| above will be invoked asynchronously to
 | 
						|
    // continue or cancel the request.
 | 
						|
    //
 | 
						|
    // We pause the receiver here to prevent further client message processing.
 | 
						|
    if (proxied_client_receiver_.is_bound())
 | 
						|
      proxied_client_receiver_.Pause();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  DCHECK_EQ(net::OK, result);
 | 
						|
 | 
						|
  std::move(callback_pair.second).Run(net::OK);
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::InProgressRequest::OnRequestError(
 | 
						|
    const network::URLLoaderCompletionStatus& status) {
 | 
						|
  if (target_client_)
 | 
						|
    target_client_->OnComplete(status);
 | 
						|
  factory_->web_request_api()->OnErrorOccurred(&info_.value(), request_,
 | 
						|
                                               status.error_code);
 | 
						|
 | 
						|
  // Deletes |this|.
 | 
						|
  factory_->RemoveRequest(network_service_request_id_, request_id_);
 | 
						|
}
 | 
						|
 | 
						|
ProxyingURLLoaderFactory::ProxyingURLLoaderFactory(
 | 
						|
    WebRequestAPI* web_request_api,
 | 
						|
    const HandlersMap& intercepted_handlers,
 | 
						|
    int render_process_id,
 | 
						|
    int frame_routing_id,
 | 
						|
    uint64_t* request_id_generator,
 | 
						|
    std::unique_ptr<extensions::ExtensionNavigationUIData> navigation_ui_data,
 | 
						|
    absl::optional<int64_t> navigation_id,
 | 
						|
    mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_request,
 | 
						|
    mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory_remote,
 | 
						|
    mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient>
 | 
						|
        header_client_receiver,
 | 
						|
    content::ContentBrowserClient::URLLoaderFactoryType loader_factory_type)
 | 
						|
    : web_request_api_(web_request_api),
 | 
						|
      intercepted_handlers_(intercepted_handlers),
 | 
						|
      render_process_id_(render_process_id),
 | 
						|
      frame_routing_id_(frame_routing_id),
 | 
						|
      request_id_generator_(request_id_generator),
 | 
						|
      navigation_ui_data_(std::move(navigation_ui_data)),
 | 
						|
      navigation_id_(std::move(navigation_id)),
 | 
						|
      loader_factory_type_(loader_factory_type) {
 | 
						|
  target_factory_.Bind(std::move(target_factory_remote));
 | 
						|
  target_factory_.set_disconnect_handler(base::BindOnce(
 | 
						|
      &ProxyingURLLoaderFactory::OnTargetFactoryError, base::Unretained(this)));
 | 
						|
  proxy_receivers_.Add(this, std::move(loader_request));
 | 
						|
  proxy_receivers_.set_disconnect_handler(base::BindRepeating(
 | 
						|
      &ProxyingURLLoaderFactory::OnProxyBindingError, base::Unretained(this)));
 | 
						|
 | 
						|
  if (header_client_receiver)
 | 
						|
    url_loader_header_client_receiver_.Bind(std::move(header_client_receiver));
 | 
						|
 | 
						|
  ignore_connections_limit_domains_ = base::SplitString(
 | 
						|
      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
 | 
						|
          switches::kIgnoreConnectionsLimit),
 | 
						|
      ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
 | 
						|
}
 | 
						|
 | 
						|
bool ProxyingURLLoaderFactory::ShouldIgnoreConnectionsLimit(
 | 
						|
    const network::ResourceRequest& request) {
 | 
						|
  for (const auto& domain : ignore_connections_limit_domains_) {
 | 
						|
    if (request.url.DomainIs(domain)) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::CreateLoaderAndStart(
 | 
						|
    mojo::PendingReceiver<network::mojom::URLLoader> loader,
 | 
						|
    int32_t request_id,
 | 
						|
    uint32_t options,
 | 
						|
    const network::ResourceRequest& original_request,
 | 
						|
    mojo::PendingRemote<network::mojom::URLLoaderClient> client,
 | 
						|
    const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
 | 
						|
  // Take a copy so we can mutate the request.
 | 
						|
  network::ResourceRequest request = original_request;
 | 
						|
 | 
						|
  if (ShouldIgnoreConnectionsLimit(request)) {
 | 
						|
    request.priority = net::RequestPriority::MAXIMUM_PRIORITY;
 | 
						|
    request.load_flags |= net::LOAD_IGNORE_LIMITS;
 | 
						|
  }
 | 
						|
 | 
						|
  // Check if user has intercepted this scheme.
 | 
						|
  bool bypass_custom_protocol_handlers =
 | 
						|
      options & kBypassCustomProtocolHandlers;
 | 
						|
  if (!bypass_custom_protocol_handlers) {
 | 
						|
    auto it = intercepted_handlers_->find(request.url.scheme());
 | 
						|
    if (it != intercepted_handlers_->end()) {
 | 
						|
      mojo::PendingRemote<network::mojom::URLLoaderFactory> loader_remote;
 | 
						|
      this->Clone(loader_remote.InitWithNewPipeAndPassReceiver());
 | 
						|
 | 
						|
      // <scheme, <type, handler>>
 | 
						|
      it->second.second.Run(
 | 
						|
          request,
 | 
						|
          base::BindOnce(&ElectronURLLoaderFactory::StartLoading,
 | 
						|
                         std::move(loader), request_id, options, request,
 | 
						|
                         std::move(client), traffic_annotation,
 | 
						|
                         std::move(loader_remote), it->second.first));
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // The loader of ServiceWorker forbids loading scripts from file:// URLs, and
 | 
						|
  // Chromium does not provide a way to override this behavior. So in order to
 | 
						|
  // make ServiceWorker work with file:// URLs, we have to intercept its
 | 
						|
  // requests here.
 | 
						|
  if (IsForServiceWorkerScript() && request.url.SchemeIsFile()) {
 | 
						|
    asar::CreateAsarURLLoader(
 | 
						|
        request, std::move(loader), std::move(client),
 | 
						|
        base::MakeRefCounted<net::HttpResponseHeaders>(""));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!web_request_api()->HasListener()) {
 | 
						|
    // Pass-through to the original factory.
 | 
						|
    target_factory_->CreateLoaderAndStart(std::move(loader), request_id,
 | 
						|
                                          options, request, std::move(client),
 | 
						|
                                          traffic_annotation);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // The request ID doesn't really matter. It just needs to be unique
 | 
						|
  // per-BrowserContext so extensions can make sense of it.  Note that
 | 
						|
  // |network_service_request_id_| by contrast is not necessarily unique, so we
 | 
						|
  // don't use it for identity here.
 | 
						|
  const uint64_t web_request_id = ++(*request_id_generator_);
 | 
						|
 | 
						|
  // Notes: Chromium assumes that requests with zero-ID would never use the
 | 
						|
  // "extraHeaders" code path, however in Electron requests started from
 | 
						|
  // the net module would have zero-ID because they do not have renderer process
 | 
						|
  // associated.
 | 
						|
  if (request_id)
 | 
						|
    network_request_id_to_web_request_id_.emplace(request_id, web_request_id);
 | 
						|
 | 
						|
  auto result = requests_.emplace(
 | 
						|
      web_request_id,
 | 
						|
      std::make_unique<InProgressRequest>(
 | 
						|
          this, web_request_id, frame_routing_id_, request_id, options, request,
 | 
						|
          traffic_annotation, std::move(loader), std::move(client)));
 | 
						|
  result.first->second->Restart();
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::Clone(
 | 
						|
    mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver) {
 | 
						|
  proxy_receivers_.Add(this, std::move(loader_receiver));
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::OnLoaderCreated(
 | 
						|
    int32_t request_id,
 | 
						|
    mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) {
 | 
						|
  auto it = network_request_id_to_web_request_id_.find(request_id);
 | 
						|
  if (it == network_request_id_to_web_request_id_.end())
 | 
						|
    return;
 | 
						|
 | 
						|
  auto request_it = requests_.find(it->second);
 | 
						|
  DCHECK(request_it != requests_.end());
 | 
						|
  request_it->second->OnLoaderCreated(std::move(receiver));
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::OnLoaderForCorsPreflightCreated(
 | 
						|
    const network::ResourceRequest& request,
 | 
						|
    mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) {
 | 
						|
  // Please note that the URLLoader is now starting, without waiting for
 | 
						|
  // additional signals from here. The URLLoader will be blocked before
 | 
						|
  // sending HTTP request headers (TrustedHeaderClient.OnBeforeSendHeaders),
 | 
						|
  // but the connection set up will be done before that. This is acceptable from
 | 
						|
  // Web Request API because the extension has already allowed to set up
 | 
						|
  // a connection to the same URL (i.e., the actual request), and distinguishing
 | 
						|
  // two connections for the actual request and the preflight request before
 | 
						|
  // sending request headers is very difficult.
 | 
						|
  const uint64_t web_request_id = ++(*request_id_generator_);
 | 
						|
 | 
						|
  auto result = requests_.insert(std::make_pair(
 | 
						|
      web_request_id, std::make_unique<InProgressRequest>(
 | 
						|
                          this, web_request_id, frame_routing_id_, request)));
 | 
						|
 | 
						|
  result.first->second->OnLoaderCreated(std::move(receiver));
 | 
						|
  result.first->second->Restart();
 | 
						|
}
 | 
						|
 | 
						|
ProxyingURLLoaderFactory::~ProxyingURLLoaderFactory() = default;
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::OnTargetFactoryError() {
 | 
						|
  target_factory_.reset();
 | 
						|
  proxy_receivers_.Clear();
 | 
						|
 | 
						|
  MaybeDeleteThis();
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::OnProxyBindingError() {
 | 
						|
  if (proxy_receivers_.empty())
 | 
						|
    target_factory_.reset();
 | 
						|
 | 
						|
  MaybeDeleteThis();
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::RemoveRequest(int32_t network_service_request_id,
 | 
						|
                                             uint64_t request_id) {
 | 
						|
  network_request_id_to_web_request_id_.erase(network_service_request_id);
 | 
						|
  requests_.erase(request_id);
 | 
						|
 | 
						|
  MaybeDeleteThis();
 | 
						|
}
 | 
						|
 | 
						|
void ProxyingURLLoaderFactory::MaybeDeleteThis() {
 | 
						|
  // Even if all URLLoaderFactory pipes connected to this object have been
 | 
						|
  // closed it has to stay alive until all active requests have completed.
 | 
						|
  if (target_factory_.is_bound() || !requests_.empty() ||
 | 
						|
      !proxy_receivers_.empty())
 | 
						|
    return;
 | 
						|
 | 
						|
  delete this;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace electron
 |