summaryrefslogtreecommitdiff
path: root/tests/specs/run/tls_starttls
diff options
context:
space:
mode:
Diffstat (limited to 'tests/specs/run/tls_starttls')
-rw-r--r--tests/specs/run/tls_starttls/RootCA.pem19
-rw-r--r--tests/specs/run/tls_starttls/__test__.jsonc4
-rw-r--r--tests/specs/run/tls_starttls/deno.json4
-rw-r--r--tests/specs/run/tls_starttls/localhost.crt21
-rw-r--r--tests/specs/run/tls_starttls/localhost.key28
-rw-r--r--tests/specs/run/tls_starttls/textproto.ts170
-rw-r--r--tests/specs/run/tls_starttls/tls.out1
-rw-r--r--tests/specs/run/tls_starttls/tls_starttls.js64
8 files changed, 311 insertions, 0 deletions
diff --git a/tests/specs/run/tls_starttls/RootCA.pem b/tests/specs/run/tls_starttls/RootCA.pem
new file mode 100644
index 000000000..c2f84ceeb
--- /dev/null
+++ b/tests/specs/run/tls_starttls/RootCA.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDIzCCAgugAwIBAgIJAMKPPW4tsOymMA0GCSqGSIb3DQEBCwUAMCcxCzAJBgNV
+BAYTAlVTMRgwFgYDVQQDDA9FeGFtcGxlLVJvb3QtQ0EwIBcNMTkxMDIxMTYyODIy
+WhgPMjExODA5MjcxNjI4MjJaMCcxCzAJBgNVBAYTAlVTMRgwFgYDVQQDDA9FeGFt
+cGxlLVJvb3QtQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMH/IO
+2qtHfyBKwANNPB4K0q5JVSg8XxZdRpTTlz0CwU0oRO3uHrI52raCCfVeiQutyZop
+eFZTDWeXGudGAFA2B5m3orWt0s+touPi8MzjsG2TQ+WSI66QgbXTNDitDDBtTVcV
+5G3Ic+3SppQAYiHSekLISnYWgXLl+k5CnEfTowg6cjqjVr0KjL03cTN3H7b+6+0S
+ws4rYbW1j4ExR7K6BFNH6572yq5qR20E6GqlY+EcOZpw4CbCk9lS8/CWuXze/vMs
+OfDcc6K+B625d27wyEGZHedBomT2vAD7sBjvO8hn/DP1Qb46a8uCHR6NSfnJ7bXO
+G1igaIbgY1zXirNdAgMBAAGjUDBOMB0GA1UdDgQWBBTzut+pwwDfqmMYcI9KNWRD
+hxcIpTAfBgNVHSMEGDAWgBTzut+pwwDfqmMYcI9KNWRDhxcIpTAMBgNVHRMEBTAD
+AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB9AqSbZ+hEglAgSHxAMCqRFdhVu7MvaQM0
+P090mhGlOCt3yB7kdGfsIrUW6nQcTz7PPQFRaJMrFHPvFvPootkBUpTYR4hTkdce
+H6RCRu2Jxl4Y9bY/uezd9YhGCYfUtfjA6/TH9FcuZfttmOOlxOt01XfNvVMIR6RM
+z/AYhd+DeOXjr35F/VHeVpnk+55L0PYJsm1CdEbOs5Hy1ecR7ACuDkXnbM4fpz9I
+kyIWJwk2zJReKcJMgi1aIinDM9ao/dca1G99PHOw8dnr4oyoTiv8ao6PWiSRHHMi
+MNf4EgWfK+tZMnuqfpfO9740KzfcVoMNo4QJD4yn5YxroUOO/Azi
+-----END CERTIFICATE-----
diff --git a/tests/specs/run/tls_starttls/__test__.jsonc b/tests/specs/run/tls_starttls/__test__.jsonc
new file mode 100644
index 000000000..4c1fe6324
--- /dev/null
+++ b/tests/specs/run/tls_starttls/__test__.jsonc
@@ -0,0 +1,4 @@
+{
+ "args": "run --quiet --reload --allow-net --allow-read --cert RootCA.pem --config deno.json tls_starttls.js",
+ "output": "tls.out"
+}
diff --git a/tests/specs/run/tls_starttls/deno.json b/tests/specs/run/tls_starttls/deno.json
new file mode 100644
index 000000000..105514e13
--- /dev/null
+++ b/tests/specs/run/tls_starttls/deno.json
@@ -0,0 +1,4 @@
+{
+ "lock": false,
+ "importMap": "../../../../import_map.json"
+}
diff --git a/tests/specs/run/tls_starttls/localhost.crt b/tests/specs/run/tls_starttls/localhost.crt
new file mode 100644
index 000000000..a71ae9050
--- /dev/null
+++ b/tests/specs/run/tls_starttls/localhost.crt
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDajCCAlKgAwIBAgIJAOPyQVdy/UpPMA0GCSqGSIb3DQEBCwUAMCcxCzAJBgNV
+BAYTAlVTMRgwFgYDVQQDDA9FeGFtcGxlLVJvb3QtQ0EwIBcNMTkxMDIxMTYyODU4
+WhgPMjExODA5MjcxNjI4NThaMG0xCzAJBgNVBAYTAlVTMRIwEAYDVQQIDAlZb3Vy
+U3RhdGUxETAPBgNVBAcMCFlvdXJDaXR5MR0wGwYDVQQKDBRFeGFtcGxlLUNlcnRp
+ZmljYXRlczEYMBYGA1UEAwwPbG9jYWxob3N0LmxvY2FsMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAz9svjVdf5jihUBtofd84XKdb8dEHQRJfDNKaJ4Ar
+baqMHAdnqi/fWtlqEEMn8gweZ7+4hshECY5mnx4Hhy7IAbePDsTTbSm01dChhlxF
+uvd9QuvzvrqSjSq+v4Jlau+pQIhUzzV12dF5bFvrIrGWxCZp+W7lLDZI6Pd6Su+y
+ZIeiwrUaPMzdUePNf2hZI/IvWCUMCIyoqrrKHdHoPuvQCW17IyxsnFQJNbmN+Rtp
+BQilhtwvBbggCBWhHxEdiqBaZHDw6Zl+bU7ejx1mu9A95wpQ9SCL2cRkAlz2LDOy
+wznrTAwGcvqvFKxlV+3HsaD7rba4kCA1Ihp5mm/dS2k94QIDAQABo1EwTzAfBgNV
+HSMEGDAWgBTzut+pwwDfqmMYcI9KNWRDhxcIpTAJBgNVHRMEAjAAMAsGA1UdDwQE
+AwIE8DAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAKVu
+vVpu5nPGAGn1SX4FQUcbn9Z5wgBkjnZxfJHJQX4sYIRlcirZviPHCZGPWex4VHC+
+lFMm+70YEN2uoe5jGrdgcugzx2Amc7/mLrsvvpMsaS0PlxNMcqhdM1WHbGjjdNln
+XICVITSKnB1fSGH6uo9CMCWw5kgPS9o4QWrLLkxnds3hoz7gVEUyi/6V65mcfFNA
+lof9iKcK9JsSHdBs35vpv7UKLX+96RM7Nm2Mu0yue5JiS79/zuMA/Kryxot4jv5z
+ecdWFl0eIyQBZmBzMw2zPUqkxEnXLiKjV8jutEg/4qovTOB6YiA41qbARXdzNA2V
+FYuchcTcWmnmVVRFyyU=
+-----END CERTIFICATE-----
diff --git a/tests/specs/run/tls_starttls/localhost.key b/tests/specs/run/tls_starttls/localhost.key
new file mode 100644
index 000000000..42774c977
--- /dev/null
+++ b/tests/specs/run/tls_starttls/localhost.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDP2y+NV1/mOKFQ
+G2h93zhcp1vx0QdBEl8M0pongCttqowcB2eqL99a2WoQQyfyDB5nv7iGyEQJjmaf
+HgeHLsgBt48OxNNtKbTV0KGGXEW6931C6/O+upKNKr6/gmVq76lAiFTPNXXZ0Xls
+W+sisZbEJmn5buUsNkjo93pK77Jkh6LCtRo8zN1R481/aFkj8i9YJQwIjKiqusod
+0eg+69AJbXsjLGycVAk1uY35G2kFCKWG3C8FuCAIFaEfER2KoFpkcPDpmX5tTt6P
+HWa70D3nClD1IIvZxGQCXPYsM7LDOetMDAZy+q8UrGVX7cexoPuttriQIDUiGnma
+b91LaT3hAgMBAAECggEBAJABfn+BQorBP1m9s3ZJmcXvmW7+7/SwYrQCkRS+4te2
+6h1dMAAj7K4HpUkhDeLPbJ1aoeCXjTPFuemRp4uL6Lvvzahgy059L7FXOyFYemMf
+pmQgDx5cKr6tF7yc/eDJrExuZ7urgTvouiRNxqmhuh+psZBDuXkZHwhwtQSH7uNg
+KBDKu0qWO73vFLcLckdGEU3+H9oIWs5xcvvOkWzyvHbRGFJSihgcRpPPHodF5xB9
+T/gZIoJHMmCbUMlWaSasUyNXTuvCnkvBDol8vXrMJCVzKZj9GpPDcIFdc08GSn4I
+pTdSNwzUcHbdERzdVU28Xt+t6W5rvp/4FWrssi4IzkUCgYEA//ZcEcBguRD4OFrx
+6wbSjzCcUW1NWhzA8uTOORZi4SvndcH1cU4S2wznuHNubU1XlrGwJX6PUGebmY/l
+53B5PJvStbVtZCVIxllR+ZVzRuL8wLodRHzlYH8GOzHwoa4ivSupkzl72ij1u/tI
+NMLGfYEKVdNd8zXIESUY88NszvsCgYEAz+MDp3xOhFaCe+CPv80A592cJcfzc8Al
++rahEOu+VdN2QBZf86PIf2Bfv/t0QvnRvs1z648TuH6h83YSggOAbmfHyd789jkq
+UWlktIaXbVn+VaHmPTcBWTg3ZTlvG+fiFCbZXiYhm+UUf1MDqZHdiifAoyVIjV/Z
+YhCNJo3q39MCgYEAknrpK5t9fstwUcfyA/9OhnVaL9suVjB4V0iLn+3ovlXCywgp
+ryLv9X3IKi2c9144jtu3I23vFCOGz3WjKzSZnQ7LogNmy9XudNxu5jcZ1mpWHPEl
+iKk1F2j6Juwoek5OQRX4oHFYKHwiTOa75r3Em9Q6Fu20KVgQ24bwZafj3/sCgYAy
+k0AoVw2jFIjaKl/Ogclen4OFjYek+XJD9Hpq62964d866Dafx5DXrFKfGkXGpZBp
+owI4pK5fjC9KU8dc6g0szwLEEgPowy+QbtuZL8VXTTWbD7A75E3nrs2LStXFLDzM
+OkdXqF801h6Oe1vAvUPwgItVJZTpEBCK0wwD/TLPEQKBgQDRkhlTtAoHW7W6STd0
+A/OWc0dxhzMurpxg0bLgCqUjw1ESGrSCGhffFn0IWa8sv19VWsZuBhTgjNatZsYB
+AhDs/6OosT/3nJoh2/t0hYDj1FBI0lPXWYD4pesuZ5yIMrmSaAOtIzp4BGY7ui8N
+wOqcq/jdiHj/MKEdqOXy3YAJrA==
+-----END PRIVATE KEY-----
diff --git a/tests/specs/run/tls_starttls/textproto.ts b/tests/specs/run/tls_starttls/textproto.ts
new file mode 100644
index 000000000..9e0f5f5f0
--- /dev/null
+++ b/tests/specs/run/tls_starttls/textproto.ts
@@ -0,0 +1,170 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/** **Deprecated**. Use `TextLineStream` from `std/steams` for line-by-line text reading instead.
+ *
+ * A reader for dealing with low level text based protocols.
+ *
+ * Based on
+ * [net/textproto](https://github.com/golang/go/tree/master/src/net/textproto).
+ *
+ * @deprecated (will be removed after 0.159.0) Use `TextLineStream` from `std/steams` for line-by-line text reading instead.
+ * @module
+ */
+
+import type { BufReader, ReadLineResult } from "@std/io/buf-reader";
+import { concat } from "@std/bytes/concat";
+
+// Constants created for DRY
+const CHAR_SPACE: number = " ".charCodeAt(0);
+const CHAR_TAB: number = "\t".charCodeAt(0);
+const CHAR_COLON: number = ":".charCodeAt(0);
+
+const WHITESPACES: Array<number> = [CHAR_SPACE, CHAR_TAB];
+
+const decoder = new TextDecoder();
+
+// FROM https://github.com/denoland/deno/blob/b34628a26ab0187a827aa4ebe256e23178e25d39/cli/js/web/headers.ts#L9
+const invalidHeaderCharRegex = /[^\t\x20-\x7e\x80-\xff]/g;
+
+function str(buf: Uint8Array | null | undefined): string {
+ return !buf ? "" : decoder.decode(buf);
+}
+
+/**
+ * @deprecated (will be removed after 0.159.0) Use `TextLineStream` from `std/steams` for line-by-line text reading instead.
+ */
+export class TextProtoReader {
+ constructor(readonly r: BufReader) {}
+
+ /** readLine() reads a single line from the TextProtoReader,
+ * eliding the final \n or \r\n from the returned string.
+ */
+ async readLine(): Promise<string | null> {
+ const s = await this.readLineSlice();
+ return s === null ? null : str(s);
+ }
+
+ /** ReadMimeHeader reads a MIME-style header from r.
+ * The header is a sequence of possibly continued Key: Value lines
+ * ending in a blank line.
+ * The returned map m maps CanonicalMIMEHeaderKey(key) to a
+ * sequence of values in the same order encountered in the input.
+ *
+ * For example, consider this input:
+ *
+ * My-Key: Value 1
+ * Long-Key: Even
+ * Longer Value
+ * My-Key: Value 2
+ *
+ * Given that input, ReadMIMEHeader returns the map:
+ *
+ * map[string][]string{
+ * "My-Key": {"Value 1", "Value 2"},
+ * "Long-Key": {"Even Longer Value"},
+ * }
+ */
+ async readMimeHeader(): Promise<Headers | null> {
+ const m = new Headers();
+ let line: Uint8Array | undefined;
+
+ // The first line cannot start with a leading space.
+ let buf = await this.r.peek(1);
+ if (buf === null) {
+ return null;
+ } else if (WHITESPACES.includes(buf[0])) {
+ line = (await this.readLineSlice()) as Uint8Array;
+ }
+
+ buf = await this.r.peek(1);
+ if (buf === null) {
+ throw new Deno.errors.UnexpectedEof();
+ } else if (WHITESPACES.includes(buf[0])) {
+ throw new Deno.errors.InvalidData(
+ `malformed MIME header initial line: ${str(line)}`,
+ );
+ }
+
+ while (true) {
+ const kv = await this.readLineSlice(); // readContinuedLineSlice
+ if (kv === null) throw new Deno.errors.UnexpectedEof();
+ if (kv.byteLength === 0) return m;
+
+ // Key ends at first colon
+ let i = kv.indexOf(CHAR_COLON);
+ if (i < 0) {
+ throw new Deno.errors.InvalidData(
+ `malformed MIME header line: ${str(kv)}`,
+ );
+ }
+
+ //let key = canonicalMIMEHeaderKey(kv.subarray(0, endKey));
+ const key = str(kv.subarray(0, i));
+
+ // As per RFC 7230 field-name is a token,
+ // tokens consist of one or more chars.
+ // We could throw `Deno.errors.InvalidData` here,
+ // but better to be liberal in what we
+ // accept, so if we get an empty key, skip it.
+ if (key == "") {
+ continue;
+ }
+
+ // Skip initial spaces in value.
+ i++; // skip colon
+ while (
+ i < kv.byteLength &&
+ (WHITESPACES.includes(kv[i]))
+ ) {
+ i++;
+ }
+ const value = str(kv.subarray(i)).replace(
+ invalidHeaderCharRegex,
+ encodeURI,
+ );
+
+ // In case of invalid header we swallow the error
+ // example: "Audio Mode" => invalid due to space in the key
+ try {
+ m.append(key, value);
+ } catch {
+ // Pass
+ }
+ }
+ }
+
+ async readLineSlice(): Promise<Uint8Array | null> {
+ let line = new Uint8Array(0);
+ let r: ReadLineResult | null = null;
+
+ do {
+ r = await this.r.readLine();
+ // TODO(ry):
+ // This skipSpace() is definitely misplaced, but I don't know where it
+ // comes from nor how to fix it.
+
+ //TODO(SmashingQuasar): Kept skipSpace to preserve behavior but it should be looked into to check if it makes sense when this is used.
+
+ if (r !== null && this.skipSpace(r.line) !== 0) {
+ line = concat([line, r.line]);
+ }
+ } while (r !== null && r.more);
+
+ return r === null ? null : line;
+ }
+
+ skipSpace(l: Uint8Array): number {
+ let n = 0;
+
+ for (const val of l) {
+ if (!WHITESPACES.includes(val)) {
+ n++;
+ }
+ }
+
+ return n;
+ }
+}
diff --git a/tests/specs/run/tls_starttls/tls.out b/tests/specs/run/tls_starttls/tls.out
new file mode 100644
index 000000000..c8e8a135c
--- /dev/null
+++ b/tests/specs/run/tls_starttls/tls.out
@@ -0,0 +1 @@
+DONE
diff --git a/tests/specs/run/tls_starttls/tls_starttls.js b/tests/specs/run/tls_starttls/tls_starttls.js
new file mode 100644
index 000000000..cd5718ff5
--- /dev/null
+++ b/tests/specs/run/tls_starttls/tls_starttls.js
@@ -0,0 +1,64 @@
+import { assert, assertEquals } from "@std/assert";
+import { BufReader } from "@std/io/buf-reader";
+import { BufWriter } from "@std/io/buf-writer";
+import { TextProtoReader } from "./textproto.ts";
+
+const encoder = new TextEncoder();
+const decoder = new TextDecoder();
+
+const { promise, resolve } = Promise.withResolvers();
+const hostname = "localhost";
+const port = 3504;
+
+const listener = Deno.listenTls({
+ hostname,
+ port,
+ cert: Deno.readTextFileSync("./localhost.crt"),
+ key: Deno.readTextFileSync("./localhost.key"),
+});
+
+const response = encoder.encode(
+ "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n",
+);
+
+listener.accept().then(
+ async (conn) => {
+ assert(conn.remoteAddr != null);
+ assert(conn.localAddr != null);
+ await conn.write(response);
+ // TODO(bartlomieju): this might be a bug
+ setTimeout(() => {
+ conn.close();
+ resolve();
+ }, 0);
+ },
+);
+
+let conn = await Deno.connect({ hostname, port });
+conn = await Deno.startTls(conn, { hostname });
+const w = new BufWriter(conn);
+const r = new BufReader(conn);
+const body = `GET / HTTP/1.1\r\nHost: ${hostname}:${port}\r\n\r\n`;
+const writeResult = await w.write(encoder.encode(body));
+assertEquals(body.length, writeResult);
+await w.flush();
+const tpr = new TextProtoReader(r);
+const statusLine = await tpr.readLine();
+assert(statusLine !== null, `line must be read: ${String(statusLine)}`);
+const m = statusLine.match(/^(.+?) (.+?) (.+?)$/);
+assert(m !== null, "must be matched");
+const [_, proto, status, ok] = m;
+assertEquals(proto, "HTTP/1.1");
+assertEquals(status, "200");
+assertEquals(ok, "OK");
+const headers = await tpr.readMimeHeader();
+assert(headers !== null);
+const contentLength = parseInt(headers.get("content-length"));
+const bodyBuf = new Uint8Array(contentLength);
+await r.readFull(bodyBuf);
+assertEquals(decoder.decode(bodyBuf), "Hello World\n");
+conn.close();
+listener.close();
+await promise;
+
+console.log("DONE");