Compare commits

...

1 Commits

Author SHA1 Message Date
Jarred Sumner
15415c72d5 Define Request.prototype.body 2022-08-29 13:34:44 -07:00
5 changed files with 57 additions and 2 deletions

View File

@@ -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);
}

View File

@@ -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 {

View File

@@ -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" });

View File

@@ -8,6 +8,10 @@ export default [
klass: {},
JSType: "0b11101110",
proto: {
body: {
getter: "getBody",
cache: true,
},
text: { fn: "getText" },
json: { fn: "getJSON" },
arrayBuffer: { fn: "getArrayBuffer" },

View File

@@ -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 () => {