Commit b5b5c29f authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

Report CORS error status to DevTools

Bug: chromium:1140445
Change-Id: I369d9b05e1808090bcc1eba07a6801eb336037ff
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2497444Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Reviewed-by: default avatarMike West <mkwst@chromium.org>
Reviewed-by: default avatarPeter Marshall <petermarshall@chromium.org>
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#822095}
parent c5e6207e
...@@ -1814,6 +1814,99 @@ void NetworkHandler::RequestSent(const std::string& request_id, ...@@ -1814,6 +1814,99 @@ void NetworkHandler::RequestSent(const std::string& request_id,
Maybe<std::string>() /* frame_id */, request.has_user_gesture); Maybe<std::string>() /* frame_id */, request.has_user_gesture);
} }
namespace {
String BuildCorsError(network::mojom::CorsError cors_error) {
switch (cors_error) {
case network::mojom::CorsError::kDisallowedByMode:
return protocol::Network::CorsErrorEnum::DisallowedByMode;
case network::mojom::CorsError::kInvalidResponse:
return protocol::Network::CorsErrorEnum::InvalidResponse;
case network::mojom::CorsError::kWildcardOriginNotAllowed:
return protocol::Network::CorsErrorEnum::WildcardOriginNotAllowed;
case network::mojom::CorsError::kMissingAllowOriginHeader:
return protocol::Network::CorsErrorEnum::MissingAllowOriginHeader;
case network::mojom::CorsError::kMultipleAllowOriginValues:
return protocol::Network::CorsErrorEnum::MultipleAllowOriginValues;
case network::mojom::CorsError::kInvalidAllowOriginValue:
return protocol::Network::CorsErrorEnum::InvalidAllowOriginValue;
case network::mojom::CorsError::kAllowOriginMismatch:
return protocol::Network::CorsErrorEnum::AllowOriginMismatch;
case network::mojom::CorsError::kInvalidAllowCredentials:
return protocol::Network::CorsErrorEnum::InvalidAllowCredentials;
case network::mojom::CorsError::kCorsDisabledScheme:
return protocol::Network::CorsErrorEnum::CorsDisabledScheme;
case network::mojom::CorsError::kPreflightInvalidStatus:
return protocol::Network::CorsErrorEnum::PreflightInvalidStatus;
case network::mojom::CorsError::kPreflightDisallowedRedirect:
return protocol::Network::CorsErrorEnum::PreflightDisallowedRedirect;
case network::mojom::CorsError::kPreflightWildcardOriginNotAllowed:
return protocol::Network::CorsErrorEnum::
PreflightWildcardOriginNotAllowed;
case network::mojom::CorsError::kPreflightMissingAllowOriginHeader:
return protocol::Network::CorsErrorEnum::
PreflightMissingAllowOriginHeader;
case network::mojom::CorsError::kPreflightMultipleAllowOriginValues:
return protocol::Network::CorsErrorEnum::
PreflightMultipleAllowOriginValues;
case network::mojom::CorsError::kPreflightInvalidAllowOriginValue:
return protocol::Network::CorsErrorEnum::PreflightInvalidAllowOriginValue;
case network::mojom::CorsError::kPreflightAllowOriginMismatch:
return protocol::Network::CorsErrorEnum::PreflightAllowOriginMismatch;
case network::mojom::CorsError::kPreflightInvalidAllowCredentials:
return protocol::Network::CorsErrorEnum::PreflightInvalidAllowCredentials;
case network::mojom::CorsError::kPreflightMissingAllowExternal:
return protocol::Network::CorsErrorEnum::PreflightMissingAllowExternal;
case network::mojom::CorsError::kPreflightInvalidAllowExternal:
return protocol::Network::CorsErrorEnum::PreflightInvalidAllowExternal;
case network::mojom::CorsError::kInvalidAllowMethodsPreflightResponse:
return protocol::Network::CorsErrorEnum::
InvalidAllowMethodsPreflightResponse;
case network::mojom::CorsError::kInvalidAllowHeadersPreflightResponse:
return protocol::Network::CorsErrorEnum::
InvalidAllowHeadersPreflightResponse;
case network::mojom::CorsError::kMethodDisallowedByPreflightResponse:
return protocol::Network::CorsErrorEnum::
MethodDisallowedByPreflightResponse;
case network::mojom::CorsError::kHeaderDisallowedByPreflightResponse:
return protocol::Network::CorsErrorEnum::
HeaderDisallowedByPreflightResponse;
case network::mojom::CorsError::kRedirectContainsCredentials:
return protocol::Network::CorsErrorEnum::RedirectContainsCredentials;
}
}
std::unique_ptr<protocol::Network::CorsErrorStatus> BuildCorsErrorStatus(
network::CorsErrorStatus status) {
return protocol::Network::CorsErrorStatus::Create()
.SetCorsError(BuildCorsError(status.cors_error))
.SetFailedParameter(status.failed_parameter)
.Build();
}
} // namespace
void NetworkHandler::ResponseReceived( void NetworkHandler::ResponseReceived(
const std::string& request_id, const std::string& request_id,
const std::string& loader_id, const std::string& loader_id,
...@@ -1845,7 +1938,10 @@ void NetworkHandler::LoadingComplete( ...@@ -1845,7 +1938,10 @@ void NetworkHandler::LoadingComplete(
static_cast<double>(base::Time::kMicrosecondsPerSecond), static_cast<double>(base::Time::kMicrosecondsPerSecond),
resource_type, net::ErrorToString(status.error_code), resource_type, net::ErrorToString(status.error_code),
status.error_code == net::Error::ERR_ABORTED, status.error_code == net::Error::ERR_ABORTED,
GetBlockedReasonFor(status)); GetBlockedReasonFor(status),
status.cors_error_status
? BuildCorsErrorStatus(*status.cors_error_status)
: Maybe<protocol::Network::CorsErrorStatus>());
return; return;
} }
frontend_->LoadingFinished( frontend_->LoadingFinished(
......
...@@ -4485,6 +4485,39 @@ domain Network ...@@ -4485,6 +4485,39 @@ domain Network
corp-not-same-origin-after-defaulted-to-same-origin-by-coep corp-not-same-origin-after-defaulted-to-same-origin-by-coep
corp-not-same-site corp-not-same-site
# The reason why request was blocked.
type CorsError extends string
enum
DisallowedByMode
InvalidResponse
WildcardOriginNotAllowed
MissingAllowOriginHeader
MultipleAllowOriginValues
InvalidAllowOriginValue
AllowOriginMismatch
InvalidAllowCredentials
CorsDisabledScheme
PreflightInvalidStatus
PreflightDisallowedRedirect
PreflightWildcardOriginNotAllowed
PreflightMissingAllowOriginHeader
PreflightMultipleAllowOriginValues
PreflightInvalidAllowOriginValue
PreflightAllowOriginMismatch
PreflightInvalidAllowCredentials
PreflightMissingAllowExternal
PreflightInvalidAllowExternal
InvalidAllowMethodsPreflightResponse
InvalidAllowHeadersPreflightResponse
MethodDisallowedByPreflightResponse
HeaderDisallowedByPreflightResponse
RedirectContainsCredentials
type CorsErrorStatus extends object
properties
CorsError corsError
string failedParameter
# Source of serviceworker response. # Source of serviceworker response.
type ServiceWorkerResponseSource extends string type ServiceWorkerResponseSource extends string
enum enum
...@@ -5235,6 +5268,8 @@ domain Network ...@@ -5235,6 +5268,8 @@ domain Network
optional boolean canceled optional boolean canceled
# The reason why loading was blocked, if any. # The reason why loading was blocked, if any.
optional BlockedReason blockedReason optional BlockedReason blockedReason
# The reason why loading was blocked by CORS, if any.
optional CorsErrorStatus corsErrorStatus
# Fired when HTTP request has finished loading. # Fired when HTTP request has finished loading.
event loadingFinished event loadingFinished
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "net/base/ip_address.h" #include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h" #include "net/base/ip_endpoint.h"
#include "net/http/http_status_code.h" #include "net/http/http_status_code.h"
#include "services/network/public/cpp/cors/cors_error_status.h"
#include "services/network/public/mojom/referrer_policy.mojom-blink.h" #include "services/network/public/mojom/referrer_policy.mojom-blink.h"
#include "services/network/public/mojom/trust_tokens.mojom-blink.h" #include "services/network/public/mojom/trust_tokens.mojom-blink.h"
#include "services/network/public/mojom/websocket.mojom-blink.h" #include "services/network/public/mojom/websocket.mojom-blink.h"
...@@ -394,6 +395,97 @@ String BuildBlockedReason(ResourceRequestBlockedReason reason) { ...@@ -394,6 +395,97 @@ String BuildBlockedReason(ResourceRequestBlockedReason reason) {
return protocol::Network::BlockedReasonEnum::Other; return protocol::Network::BlockedReasonEnum::Other;
} }
String BuildCorsError(network::mojom::CorsError cors_error) {
switch (cors_error) {
case network::mojom::CorsError::kDisallowedByMode:
return protocol::Network::CorsErrorEnum::DisallowedByMode;
case network::mojom::CorsError::kInvalidResponse:
return protocol::Network::CorsErrorEnum::InvalidResponse;
case network::mojom::CorsError::kWildcardOriginNotAllowed:
return protocol::Network::CorsErrorEnum::WildcardOriginNotAllowed;
case network::mojom::CorsError::kMissingAllowOriginHeader:
return protocol::Network::CorsErrorEnum::MissingAllowOriginHeader;
case network::mojom::CorsError::kMultipleAllowOriginValues:
return protocol::Network::CorsErrorEnum::MultipleAllowOriginValues;
case network::mojom::CorsError::kInvalidAllowOriginValue:
return protocol::Network::CorsErrorEnum::InvalidAllowOriginValue;
case network::mojom::CorsError::kAllowOriginMismatch:
return protocol::Network::CorsErrorEnum::AllowOriginMismatch;
case network::mojom::CorsError::kInvalidAllowCredentials:
return protocol::Network::CorsErrorEnum::InvalidAllowCredentials;
case network::mojom::CorsError::kCorsDisabledScheme:
return protocol::Network::CorsErrorEnum::CorsDisabledScheme;
case network::mojom::CorsError::kPreflightInvalidStatus:
return protocol::Network::CorsErrorEnum::PreflightInvalidStatus;
case network::mojom::CorsError::kPreflightDisallowedRedirect:
return protocol::Network::CorsErrorEnum::PreflightDisallowedRedirect;
case network::mojom::CorsError::kPreflightWildcardOriginNotAllowed:
return protocol::Network::CorsErrorEnum::
PreflightWildcardOriginNotAllowed;
case network::mojom::CorsError::kPreflightMissingAllowOriginHeader:
return protocol::Network::CorsErrorEnum::
PreflightMissingAllowOriginHeader;
case network::mojom::CorsError::kPreflightMultipleAllowOriginValues:
return protocol::Network::CorsErrorEnum::
PreflightMultipleAllowOriginValues;
case network::mojom::CorsError::kPreflightInvalidAllowOriginValue:
return protocol::Network::CorsErrorEnum::PreflightInvalidAllowOriginValue;
case network::mojom::CorsError::kPreflightAllowOriginMismatch:
return protocol::Network::CorsErrorEnum::PreflightAllowOriginMismatch;
case network::mojom::CorsError::kPreflightInvalidAllowCredentials:
return protocol::Network::CorsErrorEnum::PreflightInvalidAllowCredentials;
case network::mojom::CorsError::kPreflightMissingAllowExternal:
return protocol::Network::CorsErrorEnum::PreflightMissingAllowExternal;
case network::mojom::CorsError::kPreflightInvalidAllowExternal:
return protocol::Network::CorsErrorEnum::PreflightInvalidAllowExternal;
case network::mojom::CorsError::kInvalidAllowMethodsPreflightResponse:
return protocol::Network::CorsErrorEnum::
InvalidAllowMethodsPreflightResponse;
case network::mojom::CorsError::kInvalidAllowHeadersPreflightResponse:
return protocol::Network::CorsErrorEnum::
InvalidAllowHeadersPreflightResponse;
case network::mojom::CorsError::kMethodDisallowedByPreflightResponse:
return protocol::Network::CorsErrorEnum::
MethodDisallowedByPreflightResponse;
case network::mojom::CorsError::kHeaderDisallowedByPreflightResponse:
return protocol::Network::CorsErrorEnum::
HeaderDisallowedByPreflightResponse;
case network::mojom::CorsError::kRedirectContainsCredentials:
return protocol::Network::CorsErrorEnum::RedirectContainsCredentials;
}
}
std::unique_ptr<protocol::Network::CorsErrorStatus> BuildCorsErrorStatus(
network::CorsErrorStatus status) {
return protocol::Network::CorsErrorStatus::create()
.setCorsError(BuildCorsError(status.cors_error))
.setFailedParameter(String::FromUTF8(status.failed_parameter))
.build();
}
String BuildServiceWorkerResponseSource(const ResourceResponse& response) { String BuildServiceWorkerResponseSource(const ResourceResponse& response) {
switch (response.GetServiceWorkerResponseSource()) { switch (response.GetServiceWorkerResponseSource()) {
case network::mojom::FetchResponseSource::kCacheStorage: case network::mojom::FetchResponseSource::kCacheStorage:
...@@ -1290,15 +1382,21 @@ void InspectorNetworkAgent::DidFailLoading( ...@@ -1290,15 +1382,21 @@ void InspectorNetworkAgent::DidFailLoading(
error.GetResourceRequestBlockedReason(); error.GetResourceRequestBlockedReason();
protocol::Maybe<String> blocked_reason; protocol::Maybe<String> blocked_reason;
if (resource_request_blocked_reason) { if (resource_request_blocked_reason) {
blocked_reason = blocked_reason = BuildBlockedReason(*resource_request_blocked_reason);
BuildBlockedReason(resource_request_blocked_reason.value()); }
auto cors_error_status = error.CorsErrorStatus();
protocol::Maybe<protocol::Network::CorsErrorStatus>
protocol_cors_error_status;
if (cors_error_status) {
protocol_cors_error_status = BuildCorsErrorStatus(*cors_error_status);
} }
is_handling_sync_xhr_ = false; is_handling_sync_xhr_ = false;
GetFrontend()->loadingFailed( GetFrontend()->loadingFailed(
request_id, base::TimeTicks::Now().since_origin().InSecondsF(), request_id, base::TimeTicks::Now().since_origin().InSecondsF(),
InspectorPageAgent::ResourceTypeJson( InspectorPageAgent::ResourceTypeJson(
resources_data_->GetResourceType(request_id)), resources_data_->GetResourceType(request_id)),
error.LocalizedDescription(), canceled, std::move(blocked_reason)); error.LocalizedDescription(), canceled, std::move(blocked_reason),
std::move(protocol_cors_error_status));
} }
void InspectorNetworkAgent::ScriptImported(uint64_t identifier, void InspectorNetworkAgent::ScriptImported(uint64_t identifier,
......
Test to make sure CORS errors are correctly reported.
{
canceled : false
corsErrorStatus : {
corsError : AllowOriginMismatch
failedParameter : http://127.0.0.1
}
errorText : net::ERR_FAILED
requestId : <string>
timestamp : <number>
type : Fetch
}
{
canceled : false
corsErrorStatus : {
corsError : MissingAllowOriginHeader
failedParameter :
}
errorText : net::ERR_FAILED
requestId : <string>
timestamp : <number>
type : Fetch
}
{
canceled : false
corsErrorStatus : {
corsError : PreflightInvalidAllowOriginValue
failedParameter : 1
}
errorText : net::ERR_FAILED
requestId : <string>
timestamp : <number>
type : Fetch
}
(async function(testRunner) {
const {page, session, dp} = await testRunner.startBlank(
`Test to make sure CORS errors are correctly reported.`);
// This url should be cross origin.
const url =
`https://127.0.0.1:8443/inspector-protocol/network/resources/cors-headers.php`;
await dp.Network.enable();
const failures = [];
let checkComplete;
let completion = new Promise(r => {
checkComplete = () => failures.length == 3 && r();
});
dp.Network.onLoadingFailed(event => {
failures.push(event.params);
checkComplete();
});
session.evaluate(`
fetch('${url}');
`);
session.evaluate(`
fetch('${url}?origin=${encodeURIComponent('http://127.0.0.1')}');
`);
session.evaluate(`
fetch("${
url}?methods=GET&origin=1", {method: 'POST', mode: 'cors', body: 'FOO', cache: 'no-cache', headers: { 'Content-Type': 'application/json'} });
`);
await completion;
failures.sort(
(a, b) => a.corsErrorStatus.corsError.localeCompare(
b.corsErrorStatus.corsError));
for (const failure of failures) {
testRunner.log(failure);
}
testRunner.completeTest();
})
<?php
$origin = !empty($_GET['origin']) ? $_GET['origin'] : '*';
if (isset($_GET['origin'])) {
header("Access-Control-Allow-Origin: $origin");
}
$methods = !empty($_GET['methods']) ? $_GET['methods'] : 'OPTIONS';
header("Access-Control-Allow-Methods: $methods");
header('Access-Control-Allow-Headers: content-type');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
echo 'replied to options with Access-Control-Allow headers';
http_response_code(400);
} else {
echo 'post data: ' . file_get_contents('php://input');
}
?>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment