in shell/browser/net/electron_url_loader_factory.cc [309:424]
void ElectronURLLoaderFactory::StartLoading(
mojo::PendingReceiver<network::mojom::URLLoader> loader,
int32_t request_id,
uint32_t options,
const network::ResourceRequest& request,
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory,
ProtocolType type,
gin::Arguments* args) {
// Send network error when there is no argument passed.
//
// Note that we should not throw JS error in the callback no matter what is
// passed, to keep compatibility with old code.
v8::Local<v8::Value> response;
if (!args->GetNext(&response)) {
OnComplete(std::move(client), request_id,
network::URLLoaderCompletionStatus(net::ERR_NOT_IMPLEMENTED));
return;
}
// Parse {error} object.
gin_helper::Dictionary dict = ToDict(args->isolate(), response);
if (!dict.IsEmpty()) {
int error_code;
if (dict.Get("error", &error_code)) {
OnComplete(std::move(client), request_id,
network::URLLoaderCompletionStatus(error_code));
return;
}
}
network::mojom::URLResponseHeadPtr head = ToResponseHead(dict);
// Handle redirection.
//
// Note that with NetworkService, sending the "Location" header no longer
// automatically redirects the request, we have explicitly create a new loader
// to implement redirection. This is also what Chromium does with WebRequest
// API in WebRequestProxyingURLLoaderFactory.
std::string location;
if (head->headers->IsRedirect(&location)) {
// If the request is a MAIN_FRAME request, the first-party URL gets
// updated on redirects.
const net::RedirectInfo::FirstPartyURLPolicy first_party_url_policy =
request.resource_type ==
static_cast<int>(blink::mojom::ResourceType::kMainFrame)
? net::RedirectInfo::FirstPartyURLPolicy::UPDATE_URL_ON_REDIRECT
: net::RedirectInfo::FirstPartyURLPolicy::NEVER_CHANGE_URL;
net::RedirectInfo redirect_info = net::RedirectInfo::ComputeRedirectInfo(
request.method, request.url, request.site_for_cookies,
first_party_url_policy, request.referrer_policy,
request.referrer.GetAsReferrer().spec(), head->headers->response_code(),
request.url.Resolve(location),
net::RedirectUtil::GetReferrerPolicyHeader(head->headers.get()), false);
DCHECK(client.is_valid());
mojo::Remote<network::mojom::URLLoaderClient> client_remote(
std::move(client));
client_remote->OnReceiveRedirect(redirect_info, std::move(head));
// Bind the URLLoader receiver and wait for a FollowRedirect request, or for
// the remote to disconnect, which will happen if the request is aborted.
// That may happen when the redirect is to a different scheme, which will
// cause the URL loader to be destroyed and a new one created using the
// factory for that scheme.
new RedirectedRequest(redirect_info, std::move(loader), request_id, options,
request, client_remote.Unbind(), traffic_annotation,
std::move(target_factory));
return;
}
// Some protocol accepts non-object responses.
if (dict.IsEmpty() && ResponseMustBeObject(type)) {
OnComplete(std::move(client), request_id,
network::URLLoaderCompletionStatus(net::ERR_NOT_IMPLEMENTED));
return;
}
switch (type) {
case ProtocolType::kBuffer:
StartLoadingBuffer(std::move(client), std::move(head), dict);
break;
case ProtocolType::kString:
StartLoadingString(std::move(client), std::move(head), dict,
args->isolate(), response);
break;
case ProtocolType::kFile:
StartLoadingFile(std::move(loader), request, std::move(client),
std::move(head), dict, args->isolate(), response);
break;
case ProtocolType::kHttp:
StartLoadingHttp(std::move(loader), request, std::move(client),
traffic_annotation, dict);
break;
case ProtocolType::kStream:
StartLoadingStream(std::move(loader), std::move(client), std::move(head),
dict);
break;
case ProtocolType::kFree:
ProtocolType type;
if (!gin::ConvertFromV8(args->isolate(), response, &type)) {
OnComplete(std::move(client), request_id,
network::URLLoaderCompletionStatus(net::ERR_FAILED));
return;
}
StartLoading(std::move(loader), request_id, options, request,
std::move(client), traffic_annotation,
std::move(target_factory), type, args);
break;
}
}