diff options
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses.cpp | 26 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses.h | 3 | ||||
-rw-r--r-- | src/bun.js/bindings/generated_classes.zig | 4 | ||||
-rw-r--r-- | src/bun.js/webcore/response.classes.ts | 4 | ||||
-rw-r--r-- | test/bun.js/serve.test.ts | 22 |
5 files changed, 57 insertions, 2 deletions
diff --git a/src/bun.js/bindings/ZigGeneratedClasses.cpp b/src/bun.js/bindings/ZigGeneratedClasses.cpp index 12db35785..f145424ed 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses.cpp +++ b/src/bun.js/bindings/ZigGeneratedClasses.cpp @@ -2128,6 +2128,10 @@ extern "C" EncodedJSValue RequestPrototype__getBlob(void* ptr, JSC::JSGlobalObje JSC_DECLARE_HOST_FUNCTION(RequestPrototype__blobCallback); +extern "C" JSC::EncodedJSValue RequestPrototype__getBody(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); +JSC_DECLARE_CUSTOM_GETTER(RequestPrototype__bodyGetterWrap); + + extern "C" JSC::EncodedJSValue RequestPrototype__getBodyUsed(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(RequestPrototype__bodyUsedGetterWrap); @@ -2194,6 +2198,7 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSRequestPrototype, JSRequestPrototype::Base static const HashTableValue JSRequestPrototypeTableValues[] = { { "arrayBuffer"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, RequestPrototype__arrayBufferCallback, 0 } } , { "blob"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, RequestPrototype__blobCallback, 0 } } , +{ "body"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, RequestPrototype__bodyGetterWrap, 0 } } , { "bodyUsed"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, RequestPrototype__bodyUsedGetterWrap, 0 } } , { "cache"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, RequestPrototype__cacheGetterWrap, 0 } } , { "clone"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, RequestPrototype__cloneCallback, 1 } } , @@ -2264,6 +2269,26 @@ JSC_DEFINE_HOST_FUNCTION(RequestPrototype__blobCallback, (JSGlobalObject * lexic } +JSC_DEFINE_CUSTOM_GETTER(RequestPrototype__bodyGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) +{ + auto& vm = lexicalGlobalObject->vm(); + Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + JSRequest* thisObject = jsCast<JSRequest*>(JSValue::decode(thisValue)); + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + if (JSValue cachedValue = thisObject->m_body.get()) + return JSValue::encode(cachedValue); + + JSC::JSValue result = JSC::JSValue::decode( + RequestPrototype__getBody(thisObject->wrapped(), globalObject) + ); + RETURN_IF_EXCEPTION(throwScope, {}); + thisObject->m_body.set(vm, thisObject, result); + RELEASE_AND_RETURN(throwScope, JSValue::encode(result)); +} + + JSC_DEFINE_CUSTOM_GETTER(RequestPrototype__bodyUsedGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) { auto& vm = lexicalGlobalObject->vm(); @@ -2625,6 +2650,7 @@ void JSRequest::visitChildrenImpl(JSCell* cell, Visitor& visitor) JSRequest* thisObject = jsCast<JSRequest*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); Base::visitChildren(thisObject, visitor); + visitor.append(thisObject->m_body); visitor.append(thisObject->m_headers); visitor.append(thisObject->m_url); } diff --git a/src/bun.js/bindings/ZigGeneratedClasses.h b/src/bun.js/bindings/ZigGeneratedClasses.h index bc0a2ec6f..7b10cfd20 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses.h +++ b/src/bun.js/bindings/ZigGeneratedClasses.h @@ -1182,7 +1182,8 @@ class JSRequest final : public JSC::JSDestructibleObject { DECLARE_VISIT_CHILDREN; - mutable JSC::WriteBarrier<JSC::Unknown> m_headers; + mutable JSC::WriteBarrier<JSC::Unknown> m_body; +mutable JSC::WriteBarrier<JSC::Unknown> m_headers; mutable JSC::WriteBarrier<JSC::Unknown> m_url; }; class JSRequestPrototype final : public JSC::JSNonFinalObject { diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig index 0bc48964c..f6fa71fd5 100644 --- a/src/bun.js/bindings/generated_classes.zig +++ b/src/bun.js/bindings/generated_classes.zig @@ -752,6 +752,9 @@ pub const JSRequest = struct { @compileLog("Expected Request.getArrayBuffer to be a callback"); if (@TypeOf(Request.getBlob) != CallbackType) @compileLog("Expected Request.getBlob to be a callback"); + if (@TypeOf(Request.getBody) != GetterType) + @compileLog("Expected Request.getBody to be a getter"); + if (@TypeOf(Request.getBodyUsed) != GetterType) @compileLog("Expected Request.getBodyUsed to be a getter"); @@ -800,6 +803,7 @@ pub const JSRequest = struct { @export(Request.finalize, .{ .name = "RequestClass__finalize" }); @export(Request.getArrayBuffer, .{ .name = "RequestPrototype__getArrayBuffer" }); @export(Request.getBlob, .{ .name = "RequestPrototype__getBlob" }); + @export(Request.getBody, .{ .name = "RequestPrototype__getBody" }); @export(Request.getBodyUsed, .{ .name = "RequestPrototype__getBodyUsed" }); @export(Request.getCache, .{ .name = "RequestPrototype__getCache" }); @export(Request.getCredentials, .{ .name = "RequestPrototype__getCredentials" }); diff --git a/src/bun.js/webcore/response.classes.ts b/src/bun.js/webcore/response.classes.ts index 45df255e1..eeeaa8a60 100644 --- a/src/bun.js/webcore/response.classes.ts +++ b/src/bun.js/webcore/response.classes.ts @@ -8,6 +8,10 @@ export default [ klass: {}, JSType: "0b11101110", proto: { + body: { + getter: "getBody", + cache: true, + }, text: { fn: "getText" }, json: { fn: "getJSON" }, arrayBuffer: { fn: "getArrayBuffer" }, diff --git a/test/bun.js/serve.test.ts b/test/bun.js/serve.test.ts index 8961372c1..fb541da24 100644 --- a/test/bun.js/serve.test.ts +++ b/test/bun.js/serve.test.ts @@ -1,4 +1,4 @@ -import { file, serve } from "bun"; +import { file, readableStreamToText, serve } from "bun"; import { describe, expect, it } from "bun:test"; import { readFileSync } from "fs"; import { resolve } from "path"; @@ -12,6 +12,26 @@ class TestPass extends Error { } } +describe("request body streaming", () => { + it("works", async () => { + var server = serve({ + port: port++, + development: false, + + async fetch(req: Request) { + const text = await readableStreamToText(req.body); + return new Response(text); + }, + }); + + var res = await fetch(`http://localhost:${server.port}`, { + body: "hello", + method: "POST", + }); + expect(await res.text()).toBe("hello"); + }); +}); + describe("streaming", () => { describe("error handler", () => { it("throw on pull reports an error and close the connection", async () => { |