#include "InspectorHTTPServerAgent.h" #include #include #include #include #include #include #include #include "ZigGlobalObject.h" namespace Inspector { WTF_MAKE_TZONE_ALLOCATED_IMPL(InspectorHTTPServerAgent); // Zig bindings implementation extern "C" { void Bun__HTTPServerAgent__setEnabled(Inspector::InspectorHTTPServerAgent* agent); // void Bun__HTTPServerAgentStartListening(Inspector::InspectorHTTPServerAgent* agent, int serverId); // void Bun__HTTPServerAgentStopListening(Inspector::InspectorHTTPServerAgent* agent, int serverId); // void Bun__HTTPServerAgentGetRequestBody(Inspector::InspectorHTTPServerAgent* agent, int requestId, int serverId); // void Bun__HTTPServerAgentGetResponseBody(Inspector::InspectorHTTPServerAgent* agent, int requestId, int serverId); } InspectorHTTPServerAgent::InspectorHTTPServerAgent(JSC::JSGlobalObject& globalObject) : InspectorAgentBase("HTTPServer"_s) , m_backendDispatcher(HTTPServerBackendDispatcher::create(globalObject.inspectorController().backendDispatcher(), this)) , m_frontendDispatcher(makeUnique(const_cast(globalObject.inspectorController().frontendRouter()))) , m_enabled(false) { } InspectorHTTPServerAgent::~InspectorHTTPServerAgent() { if (m_enabled) { Bun__HTTPServerAgent__setEnabled(nullptr); } } void InspectorHTTPServerAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*) { } void InspectorHTTPServerAgent::willDestroyFrontendAndBackend(DisconnectReason) { m_frontendDispatcher = nullptr; m_enabled = false; } Protocol::ErrorStringOr InspectorHTTPServerAgent::enable() { if (m_enabled) return {}; m_enabled = true; Bun__HTTPServerAgent__setEnabled(this); return {}; } Protocol::ErrorStringOr InspectorHTTPServerAgent::disable() { if (!m_enabled) return {}; m_enabled = false; Bun__HTTPServerAgent__setEnabled(nullptr); return {}; } Protocol::ErrorStringOr InspectorHTTPServerAgent::startListening(int serverId) { if (!m_enabled) return {}; return {}; } Protocol::ErrorStringOr InspectorHTTPServerAgent::stopListening(int serverId) { if (!m_enabled) return {}; // TODO: // Bun__HTTPServerAgentStopListening(this, serverId); return {}; } Protocol::ErrorStringOr InspectorHTTPServerAgent::getRequestBody(int requestId, int serverId) { if (!m_enabled) return {}; // TODO: // Bun__HTTPServerAgentGetRequestBody(this, requestId, serverId); return {}; } Protocol::ErrorStringOr InspectorHTTPServerAgent::getResponseBody(int requestId, int serverId) { if (!m_enabled) return {}; // TODO: // Bun__HTTPServerAgentGetResponseBody(this, requestId, serverId); return {}; } // Event dispatchers void InspectorHTTPServerAgent::serverStarted(int serverId, const String& url, double startTime, AnyServerPtr serverInstance) { this->m_serverIdToServerInstance.set(serverId, serverInstance); if (!m_enabled || !m_frontendDispatcher) { return; } this->m_frontendDispatcher->listen(serverId, url, startTime); } void InspectorHTTPServerAgent::serverStopped(int serverId, double timestamp) { this->m_serverIdToServerInstance.remove(serverId); if (!m_enabled || !m_frontendDispatcher) { return; } this->m_frontendDispatcher->close(serverId, timestamp); } void InspectorHTTPServerAgent::serverRoutesUpdated(int serverId, int hotReloadId, Ref>&& routes) { if (!m_enabled || !m_frontendDispatcher) { return; } this->m_frontendDispatcher->serverRoutesUpdated(serverId, hotReloadId, WTFMove(routes)); } void InspectorHTTPServerAgent::requestWillBeSent(Ref&& request) { if (!m_enabled || !m_frontendDispatcher) { return; } this->m_frontendDispatcher->requestWillBeSent(WTFMove(request)); } void InspectorHTTPServerAgent::responseReceived(Ref&& response) { if (!m_enabled || !m_frontendDispatcher) { return; } this->m_frontendDispatcher->responseReceived(WTFMove(response)); } void InspectorHTTPServerAgent::bodyChunkReceived(Ref&& chunk) { if (!m_enabled || !m_frontendDispatcher) { return; } this->m_frontendDispatcher->bodyChunkReceived(WTFMove(chunk)); } void InspectorHTTPServerAgent::requestFinished(int requestId, int serverId, double timestamp, std::optional&& opt_duration) { if (!m_enabled || !m_frontendDispatcher) { return; } this->m_frontendDispatcher->requestFinished(requestId, serverId, timestamp, WTFMove(opt_duration)); } void InspectorHTTPServerAgent::requestHandlerException(Ref&& error) { if (!m_enabled || !m_frontendDispatcher) { return; } this->m_frontendDispatcher->requestHandlerException(WTFMove(error)); } } // Zig API implementation extern "C" { // Functions for Zig to call to notify about HTTP server events void Bun__HTTPServerAgent__notifyServerStarted(Inspector::InspectorHTTPServerAgent* agent, int serverId, int hotReloadId, BunString* address, double startTime, void* serverInstance) { agent->serverStarted(serverId, address->toWTFString(), startTime, serverInstance); } void Bun__HTTPServerAgent__notifyServerStopped(Inspector::InspectorHTTPServerAgent* agent, int serverId, double timestamp) { agent->serverStopped(serverId, timestamp); } // This matches the Route extern struct in Zig struct Route { enum class Type : uint8_t { Default = 1, Api = 2, Html = 3, Static = 4 }; int route_id; BunString path; Type type; int script_line; BunString* param_names; size_t param_names_len; BunString file_path; BunString script_id; BunString script_url; }; void Bun__HTTPServerAgent__notifyServerRoutesUpdated(Inspector::InspectorHTTPServerAgent* agent, int serverId, int hotReloadId, Route* routes_ptr, size_t routes_len) { auto routes = JSON::ArrayOf::create(); for (size_t i = 0; i < routes_len; i++) { auto& route = routes_ptr[i]; auto route_type = Inspector::Protocol::HTTPServer::RouteType::Default; switch (route.type) { case Route::Type::Api: route_type = Inspector::Protocol::HTTPServer::RouteType::API; break; case Route::Type::Html: route_type = Inspector::Protocol::HTTPServer::RouteType::HTML; break; case Route::Type::Static: route_type = Inspector::Protocol::HTTPServer::RouteType::Static; break; default: route_type = Inspector::Protocol::HTTPServer::RouteType::Default; break; } auto object = Inspector::Protocol::HTTPServer::Route::create() .setRouteId(route.route_id) .setPath(route.path.toWTFString()) .setType(route_type) .setScriptLine(route.script_line) .release(); if (!route.file_path.isEmpty()) { object->setFilePath(route.file_path.toWTFString()); } if (!route.script_url.isEmpty()) { object->setScriptUrl(route.script_url.toWTFString()); } routes->addItem(WTFMove(object)); } agent->serverRoutesUpdated(serverId, hotReloadId, WTFMove(routes)); } }