mirror of
https://github.com/oven-sh/bun
synced 2026-02-14 21:01:52 +00:00
node:http improvements (#17093)
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com> Co-authored-by: Pham Minh Triet <92496972+Nanome203@users.noreply.github.com> Co-authored-by: snwy <snwy@snwy.me> Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com> Co-authored-by: cirospaciari <cirospaciari@users.noreply.github.com> Co-authored-by: Ben Grant <ben@bun.sh>
This commit is contained in:
@@ -5,25 +5,434 @@
|
||||
#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 <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" uint64_t uws_res_get_remote_address_info(void* res, const char** dest, int* port, bool* is_ipv6);
|
||||
|
||||
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(jsNodeHttpServerSocketGetterClosed);
|
||||
JSC_DECLARE_CUSTOM_SETTER(jsNodeHttpServerSocketSetterOnClose);
|
||||
JSC_DECLARE_HOST_FUNCTION(jsFunctionNodeHTTPServerSocketClose);
|
||||
JSC_DECLARE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterResponse);
|
||||
JSC_DECLARE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterRemoteAddress);
|
||||
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__drainMicrotasksFromJS);
|
||||
JSC_DECLARE_CUSTOM_GETTER(jsNodeHttpServerSocketGetterDuplex);
|
||||
JSC_DECLARE_CUSTOM_SETTER(jsNodeHttpServerSocketSetterDuplex);
|
||||
|
||||
// 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 } },
|
||||
{ "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 } },
|
||||
{ "close"_s, static_cast<unsigned>(PropertyAttribute::Function | PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFunctionNodeHTTPServerSocketClose, 0 } },
|
||||
};
|
||||
|
||||
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;
|
||||
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);
|
||||
if (httpResponseData->socketData) {
|
||||
httpResponseData->socketData = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
auto* socket = this->socket;
|
||||
if (socket) {
|
||||
us_socket_close(is_ssl, socket, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool isClosed() const
|
||||
{
|
||||
return !socket || us_socket_is_closed(is_ssl, socket);
|
||||
}
|
||||
|
||||
~JSNodeHTTPServerSocket()
|
||||
{
|
||||
if (socket) {
|
||||
if (is_ssl) {
|
||||
clearSocketData<true>(socket);
|
||||
} else {
|
||||
clearSocketData<false>(socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<WebCore::JSNodeHTTPResponse> currentResponseObject;
|
||||
mutable WriteBarrier<JSObject> m_remoteAddress;
|
||||
mutable WriteBarrier<JSObject> m_duplex;
|
||||
|
||||
unsigned is_ssl : 1;
|
||||
us_socket_t* socket;
|
||||
JSC::Strong<JSNodeHTTPServerSocket> strongThis = {};
|
||||
|
||||
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 onClose()
|
||||
{
|
||||
this->socket = nullptr;
|
||||
this->m_duplex.clear();
|
||||
this->currentResponseObject.clear();
|
||||
|
||||
// This function can be called during GC!
|
||||
Zig::GlobalObject* globalObject = static_cast<Zig::GlobalObject*>(this->globalObject());
|
||||
if (!functionToCallOnClose) {
|
||||
this->strongThis.clear();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
WebCore::ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext();
|
||||
|
||||
if (scriptExecutionContext) {
|
||||
JSC::gcProtect(this);
|
||||
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) {
|
||||
JSC::gcUnprotect(self);
|
||||
return;
|
||||
}
|
||||
auto callData = JSC::getCallData(callbackObject);
|
||||
MarkedArgumentBuffer args;
|
||||
EnsureStillAliveScope ensureStillAlive(self);
|
||||
JSC::gcUnprotect(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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this->strongThis.clear();
|
||||
}
|
||||
|
||||
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 (UNLIKELY(!thisObject)) {
|
||||
return JSValue::encode(JSC::jsUndefined());
|
||||
}
|
||||
if (thisObject->isClosed()) {
|
||||
return JSValue::encode(JSC::jsUndefined());
|
||||
}
|
||||
thisObject->close();
|
||||
return JSValue::encode(JSC::jsUndefined());
|
||||
}
|
||||
|
||||
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(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_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(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->m_remoteAddress);
|
||||
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(int 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(int 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;
|
||||
}
|
||||
|
||||
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*);
|
||||
static EncodedJSValue assignHeadersFromFetchHeaders(FetchHeaders& impl, JSObject* prototype, JSObject* objectValue, JSC::InternalFieldTuple* tuple, JSC::JSGlobalObject* globalObject, JSC::VM& vm)
|
||||
{
|
||||
@@ -94,6 +503,164 @@ static EncodedJSValue assignHeadersFromFetchHeaders(FetchHeaders& impl, JSObject
|
||||
return JSValue::encode(tuple);
|
||||
}
|
||||
|
||||
static void assignHeadersFromUWebSocketsForCall(uWS::HttpRequest* request, 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() });
|
||||
|
||||
// Get the URL.
|
||||
{
|
||||
args.append(jsString(vm, fullURL));
|
||||
}
|
||||
|
||||
// Get the method.
|
||||
{
|
||||
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() });
|
||||
}
|
||||
|
||||
args.append(jsString(vm, 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* array = constructEmptyArray(globalObject, nullptr, size * 2);
|
||||
JSC::JSArray* setCookiesHeaderArray = nullptr;
|
||||
JSC::JSString* setCookiesHeaderString = nullptr;
|
||||
|
||||
args.append(headersObject);
|
||||
args.append(array);
|
||||
|
||||
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::createUninitialized(pair.second.length(), data);
|
||||
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);
|
||||
setCookiesHeaderString = jsString(vm, nameString);
|
||||
headersObject->putDirect(vm, Identifier::fromString(vm, lowercasedNameString), setCookiesHeaderArray, 0);
|
||||
RETURN_IF_EXCEPTION(scope, void());
|
||||
}
|
||||
array->putDirectIndex(globalObject, i++, setCookiesHeaderString);
|
||||
array->putDirectIndex(globalObject, i++, jsValue);
|
||||
setCookiesHeaderArray->push(globalObject, jsValue);
|
||||
RETURN_IF_EXCEPTION(scope, void());
|
||||
|
||||
} 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, void());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is an 8% speedup.
|
||||
static EncodedJSValue assignHeadersFromUWebSockets(uWS::HttpRequest* request, JSObject* prototype, JSObject* objectValue, JSC::InternalFieldTuple* tuple, JSC::JSGlobalObject* globalObject, JSC::VM& vm)
|
||||
{
|
||||
@@ -261,6 +828,301 @@ static EncodedJSValue assignHeadersFromUWebSockets(uWS::HttpRequest* request, JS
|
||||
return JSValue::encode(tuple);
|
||||
}
|
||||
|
||||
template<bool isSSL>
|
||||
static void assignOnCloseFunction(uWS::TemplatedApp<isSSL>* app)
|
||||
{
|
||||
app->setOnClose([](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();
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" void NodeHTTP_assignOnCloseFunction(int is_ssl, void* uws_app)
|
||||
{
|
||||
if (is_ssl) {
|
||||
assignOnCloseFunction<true>(reinterpret_cast<uWS::TemplatedApp<true>*>(uws_app));
|
||||
} else {
|
||||
assignOnCloseFunction<false>(reinterpret_cast<uWS::TemplatedApp<false>*>(uws_app));
|
||||
}
|
||||
}
|
||||
extern "C" EncodedJSValue NodeHTTPResponse__createForJS(size_t any_server, JSC::JSGlobalObject* globalObject, int* 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,
|
||||
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, args, globalObject, vm);
|
||||
if (scope.exception()) {
|
||||
auto* exception = scope.exception();
|
||||
response->endWithoutBody();
|
||||
scope.clearException();
|
||||
return JSValue::encode(exception);
|
||||
}
|
||||
|
||||
int hasBody = 0;
|
||||
WebCore::JSNodeHTTPResponse* nodeHTTPResponseObject = jsCast<WebCore::JSNodeHTTPResponse*>(JSValue::decode(NodeHTTPResponse__createForJS(any_server, globalObject, &hasBody, request, isSSL, response, upgrade_ctx, nodeHttpResponsePtr)));
|
||||
|
||||
JSC::CallData callData = getCallData(callbackObject);
|
||||
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(true));
|
||||
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(false));
|
||||
args.append(jsUndefined());
|
||||
}
|
||||
|
||||
WTF::NakedPtr<JSC::Exception> exception;
|
||||
JSValue returnValue = JSC::profiledCall(globalObject, JSC::ProfilingReason::API, callbackObject, callData, jsUndefined(), args, exception);
|
||||
if (exception) {
|
||||
auto* ptr = exception.get();
|
||||
exception.clear();
|
||||
return JSValue::encode(ptr);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
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 (UNLIKELY(headersObject->hasNonReifiedStaticProperties())) {
|
||||
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);
|
||||
if (scope.exception()) {
|
||||
return 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]);
|
||||
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,
|
||||
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), request, response, upgrade_ctx, nodeHttpResponsePtr);
|
||||
}
|
||||
|
||||
extern "C" EncodedJSValue NodeHTTPServer__onRequest_https(
|
||||
size_t any_server,
|
||||
Zig::GlobalObject* globalObject,
|
||||
EncodedJSValue thisValue,
|
||||
EncodedJSValue callback,
|
||||
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), request, response, upgrade_ctx, nodeHttpResponsePtr);
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(jsHTTPAssignHeaders, (JSGlobalObject * globalObject, CallFrame* callFrame))
|
||||
{
|
||||
auto& vm = JSC::getVM(globalObject);
|
||||
@@ -361,6 +1223,10 @@ JSC_DEFINE_HOST_FUNCTION(jsHTTPSetTimeout, (JSGlobalObject * globalObject, CallF
|
||||
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))
|
||||
@@ -422,14 +1288,15 @@ JSC_DEFINE_HOST_FUNCTION(jsHTTPSetHeader, (JSGlobalObject * globalObject, CallFr
|
||||
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)) {
|
||||
JSValue nameValue = callFrame->argument(1);
|
||||
|
||||
if (nameValue.isString()) {
|
||||
String name = nameValue.toWTFString(globalObject);
|
||||
FetchHeaders* impl = &headers->wrapped();
|
||||
|
||||
JSValue valueValue = callFrame->argument(2);
|
||||
if (valueValue.isUndefined())
|
||||
return JSValue::encode(jsUndefined());
|
||||
|
||||
@@ -440,23 +1307,28 @@ JSC_DEFINE_HOST_FUNCTION(jsHTTPSetHeader, (JSGlobalObject * globalObject, CallFr
|
||||
JSValue item = array->getIndex(globalObject, 0);
|
||||
if (UNLIKELY(scope.exception()))
|
||||
return JSValue::encode(jsUndefined());
|
||||
impl->set(name, item.getString(globalObject));
|
||||
|
||||
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);
|
||||
if (UNLIKELY(scope.exception()))
|
||||
return JSValue::encode(jsUndefined());
|
||||
if (!value.isString())
|
||||
continue;
|
||||
impl->append(name, value.getString(globalObject));
|
||||
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());
|
||||
}
|
||||
|
||||
impl->set(name, valueValue.getString(globalObject));
|
||||
auto value = valueValue.toWTFString(globalObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
impl->set(name, value);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
return JSValue::encode(jsUndefined());
|
||||
}
|
||||
@@ -504,7 +1376,31 @@ JSValue createNodeHTTPInternalBinding(Zig::GlobalObject* globalObject)
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user