Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions builtins/web/fetch/fetch_event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include <iostream>
#include <memory>
#include <optional>

using builtins::web::event::Event;
using builtins::web::event::EventTarget;
Expand All @@ -32,6 +33,8 @@ JSString *fetch_type_atom;
JS::PersistentRootedObject INSTANCE;
host_api::HttpOutgoingBody *STREAMING_BODY;

constexpr const std::string_view DEFAULT_NO_HANDLER_ERROR_MSG = "ERROR: no fetch-event handler triggered, was one registered?";

void inc_pending_promise_count(JSObject *self) {
MOZ_ASSERT(FetchEvent::is_instance(self));
auto count = JS::GetReservedSlot(self, FetchEvent::Slots::PendingPromiseCount).toInt32();
Expand Down Expand Up @@ -322,10 +325,16 @@ bool FetchEvent::respondWith(JSContext *cx, unsigned argc, JS::Value *vp) {
return true;
}

bool FetchEvent::respondWithError(JSContext *cx, JS::HandleObject self) {
bool FetchEvent::respondWithError(JSContext *cx, JS::HandleObject self, std::optional<std::string_view> body_text) {
MOZ_RELEASE_ASSERT(state(self) == State::unhandled || state(self) == State::waitToRespond);

auto headers = std::make_unique<host_api::HttpHeaders>();
auto header_set_res = headers->set("content-type", "text/plain");
if (auto *err = header_set_res.to_err()) {
HANDLE_ERROR(cx, *err);
return false;
}

auto *response = host_api::HttpOutgoingResponse::make(500, std::move(headers));

auto body_res = response->body();
Expand All @@ -334,6 +343,11 @@ bool FetchEvent::respondWithError(JSContext *cx, JS::HandleObject self) {
return false;
}

if (body_text) {
auto body = std::move(body_res.unwrap());
body->write(reinterpret_cast<const uint8_t*>(body_text->data()), body_text->length());
}

return send_response(response, self, FetchEvent::State::respondedWithError);
}

Expand Down Expand Up @@ -504,7 +518,9 @@ bool handle_incoming_request(host_api::HttpIncomingRequest *request) {
}

if (!FetchEvent::response_started(fetch_event)) {
FetchEvent::respondWithError(ENGINE->cx(), fetch_event);
// If at this point no fetch event handler has run, we can
// send a specific error indicating that there is likely no handler registered
FetchEvent::respondWithError(ENGINE->cx(), fetch_event, DEFAULT_NO_HANDLER_ERROR_MSG);
return true;
}

Expand Down
16 changes: 15 additions & 1 deletion builtins/web/fetch/fetch_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

#include "../event/event.h"

#include <optional>

namespace builtins::web::fetch::fetch_event {

class FetchEvent final : public BuiltinNoConstructor<FetchEvent> {
Expand Down Expand Up @@ -57,7 +59,19 @@ class FetchEvent final : public BuiltinNoConstructor<FetchEvent> {
static bool init_incoming_request(JSContext *cx, JS::HandleObject self,
host_api::HttpIncomingRequest *req);

static bool respondWithError(JSContext *cx, JS::HandleObject self);
/**
* @brief Responds with an error that contains some text for the HTTP response body
*
* @param cx The Javascript context
* @param self A handle to the `FetchEvent` object
* @param body_text optional text to send as the body
*
* @return True if the response was sent successfully
* @throws None directly, but surfaces errors to JS via `HANDLE_ERROR`
*/
static bool respondWithError(JSContext *cx,
JS::HandleObject self,
std::optional<std::string_view> body_text = std::nullopt);
static bool is_active(JSObject *self);

static State state(JSObject *self);
Expand Down