summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
Diffstat (limited to 'js')
-rw-r--r--js/fetch.ts16
-rw-r--r--js/fetch_test.ts71
-rw-r--r--js/util.ts6
3 files changed, 86 insertions, 7 deletions
diff --git a/js/fetch.ts b/js/fetch.ts
index 636bbba10..06ed5dbca 100644
--- a/js/fetch.ts
+++ b/js/fetch.ts
@@ -1,5 +1,5 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
-import { assert, createResolvable, notImplemented } from "./util";
+import { assert, createResolvable, notImplemented, isTypedArray } from "./util";
import * as flatbuffers from "./flatbuffers";
import { sendAsync } from "./dispatch";
import * as msg from "gen/msg_generated";
@@ -204,6 +204,7 @@ export async function fetch(
let url: string;
let method: string | null = null;
let headers: domTypes.Headers | null = null;
+ let body: ArrayBufferView | undefined;
if (typeof input === "string") {
url = input;
@@ -217,6 +218,16 @@ export async function fetch(
} else {
headers = null;
}
+
+ if (init.body) {
+ if (typeof init.body === "string") {
+ body = new TextEncoder().encode(init.body);
+ } else if (isTypedArray(init.body)) {
+ body = init.body;
+ } else {
+ notImplemented();
+ }
+ }
}
} else {
url = input.url;
@@ -232,7 +243,8 @@ export async function fetch(
const resBase = await sendAsync(
builder,
msg.Any.Fetch,
- msg.Fetch.endFetch(builder)
+ msg.Fetch.endFetch(builder),
+ body
);
// Decode FetchRes
diff --git a/js/fetch_test.ts b/js/fetch_test.ts
index 8fad8da75..e488e97e2 100644
--- a/js/fetch_test.ts
+++ b/js/fetch_test.ts
@@ -47,24 +47,36 @@ testPerm({ net: true }, async function responseClone() {
}
});
-testPerm({ net: true }, async function fetchRequest() {
- const addr = "127.0.0.1:4501";
+function bufferServer(addr: string): deno.Buffer {
const listener = deno.listen("tcp", addr);
const buf = new deno.Buffer();
listener.accept().then(async conn => {
- buf.readFrom(conn);
- await conn.write(
+ const p1 = buf.readFrom(conn);
+ const p2 = conn.write(
new TextEncoder().encode(
"HTTP/1.0 404 Not Found\r\nContent-Length: 2\r\n\r\nNF"
)
);
+ // Wait for both an EOF on the read side of the socket and for the write to
+ // complete before closing it. Due to keep-alive, the EOF won't be sent
+ // until the Connection close (HTTP/1.0) response, so readFrom() can't
+ // proceed write. Conversely, if readFrom() is async, waiting for the
+ // write() to complete is not a guarantee that we've read the incoming
+ // request.
+ await Promise.all([p1, p2]);
conn.close();
+ listener.close();
});
+ return buf;
+}
+
+testPerm({ net: true }, async function fetchRequest() {
+ const addr = "127.0.0.1:4501";
+ const buf = bufferServer(addr);
const response = await fetch(`http://${addr}/blah`, {
method: "POST",
headers: [["Hello", "World"], ["Foo", "Bar"]]
});
- listener.close();
assertEqual(response.status, 404);
assertEqual(response.headers.get("Content-Length"), "2");
@@ -77,3 +89,52 @@ testPerm({ net: true }, async function fetchRequest() {
].join("");
assertEqual(actual, expected);
});
+
+testPerm({ net: true }, async function fetchPostBodyString() {
+ const addr = "127.0.0.1:4502";
+ const buf = bufferServer(addr);
+ const body = "hello world";
+ const response = await fetch(`http://${addr}/blah`, {
+ method: "POST",
+ headers: [["Hello", "World"], ["Foo", "Bar"]],
+ body
+ });
+ assertEqual(response.status, 404);
+ assertEqual(response.headers.get("Content-Length"), "2");
+
+ const actual = new TextDecoder().decode(buf.bytes());
+ const expected = [
+ "POST /blah HTTP/1.1\r\n",
+ "hello: World\r\n",
+ "foo: Bar\r\n",
+ `host: ${addr}\r\n`,
+ `content-length: ${body.length}\r\n\r\n`,
+ body
+ ].join("");
+ assertEqual(actual, expected);
+});
+
+testPerm({ net: true }, async function fetchPostBodyTypedArray() {
+ const addr = "127.0.0.1:4503";
+ const buf = bufferServer(addr);
+ const bodyStr = "hello world";
+ const body = new TextEncoder().encode(bodyStr);
+ const response = await fetch(`http://${addr}/blah`, {
+ method: "POST",
+ headers: [["Hello", "World"], ["Foo", "Bar"]],
+ body
+ });
+ assertEqual(response.status, 404);
+ assertEqual(response.headers.get("Content-Length"), "2");
+
+ const actual = new TextDecoder().decode(buf.bytes());
+ const expected = [
+ "POST /blah HTTP/1.1\r\n",
+ "hello: World\r\n",
+ "foo: Bar\r\n",
+ `host: ${addr}\r\n`,
+ `content-length: ${body.byteLength}\r\n\r\n`,
+ bodyStr
+ ].join("");
+ assertEqual(actual, expected);
+});
diff --git a/js/util.ts b/js/util.ts
index 0c50acebb..9ba1d6346 100644
--- a/js/util.ts
+++ b/js/util.ts
@@ -125,3 +125,9 @@ export function deferred(): Deferred {
reject: reject!
};
}
+
+// tslint:disable-next-line:variable-name
+const TypedArrayConstructor = Object.getPrototypeOf(Uint8Array);
+export function isTypedArray(x: unknown): x is TypedArray {
+ return x instanceof TypedArrayConstructor;
+}