diff options
author | qti3e <me@qti3e.com> | 2018-09-12 23:46:42 +0430 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2018-09-12 15:16:42 -0400 |
commit | 41c70b154f4dd9adf6df875c653bcf8701511ff0 (patch) | |
tree | bddea2fdb2478aab9de7e2a3b092b9295e9b1570 /js | |
parent | cb6c78c6d2dbd7298f27d7a0c3ffaa7ca255dca4 (diff) |
Add support for fetch() headers (#727)
Diffstat (limited to 'js')
-rw-r--r-- | js/deno.ts | 6 | ||||
-rw-r--r-- | js/fetch.ts | 81 | ||||
-rw-r--r-- | js/fetch_test.ts | 17 | ||||
-rw-r--r-- | js/fetch_types.d.ts | 2 | ||||
-rw-r--r-- | js/globals.ts | 6 | ||||
-rw-r--r-- | js/rename.ts | 8 |
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"; |