summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Smith <brian@dbsoft.org>2023-09-28 21:18:27 -0500
committerBrian Smith <brian@dbsoft.org>2023-09-28 21:18:27 -0500
commitb1d111ab6b7e5493226f6d9fe1ba38dc5c467379 (patch)
tree73a3aa461f3977bc889898d0b9bf89e4ae6c38cc
parent99c25d8e984905ef96990df66fea6bc12c310bbb (diff)
downloaduxp-b1d111ab6b7e5493226f6d9fe1ba38dc5c467379.tar.gz
Issue #1442 - Part 16 - Report stream errors during consumption.
https://bugzilla.mozilla.org/show_bug.cgi?id=1128959
-rw-r--r--dom/base/nsContentUtils.cpp71
-rw-r--r--dom/base/nsContentUtils.h4
-rw-r--r--dom/fetch/Fetch.h2
-rw-r--r--dom/fetch/FetchStreamReader.cpp51
-rw-r--r--dom/fetch/FetchStreamReader.h3
-rw-r--r--dom/workers/ServiceWorkerEvents.cpp85
6 files changed, 139 insertions, 77 deletions
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index 8dac3e70d4..4c00f358f2 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -39,6 +39,8 @@
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/CustomElementRegistry.h"
#include "mozilla/dom/DocumentFragment.h"
+#include "mozilla/dom/DOMException.h"
+#include "mozilla/dom/DOMExceptionBinding.h"
#include "mozilla/dom/DOMTypes.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/FileSystemSecurity.h"
@@ -10079,3 +10081,72 @@ void nsContentUtils::StructuredClone(JSContext* aCx,
nsTArray<RefPtr<MessagePort>> ports = holder.TakeTransferredPorts();
Unused << ports;
}
+
+/* static */ void
+nsContentUtils::ExtractErrorValues(JSContext* aCx,
+ JS::Handle<JS::Value> aValue,
+ nsACString& aSourceSpecOut,
+ uint32_t* aLineOut,
+ uint32_t* aColumnOut,
+ nsString& aMessageOut)
+{
+ MOZ_ASSERT(aLineOut);
+ MOZ_ASSERT(aColumnOut);
+
+ if (aValue.isObject()) {
+ JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
+ RefPtr<dom::DOMException> domException;
+
+ // Try to process as an Error object. Use the file/line/column values
+ // from the Error as they will be more specific to the root cause of
+ // the problem.
+ JSErrorReport* err = obj ? JS_ErrorFromException(aCx, obj) : nullptr;
+ if (err) {
+ // Use xpc to extract the error message only. We don't actually send
+ // this report anywhere.
+ RefPtr<xpc::ErrorReport> report = new xpc::ErrorReport();
+ report->Init(err,
+ "<unknown>", // toString result
+ false, // chrome
+ 0); // window ID
+
+ if (!report->mFileName.IsEmpty()) {
+ CopyUTF16toUTF8(report->mFileName, aSourceSpecOut);
+ *aLineOut = report->mLineNumber;
+ *aColumnOut = report->mColumn;
+ }
+ aMessageOut.Assign(report->mErrorMsg);
+ }
+
+ // Next, try to unwrap the rejection value as a DOMException.
+ else if(NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, obj, domException))) {
+
+ nsAutoString filename;
+ domException->GetFilename(aCx, filename);
+ if (!filename.IsEmpty()) {
+ CopyUTF16toUTF8(filename, aSourceSpecOut);
+ *aLineOut = domException->LineNumber(aCx);
+ *aColumnOut = domException->ColumnNumber();
+ }
+
+ domException->GetName(aMessageOut);
+ aMessageOut.AppendLiteral(": ");
+
+ nsAutoString message;
+ domException->GetMessageMoz(message);
+ aMessageOut.Append(message);
+ }
+ }
+
+ // If we could not unwrap a specific error type, then perform default safe
+ // string conversions on primitives. Objects will result in "[Object]"
+ // unfortunately.
+ if (aMessageOut.IsEmpty()) {
+ nsAutoJSString jsString;
+ if (jsString.init(aCx, aValue)) {
+ aMessageOut = jsString;
+ } else {
+ JS_ClearPendingException(aCx);
+ }
+ }
+}
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index 9bfb91add2..6e9f23054a 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1010,6 +1010,10 @@ public:
static bool PrefetchEnabled(nsIDocShell* aDocShell);
+ static void ExtractErrorValues(JSContext* aCx, JS::Handle<JS::Value> aValue,
+ nsACString& aSourceSpecOut, uint32_t *aLineOut,
+ uint32_t *aColumnOut, nsString& aMessageOut);
+
static nsresult CalculateBufferSizeForImage(const uint32_t& aStride,
const mozilla::gfx::IntSize& aImageSize,
const mozilla::gfx::SurfaceFormat& aFormat,
diff --git a/dom/fetch/Fetch.h b/dom/fetch/Fetch.h
index cd7dc598fb..839d003833 100644
--- a/dom/fetch/Fetch.h
+++ b/dom/fetch/Fetch.h
@@ -209,7 +209,7 @@ public:
// reporting way.
//
// Exceptions generated when reading from the ReadableStream are directly sent
- // to the Console (NOTE FOR THE REVIEWER: this is part of patch 16)
+ // to the Console.
void
SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
diff --git a/dom/fetch/FetchStreamReader.cpp b/dom/fetch/FetchStreamReader.cpp
index 5d9719a0c1..3a24844dd9 100644
--- a/dom/fetch/FetchStreamReader.cpp
+++ b/dom/fetch/FetchStreamReader.cpp
@@ -7,6 +7,9 @@
#include "FetchStreamReader.h"
#include "InternalResponse.h"
#include "mozilla/dom/PromiseBinding.h"
+#include "nsContentUtils.h"
+#include "nsIScriptError.h"
+#include "nsPIDOMWindow.h"
namespace mozilla {
namespace dom {
@@ -296,8 +299,56 @@ void
FetchStreamReader::RejectedCallback(JSContext* aCx,
JS::Handle<JS::Value> aValue)
{
+ ReportErrorToConsole(aCx, aValue);
CloseAndRelease(NS_ERROR_FAILURE);
}
+void
+FetchStreamReader::ReportErrorToConsole(JSContext* aCx,
+ JS::Handle<JS::Value> aValue)
+{
+ nsCString sourceSpec;
+ uint32_t line = 0;
+ uint32_t column = 0;
+ nsString valueString;
+
+ nsContentUtils::ExtractErrorValues(aCx, aValue, sourceSpec, &line,
+ &column, valueString);
+
+ nsTArray<nsString> params;
+ params.AppendElement(valueString);
+
+ RefPtr<ConsoleReportCollector> reporter = new ConsoleReportCollector();
+ reporter->AddConsoleReport(nsIScriptError::errorFlag,
+ NS_LITERAL_CSTRING("ReadableStreamReader.read"),
+ nsContentUtils::eDOM_PROPERTIES,
+ sourceSpec, line, column,
+ NS_LITERAL_CSTRING("ReadableStreamReadingFailed"),
+ params);
+
+ uint64_t innerWindowId = 0;
+
+ if (NS_IsMainThread()) {
+ nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal);
+ if (window) {
+ innerWindowId = window->WindowID();
+ }
+ reporter->FlushReportsByWindowId(innerWindowId);
+ return;
+ }
+
+ WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+ if (workerPrivate) {
+ innerWindowId = workerPrivate->WindowID();
+ }
+
+ RefPtr<Runnable> r = NS_NewRunnableFunction(
+ [reporter, innerWindowId] () {
+ reporter->FlushReportsByWindowId(innerWindowId);
+ });
+
+ workerPrivate->DispatchToMainThread(r.forget());
+}
+
} // dom namespace
} // mozilla namespace
diff --git a/dom/fetch/FetchStreamReader.h b/dom/fetch/FetchStreamReader.h
index 8984a2ea73..d71021fdc8 100644
--- a/dom/fetch/FetchStreamReader.h
+++ b/dom/fetch/FetchStreamReader.h
@@ -55,6 +55,9 @@ private:
nsresult
WriteBuffer();
+ void
+ ReportErrorToConsole(JSContext* aCx, JS::Handle<JS::Value> aValue);
+
nsCOMPtr<nsIGlobalObject> mGlobal;
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
diff --git a/dom/workers/ServiceWorkerEvents.cpp b/dom/workers/ServiceWorkerEvents.cpp
index 7c9add4060..569422da25 100644
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -6,6 +6,7 @@
#include "ServiceWorkerEvents.h"
#include "nsAutoPtr.h"
+#include "nsContentUtils.h"
#include "nsIConsoleReportCollector.h"
#include "nsIHttpChannelInternal.h"
#include "nsINetworkInterceptController.h"
@@ -30,8 +31,6 @@
#include "mozilla/Move.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/BodyUtil.h"
-#include "mozilla/dom/DOMException.h"
-#include "mozilla/dom/DOMExceptionBinding.h"
#include "mozilla/dom/EncodingUtils.h"
#include "mozilla/dom/FetchEventBinding.h"
#include "mozilla/dom/MessagePort.h"
@@ -404,76 +403,6 @@ void RespondWithCopyComplete(void* aClosure, nsresult aStatus)
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(event));
}
-namespace {
-
-void
-ExtractErrorValues(JSContext* aCx, JS::Handle<JS::Value> aValue,
- nsACString& aSourceSpecOut, uint32_t *aLineOut,
- uint32_t *aColumnOut, nsString& aMessageOut)
-{
- MOZ_ASSERT(aLineOut);
- MOZ_ASSERT(aColumnOut);
-
- if (aValue.isObject()) {
- JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
- RefPtr<DOMException> domException;
-
- // Try to process as an Error object. Use the file/line/column values
- // from the Error as they will be more specific to the root cause of
- // the problem.
- JSErrorReport* err = obj ? JS_ErrorFromException(aCx, obj) : nullptr;
- if (err) {
- // Use xpc to extract the error message only. We don't actually send
- // this report anywhere.
- RefPtr<xpc::ErrorReport> report = new xpc::ErrorReport();
- report->Init(err,
- "<unknown>", // toString result
- false, // chrome
- 0); // window ID
-
- if (!report->mFileName.IsEmpty()) {
- CopyUTF16toUTF8(report->mFileName, aSourceSpecOut);
- *aLineOut = report->mLineNumber;
- *aColumnOut = report->mColumn;
- }
- aMessageOut.Assign(report->mErrorMsg);
- }
-
- // Next, try to unwrap the rejection value as a DOMException.
- else if(NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, obj, domException))) {
-
- nsAutoString filename;
- domException->GetFilename(aCx, filename);
- if (!filename.IsEmpty()) {
- CopyUTF16toUTF8(filename, aSourceSpecOut);
- *aLineOut = domException->LineNumber(aCx);
- *aColumnOut = domException->ColumnNumber();
- }
-
- domException->GetName(aMessageOut);
- aMessageOut.AppendLiteral(": ");
-
- nsAutoString message;
- domException->GetMessageMoz(message);
- aMessageOut.Append(message);
- }
- }
-
- // If we could not unwrap a specific error type, then perform default safe
- // string conversions on primitives. Objects will result in "[Object]"
- // unfortunately.
- if (aMessageOut.IsEmpty()) {
- nsAutoJSString jsString;
- if (jsString.init(aCx, aValue)) {
- aMessageOut = jsString;
- } else {
- JS_ClearPendingException(aCx);
- }
- }
-}
-
-} // anonymous namespace
-
class MOZ_STACK_CLASS AutoCancel
{
RefPtr<RespondWithHandler> mOwner;
@@ -595,7 +524,8 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
uint32_t line = 0;
uint32_t column = 0;
nsString valueString;
- ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column, valueString);
+ nsContentUtils::ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column,
+ valueString);
autoCancel.SetCancelMessageAndLocation(sourceSpec, line, column,
NS_LITERAL_CSTRING("InterceptedNonResponseWithURL"),
@@ -610,7 +540,8 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
uint32_t line = 0;
uint32_t column = 0;
nsString valueString;
- ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column, valueString);
+ nsContentUtils::ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column,
+ valueString);
autoCancel.SetCancelMessageAndLocation(sourceSpec, line, column,
NS_LITERAL_CSTRING("InterceptedNonResponseWithURL"),
@@ -758,7 +689,8 @@ RespondWithHandler::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
uint32_t column = mRespondWithColumnNumber;
nsString valueString;
- ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column, valueString);
+ nsContentUtils::ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column,
+ valueString);
::AsyncLog(mInterceptedChannel, sourceSpec, line, column,
NS_LITERAL_CSTRING("InterceptionRejectedResponseWithURL"),
@@ -896,7 +828,8 @@ public:
nsCString spec;
uint32_t line = 0;
uint32_t column = 0;
- ExtractErrorValues(aCx, aValue, spec, &line, &column, mRejectValue);
+ nsContentUtils::ExtractErrorValues(aCx, aValue, spec, &line, &column,
+ mRejectValue);
// only use the extracted location if we found one
if (!spec.IsEmpty()) {