summaryrefslogtreecommitdiff
path: root/ext/http/01_http.js
diff options
context:
space:
mode:
authorMatt Mastracci <matthew@mastracci.com>2024-04-19 20:02:39 -0600
committerGitHub <noreply@github.com>2024-04-19 20:02:39 -0600
commit9425dce6dbc3a10bbde963d7a6192884c47185a5 (patch)
tree0dd4aeaf3dc3e5403095a5e37750a09adb3599a8 /ext/http/01_http.js
parent79e6751cf753612f99438ee2f158f54a1bf44815 (diff)
refactor(ext/http): extract 02_websocket.ts from 01_http.js (#23460)
Landing part of https://github.com/denoland/deno/pull/21903 This will allow us to more easily refactor `serveHttp` to live on top of `serve` by splitting the websocket code out. There's probably a lot more we could do here but this helps.
Diffstat (limited to 'ext/http/01_http.js')
-rw-r--r--ext/http/01_http.js167
1 files changed, 3 insertions, 164 deletions
diff --git a/ext/http/01_http.js b/ext/http/01_http.js
index b41c36446..580ba1166 100644
--- a/ext/http/01_http.js
+++ b/ext/http/01_http.js
@@ -12,45 +12,34 @@ import {
op_http_shutdown,
op_http_start,
op_http_upgrade_websocket,
- op_http_websocket_accept_header,
op_http_write,
op_http_write_headers,
op_http_write_resource,
} from "ext:core/ops";
const {
- ArrayPrototypeIncludes,
- ArrayPrototypeMap,
- ArrayPrototypePush,
ObjectPrototypeIsPrototypeOf,
SafeSet,
SafeSetIterator,
SetPrototypeAdd,
SetPrototypeDelete,
- StringPrototypeCharCodeAt,
StringPrototypeIncludes,
- StringPrototypeSplit,
- StringPrototypeToLowerCase,
- StringPrototypeToUpperCase,
Symbol,
SymbolAsyncIterator,
TypeError,
TypedArrayPrototypeGetSymbolToStringTag,
Uint8Array,
} = primordials;
-
+import { _ws } from "ext:deno_http/02_websocket.ts";
import { InnerBody } from "ext:deno_fetch/22_body.js";
-import { Event, setEventTargetData } from "ext:deno_web/02_event.js";
+import { Event } from "ext:deno_web/02_event.js";
import { BlobPrototype } from "ext:deno_web/09_file.js";
import {
- fromInnerResponse,
- newInnerResponse,
ResponsePrototype,
toInnerResponse,
} from "ext:deno_fetch/23_response.js";
import {
fromInnerRequest,
newInnerRequest,
- toInnerRequest,
} from "ext:deno_fetch/23_request.js";
import { AbortController } from "ext:deno_web/03_abort_signal.js";
import {
@@ -63,7 +52,6 @@ import {
_role,
_server,
_serverHandleIdleTimeout,
- createWebSocketBranded,
SERVER,
WebSocket,
} from "ext:deno_websocket/01_websocket.js";
@@ -409,155 +397,6 @@ function createRespondWith(
};
}
-const _ws = Symbol("[[associated_ws]]");
-const websocketCvf = buildCaseInsensitiveCommaValueFinder("websocket");
-const upgradeCvf = buildCaseInsensitiveCommaValueFinder("upgrade");
-
-function upgradeWebSocket(request, options = {}) {
- const inner = toInnerRequest(request);
- const upgrade = request.headers.get("upgrade");
- const upgradeHasWebSocketOption = upgrade !== null &&
- websocketCvf(upgrade);
- if (!upgradeHasWebSocketOption) {
- throw new TypeError(
- "Invalid Header: 'upgrade' header must contain 'websocket'",
- );
- }
-
- const connection = request.headers.get("connection");
- const connectionHasUpgradeOption = connection !== null &&
- upgradeCvf(connection);
- if (!connectionHasUpgradeOption) {
- throw new TypeError(
- "Invalid Header: 'connection' header must contain 'Upgrade'",
- );
- }
-
- const websocketKey = request.headers.get("sec-websocket-key");
- if (websocketKey === null) {
- throw new TypeError(
- "Invalid Header: 'sec-websocket-key' header must be set",
- );
- }
-
- const accept = op_http_websocket_accept_header(websocketKey);
-
- const r = newInnerResponse(101);
- r.headerList = [
- ["upgrade", "websocket"],
- ["connection", "Upgrade"],
- ["sec-websocket-accept", accept],
- ];
-
- const protocolsStr = request.headers.get("sec-websocket-protocol") || "";
- const protocols = StringPrototypeSplit(protocolsStr, ", ");
- if (protocols && options.protocol) {
- if (ArrayPrototypeIncludes(protocols, options.protocol)) {
- ArrayPrototypePush(r.headerList, [
- "sec-websocket-protocol",
- options.protocol,
- ]);
- } else {
- throw new TypeError(
- `Protocol '${options.protocol}' not in the request's protocol list (non negotiable)`,
- );
- }
- }
-
- const socket = createWebSocketBranded(WebSocket);
- setEventTargetData(socket);
- socket[_server] = true;
- socket[_idleTimeoutDuration] = options.idleTimeout ?? 120;
- socket[_idleTimeoutTimeout] = null;
-
- if (inner._wantsUpgrade) {
- return inner._wantsUpgrade("upgradeWebSocket", r, socket);
- }
-
- const response = fromInnerResponse(r, "immutable");
-
- response[_ws] = socket;
-
- return { response, socket };
-}
-
-const spaceCharCode = StringPrototypeCharCodeAt(" ", 0);
-const tabCharCode = StringPrototypeCharCodeAt("\t", 0);
-const commaCharCode = StringPrototypeCharCodeAt(",", 0);
-
-/** Builds a case function that can be used to find a case insensitive
- * value in some text that's separated by commas.
- *
- * This is done because it doesn't require any allocations.
- * @param checkText {string} - The text to find. (ex. "websocket")
- */
-function buildCaseInsensitiveCommaValueFinder(checkText) {
- const charCodes = ArrayPrototypeMap(
- StringPrototypeSplit(
- StringPrototypeToLowerCase(checkText),
- "",
- ),
- (c) => [
- StringPrototypeCharCodeAt(c, 0),
- StringPrototypeCharCodeAt(StringPrototypeToUpperCase(c), 0),
- ],
- );
- /** @type {number} */
- let i;
- /** @type {number} */
- let char;
-
- /** @param {string} value */
- return function (value) {
- for (i = 0; i < value.length; i++) {
- char = StringPrototypeCharCodeAt(value, i);
- skipWhitespace(value);
-
- if (hasWord(value)) {
- skipWhitespace(value);
- if (i === value.length || char === commaCharCode) {
- return true;
- }
- } else {
- skipUntilComma(value);
- }
- }
-
- return false;
- };
-
- /** @param value {string} */
- function hasWord(value) {
- for (let j = 0; j < charCodes.length; ++j) {
- const { 0: cLower, 1: cUpper } = charCodes[j];
- if (cLower === char || cUpper === char) {
- char = StringPrototypeCharCodeAt(value, ++i);
- } else {
- return false;
- }
- }
- return true;
- }
-
- /** @param value {string} */
- function skipWhitespace(value) {
- while (char === spaceCharCode || char === tabCharCode) {
- char = StringPrototypeCharCodeAt(value, ++i);
- }
- }
-
- /** @param value {string} */
- function skipUntilComma(value) {
- while (char !== commaCharCode && i < value.length) {
- char = StringPrototypeCharCodeAt(value, ++i);
- }
- }
-}
-
-// Expose this function for unit tests
-internals.buildCaseInsensitiveCommaValueFinder =
- buildCaseInsensitiveCommaValueFinder;
-
function serveHttp(conn) {
internals.warnOnDeprecatedApi(
"Deno.serveHttp()",
@@ -568,4 +407,4 @@ function serveHttp(conn) {
return new HttpConn(rid, conn.remoteAddr, conn.localAddr);
}
-export { _ws, HttpConn, serveHttp, upgradeWebSocket };
+export { HttpConn, serveHttp };