diff --git a/cli/BUILD.gn b/cli/BUILD.gn index cfc397d65174ec..7fd8ba7da8a738 100644 --- a/cli/BUILD.gn +++ b/cli/BUILD.gn @@ -62,6 +62,7 @@ if (is_posix) { ts_sources = [ "../js/assets.ts", + "../js/base64.ts", "../js/blob.ts", "../js/body.ts", "../js/buffer.ts", @@ -265,11 +266,3 @@ snapshot("snapshot_compiler") { ":compiler_bundle", ] } - -action("write_gn_args") { - script = "//tools/write_gn_args.py" - outputs = [ - "$target_gen_dir/gn_args.txt", - ] - args = [ rebase_path(outputs[0], root_build_dir) ] -} diff --git a/js/base64.ts b/js/base64.ts new file mode 100644 index 00000000000000..38fd9824de6eaa --- /dev/null +++ b/js/base64.ts @@ -0,0 +1,149 @@ +// Forked from https://github.com/beatgammit/base64-js +// Copyright (c) 2014 Jameson Little. MIT License. + +const lookup: string[] = []; +const revLookup: number[] = []; + +const code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +for (var i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i]; + revLookup[code.charCodeAt(i)] = i; +} + +// Support decoding URL-safe base64 strings, as Node.js does. +// See: https://en.wikipedia.org/wiki/Base64#URL_applications +revLookup["-".charCodeAt(0)] = 62; +revLookup["_".charCodeAt(0)] = 63; + +function getLens(b64: string): [number, number] { + var len = b64.length; + + if (len % 4 > 0) { + throw new Error("Invalid string. Length must be a multiple of 4"); + } + + // Trim off extra bytes after placeholder bytes are found + // See: https://github.com/beatgammit/base64-js/issues/42 + var validLen = b64.indexOf("="); + if (validLen === -1) validLen = len; + + var placeHoldersLen = validLen === len ? 0 : 4 - (validLen % 4); + + return [validLen, placeHoldersLen]; +} + +// base64 is 4/3 + up to two characters of the original data +export function byteLength(b64: string): number { + var lens = getLens(b64); + var validLen = lens[0]; + var placeHoldersLen = lens[1]; + return ((validLen + placeHoldersLen) * 3) / 4 - placeHoldersLen; +} + +function _byteLength( + b64: string, + validLen: number, + placeHoldersLen: number +): number { + return ((validLen + placeHoldersLen) * 3) / 4 - placeHoldersLen; +} + +export function toByteArray(b64: string): Uint8Array { + var tmp; + var lens = getLens(b64); + var validLen = lens[0]; + var placeHoldersLen = lens[1]; + + var arr = new Uint8Array(_byteLength(b64, validLen, placeHoldersLen)); + + var curByte = 0; + + // if there are placeholders, only get up to the last complete 4 chars + var len = placeHoldersLen > 0 ? validLen - 4 : validLen; + + for (var i = 0; i < len; i += 4) { + tmp = + (revLookup[b64.charCodeAt(i)] << 18) | + (revLookup[b64.charCodeAt(i + 1)] << 12) | + (revLookup[b64.charCodeAt(i + 2)] << 6) | + revLookup[b64.charCodeAt(i + 3)]; + arr[curByte++] = (tmp >> 16) & 0xff; + arr[curByte++] = (tmp >> 8) & 0xff; + arr[curByte++] = tmp & 0xff; + } + + if (placeHoldersLen === 2) { + tmp = + (revLookup[b64.charCodeAt(i)] << 2) | + (revLookup[b64.charCodeAt(i + 1)] >> 4); + arr[curByte++] = tmp & 0xff; + } + + if (placeHoldersLen === 1) { + tmp = + (revLookup[b64.charCodeAt(i)] << 10) | + (revLookup[b64.charCodeAt(i + 1)] << 4) | + (revLookup[b64.charCodeAt(i + 2)] >> 2); + arr[curByte++] = (tmp >> 8) & 0xff; + arr[curByte++] = tmp & 0xff; + } + + return arr; +} + +function tripletToBase64(num: number): string { + return ( + lookup[(num >> 18) & 0x3f] + + lookup[(num >> 12) & 0x3f] + + lookup[(num >> 6) & 0x3f] + + lookup[num & 0x3f] + ); +} + +function encodeChunk(uint8: Uint8Array, start: number, end: number): string { + var tmp; + var output = []; + for (var i = start; i < end; i += 3) { + tmp = + ((uint8[i] << 16) & 0xff0000) + + ((uint8[i + 1] << 8) & 0xff00) + + (uint8[i + 2] & 0xff); + output.push(tripletToBase64(tmp)); + } + return output.join(""); +} + +export function fromByteArray(uint8: Uint8Array): string { + var tmp; + var len = uint8.length; + var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes + var parts = []; + var maxChunkLength = 16383; // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push( + encodeChunk( + uint8, + i, + i + maxChunkLength > len2 ? len2 : i + maxChunkLength + ) + ); + } + + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1]; + parts.push(lookup[tmp >> 2] + lookup[(tmp << 4) & 0x3f] + "=="); + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + uint8[len - 1]; + parts.push( + lookup[tmp >> 10] + + lookup[(tmp >> 4) & 0x3f] + + lookup[(tmp << 2) & 0x3f] + + "=" + ); + } + + return parts.join(""); +} diff --git a/js/body.ts b/js/body.ts index fdf7fef062dd3b..b1f1af8a57b74c 100644 --- a/js/body.ts +++ b/js/body.ts @@ -1,27 +1,17 @@ -import * as streams from "@stardazed/streams"; import * as formData from "./form_data"; import * as blob from "./blob"; import * as encoding from "./text_encoding"; import * as headers from "./headers"; - import * as domTypes from "./dom_types"; const { Headers } = headers; // only namespace imports work for now, plucking out what we need -const { ReadableStream } = streams; const { FormData } = formData; const { TextEncoder, TextDecoder } = encoding; const Blob = blob.DenoBlob; const DenoBlob = blob.DenoBlob; -type ReadableStreamReader = domTypes.ReadableStreamReader; - -interface ReadableStreamController { - enqueue(chunk: string | ArrayBuffer): void; - close(): void; -} - export type BodySource = | domTypes.Blob | domTypes.BufferSource @@ -47,8 +37,6 @@ function validateBodyType(owner: Body, bodySource: BodySource): boolean { return true; } else if (typeof bodySource === "string") { return true; - } else if (bodySource instanceof ReadableStream) { - return true; } else if (bodySource instanceof FormData) { return true; } else if (!bodySource) { @@ -59,58 +47,6 @@ function validateBodyType(owner: Body, bodySource: BodySource): boolean { ); } -function concatenate(...arrays: Uint8Array[]): ArrayBuffer { - let totalLength = 0; - for (const arr of arrays) { - totalLength += arr.length; - } - const result = new Uint8Array(totalLength); - let offset = 0; - for (const arr of arrays) { - result.set(arr, offset); - offset += arr.length; - } - return result.buffer as ArrayBuffer; -} - -function bufferFromStream(stream: ReadableStreamReader): Promise { - return new Promise( - (resolve, reject): void => { - const parts: Uint8Array[] = []; - const encoder = new TextEncoder(); - // recurse - (function pump(): void { - stream - .read() - .then( - ({ done, value }): void => { - if (done) { - return resolve(concatenate(...parts)); - } - - if (typeof value === "string") { - parts.push(encoder.encode(value)); - } else if (value instanceof ArrayBuffer) { - parts.push(new Uint8Array(value)); - } else if (!value) { - // noop for undefined - } else { - reject("unhandled type on stream read"); - } - - return pump(); - } - ) - .catch( - (err): void => { - reject(err); - } - ); - })(); - } - ); -} - function getHeaderValueParams(value: string): Map { const params = new Map(); // Forced to do so for some Map constructor param mismatch @@ -145,17 +81,8 @@ export class Body implements domTypes.Body { if (this._stream) { return this._stream; } - if (this._bodySource instanceof ReadableStream) { - // @ts-ignore - this._stream = this._bodySource; - } if (typeof this._bodySource === "string") { - this._stream = new ReadableStream({ - start(controller: ReadableStreamController): void { - controller.enqueue(this._bodySource); - controller.close(); - } - }); + throw Error("not implemented"); } return this._stream; } @@ -332,9 +259,6 @@ export class Body implements domTypes.Body { } else if (typeof this._bodySource === "string") { const enc = new TextEncoder(); return enc.encode(this._bodySource).buffer as ArrayBuffer; - } else if (this._bodySource instanceof ReadableStream) { - // @ts-ignore - return bufferFromStream(this._bodySource.getReader()); } else if (this._bodySource instanceof FormData) { const enc = new TextEncoder(); return enc.encode(this._bodySource.toString()).buffer as ArrayBuffer; diff --git a/js/request.ts b/js/request.ts index 97bb8944b7f683..5ed1e9d634cfc3 100644 --- a/js/request.ts +++ b/js/request.ts @@ -1,13 +1,9 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. import * as headers from "./headers"; import * as body from "./body"; - -import * as streams from "@stardazed/streams"; - import * as domTypes from "./dom_types"; const { Headers } = headers; -const { ReadableStream } = streams; function byteUpperCase(s: string): string { return String(s).replace(/[a-z]/g, function byteUpperCaseReplace(c): string { @@ -144,11 +140,6 @@ export class Request extends body.Body implements domTypes.Request { let body2 = this._bodySource; - if (this._bodySource instanceof ReadableStream) { - const tees = (this._bodySource as domTypes.ReadableStream).tee(); - this._stream = this._bodySource = tees[0]; - body2 = tees[1]; - } const cloned = new Request(this.url, { body: body2, method: this.method, diff --git a/js/request_test.ts b/js/request_test.ts index 7421544fe690ec..e9e1f5164c6a21 100644 --- a/js/request_test.ts +++ b/js/request_test.ts @@ -1,5 +1,5 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -import { test, assertEquals, assert } from "./test_util.ts"; +import { test, assertEquals } from "./test_util.ts"; test(function fromInit(): void { const req = new Request("https://example.com", { @@ -15,35 +15,3 @@ test(function fromInit(): void { assertEquals(req.url, "https://example.com"); assertEquals(req.headers.get("test-header"), "value"); }); - -test(function fromRequest(): void { - const r = new Request("https://example.com"); - // @ts-ignore - r._bodySource = "ahoyhoy"; - r.headers.set("test-header", "value"); - - const req = new Request(r); - - // @ts-ignore - assertEquals(req._bodySource, r._bodySource); - assertEquals(req.url, r.url); - assertEquals(req.headers.get("test-header"), r.headers.get("test-header")); -}); - -test(async function cloneRequestBodyStream(): Promise { - // hack to get a stream - const stream = new Request("", { body: "a test body" }).body; - const r1 = new Request("https://example.com", { - body: stream - }); - - const r2 = r1.clone(); - - const b1 = await r1.text(); - const b2 = await r2.text(); - - assertEquals(b1, b2); - - // @ts-ignore - assert(r1._bodySource !== r2._bodySource); -}); diff --git a/js/text_encoding.ts b/js/text_encoding.ts index 025a17f4f5e5d5..830b4278e030b4 100644 --- a/js/text_encoding.ts +++ b/js/text_encoding.ts @@ -23,7 +23,7 @@ // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. -import * as base64 from "base64-js"; +import * as base64 from "./base64"; import * as domTypes from "./dom_types"; import { DenoError, ErrorKind } from "./errors"; diff --git a/package.json b/package.json index 7d11915b47f3d5..23e4c8f4e28ef7 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,9 @@ { "name": "deno", "devDependencies": { - "@stardazed/streams": "3.0.0", - "@types/base64-js": "1.2.5", "@types/prettier": "1.16.1", "@typescript-eslint/eslint-plugin": "1.6.0", "@typescript-eslint/parser": "1.6.0", - "base64-js": "1.3.0", "eslint": "5.15.1", "eslint-config-prettier": "4.1.0", "magic-string": "0.25.2", diff --git a/third_party b/third_party index a338942cea812a..47a8f150bcbe3b 160000 --- a/third_party +++ b/third_party @@ -1 +1 @@ -Subproject commit a338942cea812ab197ef0abaafd312ef28a3ff14 +Subproject commit 47a8f150bcbe3b78f174ae79dcc07a12adb0d5b5