зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1173934 Show a message if a docshell fails to load due to SW intercept failure. r=ehsan r=jdm
This commit is contained in:
Родитель
67e02ffc14
Коммит
2a31a01e4b
|
@ -5198,6 +5198,16 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
|
|||
// Broken Content Detected. e.g. Content-MD5 check failure.
|
||||
error.AssignLiteral("corruptedContentError");
|
||||
break;
|
||||
case NS_ERROR_INTERCEPTION_FAILED:
|
||||
case NS_ERROR_OPAQUE_INTERCEPTION_DISABLED:
|
||||
case NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE:
|
||||
case NS_ERROR_INTERCEPTED_ERROR_RESPONSE:
|
||||
case NS_ERROR_INTERCEPTED_USED_RESPONSE:
|
||||
// ServiceWorker intercepted request, but something went wrong.
|
||||
nsContentUtils::MaybeReportInterceptionErrorToConsole(GetDocument(),
|
||||
aError);
|
||||
error.AssignLiteral("corruptedContentError");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -7825,6 +7835,11 @@ nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
|
|||
aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
|
||||
aStatus == NS_ERROR_REMOTE_XUL ||
|
||||
aStatus == NS_ERROR_OFFLINE ||
|
||||
aStatus == NS_ERROR_INTERCEPTION_FAILED ||
|
||||
aStatus == NS_ERROR_OPAQUE_INTERCEPTION_DISABLED ||
|
||||
aStatus == NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE ||
|
||||
aStatus == NS_ERROR_INTERCEPTED_ERROR_RESPONSE ||
|
||||
aStatus == NS_ERROR_INTERCEPTED_USED_RESPONSE ||
|
||||
NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) {
|
||||
// Errors to be shown for any frame
|
||||
DisplayLoadError(aStatus, url, nullptr, aChannel);
|
||||
|
@ -14090,7 +14105,7 @@ nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel)
|
|||
{
|
||||
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
if (!swm) {
|
||||
aChannel->Cancel();
|
||||
aChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -3416,6 +3416,34 @@ nsContentUtils::ReportToConsole(uint32_t aErrorFlags,
|
|||
aLineNumber, aColumnNumber);
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
nsContentUtils::MaybeReportInterceptionErrorToConsole(nsIDocument* aDocument,
|
||||
nsresult aError)
|
||||
{
|
||||
const char* messageName = nullptr;
|
||||
if (aError == NS_ERROR_INTERCEPTION_FAILED) {
|
||||
messageName = "InterceptionFailed";
|
||||
} else if (aError == NS_ERROR_OPAQUE_INTERCEPTION_DISABLED) {
|
||||
messageName = "OpaqueInterceptionDisabled";
|
||||
} else if (aError == NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE) {
|
||||
messageName = "BadOpaqueInterceptionRequestMode";
|
||||
} else if (aError == NS_ERROR_INTERCEPTED_ERROR_RESPONSE) {
|
||||
messageName = "InterceptedErrorResponse";
|
||||
} else if (aError == NS_ERROR_INTERCEPTED_USED_RESPONSE) {
|
||||
messageName = "InterceptedUsedResponse";
|
||||
}
|
||||
|
||||
if (messageName) {
|
||||
return ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("Service Worker Interception"),
|
||||
aDocument,
|
||||
nsContentUtils::eDOM_PROPERTIES,
|
||||
messageName);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/* static */ nsresult
|
||||
nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
|
||||
|
|
|
@ -842,6 +842,9 @@ public:
|
|||
uint32_t aLineNumber = 0,
|
||||
uint32_t aColumnNumber = 0);
|
||||
|
||||
static nsresult
|
||||
MaybeReportInterceptionErrorToConsole(nsIDocument* aDocument, nsresult aError);
|
||||
|
||||
static void LogMessageToConsole(const char* aMsg, ...);
|
||||
|
||||
/**
|
||||
|
|
|
@ -166,3 +166,13 @@ HittingMaxWorkersPerDomain=A ServiceWorker could not be started immediately beca
|
|||
PannerNodeDopplerWarning=Use of setVelocity on the PannerNode and AudioListener, and speedOfSound and dopplerFactor on the AudioListener are deprecated and those members will be removed. For more help https://developer.mozilla.org/en-US/docs/Web/API/AudioListener#Deprecated_features
|
||||
# LOCALIZATION NOTE: Do not translate "Worker".
|
||||
EmptyWorkerSourceWarning=Attempting to create a Worker from an empty source. This is probably unintentional.
|
||||
# LOCALIZATION NOTE: Do not translate "ServiceWorker".
|
||||
InterceptionFailed=ServiceWorker network interception failed due to an unexpected error.
|
||||
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "FetchEvent.respondWith()", "opaque", or "Response".
|
||||
OpaqueInterceptionDisabled=A ServiceWorker passed an opaque Response to FetchEvent.respondWith() while opaque interception is disabled.
|
||||
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "FetchEvent.respondWith()", "FetchEvent.request.type", "same-origin", "cors", "no-cors", "opaque", "Response", or "RequestMode".
|
||||
BadOpaqueInterceptionRequestMode=A ServiceWorker passed an opaque Response to FetchEvent.respondWith() while the FetchEvent.request.type was either "same-origin" or "cors". Opaque Response objects are only valid when the RequestMode is "no-cors".
|
||||
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "Error", "Response", "FetchEvent.respondWith()", or "fetch()".
|
||||
InterceptedErrorResponse=A ServiceWorker passed an Error Response to FetchEvent.respondWith(). This typically means the ServiceWorker performed an invalid fetch() call.
|
||||
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "Response", "FetchEvent.respondWith()", or "Response.clone()".
|
||||
InterceptedUsedResponse=A ServiceWorker passed a used Response to FetchEvent.respondWith(). The body of a Response may only be read once. Use Response.clone() to access the body multiple times.
|
||||
|
|
|
@ -79,16 +79,19 @@ namespace {
|
|||
class CancelChannelRunnable final : public nsRunnable
|
||||
{
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
|
||||
const nsresult mStatus;
|
||||
public:
|
||||
explicit CancelChannelRunnable(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel)
|
||||
CancelChannelRunnable(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
nsresult aStatus)
|
||||
: mChannel(aChannel)
|
||||
, mStatus(aStatus)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsresult rv = mChannel->Cancel();
|
||||
nsresult rv = mChannel->Cancel(mStatus);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -160,7 +163,7 @@ public:
|
|||
|
||||
void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
|
||||
|
||||
void CancelRequest();
|
||||
void CancelRequest(nsresult aStatus);
|
||||
};
|
||||
|
||||
struct RespondWithClosure
|
||||
|
@ -188,7 +191,8 @@ void RespondWithCopyComplete(void* aClosure, nsresult aStatus)
|
|||
data->mInternalResponse,
|
||||
data->mWorkerChannelInfo);
|
||||
} else {
|
||||
event = new CancelChannelRunnable(data->mInterceptedChannel);
|
||||
event = new CancelChannelRunnable(data->mInterceptedChannel,
|
||||
NS_ERROR_INTERCEPTION_FAILED);
|
||||
}
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(event)));
|
||||
}
|
||||
|
@ -196,20 +200,28 @@ void RespondWithCopyComplete(void* aClosure, nsresult aStatus)
|
|||
class MOZ_STACK_CLASS AutoCancel
|
||||
{
|
||||
nsRefPtr<RespondWithHandler> mOwner;
|
||||
nsresult mStatus;
|
||||
|
||||
public:
|
||||
explicit AutoCancel(RespondWithHandler* aOwner)
|
||||
: mOwner(aOwner)
|
||||
, mStatus(NS_ERROR_INTERCEPTION_FAILED)
|
||||
{
|
||||
}
|
||||
|
||||
~AutoCancel()
|
||||
{
|
||||
if (mOwner) {
|
||||
mOwner->CancelRequest();
|
||||
mOwner->CancelRequest(mStatus);
|
||||
}
|
||||
}
|
||||
|
||||
void SetCancelStatus(nsresult aStatus)
|
||||
{
|
||||
MOZ_ASSERT(NS_FAILED(aStatus));
|
||||
mStatus = aStatus;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
mOwner = nullptr;
|
||||
|
@ -240,17 +252,24 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
|
|||
// security implications are not a complete disaster.
|
||||
if (response->Type() == ResponseType::Opaque &&
|
||||
!worker->OpaqueInterceptionEnabled()) {
|
||||
autoCancel.SetCancelStatus(NS_ERROR_OPAQUE_INTERCEPTION_DISABLED);
|
||||
return;
|
||||
}
|
||||
|
||||
// Section 4.2, step 2.2 "If either response's type is "opaque" and request's
|
||||
// mode is not "no-cors" or response's type is error, return a network error."
|
||||
if (((response->Type() == ResponseType::Opaque) && (mRequestMode != RequestMode::No_cors)) ||
|
||||
response->Type() == ResponseType::Error) {
|
||||
if (response->Type() == ResponseType::Opaque && mRequestMode != RequestMode::No_cors) {
|
||||
autoCancel.SetCancelStatus(NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (response->Type() == ResponseType::Error) {
|
||||
autoCancel.SetCancelStatus(NS_ERROR_INTERCEPTED_ERROR_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(response->BodyUsed())) {
|
||||
autoCancel.SetCancelStatus(NS_ERROR_INTERCEPTED_USED_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -296,13 +315,14 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
|
|||
void
|
||||
RespondWithHandler::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
CancelRequest();
|
||||
CancelRequest(NS_ERROR_INTERCEPTION_FAILED);
|
||||
}
|
||||
|
||||
void
|
||||
RespondWithHandler::CancelRequest()
|
||||
RespondWithHandler::CancelRequest(nsresult aStatus)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable = new CancelChannelRunnable(mInterceptedChannel);
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
new CancelChannelRunnable(mInterceptedChannel, aStatus);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
|
|
|
@ -89,13 +89,15 @@ InterceptedJARChannel::FinishSynthesizedResponse()
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptedJARChannel::Cancel()
|
||||
InterceptedJARChannel::Cancel(nsresult aStatus)
|
||||
{
|
||||
MOZ_ASSERT(NS_FAILED(aStatus));
|
||||
|
||||
if (!mChannel) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = mChannel->Cancel(NS_BINDING_ABORTED);
|
||||
nsresult rv = mChannel->Cancel(aStatus);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mResponseBody = nullptr;
|
||||
mChannel = nullptr;
|
||||
|
|
|
@ -26,7 +26,7 @@ class ChannelInfo;
|
|||
* which do not implement nsIChannel.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(f2c07a6b-366d-4ef4-85ab-a77f4bcb1646)]
|
||||
[scriptable, uuid(1062c96a-d73c-4ad5-beb7-6e803e414973)]
|
||||
interface nsIInterceptedChannel : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -59,7 +59,7 @@ interface nsIInterceptedChannel : nsISupports
|
|||
* @return NS_ERROR_FAILURE if the response has already been synthesized or
|
||||
* the original request has been instructed to continue.
|
||||
*/
|
||||
void cancel();
|
||||
void cancel(in nsresult status);
|
||||
|
||||
/**
|
||||
* The synthesized response body to be produced.
|
||||
|
|
|
@ -98,7 +98,7 @@ HttpChannelParent::ActorDestroy(ActorDestroyReason why)
|
|||
// If this is an intercepted channel, we need to make sure that any resources are
|
||||
// cleaned up to avoid leaks.
|
||||
if (mInterceptedChannel) {
|
||||
mInterceptedChannel->Cancel();
|
||||
mInterceptedChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED);
|
||||
mInterceptedChannel = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -230,15 +230,17 @@ InterceptedChannelChrome::FinishSynthesizedResponse()
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptedChannelChrome::Cancel()
|
||||
InterceptedChannelChrome::Cancel(nsresult aStatus)
|
||||
{
|
||||
MOZ_ASSERT(NS_FAILED(aStatus));
|
||||
|
||||
if (!mChannel) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// we need to use AsyncAbort instead of Cancel since there's no active pump
|
||||
// to cancel which will provide OnStart/OnStopRequest to the channel.
|
||||
nsresult rv = mChannel->AsyncAbort(NS_BINDING_ABORTED);
|
||||
nsresult rv = mChannel->AsyncAbort(aStatus);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -335,15 +337,17 @@ InterceptedChannelContent::FinishSynthesizedResponse()
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptedChannelContent::Cancel()
|
||||
InterceptedChannelContent::Cancel(nsresult aStatus)
|
||||
{
|
||||
MOZ_ASSERT(NS_FAILED(aStatus));
|
||||
|
||||
if (!mChannel) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// we need to use AsyncAbort instead of Cancel since there's no active pump
|
||||
// to cancel which will provide OnStart/OnStopRequest to the channel.
|
||||
nsresult rv = mChannel->AsyncAbort(NS_BINDING_ABORTED);
|
||||
nsresult rv = mChannel->AsyncAbort(aStatus);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mChannel = nullptr;
|
||||
mStreamListener = nullptr;
|
||||
|
|
|
@ -81,7 +81,7 @@ public:
|
|||
NS_IMETHOD GetChannel(nsIChannel** aChannel) override;
|
||||
NS_IMETHOD SynthesizeStatus(uint16_t aStatus, const nsACString& aReason) override;
|
||||
NS_IMETHOD SynthesizeHeader(const nsACString& aName, const nsACString& aValue) override;
|
||||
NS_IMETHOD Cancel() override;
|
||||
NS_IMETHOD Cancel(nsresult aStatus) override;
|
||||
NS_IMETHOD SetChannelInfo(mozilla::dom::ChannelInfo* aChannelInfo) override;
|
||||
|
||||
virtual void NotifyController() override;
|
||||
|
@ -108,7 +108,7 @@ public:
|
|||
NS_IMETHOD GetChannel(nsIChannel** aChannel) override;
|
||||
NS_IMETHOD SynthesizeStatus(uint16_t aStatus, const nsACString& aReason) override;
|
||||
NS_IMETHOD SynthesizeHeader(const nsACString& aName, const nsACString& aValue) override;
|
||||
NS_IMETHOD Cancel() override;
|
||||
NS_IMETHOD Cancel(nsresult aStatus) override;
|
||||
NS_IMETHOD SetChannelInfo(mozilla::dom::ChannelInfo* aChannelInfo) override;
|
||||
|
||||
virtual void NotifyController() override;
|
||||
|
|
|
@ -318,6 +318,19 @@
|
|||
ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)),
|
||||
ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)),
|
||||
ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)),
|
||||
|
||||
/* nsIInterceptedChannel */
|
||||
/* Generic error for non-specific failures during service worker interception */
|
||||
ERROR(NS_ERROR_INTERCEPTION_FAILED, FAILURE(100)),
|
||||
/* Service worker intercepted with an opaque response while
|
||||
dom.serviceWorkers.interception.opaque.enabled pref was set to false */
|
||||
ERROR(NS_ERROR_OPAQUE_INTERCEPTION_DISABLED, FAILURE(101)),
|
||||
/* Attempt to return opaque response for anything but "non-cors" request */
|
||||
ERROR(NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE, FAILURE(102)),
|
||||
/* Service worker intercepted with an error response */
|
||||
ERROR(NS_ERROR_INTERCEPTED_ERROR_RESPONSE, FAILURE(103)),
|
||||
/* Service worker intercepted with a response with bodyUsed set to true */
|
||||
ERROR(NS_ERROR_INTERCEPTED_USED_RESPONSE, FAILURE(104)),
|
||||
#undef MODULE
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче