Files
bun.sh/src/bun.js/bindings/NodeHTTP.cpp
Ciro Spaciari 85271f9dd9 fix(node:http) allow CONNECT in node http/https servers (#22756)
### What does this PR do?
Fixes https://github.com/oven-sh/bun/issues/22755
Fixes https://github.com/oven-sh/bun/issues/19790
Fixes https://github.com/oven-sh/bun/issues/16372
### How did you verify your code works?

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-23 16:46:59 -07:00

1766 lines
72 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "root.h"
#include "JSDOMGlobalObjectInlines.h"
#include "ZigGlobalObject.h"
#include <JavaScriptCore/GlobalObjectMethodTable.h>
#include "helpers.h"
#include "BunClientData.h"
#include <JavaScriptCore/AggregateError.h>
#include <JavaScriptCore/InternalFieldTuple.h>
#include <JavaScriptCore/ObjectConstructor.h>
#include <JavaScriptCore/ObjectConstructor.h>
#include <JavaScriptCore/JSFunction.h>
#include "wtf/URL.h"
#include "JSFetchHeaders.h"
#include "JSDOMExceptionHandling.h"
#include <bun-uws/src/App.h>
#include "ZigGeneratedClasses.h"
#include "ScriptExecutionContext.h"
#include "AsyncContextFrame.h"
#include "ZigGeneratedClasses.h"
#include <JavaScriptCore/LazyPropertyInlines.h>
#include <JavaScriptCore/VMTrapsInlines.h>
#include "JSSocketAddressDTO.h"
extern "C" {
struct us_socket_stream_buffer_t {
char* list_ptr = nullptr;
size_t list_cap = 0;
size_t listLen = 0;
size_t total_bytes_written = 0;
size_t cursor = 0;
size_t bufferedSize() const
{
return listLen - cursor;
}
size_t totalBytesWritten() const
{
return total_bytes_written;
}
};
}
extern "C" uint64_t uws_res_get_remote_address_info(void* res, const char** dest, int* port, bool* is_ipv6);
extern "C" uint64_t uws_res_get_local_address_info(void* res, const char** dest, int* port, bool* is_ipv6);
extern "C" void Bun__NodeHTTPResponse_setClosed(void* zigResponse);
extern "C" void Bun__NodeHTTPResponse_onClose(void* zigResponse, JSC::EncodedJSValue jsValue);
extern "C" EncodedJSValue us_socket_buffered_js_write(void* socket, bool is_ssl, bool ended, us_socket_stream_buffer_t* streamBuffer, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue data, JSC::EncodedJSValue encoding);
extern "C" void us_socket_free_stream_buffer(us_socket_stream_buffer_t* streamBuffer);
namespace Bun {
using namespace JSC;
using namespace WebCore;
JSC_DEFINE_CUSTOM_SETTER(noOpSetter, (JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue value, PropertyName propertyName))
{
return false;
}
JSC_DECLARE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterOnClose);
JSC_DECLARE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterOnDrain);
JSC_DECLARE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterClosed);
JSC_DECLARE_CUSTOM_SETTER(jsNodeHttpServerSocketSetterOnClose);
JSC_DECLARE_CUSTOM_SETTER(jsNodeHttpServerSocketSetterOnDrain);
JSC_DECLARE_CUSTOM_SETTER(jsNodeHttpServerSocketSetterOnData);
JSC_DECLARE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterOnData);
JSC_DECLARE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterBytesWritten);
JSC_DECLARE_HOST_FUNCTION(jsFunctionNodeHTTPServerSocketClose);
JSC_DECLARE_HOST_FUNCTION(jsFunctionNodeHTTPServerSocketWrite);
JSC_DECLARE_HOST_FUNCTION(jsFunctionNodeHTTPServerSocketEnd);
JSC_DECLARE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterResponse);
JSC_DECLARE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterRemoteAddress);
JSC_DECLARE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterLocalAddress);
BUN_DECLARE_HOST_FUNCTION(Bun__drainMicrotasksFromJS);
JSC_DECLARE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterDuplex);
JSC_DECLARE_CUSTOM_SETTER(jsNodeHttpServerSocketSetterDuplex);
JSC_DECLARE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterIsSecureEstablished);
// Create a static hash table of values containing an onclose DOMAttributeGetterSetter and a close function
static const HashTableValue JSNodeHTTPServerSocketPrototypeTableValues[] = {
{ "onclose"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsNodeHttpServerSocketGetterOnClose, jsNodeHttpServerSocketSetterOnClose } },
{ "ondrain"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsNodeHttpServerSocketGetterOnDrain, jsNodeHttpServerSocketSetterOnDrain } },
{ "ondata"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsNodeHttpServerSocketGetterOnData, jsNodeHttpServerSocketSetterOnData } },
{ "bytesWritten"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsNodeHttpServerSocketGetterBytesWritten, noOpSetter } },
{ "closed"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::GetterSetterType, jsNodeHttpServerSocketGetterClosed, noOpSetter } },
{ "response"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::GetterSetterType, jsNodeHttpServerSocketGetterResponse, noOpSetter } },
{ "duplex"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsNodeHttpServerSocketGetterDuplex, jsNodeHttpServerSocketSetterDuplex } },
{ "remoteAddress"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::GetterSetterType, jsNodeHttpServerSocketGetterRemoteAddress, noOpSetter } },
{ "localAddress"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::GetterSetterType, jsNodeHttpServerSocketGetterLocalAddress, noOpSetter } },
{ "close"_s, static_cast<unsigned>(PropertyAttribute::Function | PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFunctionNodeHTTPServerSocketClose, 0 } },
{ "write"_s, static_cast<unsigned>(PropertyAttribute::Function | PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFunctionNodeHTTPServerSocketWrite, 2 } },
{ "end"_s, static_cast<unsigned>(PropertyAttribute::Function | PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFunctionNodeHTTPServerSocketEnd, 0 } },
{ "secureEstablished"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::GetterSetterType, jsNodeHttpServerSocketGetterIsSecureEstablished, noOpSetter } },
};
class JSNodeHTTPServerSocketPrototype final : public JSC::JSNonFinalObject {
public:
using Base = JSC::JSNonFinalObject;
static JSNodeHTTPServerSocketPrototype* create(VM& vm, Structure* structure)
{
JSNodeHTTPServerSocketPrototype* prototype = new (NotNull, allocateCell<JSNodeHTTPServerSocketPrototype>(vm)) JSNodeHTTPServerSocketPrototype(vm, structure);
prototype->finishCreation(vm);
return prototype;
}
DECLARE_INFO;
static constexpr bool needsDestruction = false;
static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable;
template<typename CellType, JSC::SubspaceAccess>
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
{
STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSNodeHTTPServerSocketPrototype, Base);
return &vm.plainObjectSpace();
}
private:
JSNodeHTTPServerSocketPrototype(VM& vm, Structure* structure)
: Base(vm, structure)
{
}
void finishCreation(VM& vm)
{
Base::finishCreation(vm);
ASSERT(inherits(info()));
reifyStaticProperties(vm, info(), JSNodeHTTPServerSocketPrototypeTableValues, *this);
this->structure()->setMayBePrototype(true);
}
};
class JSNodeHTTPServerSocket : public JSC::JSDestructibleObject {
public:
using Base = JSC::JSDestructibleObject;
us_socket_stream_buffer_t streamBuffer = {};
us_socket_t* socket = nullptr;
unsigned is_ssl : 1 = 0;
unsigned ended : 1 = 0;
JSC::Strong<JSNodeHTTPServerSocket> strongThis = {};
static JSNodeHTTPServerSocket* create(JSC::VM& vm, JSC::Structure* structure, us_socket_t* socket, bool is_ssl, WebCore::JSNodeHTTPResponse* response)
{
auto* object = new (JSC::allocateCell<JSNodeHTTPServerSocket>(vm)) JSNodeHTTPServerSocket(vm, structure, socket, is_ssl, response);
object->finishCreation(vm);
return object;
}
static JSNodeHTTPServerSocket* create(JSC::VM& vm, Zig::GlobalObject* globalObject, us_socket_t* socket, bool is_ssl, WebCore::JSNodeHTTPResponse* response)
{
auto* structure = globalObject->m_JSNodeHTTPServerSocketStructure.getInitializedOnMainThread(globalObject);
return create(vm, structure, socket, is_ssl, response);
}
static void destroy(JSC::JSCell* cell)
{
static_cast<JSNodeHTTPServerSocket*>(cell)->JSNodeHTTPServerSocket::~JSNodeHTTPServerSocket();
}
template<bool SSL>
static void clearSocketData(us_socket_t* socket)
{
auto* httpResponseData = (uWS::HttpResponseData<SSL>*)us_socket_ext(SSL, socket);
httpResponseData->socketData = nullptr;
}
void close()
{
if (socket) {
us_socket_close(is_ssl, socket, 0, nullptr);
}
}
bool isClosed() const
{
return !socket || us_socket_is_closed(is_ssl, socket);
}
// This means:
// - [x] TLS
// - [x] Handshake has completed
// - [x] Handshake marked the connection as authorized
bool isAuthorized() const
{
// is secure means that tls was established successfully
if (!is_ssl || !socket) return false;
auto* context = us_socket_context(is_ssl, socket);
if (!context) return false;
auto* data = (uWS::HttpContextData<true>*)us_socket_context_ext(is_ssl, context);
if (!data) return false;
return data->flags.isAuthorized;
}
~JSNodeHTTPServerSocket()
{
if (socket) {
if (is_ssl) {
clearSocketData<true>(socket);
} else {
clearSocketData<false>(socket);
}
}
us_socket_free_stream_buffer(&streamBuffer);
}
JSNodeHTTPServerSocket(JSC::VM& vm, JSC::Structure* structure, us_socket_t* socket, bool is_ssl, WebCore::JSNodeHTTPResponse* response)
: JSC::JSDestructibleObject(vm, structure)
, socket(socket)
, is_ssl(is_ssl)
{
currentResponseObject.setEarlyValue(vm, this, response);
}
mutable WriteBarrier<JSObject> functionToCallOnClose;
mutable WriteBarrier<JSObject> functionToCallOnDrain;
mutable WriteBarrier<JSObject> functionToCallOnData;
mutable WriteBarrier<WebCore::JSNodeHTTPResponse> currentResponseObject;
mutable WriteBarrier<JSObject> m_remoteAddress;
mutable WriteBarrier<JSObject> m_localAddress;
mutable WriteBarrier<JSObject> m_duplex;
DECLARE_INFO;
DECLARE_VISIT_CHILDREN;
template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
{
if constexpr (mode == JSC::SubspaceAccess::Concurrently)
return nullptr;
return WebCore::subspaceForImpl<JSNodeHTTPServerSocket, UseCustomHeapCellType::No>(
vm,
[](auto& spaces) { return spaces.m_clientSubspaceForJSNodeHTTPServerSocket.get(); },
[](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSNodeHTTPServerSocket = std::forward<decltype(space)>(space); },
[](auto& spaces) { return spaces.m_subspaceForJSNodeHTTPServerSocket.get(); },
[](auto& spaces, auto&& space) { spaces.m_subspaceForJSNodeHTTPServerSocket = std::forward<decltype(space)>(space); });
}
void detach()
{
this->m_duplex.clear();
this->currentResponseObject.clear();
this->strongThis.clear();
}
void onClose()
{
this->socket = nullptr;
if (auto* res = this->currentResponseObject.get(); res != nullptr && res->m_ctx != nullptr) {
Bun__NodeHTTPResponse_setClosed(res->m_ctx);
}
// This function can be called during GC!
Zig::GlobalObject* globalObject = static_cast<Zig::GlobalObject*>(this->globalObject());
if (!functionToCallOnClose) {
if (auto* res = this->currentResponseObject.get(); res != nullptr && res->m_ctx != nullptr) {
Bun__NodeHTTPResponse_onClose(res->m_ctx, JSValue::encode(res));
}
this->detach();
return;
}
WebCore::ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext();
if (scriptExecutionContext) {
scriptExecutionContext->postTask([self = this](ScriptExecutionContext& context) {
WTF::NakedPtr<JSC::Exception> exception;
auto* globalObject = defaultGlobalObject(context.globalObject());
auto* thisObject = self;
auto* callbackObject = thisObject->functionToCallOnClose.get();
if (!callbackObject) {
if (auto* res = thisObject->currentResponseObject.get(); res != nullptr && res->m_ctx != nullptr) {
Bun__NodeHTTPResponse_onClose(res->m_ctx, JSValue::encode(res));
}
thisObject->detach();
return;
}
auto callData = JSC::getCallData(callbackObject);
MarkedArgumentBuffer args;
EnsureStillAliveScope ensureStillAlive(self);
if (globalObject->scriptExecutionStatus(globalObject, thisObject) == ScriptExecutionStatus::Running) {
if (auto* res = thisObject->currentResponseObject.get(); res != nullptr && res->m_ctx != nullptr) {
Bun__NodeHTTPResponse_onClose(res->m_ctx, JSValue::encode(res));
}
profiledCall(globalObject, JSC::ProfilingReason::API, callbackObject, callData, thisObject, args, exception);
if (auto* ptr = exception.get()) {
exception.clear();
globalObject->reportUncaughtExceptionAtEventLoop(globalObject, ptr);
}
}
thisObject->detach();
});
}
}
void onDrain()
{
// This function can be called during GC!
Zig::GlobalObject* globalObject = static_cast<Zig::GlobalObject*>(this->globalObject());
if (!functionToCallOnDrain) {
return;
}
auto bufferedSize = this->streamBuffer.bufferedSize();
if (bufferedSize > 0) {
auto* globalObject = defaultGlobalObject(this->globalObject());
auto scope = DECLARE_CATCH_SCOPE(globalObject->vm());
us_socket_buffered_js_write(this->socket, this->is_ssl, this->ended, &this->streamBuffer, globalObject, JSValue::encode(JSC::jsUndefined()), JSValue::encode(JSC::jsUndefined()));
if (scope.exception()) {
globalObject->reportUncaughtExceptionAtEventLoop(globalObject, scope.exception());
return;
}
bufferedSize = this->streamBuffer.bufferedSize();
if (bufferedSize > 0) {
// need to drain more
return;
}
}
WebCore::ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext();
if (scriptExecutionContext) {
scriptExecutionContext->postTask([self = this](ScriptExecutionContext& context) {
WTF::NakedPtr<JSC::Exception> exception;
auto* globalObject = defaultGlobalObject(context.globalObject());
auto* thisObject = self;
auto* callbackObject = thisObject->functionToCallOnDrain.get();
if (!callbackObject) {
return;
}
auto callData = JSC::getCallData(callbackObject);
MarkedArgumentBuffer args;
EnsureStillAliveScope ensureStillAlive(self);
if (globalObject->scriptExecutionStatus(globalObject, thisObject) == ScriptExecutionStatus::Running) {
profiledCall(globalObject, JSC::ProfilingReason::API, callbackObject, callData, thisObject, args, exception);
if (auto* ptr = exception.get()) {
exception.clear();
globalObject->reportUncaughtExceptionAtEventLoop(globalObject, ptr);
}
}
});
}
}
void
onData(const char* data, int length, bool last)
{
// This function can be called during GC!
Zig::GlobalObject* globalObject = static_cast<Zig::GlobalObject*>(this->globalObject());
if (!functionToCallOnData) {
return;
}
WebCore::ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext();
if (scriptExecutionContext) {
auto scope = DECLARE_CATCH_SCOPE(globalObject->vm());
JSC::JSUint8Array* buffer = WebCore::createBuffer(globalObject, std::span<const uint8_t>(reinterpret_cast<const uint8_t*>(data), length));
auto chunk = JSC::JSValue(buffer);
if (scope.exception()) {
globalObject->reportUncaughtExceptionAtEventLoop(globalObject, scope.exception());
return;
}
gcProtect(chunk);
scriptExecutionContext->postTask([self = this, chunk = chunk, last = last](ScriptExecutionContext& context) {
WTF::NakedPtr<JSC::Exception> exception;
auto* globalObject = defaultGlobalObject(context.globalObject());
auto* thisObject = self;
auto* callbackObject = thisObject->functionToCallOnData.get();
EnsureStillAliveScope ensureChunkStillAlive(chunk);
gcUnprotect(chunk);
if (!callbackObject) {
return;
}
auto callData = JSC::getCallData(callbackObject);
MarkedArgumentBuffer args;
args.append(chunk);
args.append(JSC::jsBoolean(last));
EnsureStillAliveScope ensureStillAlive(self);
if (globalObject->scriptExecutionStatus(globalObject, thisObject) == ScriptExecutionStatus::Running) {
profiledCall(globalObject, JSC::ProfilingReason::API, callbackObject, callData, thisObject, args, exception);
if (auto* ptr = exception.get()) {
exception.clear();
globalObject->reportUncaughtExceptionAtEventLoop(globalObject, ptr);
}
}
});
}
}
static Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
{
auto* structure = JSC::Structure::create(vm, globalObject, globalObject->objectPrototype(), JSC::TypeInfo(JSC::ObjectType, StructureFlags), JSNodeHTTPServerSocketPrototype::info());
auto* prototype = JSNodeHTTPServerSocketPrototype::create(vm, structure);
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
}
void finishCreation(JSC::VM& vm)
{
Base::finishCreation(vm);
}
};
JSC_DEFINE_HOST_FUNCTION(jsFunctionNodeHTTPServerSocketClose, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
auto* thisObject = jsDynamicCast<JSNodeHTTPServerSocket*>(callFrame->thisValue());
if (!thisObject) [[unlikely]] {
return JSValue::encode(JSC::jsUndefined());
}
if (thisObject->isClosed()) {
return JSValue::encode(JSC::jsUndefined());
}
thisObject->close();
return JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsFunctionNodeHTTPServerSocketWrite, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
auto* thisObject = jsDynamicCast<JSNodeHTTPServerSocket*>(callFrame->thisValue());
if (!thisObject) [[unlikely]] {
return JSValue::encode(JSC::jsNumber(0));
}
if (thisObject->isClosed() || thisObject->ended) {
return JSValue::encode(JSC::jsNumber(0));
}
return us_socket_buffered_js_write(thisObject->socket, thisObject->is_ssl, thisObject->ended, &thisObject->streamBuffer, globalObject, JSValue::encode(callFrame->argument(0)), JSValue::encode(callFrame->argument(1)));
}
JSC_DEFINE_HOST_FUNCTION(jsFunctionNodeHTTPServerSocketEnd, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
auto* thisObject = jsDynamicCast<JSNodeHTTPServerSocket*>(callFrame->thisValue());
if (!thisObject) [[unlikely]] {
return JSValue::encode(JSC::jsUndefined());
}
if (thisObject->isClosed()) {
return JSValue::encode(JSC::jsUndefined());
}
thisObject->ended = true;
auto bufferedSize = thisObject->streamBuffer.bufferedSize();
if (bufferedSize == 0) {
return us_socket_buffered_js_write(thisObject->socket, thisObject->is_ssl, thisObject->ended, &thisObject->streamBuffer, globalObject, JSValue::encode(JSC::jsUndefined()), JSValue::encode(JSC::jsUndefined()));
}
return JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterIsSecureEstablished, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
auto* thisObject = jsCast<JSNodeHTTPServerSocket*>(JSC::JSValue::decode(thisValue));
return JSValue::encode(JSC::jsBoolean(thisObject->isAuthorized()));
}
JSC_DEFINE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterDuplex, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
auto* thisObject = jsCast<JSNodeHTTPServerSocket*>(JSC::JSValue::decode(thisValue));
if (thisObject->m_duplex) {
return JSValue::encode(thisObject->m_duplex.get());
}
return JSValue::encode(JSC::jsNull());
}
JSC_DEFINE_CUSTOM_SETTER(jsNodeHttpServerSocketSetterDuplex, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue encodedValue, JSC::PropertyName propertyName))
{
auto& vm = globalObject->vm();
auto* thisObject = jsCast<JSNodeHTTPServerSocket*>(JSC::JSValue::decode(thisValue));
JSValue value = JSC::JSValue::decode(encodedValue);
if (auto* object = value.getObject()) {
thisObject->m_duplex.set(vm, thisObject, object);
} else {
thisObject->m_duplex.clear();
}
return true;
}
JSC_DEFINE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterRemoteAddress, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
auto& vm = globalObject->vm();
auto* thisObject = jsCast<JSNodeHTTPServerSocket*>(JSC::JSValue::decode(thisValue));
if (thisObject->m_remoteAddress) {
return JSValue::encode(thisObject->m_remoteAddress.get());
}
us_socket_t* socket = thisObject->socket;
if (!socket) {
return JSValue::encode(JSC::jsNull());
}
const char* address = nullptr;
int port = 0;
bool is_ipv6 = false;
uws_res_get_remote_address_info(socket, &address, &port, &is_ipv6);
if (address == nullptr) {
return JSValue::encode(JSC::jsNull());
}
auto addressString = WTF::String::fromUTF8(address);
if (addressString.isEmpty()) {
return JSValue::encode(JSC::jsNull());
}
auto* object = JSSocketAddressDTO::create(defaultGlobalObject(globalObject), jsString(vm, addressString), port, is_ipv6);
thisObject->m_remoteAddress.set(vm, thisObject, object);
return JSValue::encode(object);
}
JSC_DEFINE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterLocalAddress, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
auto& vm = globalObject->vm();
auto* thisObject = jsCast<JSNodeHTTPServerSocket*>(JSC::JSValue::decode(thisValue));
if (thisObject->m_localAddress) {
return JSValue::encode(thisObject->m_localAddress.get());
}
us_socket_t* socket = thisObject->socket;
if (!socket) {
return JSValue::encode(JSC::jsNull());
}
const char* address = nullptr;
int port = 0;
bool is_ipv6 = false;
uws_res_get_local_address_info(socket, &address, &port, &is_ipv6);
if (address == nullptr) {
return JSValue::encode(JSC::jsNull());
}
auto addressString = WTF::String::fromUTF8(address);
if (addressString.isEmpty()) {
return JSValue::encode(JSC::jsNull());
}
auto* object = JSSocketAddressDTO::create(defaultGlobalObject(globalObject), jsString(vm, addressString), port, is_ipv6);
thisObject->m_localAddress.set(vm, thisObject, object);
return JSValue::encode(object);
}
JSC_DEFINE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterOnClose, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
auto* thisObject = jsCast<JSNodeHTTPServerSocket*>(JSC::JSValue::decode(thisValue));
if (thisObject->functionToCallOnClose) {
return JSValue::encode(thisObject->functionToCallOnClose.get());
}
return JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterOnDrain, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
auto* thisObject = jsCast<JSNodeHTTPServerSocket*>(JSC::JSValue::decode(thisValue));
if (thisObject->functionToCallOnDrain) {
return JSValue::encode(thisObject->functionToCallOnDrain.get());
}
return JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_CUSTOM_SETTER(jsNodeHttpServerSocketSetterOnDrain, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue encodedValue, JSC::PropertyName propertyName))
{
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsCast<JSNodeHTTPServerSocket*>(JSC::JSValue::decode(thisValue));
JSValue value = JSC::JSValue::decode(encodedValue);
if (value.isUndefined() || value.isNull()) {
thisObject->functionToCallOnDrain.clear();
return true;
}
if (!value.isCallable()) {
return false;
}
thisObject->functionToCallOnDrain.set(vm, thisObject, value.getObject());
return true;
}
JSC_DEFINE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterOnData, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
auto* thisObject = jsCast<JSNodeHTTPServerSocket*>(JSC::JSValue::decode(thisValue));
if (thisObject->functionToCallOnData) {
return JSValue::encode(thisObject->functionToCallOnData.get());
}
return JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_CUSTOM_SETTER(jsNodeHttpServerSocketSetterOnData, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue encodedValue, JSC::PropertyName propertyName))
{
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsCast<JSNodeHTTPServerSocket*>(JSC::JSValue::decode(thisValue));
JSValue value = JSC::JSValue::decode(encodedValue);
if (value.isUndefined() || value.isNull()) {
thisObject->functionToCallOnData.clear();
return true;
}
if (!value.isCallable()) {
return false;
}
thisObject->functionToCallOnData.set(vm, thisObject, value.getObject());
return true;
}
JSC_DEFINE_CUSTOM_SETTER(jsNodeHttpServerSocketSetterOnClose, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue encodedValue, JSC::PropertyName propertyName))
{
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsCast<JSNodeHTTPServerSocket*>(JSC::JSValue::decode(thisValue));
JSValue value = JSC::JSValue::decode(encodedValue);
if (value.isUndefined() || value.isNull()) {
thisObject->functionToCallOnClose.clear();
return true;
}
if (!value.isCallable()) {
return false;
}
thisObject->functionToCallOnClose.set(vm, thisObject, value.getObject());
return true;
}
JSC_DEFINE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterClosed, (JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, PropertyName propertyName))
{
auto* thisObject = jsCast<JSNodeHTTPServerSocket*>(JSC::JSValue::decode(thisValue));
return JSValue::encode(JSC::jsBoolean(thisObject->isClosed()));
}
JSC_DEFINE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterBytesWritten, (JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, PropertyName propertyName))
{
auto* thisObject = jsCast<JSNodeHTTPServerSocket*>(JSC::JSValue::decode(thisValue));
return JSValue::encode(JSC::jsNumber(thisObject->streamBuffer.totalBytesWritten()));
}
JSC_DEFINE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterResponse, (JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, PropertyName propertyName))
{
auto* thisObject = jsCast<JSNodeHTTPServerSocket*>(JSC::JSValue::decode(thisValue));
if (!thisObject->currentResponseObject) {
return JSValue::encode(JSC::jsNull());
}
return JSValue::encode(thisObject->currentResponseObject.get());
}
template<typename Visitor>
void JSNodeHTTPServerSocket::visitChildrenImpl(JSCell* cell, Visitor& visitor)
{
JSNodeHTTPServerSocket* fn = jsCast<JSNodeHTTPServerSocket*>(cell);
ASSERT_GC_OBJECT_INHERITS(fn, info());
Base::visitChildren(fn, visitor);
visitor.append(fn->currentResponseObject);
visitor.append(fn->functionToCallOnClose);
visitor.append(fn->functionToCallOnDrain);
visitor.append(fn->functionToCallOnData);
visitor.append(fn->m_remoteAddress);
visitor.append(fn->m_localAddress);
visitor.append(fn->m_duplex);
}
DEFINE_VISIT_CHILDREN(JSNodeHTTPServerSocket);
template<bool SSL>
static JSNodeHTTPServerSocket* getNodeHTTPServerSocket(us_socket_t* socket)
{
auto* httpResponseData = (uWS::HttpResponseData<SSL>*)us_socket_ext(SSL, socket);
return reinterpret_cast<JSNodeHTTPServerSocket*>(httpResponseData->socketData);
}
template<bool SSL>
static WebCore::JSNodeHTTPResponse* getNodeHTTPResponse(us_socket_t* socket)
{
auto* serverSocket = getNodeHTTPServerSocket<SSL>(socket);
if (!serverSocket) {
return nullptr;
}
return serverSocket->currentResponseObject.get();
}
const JSC::ClassInfo JSNodeHTTPServerSocket::s_info = { "NodeHTTPServerSocket"_s, &Base::s_info, nullptr, nullptr,
CREATE_METHOD_TABLE(JSNodeHTTPServerSocket) };
const JSC::ClassInfo JSNodeHTTPServerSocketPrototype::s_info = { "NodeHTTPServerSocket"_s, &Base::s_info, nullptr, nullptr,
CREATE_METHOD_TABLE(JSNodeHTTPServerSocketPrototype) };
template<bool SSL>
static void* getNodeHTTPResponsePtr(us_socket_t* socket)
{
WebCore::JSNodeHTTPResponse* responseObject = getNodeHTTPResponse<SSL>(socket);
if (!responseObject) {
return nullptr;
}
return responseObject->wrapped();
}
extern "C" EncodedJSValue Bun__getNodeHTTPResponseThisValue(bool is_ssl, us_socket_t* socket)
{
if (is_ssl) {
return JSValue::encode(getNodeHTTPResponse<true>(socket));
}
return JSValue::encode(getNodeHTTPResponse<false>(socket));
}
extern "C" EncodedJSValue Bun__getNodeHTTPServerSocketThisValue(bool is_ssl, us_socket_t* socket)
{
if (is_ssl) {
return JSValue::encode(getNodeHTTPServerSocket<true>(socket));
}
return JSValue::encode(getNodeHTTPServerSocket<false>(socket));
}
extern "C" void Bun__setNodeHTTPServerSocketUsSocketValue(EncodedJSValue thisValue, us_socket_t* socket)
{
auto* response = jsCast<JSNodeHTTPServerSocket*>(JSValue::decode(thisValue));
response->socket = socket;
}
extern "C" JSC::EncodedJSValue Bun__createNodeHTTPServerSocketForClientError(bool isSSL, us_socket_t* us_socket, Zig::GlobalObject* globalObject)
{
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
RETURN_IF_EXCEPTION(scope, {});
if (isSSL) {
uWS::HttpResponse<true>* response = reinterpret_cast<uWS::HttpResponse<true>*>(us_socket);
auto* currentSocketDataPtr = reinterpret_cast<JSC::JSCell*>(response->getHttpResponseData()->socketData);
if (currentSocketDataPtr) {
return JSValue::encode(currentSocketDataPtr);
}
} else {
uWS::HttpResponse<false>* response = reinterpret_cast<uWS::HttpResponse<false>*>(us_socket);
auto* currentSocketDataPtr = reinterpret_cast<JSC::JSCell*>(response->getHttpResponseData()->socketData);
if (currentSocketDataPtr) {
return JSValue::encode(currentSocketDataPtr);
}
}
// socket without response because is not valid http
JSNodeHTTPServerSocket* socket = JSNodeHTTPServerSocket::create(
vm,
globalObject->m_JSNodeHTTPServerSocketStructure.getInitializedOnMainThread(globalObject),
us_socket,
isSSL, nullptr);
if (isSSL) {
uWS::HttpResponse<true>* response = reinterpret_cast<uWS::HttpResponse<true>*>(us_socket);
response->getHttpResponseData()->socketData = socket;
} else {
uWS::HttpResponse<false>* response = reinterpret_cast<uWS::HttpResponse<false>*>(us_socket);
response->getHttpResponseData()->socketData = socket;
}
RETURN_IF_EXCEPTION(scope, {});
if (socket) {
socket->strongThis.set(vm, socket);
return JSValue::encode(socket);
}
return JSValue::encode(JSC::jsNull());
}
BUN_DECLARE_HOST_FUNCTION(jsFunctionRequestOrResponseHasBodyValue);
BUN_DECLARE_HOST_FUNCTION(jsFunctionGetCompleteRequestOrResponseBodyValueAsArrayBuffer);
extern "C" uWS::HttpRequest* Request__getUWSRequest(void*);
extern "C" void Request__setInternalEventCallback(void*, EncodedJSValue, JSC::JSGlobalObject*);
extern "C" void Request__setTimeout(void*, EncodedJSValue, JSC::JSGlobalObject*);
extern "C" bool NodeHTTPResponse__setTimeout(void*, EncodedJSValue, JSC::JSGlobalObject*);
extern "C" void Server__setIdleTimeout(EncodedJSValue, EncodedJSValue, JSC::JSGlobalObject*);
extern "C" EncodedJSValue Server__setAppFlags(JSC::JSGlobalObject*, EncodedJSValue, bool require_host_header, bool use_strict_method_validation);
extern "C" EncodedJSValue Server__setOnClientError(JSC::JSGlobalObject*, EncodedJSValue, EncodedJSValue);
extern "C" EncodedJSValue Server__setMaxHTTPHeaderSize(JSC::JSGlobalObject*, EncodedJSValue, uint64_t);
static EncodedJSValue assignHeadersFromFetchHeaders(FetchHeaders& impl, JSObject* prototype, JSObject* objectValue, JSC::InternalFieldTuple* tuple, JSC::JSGlobalObject* globalObject, JSC::VM& vm)
{
auto scope = DECLARE_THROW_SCOPE(vm);
uint32_t size = std::min(impl.sizeAfterJoiningSetCookieHeader(), static_cast<uint32_t>(JSFinalObject::maxInlineCapacity));
JSC::JSArray* array = constructEmptyArray(globalObject, nullptr, impl.size() * 2);
RETURN_IF_EXCEPTION(scope, {});
JSC::JSObject* obj = JSC::constructEmptyObject(globalObject, prototype, size);
RETURN_IF_EXCEPTION(scope, {});
unsigned arrayI = 0;
auto& internal = impl.internalHeaders();
{
auto& vec = internal.commonHeaders();
for (const auto& it : vec) {
const auto& name = it.key;
const auto& value = it.value;
const auto impl = WTF::httpHeaderNameStringImpl(name);
JSString* jsValue = jsString(vm, value);
obj->putDirect(vm, Identifier::fromString(vm, impl), jsValue, 0);
array->putDirectIndex(globalObject, arrayI++, jsString(vm, impl));
array->putDirectIndex(globalObject, arrayI++, jsValue);
RETURN_IF_EXCEPTION(scope, {});
}
}
{
const auto& values = internal.getSetCookieHeaders();
size_t count = values.size();
if (count > 0) {
JSC::JSArray* setCookies = constructEmptyArray(globalObject, nullptr, count);
RETURN_IF_EXCEPTION(scope, {});
const auto setCookieHeaderString = WTF::httpHeaderNameStringImpl(HTTPHeaderName::SetCookie);
JSString* setCookie = jsString(vm, setCookieHeaderString);
for (size_t i = 0; i < count; ++i) {
auto* out = jsString(vm, values[i]);
array->putDirectIndex(globalObject, arrayI++, setCookie);
array->putDirectIndex(globalObject, arrayI++, out);
setCookies->putDirectIndex(globalObject, i, out);
RETURN_IF_EXCEPTION(scope, {});
}
RETURN_IF_EXCEPTION(scope, {});
obj->putDirect(vm, JSC::Identifier::fromString(vm, setCookieHeaderString), setCookies, 0);
}
}
{
const auto& vec = internal.uncommonHeaders();
for (const auto& it : vec) {
const auto& name = it.key;
const auto& value = it.value;
auto* jsValue = jsString(vm, value);
obj->putDirect(vm, Identifier::fromString(vm, name.convertToASCIILowercase()), jsValue, 0);
array->putDirectIndex(globalObject, arrayI++, jsString(vm, name));
array->putDirectIndex(globalObject, arrayI++, jsValue);
}
}
tuple->putInternalField(vm, 0, obj);
tuple->putInternalField(vm, 1, array);
return JSValue::encode(tuple);
}
static void assignHeadersFromUWebSocketsForCall(uWS::HttpRequest* request, JSValue methodString, MarkedArgumentBuffer& args, JSC::JSGlobalObject* globalObject, JSC::VM& vm)
{
auto scope = DECLARE_THROW_SCOPE(vm);
{
std::string_view fullURLStdStr = request->getFullUrl();
String fullURL = String::fromUTF8ReplacingInvalidSequences({ reinterpret_cast<const LChar*>(fullURLStdStr.data()), fullURLStdStr.length() });
args.append(jsString(vm, WTFMove(fullURL)));
}
// Get the method.
if (methodString.isUndefinedOrNull()) [[unlikely]] {
std::string_view methodView = request->getMethod();
WTF::String methodString = String::fromUTF8ReplacingInvalidSequences({ reinterpret_cast<const LChar*>(methodView.data()), methodView.length() });
args.append(jsString(vm, WTFMove(methodString)));
} else {
args.append(methodString);
}
size_t size = 0;
for (auto it = request->begin(); it != request->end(); ++it) {
size++;
}
JSC::JSObject* headersObject = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), std::min(size, static_cast<size_t>(JSFinalObject::maxInlineCapacity)));
RETURN_IF_EXCEPTION(scope, void());
JSC::JSArray* setCookiesHeaderArray = nullptr;
JSC::JSString* setCookiesHeaderString = nullptr;
MarkedArgumentBuffer arrayValues;
args.append(headersObject);
for (auto it = request->begin(); it != request->end(); ++it) {
auto pair = *it;
StringView nameView = StringView(std::span { reinterpret_cast<const LChar*>(pair.first.data()), pair.first.length() });
std::span<LChar> data;
auto value = String::createUninitialized(pair.second.length(), data);
if (pair.second.length() > 0)
memcpy(data.data(), pair.second.data(), pair.second.length());
HTTPHeaderName name;
JSString* jsValue = jsString(vm, value);
HTTPHeaderIdentifiers& identifiers = WebCore::clientData(vm)->httpHeaderIdentifiers();
Identifier nameIdentifier;
JSString* nameString = nullptr;
if (WebCore::findHTTPHeaderName(nameView, name)) {
nameString = identifiers.stringFor(globalObject, name);
nameIdentifier = identifiers.identifierFor(vm, name);
} else {
WTF::String wtfString = nameView.toString();
nameString = jsString(vm, wtfString);
nameIdentifier = Identifier::fromString(vm, wtfString.convertToASCIILowercase());
}
if (name == WebCore::HTTPHeaderName::SetCookie) {
if (!setCookiesHeaderArray) {
setCookiesHeaderArray = constructEmptyArray(globalObject, nullptr);
RETURN_IF_EXCEPTION(scope, );
setCookiesHeaderString = nameString;
headersObject->putDirect(vm, nameIdentifier, setCookiesHeaderArray, 0);
RETURN_IF_EXCEPTION(scope, void());
}
arrayValues.append(setCookiesHeaderString);
arrayValues.append(jsValue);
setCookiesHeaderArray->push(globalObject, jsValue);
RETURN_IF_EXCEPTION(scope, void());
} else {
headersObject->putDirectMayBeIndex(globalObject, nameIdentifier, jsValue);
RETURN_IF_EXCEPTION(scope, void());
arrayValues.append(nameString);
arrayValues.append(jsValue);
RETURN_IF_EXCEPTION(scope, void());
}
}
JSC::JSArray* array;
{
ObjectInitializationScope initializationScope(vm);
if ((array = JSArray::tryCreateUninitializedRestricted(initializationScope, nullptr, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), arrayValues.size()))) [[likely]] {
EncodedJSValue* data = arrayValues.data();
for (size_t i = 0, size = arrayValues.size(); i < size; ++i) {
array->initializeIndex(initializationScope, i, JSValue::decode(data[i]));
}
} else {
RETURN_IF_EXCEPTION(scope, );
array = constructArray(globalObject, static_cast<ArrayAllocationProfile*>(nullptr), arrayValues);
RETURN_IF_EXCEPTION(scope, );
}
}
args.append(array);
}
// This is an 8% speedup.
static EncodedJSValue assignHeadersFromUWebSockets(uWS::HttpRequest* request, JSObject* prototype, JSObject* objectValue, JSC::InternalFieldTuple* tuple, JSC::JSGlobalObject* globalObject, JSC::VM& vm)
{
auto scope = DECLARE_THROW_SCOPE(vm);
auto& builtinNames = WebCore::builtinNames(vm);
{
std::string_view fullURLStdStr = request->getFullUrl();
String fullURL = String::fromUTF8ReplacingInvalidSequences({ reinterpret_cast<const LChar*>(fullURLStdStr.data()), fullURLStdStr.length() });
PutPropertySlot slot(objectValue, false);
objectValue->put(objectValue, globalObject, builtinNames.urlPublicName(), jsString(vm, WTFMove(fullURL)), slot);
RETURN_IF_EXCEPTION(scope, {});
}
{
PutPropertySlot slot(objectValue, false);
std::string_view methodView = request->getMethod();
WTF::String methodString;
switch (methodView.length()) {
case 3: {
if (methodView == std::string_view("get", 3)) {
methodString = "GET"_s;
break;
}
if (methodView == std::string_view("put", 3)) {
methodString = "PUT"_s;
break;
}
break;
}
case 4: {
if (methodView == std::string_view("post", 4)) {
methodString = "POST"_s;
break;
}
if (methodView == std::string_view("head", 4)) {
methodString = "HEAD"_s;
break;
}
if (methodView == std::string_view("copy", 4)) {
methodString = "COPY"_s;
break;
}
}
case 5: {
if (methodView == std::string_view("patch", 5)) {
methodString = "PATCH"_s;
break;
}
if (methodView == std::string_view("merge", 5)) {
methodString = "MERGE"_s;
break;
}
if (methodView == std::string_view("trace", 5)) {
methodString = "TRACE"_s;
break;
}
if (methodView == std::string_view("fetch", 5)) {
methodString = "FETCH"_s;
break;
}
if (methodView == std::string_view("purge", 5)) {
methodString = "PURGE"_s;
break;
}
break;
}
case 6: {
if (methodView == std::string_view("delete", 6)) {
methodString = "DELETE"_s;
break;
}
break;
}
case 7: {
if (methodView == std::string_view("connect", 7)) {
methodString = "CONNECT"_s;
break;
}
if (methodView == std::string_view("options", 7)) {
methodString = "OPTIONS"_s;
break;
}
break;
}
}
if (methodString.isNull()) {
methodString = String::fromUTF8ReplacingInvalidSequences({ reinterpret_cast<const LChar*>(methodView.data()), methodView.length() });
}
objectValue->put(objectValue, globalObject, builtinNames.methodPublicName(), jsString(vm, methodString), slot);
RETURN_IF_EXCEPTION(scope, {});
}
size_t size = 0;
for (auto it = request->begin(); it != request->end(); ++it) {
size++;
}
JSC::JSObject* headersObject = JSC::constructEmptyObject(globalObject, prototype, std::min(size, static_cast<size_t>(JSFinalObject::maxInlineCapacity)));
RETURN_IF_EXCEPTION(scope, {});
JSC::JSArray* array = constructEmptyArray(globalObject, nullptr, size * 2);
RETURN_IF_EXCEPTION(scope, {});
JSC::JSArray* setCookiesHeaderArray = nullptr;
JSC::JSString* setCookiesHeaderString = nullptr;
unsigned i = 0;
for (auto it = request->begin(); it != request->end(); ++it) {
auto pair = *it;
StringView nameView = StringView(std::span { reinterpret_cast<const LChar*>(pair.first.data()), pair.first.length() });
std::span<LChar> data;
auto value = String::tryCreateUninitialized(pair.second.length(), data);
if (value.isNull()) [[unlikely]] {
throwOutOfMemoryError(globalObject, scope);
return {};
}
if (pair.second.length() > 0)
memcpy(data.data(), pair.second.data(), pair.second.length());
HTTPHeaderName name;
WTF::String nameString;
WTF::String lowercasedNameString;
if (WebCore::findHTTPHeaderName(nameView, name)) {
nameString = WTF::httpHeaderNameStringImpl(name);
lowercasedNameString = nameString;
} else {
nameString = nameView.toString();
lowercasedNameString = nameString.convertToASCIILowercase();
}
JSString* jsValue = jsString(vm, value);
if (name == WebCore::HTTPHeaderName::SetCookie) {
if (!setCookiesHeaderArray) {
setCookiesHeaderArray = constructEmptyArray(globalObject, nullptr);
RETURN_IF_EXCEPTION(scope, {});
setCookiesHeaderString = jsString(vm, nameString);
headersObject->putDirect(vm, Identifier::fromString(vm, lowercasedNameString), setCookiesHeaderArray, 0);
RETURN_IF_EXCEPTION(scope, {});
}
array->putDirectIndex(globalObject, i++, setCookiesHeaderString);
array->putDirectIndex(globalObject, i++, jsValue);
setCookiesHeaderArray->push(globalObject, jsValue);
RETURN_IF_EXCEPTION(scope, {});
} else {
headersObject->putDirect(vm, Identifier::fromString(vm, lowercasedNameString), jsValue, 0);
array->putDirectIndex(globalObject, i++, jsString(vm, nameString));
array->putDirectIndex(globalObject, i++, jsValue);
RETURN_IF_EXCEPTION(scope, {});
}
}
tuple->putInternalField(vm, 0, headersObject);
tuple->putInternalField(vm, 1, array);
return JSValue::encode(tuple);
}
template<bool isSSL>
static void assignOnNodeJSCompat(uWS::TemplatedApp<isSSL>* app)
{
app->setOnSocketClosed([](void* socketData, int is_ssl, struct us_socket_t* rawSocket) -> void {
auto* socket = reinterpret_cast<JSNodeHTTPServerSocket*>(socketData);
ASSERT(rawSocket == socket->socket || socket->socket == nullptr);
socket->onClose();
});
app->setOnSocketDrain([](void* socketData, int is_ssl, struct us_socket_t* rawSocket) -> void {
auto* socket = reinterpret_cast<JSNodeHTTPServerSocket*>(socketData);
ASSERT(rawSocket == socket->socket || socket->socket == nullptr);
socket->onDrain();
});
app->setOnSocketData([](void* socketData, int is_ssl, struct us_socket_t* rawSocket, const char* data, int length, bool last) -> void {
auto* socket = reinterpret_cast<JSNodeHTTPServerSocket*>(socketData);
ASSERT(rawSocket == socket->socket || socket->socket == nullptr);
socket->onData(data, length, last);
});
}
extern "C" void NodeHTTP_assignOnNodeJSCompat(bool is_ssl, void* uws_app)
{
if (is_ssl) {
assignOnNodeJSCompat<true>(reinterpret_cast<uWS::TemplatedApp<true>*>(uws_app));
} else {
assignOnNodeJSCompat<false>(reinterpret_cast<uWS::TemplatedApp<false>*>(uws_app));
}
}
extern "C" void NodeHTTP_setUsingCustomExpectHandler(bool is_ssl, void* uws_app, bool value)
{
if (is_ssl) {
reinterpret_cast<uWS::TemplatedApp<true>*>(uws_app)->setUsingCustomExpectHandler(value);
} else {
reinterpret_cast<uWS::TemplatedApp<false>*>(uws_app)->setUsingCustomExpectHandler(value);
}
}
extern "C" EncodedJSValue NodeHTTPResponse__createForJS(size_t any_server, JSC::JSGlobalObject* globalObject, bool* hasBody, uWS::HttpRequest* request, int isSSL, void* response_ptr, void* upgrade_ctx, void** nodeHttpResponsePtr);
template<bool isSSL>
static EncodedJSValue NodeHTTPServer__onRequest(
size_t any_server,
Zig::GlobalObject* globalObject,
JSValue thisValue,
JSValue callback,
JSValue methodString,
uWS::HttpRequest* request,
uWS::HttpResponse<isSSL>* response,
void* upgrade_ctx,
void** nodeHttpResponsePtr)
{
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSObject* callbackObject = jsCast<JSObject*>(callback);
MarkedArgumentBuffer args;
args.append(thisValue);
assignHeadersFromUWebSocketsForCall(request, methodString, args, globalObject, vm);
RETURN_IF_EXCEPTION(scope, {});
bool hasBody = false;
WebCore::JSNodeHTTPResponse* nodeHTTPResponseObject = jsCast<WebCore::JSNodeHTTPResponse*>(JSValue::decode(NodeHTTPResponse__createForJS(any_server, globalObject, &hasBody, request, isSSL, response, upgrade_ctx, nodeHttpResponsePtr)));
args.append(nodeHTTPResponseObject);
args.append(jsBoolean(hasBody));
auto* currentSocketDataPtr = reinterpret_cast<JSC::JSCell*>(response->getHttpResponseData()->socketData);
if (currentSocketDataPtr) {
auto* thisSocket = jsCast<JSNodeHTTPServerSocket*>(currentSocketDataPtr);
thisSocket->currentResponseObject.set(vm, thisSocket, nodeHTTPResponseObject);
args.append(thisSocket);
args.append(jsBoolean(false));
if (thisSocket->m_duplex) {
args.append(thisSocket->m_duplex.get());
} else {
args.append(jsUndefined());
}
} else {
JSNodeHTTPServerSocket* socket = JSNodeHTTPServerSocket::create(vm, globalObject->m_JSNodeHTTPServerSocketStructure.getInitializedOnMainThread(globalObject), (us_socket_t*)response, isSSL, nodeHTTPResponseObject);
socket->strongThis.set(vm, socket);
response->getHttpResponseData()->socketData = socket;
args.append(socket);
args.append(jsBoolean(true));
args.append(jsUndefined());
}
args.append(jsBoolean(request->isAncient()));
JSValue returnValue = AsyncContextFrame::profiledCall(globalObject, callbackObject, jsUndefined(), args);
RETURN_IF_EXCEPTION(scope, {});
return JSValue::encode(returnValue);
}
template<bool isSSL>
static void writeResponseHeader(uWS::HttpResponse<isSSL>* res, const WTF::StringView& name, const WTF::StringView& value)
{
WTF::CString nameStr;
WTF::CString valueStr;
std::string_view nameView;
std::string_view valueView;
if (name.is8Bit()) {
const auto nameSpan = name.span8();
ASSERT(name.containsOnlyASCII());
nameView = std::string_view(reinterpret_cast<const char*>(nameSpan.data()), nameSpan.size());
} else {
nameStr = name.utf8();
nameView = std::string_view(nameStr.data(), nameStr.length());
}
if (value.is8Bit()) {
const auto valueSpan = value.span8();
valueView = std::string_view(reinterpret_cast<const char*>(valueSpan.data()), valueSpan.size());
} else {
valueStr = value.utf8();
valueView = std::string_view(valueStr.data(), valueStr.length());
}
res->writeHeader(nameView, valueView);
}
template<bool isSSL>
static void writeFetchHeadersToUWSResponse(WebCore::FetchHeaders& headers, uWS::HttpResponse<isSSL>* res)
{
auto& internalHeaders = headers.internalHeaders();
for (auto& value : internalHeaders.getSetCookieHeaders()) {
if (value.is8Bit()) {
const auto valueSpan = value.span8();
res->writeHeader(std::string_view("set-cookie", 10), std::string_view(reinterpret_cast<const char*>(valueSpan.data()), valueSpan.size()));
} else {
WTF::CString valueStr = value.utf8();
res->writeHeader(std::string_view("set-cookie", 10), std::string_view(valueStr.data(), valueStr.length()));
}
}
auto* data = res->getHttpResponseData();
for (const auto& header : internalHeaders.commonHeaders()) {
const auto& name = WebCore::httpHeaderNameString(header.key);
const auto& value = header.value;
// We have to tell uWS not to automatically insert a TransferEncoding or Date header.
// Otherwise, you get this when using Fastify;
//
// curl http://localhost:3000 --verbose
// * Trying [::1]:3000...
// * Connected to localhost (::1) port 3000
// > GET / HTTP/1.1
// > Host: localhost:3000
// > User-Agent: curl/8.4.0
// > Accept: */*
// >
// < HTTP/1.1 200 OK
// < Content-Type: application/json; charset=utf-8
// < Content-Length: 17
// < Date: Sun, 06 Oct 2024 13:37:01 GMT
// < Transfer-Encoding: chunked
// <
//
if (header.key == WebCore::HTTPHeaderName::ContentLength) {
if (!(data->state & uWS::HttpResponseData<isSSL>::HTTP_WROTE_CONTENT_LENGTH_HEADER)) {
data->state |= uWS::HttpResponseData<isSSL>::HTTP_WROTE_CONTENT_LENGTH_HEADER;
res->writeMark();
}
}
// Prevent automatic Date header insertion when user provides one
if (header.key == WebCore::HTTPHeaderName::Date) {
data->state |= uWS::HttpResponseData<isSSL>::HTTP_WROTE_DATE_HEADER;
}
writeResponseHeader<isSSL>(res, name, value);
}
for (auto& header : internalHeaders.uncommonHeaders()) {
const auto& name = header.key;
const auto& value = header.value;
writeResponseHeader<isSSL>(res, name, value);
}
}
template<bool isSSL>
static void NodeHTTPServer__writeHead(
JSC::JSGlobalObject* globalObject,
const char* statusMessage,
size_t statusMessageLength,
JSValue headersObjectValue,
uWS::HttpResponse<isSSL>* response)
{
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSObject* headersObject = headersObjectValue.getObject();
if (response->getLoopData()->canCork() && response->getBufferedAmount() == 0) {
response->getLoopData()->setCorkedSocket(response, isSSL);
}
response->writeStatus(std::string_view(statusMessage, statusMessageLength));
if (headersObject) {
if (auto* fetchHeaders = jsDynamicCast<WebCore::JSFetchHeaders*>(headersObject)) {
writeFetchHeadersToUWSResponse<isSSL>(fetchHeaders->wrapped(), response);
return;
}
if (headersObject->hasNonReifiedStaticProperties()) [[unlikely]] {
headersObject->reifyAllStaticProperties(globalObject);
RETURN_IF_EXCEPTION(scope, void());
}
auto* structure = headersObject->structure();
if (structure->canPerformFastPropertyEnumeration()) {
structure->forEachProperty(vm, [&](const auto& entry) {
JSValue headerValue = headersObject->getDirect(entry.offset());
if (!headerValue.isString()) {
return true;
}
String key = entry.key();
String value = headerValue.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, false);
writeResponseHeader<isSSL>(response, key, value);
return true;
});
} else {
PropertyNameArray propertyNames(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude);
headersObject->getOwnPropertyNames(headersObject, globalObject, propertyNames, DontEnumPropertiesMode::Exclude);
RETURN_IF_EXCEPTION(scope, void());
for (unsigned i = 0; i < propertyNames.size(); ++i) {
JSValue headerValue = headersObject->getIfPropertyExists(globalObject, propertyNames[i]);
RETURN_IF_EXCEPTION(scope, );
if (!headerValue.isString()) {
continue;
}
String key = propertyNames[i].string();
String value = headerValue.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, void());
writeResponseHeader<isSSL>(response, key, value);
}
}
}
RELEASE_AND_RETURN(scope, void());
}
extern "C" void NodeHTTPServer__writeHead_http(
JSC::JSGlobalObject* globalObject,
const char* statusMessage,
size_t statusMessageLength,
JSValue headersObjectValue,
uWS::HttpResponse<false>* response)
{
return NodeHTTPServer__writeHead<false>(globalObject, statusMessage, statusMessageLength, headersObjectValue, response);
}
extern "C" void NodeHTTPServer__writeHead_https(
JSC::JSGlobalObject* globalObject,
const char* statusMessage,
size_t statusMessageLength,
JSValue headersObjectValue,
uWS::HttpResponse<true>* response)
{
return NodeHTTPServer__writeHead<true>(globalObject, statusMessage, statusMessageLength, headersObjectValue, response);
}
extern "C" EncodedJSValue NodeHTTPServer__onRequest_http(
size_t any_server,
Zig::GlobalObject* globalObject,
EncodedJSValue thisValue,
EncodedJSValue callback,
EncodedJSValue methodString,
uWS::HttpRequest* request,
uWS::HttpResponse<false>* response,
void* upgrade_ctx,
void** nodeHttpResponsePtr)
{
return NodeHTTPServer__onRequest<false>(
any_server,
globalObject,
JSValue::decode(thisValue),
JSValue::decode(callback),
JSValue::decode(methodString),
request,
response,
upgrade_ctx,
nodeHttpResponsePtr);
}
extern "C" EncodedJSValue NodeHTTPServer__onRequest_https(
size_t any_server,
Zig::GlobalObject* globalObject,
EncodedJSValue thisValue,
EncodedJSValue callback,
EncodedJSValue methodString,
uWS::HttpRequest* request,
uWS::HttpResponse<true>* response,
void* upgrade_ctx,
void** nodeHttpResponsePtr)
{
return NodeHTTPServer__onRequest<true>(
any_server,
globalObject,
JSValue::decode(thisValue),
JSValue::decode(callback),
JSValue::decode(methodString),
request,
response,
upgrade_ctx,
nodeHttpResponsePtr);
}
JSC_DEFINE_HOST_FUNCTION(jsHTTPAssignHeaders, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
auto& vm = JSC::getVM(globalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
// This is an internal binding.
JSValue requestValue = callFrame->uncheckedArgument(0);
JSObject* objectValue = callFrame->uncheckedArgument(1).getObject();
JSC::InternalFieldTuple* tuple = jsCast<JSC::InternalFieldTuple*>(callFrame->uncheckedArgument(2));
ASSERT(callFrame->argumentCount() == 3);
JSValue headersValue = JSValue();
JSValue urlValue = JSValue();
if (auto* jsRequest = jsDynamicCast<WebCore::JSRequest*>(requestValue)) {
if (uWS::HttpRequest* request = Request__getUWSRequest(jsRequest->wrapped())) {
return assignHeadersFromUWebSockets(request, globalObject->objectPrototype(), objectValue, tuple, globalObject, vm);
}
if (jsRequest->m_headers) {
headersValue = jsRequest->m_headers.get();
}
if (jsRequest->m_url) {
urlValue = jsRequest->m_url.get();
}
}
if (requestValue.isObject()) {
if (!headersValue) {
headersValue = requestValue.getObject()->getIfPropertyExists(globalObject, WebCore::builtinNames(vm).headersPublicName());
RETURN_IF_EXCEPTION(scope, {});
}
if (!urlValue) {
urlValue = requestValue.getObject()->getIfPropertyExists(globalObject, WebCore::builtinNames(vm).urlPublicName());
RETURN_IF_EXCEPTION(scope, {});
}
if (headersValue) {
if (auto* headers = jsDynamicCast<WebCore::JSFetchHeaders*>(headersValue)) {
FetchHeaders& impl = headers->wrapped();
if (urlValue) {
if (urlValue.isString()) {
String url = urlValue.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
if (url.startsWith("https://"_s) || url.startsWith("http://"_s) || url.startsWith("file://"_s)) {
WTF::URL urlObj = WTF::URL({}, url);
if (urlObj.isValid()) {
urlValue = jsString(vm, makeString(urlObj.path(), urlObj.query().isEmpty() ? emptyString() : urlObj.queryWithLeadingQuestionMark()));
}
}
} else {
urlValue = jsEmptyString(vm);
}
PutPropertySlot slot(objectValue, false);
objectValue->put(objectValue, globalObject, WebCore::builtinNames(vm).urlPublicName(), urlValue, slot);
RETURN_IF_EXCEPTION(scope, {});
}
RELEASE_AND_RETURN(scope, assignHeadersFromFetchHeaders(impl, globalObject->objectPrototype(), objectValue, tuple, globalObject, vm));
}
}
}
return JSValue::encode(jsNull());
}
JSC_DEFINE_HOST_FUNCTION(jsHTTPAssignEventCallback, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
auto& vm = JSC::getVM(globalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
// This is an internal binding.
JSValue requestValue = callFrame->uncheckedArgument(0);
JSValue callback = callFrame->uncheckedArgument(1);
ASSERT(callFrame->argumentCount() == 2);
if (auto* jsRequest = jsDynamicCast<WebCore::JSRequest*>(requestValue)) {
Request__setInternalEventCallback(jsRequest->wrapped(), JSValue::encode(callback), globalObject);
}
return JSValue::encode(jsNull());
}
JSC_DEFINE_HOST_FUNCTION(jsHTTPSetTimeout, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
auto& vm = JSC::getVM(globalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
// This is an internal binding.
JSValue requestValue = callFrame->uncheckedArgument(0);
JSValue seconds = callFrame->uncheckedArgument(1);
ASSERT(callFrame->argumentCount() == 2);
if (auto* jsRequest = jsDynamicCast<WebCore::JSRequest*>(requestValue)) {
Request__setTimeout(jsRequest->wrapped(), JSValue::encode(seconds), globalObject);
}
if (auto* nodeHttpResponse = jsDynamicCast<WebCore::JSNodeHTTPResponse*>(requestValue)) {
NodeHTTPResponse__setTimeout(nodeHttpResponse->wrapped(), JSValue::encode(seconds), globalObject);
}
return JSValue::encode(jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsHTTPSetServerIdleTimeout, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
auto& vm = JSC::getVM(globalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
// This is an internal binding.
JSValue serverValue = callFrame->uncheckedArgument(0);
JSValue seconds = callFrame->uncheckedArgument(1);
ASSERT(callFrame->argumentCount() == 2);
Server__setIdleTimeout(JSValue::encode(serverValue), JSValue::encode(seconds), globalObject);
return JSValue::encode(jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsHTTPSetCustomOptions, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
auto& vm = JSC::getVM(globalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
ASSERT(callFrame->argumentCount() == 5);
// This is an internal binding.
JSValue serverValue = callFrame->uncheckedArgument(0);
JSValue requireHostHeader = callFrame->uncheckedArgument(1);
JSValue useStrictMethodValidation = callFrame->uncheckedArgument(2);
JSValue maxHeaderSize = callFrame->uncheckedArgument(3);
JSValue callback = callFrame->uncheckedArgument(4);
double maxHeaderSizeNumber = maxHeaderSize.toNumber(globalObject);
RETURN_IF_EXCEPTION(scope, {});
Server__setAppFlags(globalObject, JSValue::encode(serverValue), requireHostHeader.toBoolean(globalObject), useStrictMethodValidation.toBoolean(globalObject));
RETURN_IF_EXCEPTION(scope, {});
Server__setMaxHTTPHeaderSize(globalObject, JSValue::encode(serverValue), maxHeaderSizeNumber);
RETURN_IF_EXCEPTION(scope, {});
Server__setOnClientError(globalObject, JSValue::encode(serverValue), JSValue::encode(callback));
RETURN_IF_EXCEPTION(scope, {});
return JSValue::encode(jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsHTTPGetHeader, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
auto& vm = JSC::getVM(globalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
JSValue headersValue = callFrame->argument(0);
if (auto* headers = jsDynamicCast<WebCore::JSFetchHeaders*>(headersValue)) {
JSValue nameValue = callFrame->argument(1);
if (nameValue.isString()) {
FetchHeaders* impl = &headers->wrapped();
JSString* nameString = nameValue.toString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
const auto name = nameString->view(globalObject);
RETURN_IF_EXCEPTION(scope, {});
if (WTF::equalIgnoringASCIICase(name, "set-cookie"_s)) {
RELEASE_AND_RETURN(scope, fetchHeadersGetSetCookie(globalObject, vm, impl));
}
WebCore::ExceptionOr<String> res = impl->get(name);
if (res.hasException()) {
WebCore::propagateException(globalObject, scope, res.releaseException());
RELEASE_AND_RETURN(scope, {});
}
String value = res.returnValue();
if (value.isEmpty()) {
return JSValue::encode(jsUndefined());
}
return JSC::JSValue::encode(jsString(vm, value));
}
}
return JSValue::encode(jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsHTTPSetHeader, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
auto& vm = JSC::getVM(globalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
JSValue headersValue = callFrame->argument(0);
JSValue nameValue = callFrame->argument(1);
JSValue valueValue = callFrame->argument(2);
if (auto* headers = jsDynamicCast<WebCore::JSFetchHeaders*>(headersValue)) {
if (nameValue.isString()) {
String name = nameValue.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
FetchHeaders* impl = &headers->wrapped();
if (valueValue.isUndefined())
return JSValue::encode(jsUndefined());
if (isArray(globalObject, valueValue)) {
auto* array = jsCast<JSArray*>(valueValue);
unsigned length = array->length();
if (length > 0) {
JSValue item = array->getIndex(globalObject, 0);
RETURN_IF_EXCEPTION(scope, {});
auto value = item.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
impl->set(name, value);
RETURN_IF_EXCEPTION(scope, {});
}
for (unsigned i = 1; i < length; ++i) {
JSValue value = array->getIndex(globalObject, i);
RETURN_IF_EXCEPTION(scope, {});
auto string = value.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
impl->append(name, string);
RETURN_IF_EXCEPTION(scope, {});
}
RELEASE_AND_RETURN(scope, JSValue::encode(jsUndefined()));
return JSValue::encode(jsUndefined());
}
auto value = valueValue.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
impl->set(name, value);
RETURN_IF_EXCEPTION(scope, {});
return JSValue::encode(jsUndefined());
}
}
return JSValue::encode(jsUndefined());
}
JSValue createNodeHTTPInternalBinding(Zig::GlobalObject* globalObject)
{
auto* obj = constructEmptyObject(globalObject);
VM& vm = globalObject->vm();
obj->putDirect(
vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "setHeader"_s)),
JSC::JSFunction::create(vm, globalObject, 3, "setHeader"_s, jsHTTPSetHeader, ImplementationVisibility::Public), 0);
obj->putDirect(
vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "getHeader"_s)),
JSC::JSFunction::create(vm, globalObject, 2, "getHeader"_s, jsHTTPGetHeader, ImplementationVisibility::Public), 0);
obj->putDirect(
vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "assignHeaders"_s)),
JSC::JSFunction::create(vm, globalObject, 2, "assignHeaders"_s, jsHTTPAssignHeaders, ImplementationVisibility::Public), 0);
obj->putDirect(
vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "assignEventCallback"_s)),
JSC::JSFunction::create(vm, globalObject, 2, "assignEventCallback"_s, jsHTTPAssignEventCallback, ImplementationVisibility::Public), 0);
obj->putDirect(
vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "setRequestTimeout"_s)),
JSC::JSFunction::create(vm, globalObject, 2, "setRequestTimeout"_s, jsHTTPSetTimeout, ImplementationVisibility::Public), 0);
obj->putDirect(
vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "setServerIdleTimeout"_s)),
JSC::JSFunction::create(vm, globalObject, 2, "setServerIdleTimeout"_s, jsHTTPSetServerIdleTimeout, ImplementationVisibility::Public), 0);
obj->putDirect(
vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "setServerCustomOptions"_s)),
JSC::JSFunction::create(vm, globalObject, 2, "setServerCustomOptions"_s, jsHTTPSetCustomOptions, ImplementationVisibility::Public), 0);
obj->putDirect(
vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "Response"_s)),
globalObject->JSResponseConstructor(), 0);
obj->putDirect(
vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "Request"_s)),
globalObject->JSRequestConstructor(), 0);
obj->putDirect(
vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "Blob"_s)),
globalObject->JSBlobConstructor(), 0);
obj->putDirect(
vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "Headers"_s)),
WebCore::JSFetchHeaders::getConstructor(vm, globalObject), 0);
obj->putDirect(
vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "headersTuple"_s)),
JSC::InternalFieldTuple::create(vm, globalObject->m_internalFieldTupleStructure.get()), 0);
obj->putDirectNativeFunction(
vm, globalObject, JSC::PropertyName(JSC::Identifier::fromString(vm, "webRequestOrResponseHasBodyValue"_s)),
1, jsFunctionRequestOrResponseHasBodyValue, ImplementationVisibility::Public, Intrinsic::NoIntrinsic, 0);
obj->putDirectNativeFunction(
vm, globalObject, JSC::PropertyName(JSC::Identifier::fromString(vm, "getCompleteWebRequestOrResponseBodyValueAsArrayBuffer"_s)),
1, jsFunctionGetCompleteRequestOrResponseBodyValueAsArrayBuffer, ImplementationVisibility::Public, Intrinsic::NoIntrinsic, 0);
obj->putDirectNativeFunction(
vm, globalObject, JSC::PropertyName(JSC::Identifier::fromString(vm, "drainMicrotasks"_s)),
0, Bun__drainMicrotasksFromJS, ImplementationVisibility::Public, Intrinsic::NoIntrinsic, 0);
return obj;
}
extern "C" void WebCore__FetchHeaders__toUWSResponse(WebCore::FetchHeaders* arg0, bool is_ssl, void* arg2)
{
if (is_ssl) {
writeFetchHeadersToUWSResponse<true>(*arg0, reinterpret_cast<uWS::HttpResponse<true>*>(arg2));
} else {
writeFetchHeadersToUWSResponse<false>(*arg0, reinterpret_cast<uWS::HttpResponse<false>*>(arg2));
}
}
JSC::Structure* createNodeHTTPServerSocketStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
{
return JSNodeHTTPServerSocket::createStructure(vm, globalObject);
}
} // namespace Bun