summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
authorqti3e <me@qti3e.com>2018-09-12 23:46:42 +0430
committerRyan Dahl <ry@tinyclouds.org>2018-09-12 15:16:42 -0400
commit41c70b154f4dd9adf6df875c653bcf8701511ff0 (patch)
treebddea2fdb2478aab9de7e2a3b092b9295e9b1570 /js
parentcb6c78c6d2dbd7298f27d7a0c3ffaa7ca255dca4 (diff)
Add support for fetch() headers (#727)
Diffstat (limited to 'js')
-rw-r--r--js/deno.ts6
-rw-r--r--js/fetch.ts81
-rw-r--r--js/fetch_test.ts17
-rw-r--r--js/fetch_types.d.ts2
-rw-r--r--js/globals.ts6
-rw-r--r--js/rename.ts8
6 files changed, 104 insertions, 16 deletions
diff --git a/js/deno.ts b/js/deno.ts
index 6f71ee499..187d0f27f 100644
--- a/js/deno.ts
+++ b/js/deno.ts
@@ -1,11 +1,7 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
// Public deno module.
/// <amd-module name="deno"/>
-export {
- env,
- exit,
- makeTempDirSync
-} from "./os";
+export { env, exit, makeTempDirSync } from "./os";
export { mkdirSync, mkdir } from "./mkdir";
export { removeSync, remove, removeAllSync, removeAll } from "./remove";
export { readFileSync, readFile } from "./read_file";
diff --git a/js/fetch.ts b/js/fetch.ts
index e3aa052f9..24905694e 100644
--- a/js/fetch.ts
+++ b/js/fetch.ts
@@ -16,19 +16,75 @@ import {
Response,
Blob,
RequestInit,
+ HeadersInit,
FormData
} from "./fetch_types";
import { TextDecoder } from "./text_encoding";
-class DenoHeaders implements Headers {
+interface Header {
+ name: string;
+ value: string;
+}
+
+export class DenoHeaders implements Headers {
+ private readonly headerList: Header[] = [];
+
+ constructor(init?: HeadersInit) {
+ if (init) {
+ this._fill(init);
+ }
+ }
+
+ private _append(header: Header): void {
+ // TODO(qti3e) Check header based on the fetch spec.
+ this._appendToHeaderList(header);
+ }
+
+ private _appendToHeaderList(header: Header): void {
+ const lowerCaseName = header.name.toLowerCase();
+ for (let i = 0; i < this.headerList.length; ++i) {
+ if (this.headerList[i].name.toLowerCase() === lowerCaseName) {
+ header.name = this.headerList[i].name;
+ }
+ }
+ this.headerList.push(header);
+ }
+
+ private _fill(init: HeadersInit): void {
+ if (Array.isArray(init)) {
+ for (let i = 0; i < init.length; ++i) {
+ const header = init[i];
+ if (header.length !== 2) {
+ throw new TypeError("Failed to construct 'Headers': Invalid value");
+ }
+ this._append({
+ name: header[0],
+ value: header[1]
+ });
+ }
+ } else {
+ for (const key in init) {
+ this._append({
+ name: key,
+ value: init[key]
+ });
+ }
+ }
+ }
+
append(name: string, value: string): void {
- assert(false, "Implement me");
+ this._appendToHeaderList({ name, value });
}
+
delete(name: string): void {
assert(false, "Implement me");
}
get(name: string): string | null {
- assert(false, "Implement me");
+ for (const header of this.headerList) {
+ if (header.name.toLowerCase() === name.toLowerCase()) {
+ return header.value;
+ }
+ }
return null;
}
has(name: string): boolean {
@@ -54,15 +110,20 @@ class FetchResponse implements Response {
statusText = "FIXME"; // TODO
readonly type = "basic"; // TODO
redirected = false; // TODO
- headers = new DenoHeaders();
+ headers: DenoHeaders;
readonly trailer: Promise<Headers>;
//private bodyChunks: Uint8Array[] = [];
private first = true;
private bodyWaiter: Resolvable<ArrayBuffer>;
- constructor(readonly status: number, readonly body_: ArrayBuffer) {
+ constructor(
+ readonly status: number,
+ readonly body_: ArrayBuffer,
+ headersList: Array<[string, string]>
+ ) {
this.bodyWaiter = createResolvable();
this.trailer = createResolvable();
+ this.headers = new DenoHeaders(headersList);
setTimeout(() => {
this.bodyWaiter.resolve(body_);
}, 0);
@@ -149,6 +210,14 @@ export async function fetch(
assert(bodyArray != null);
const body = typedArrayToArrayBuffer(bodyArray!);
- const response = new FetchResponse(status, body);
+ const headersList: Array<[string, string]> = [];
+ const len = msg.headerKeyLength();
+ for (let i = 0; i < len; ++i) {
+ const key = msg.headerKey(i);
+ const value = msg.headerValue(i);
+ headersList.push([key, value]);
+ }
+
+ const response = new FetchResponse(status, body, headersList);
return response;
}
diff --git a/js/fetch_test.ts b/js/fetch_test.ts
index 1af3bc2eb..2b7f32099 100644
--- a/js/fetch_test.ts
+++ b/js/fetch_test.ts
@@ -18,3 +18,20 @@ test(async function fetchPerm() {
assertEqual(err.kind, deno.ErrorKind.PermissionDenied);
assertEqual(err.name, "PermissionDenied");
});
+
+testPerm({ net: true }, async function fetchHeaders() {
+ const response = await fetch("http://localhost:4545/package.json");
+ const headers = response.headers;
+ assertEqual(headers.get("Content-Type"), "application/json");
+ assert(headers.get("Server").startsWith("SimpleHTTP"));
+});
+
+test(async function headersAppend() {
+ let err;
+ try {
+ const headers = new Headers([["foo", "bar", "baz"]]);
+ } catch (e) {
+ err = e;
+ }
+ assert(err instanceof TypeError);
+});
diff --git a/js/fetch_types.d.ts b/js/fetch_types.d.ts
index f00bdd3c5..9d4082c35 100644
--- a/js/fetch_types.d.ts
+++ b/js/fetch_types.d.ts
@@ -13,7 +13,7 @@ See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
*******************************************************************************/
-type HeadersInit = Headers | string[][] | Record<string, string>;
+type HeadersInit = string[][] | Record<string, string>;
type BodyInit =
| Blob
| BufferSource
diff --git a/js/globals.ts b/js/globals.ts
index cd29d34c7..3805f12f5 100644
--- a/js/globals.ts
+++ b/js/globals.ts
@@ -6,6 +6,7 @@ import * as textEncoding from "./text_encoding";
import * as fetch_ from "./fetch";
import { libdeno } from "./libdeno";
import { globalEval } from "./global-eval";
+import { DenoHeaders } from "./fetch";
declare global {
interface Window {
@@ -23,6 +24,8 @@ declare global {
TextEncoder: typeof TextEncoder;
TextDecoder: typeof TextDecoder;
+
+ Headers: typeof Headers;
}
const clearTimeout: typeof timers.clearTimer;
@@ -38,6 +41,7 @@ declare global {
// tslint:disable:variable-name
const TextEncoder: typeof textEncoding.TextEncoder;
const TextDecoder: typeof textEncoding.TextDecoder;
+ const Headers: typeof DenoHeaders;
// tslint:enable:variable-name
}
@@ -57,3 +61,5 @@ window.TextEncoder = textEncoding.TextEncoder;
window.TextDecoder = textEncoding.TextDecoder;
window.fetch = fetch_.fetch;
+
+window.Headers = DenoHeaders;
diff --git a/js/rename.ts b/js/rename.ts
index 241e27490..5917912f5 100644
--- a/js/rename.ts
+++ b/js/rename.ts
@@ -4,8 +4,8 @@ import { flatbuffers } from "flatbuffers";
import * as dispatch from "./dispatch";
/**
- * Synchronously renames (moves) oldpath to newpath. If newpath already exists
- * and is not a directory, Rename replaces it. OS-specific restrictions may
+ * Synchronously renames (moves) oldpath to newpath. If newpath already exists
+ * and is not a directory, Rename replaces it. OS-specific restrictions may
* apply when oldpath and newpath are in different directories.
*
* import { renameSync } from "deno";
@@ -16,8 +16,8 @@ export function renameSync(oldpath: string, newpath: string): void {
}
/**
- * Renames (moves) oldpath to newpath. If newpath already exists
- * and is not a directory, Rename replaces it. OS-specific restrictions may
+ * Renames (moves) oldpath to newpath. If newpath already exists
+ * and is not a directory, Rename replaces it. OS-specific restrictions may
* apply when oldpath and newpath are in different directories.
*
* import { rename } from "deno";