diff options
| author | Bert Belder <bertbelder@gmail.com> | 2019-05-23 19:04:06 -0700 |
|---|---|---|
| committer | Bert Belder <bertbelder@gmail.com> | 2019-05-29 09:50:12 -0700 |
| commit | b95f79d74cbcf3492abd95d4c90839e32f51399f (patch) | |
| tree | d0c68f01c798da1e3b81930cfa58a5370c56775f /textproto | |
| parent | 5b37b560fb047e1df6e6f68fcbaece922637a93c (diff) | |
io: refactor BufReader/Writer interfaces to be more idiomatic (denoland/deno_std#444)
Thanks Vincent Le Goff (@zekth) for porting over the CSV reader
implementation.
Fixes: denoland/deno_std#436
Original: https://github.com/denoland/deno_std/commit/0ee6334b698072b50c6f5ac8d42d34dc4c94b948
Diffstat (limited to 'textproto')
| -rw-r--r-- | textproto/mod.ts | 58 | ||||
| -rw-r--r-- | textproto/reader_test.ts | 59 |
2 files changed, 59 insertions, 58 deletions
diff --git a/textproto/mod.ts b/textproto/mod.ts index 72ecd252f..66f303905 100644 --- a/textproto/mod.ts +++ b/textproto/mod.ts @@ -3,7 +3,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -import { BufReader, BufState } from "../io/bufio.ts"; +import { BufReader, EOF, UnexpectedEOFError } from "../io/bufio.ts"; import { charCode } from "../io/util.ts"; const asciiDecoder = new TextDecoder(); @@ -39,9 +39,10 @@ export class TextProtoReader { /** readLine() reads a single line from the TextProtoReader, * eliding the final \n or \r\n from the returned string. */ - async readLine(): Promise<[string, BufState]> { - let [line, err] = await this.readLineSlice(); - return [str(line), err]; + async readLine(): Promise<string | EOF> { + const s = await this.readLineSlice(); + if (s === EOF) return EOF; + return str(s); } /** ReadMIMEHeader reads a MIME-style header from r. @@ -64,29 +65,31 @@ export class TextProtoReader { * "Long-Key": {"Even Longer Value"}, * } */ - async readMIMEHeader(): Promise<[Headers, BufState]> { + async readMIMEHeader(): Promise<Headers | EOF> { let m = new Headers(); let line: Uint8Array; // The first line cannot start with a leading space. - let [buf, err] = await this.r.peek(1); - if (buf[0] == charCode(" ") || buf[0] == charCode("\t")) { - [line, err] = await this.readLineSlice(); + let buf = await this.r.peek(1); + if (buf === EOF) { + return EOF; + } else if (buf[0] == charCode(" ") || buf[0] == charCode("\t")) { + line = (await this.readLineSlice()) as Uint8Array; } - [buf, err] = await this.r.peek(1); - if (err == null && (buf[0] == charCode(" ") || buf[0] == charCode("\t"))) { + buf = await this.r.peek(1); + if (buf === EOF) { + throw new UnexpectedEOFError(); + } else if (buf[0] == charCode(" ") || buf[0] == charCode("\t")) { throw new ProtocolError( `malformed MIME header initial line: ${str(line)}` ); } while (true) { - let [kv, err] = await this.readLineSlice(); // readContinuedLineSlice - - if (kv.byteLength === 0) { - return [m, err]; - } + let kv = await this.readLineSlice(); // readContinuedLineSlice + if (kv === EOF) throw new UnexpectedEOFError(); + if (kv.byteLength === 0) return m; // Key ends at first colon; should not have trailing spaces // but they appear in the wild, violating specs, so we remove @@ -125,29 +128,26 @@ export class TextProtoReader { try { m.append(key, value); } catch {} - - if (err != null) { - throw err; - } } } - async readLineSlice(): Promise<[Uint8Array, BufState]> { + async readLineSlice(): Promise<Uint8Array | EOF> { // this.closeDot(); let line: Uint8Array; while (true) { - let [l, more, err] = await this.r.readLine(); - if (err != null) { - // Go's len(typed nil) works fine, but not in JS - return [new Uint8Array(0), err]; - } + const r = await this.r.readLine(); + if (r === EOF) return EOF; + const { line: l, more } = r; // Avoid the copy if the first call produced a full line. - if (line == null && !more) { + if (!line && !more) { + // TODO(ry): + // This skipSpace() is definitely misplaced, but I don't know where it + // comes from nor how to fix it. if (this.skipSpace(l) === 0) { - return [new Uint8Array(0), null]; + return new Uint8Array(0); } - return [l, null]; + return l; } line = append(line, l); @@ -155,7 +155,7 @@ export class TextProtoReader { break; } } - return [line, null]; + return line; } skipSpace(l: Uint8Array): number { diff --git a/textproto/reader_test.ts b/textproto/reader_test.ts index 2d054caba..bd0d39fd3 100644 --- a/textproto/reader_test.ts +++ b/textproto/reader_test.ts @@ -3,11 +3,21 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -import { BufReader } from "../io/bufio.ts"; +import { BufReader, EOF } from "../io/bufio.ts"; import { TextProtoReader, ProtocolError } from "./mod.ts"; import { stringsReader } from "../io/util.ts"; -import { assert, assertEquals, assertThrows } from "../testing/asserts.ts"; -import { test } from "../testing/mod.ts"; +import { + assert, + assertEquals, + assertNotEquals, + assertThrows +} from "../testing/asserts.ts"; +import { test, runIfMain } from "../testing/mod.ts"; + +function assertNotEOF<T extends {}>(val: T | EOF): T { + assertNotEquals(val, EOF); + return val as T; +} function reader(s: string): TextProtoReader { return new TextProtoReader(new BufReader(stringsReader(s))); @@ -21,25 +31,21 @@ function reader(s: string): TextProtoReader { // }); test(async function textprotoReadEmpty(): Promise<void> { - let r = reader(""); - let [, err] = await r.readMIMEHeader(); - // Should not crash! - assertEquals(err, "EOF"); + const r = reader(""); + const m = await r.readMIMEHeader(); + assertEquals(m, EOF); }); test(async function textprotoReader(): Promise<void> { - let r = reader("line1\nline2\n"); - let [s, err] = await r.readLine(); + const r = reader("line1\nline2\n"); + let s = await r.readLine(); assertEquals(s, "line1"); - assert(err == null); - [s, err] = await r.readLine(); + s = await r.readLine(); assertEquals(s, "line2"); - assert(err == null); - [s, err] = await r.readLine(); - assertEquals(s, ""); - assert(err == "EOF"); + s = await r.readLine(); + assert(s === EOF); }); test({ @@ -48,10 +54,9 @@ test({ const input = "my-key: Value 1 \r\nLong-key: Even Longer Value\r\nmy-Key: Value 2\r\n\n"; const r = reader(input); - const [m, err] = await r.readMIMEHeader(); + const m = assertNotEOF(await r.readMIMEHeader()); assertEquals(m.get("My-Key"), "Value 1, Value 2"); assertEquals(m.get("Long-key"), "Even Longer Value"); - assert(!err); } }); @@ -60,9 +65,8 @@ test({ async fn(): Promise<void> { const input = "Foo: bar\n\n"; const r = reader(input); - let [m, err] = await r.readMIMEHeader(); + const m = assertNotEOF(await r.readMIMEHeader()); assertEquals(m.get("Foo"), "bar"); - assert(!err); } }); @@ -71,9 +75,8 @@ test({ async fn(): Promise<void> { const input = ": bar\ntest-1: 1\n\n"; const r = reader(input); - let [m, err] = await r.readMIMEHeader(); + const m = assertNotEOF(await r.readMIMEHeader()); assertEquals(m.get("Test-1"), "1"); - assert(!err); } }); @@ -86,11 +89,9 @@ test({ data.push("x"); } const sdata = data.join(""); - const r = reader(`Cookie: ${sdata}\r\n`); - let [m] = await r.readMIMEHeader(); + const r = reader(`Cookie: ${sdata}\r\n\r\n`); + const m = assertNotEOF(await r.readMIMEHeader()); assertEquals(m.get("Cookie"), sdata); - // TODO re-enable, here err === "EOF" is has to be null - // assert(!err); } }); @@ -106,12 +107,11 @@ test({ "Audio Mode : None\r\n" + "Privilege : 127\r\n\r\n"; const r = reader(input); - let [m, err] = await r.readMIMEHeader(); + const m = assertNotEOF(await r.readMIMEHeader()); assertEquals(m.get("Foo"), "bar"); assertEquals(m.get("Content-Language"), "en"); assertEquals(m.get("SID"), "0"); assertEquals(m.get("Privilege"), "127"); - assert(!err); // Not a legal http header assertThrows( (): void => { @@ -176,9 +176,10 @@ test({ "------WebKitFormBoundaryimeZ2Le9LjohiUiG--\r\n\n" ]; const r = reader(input.join("")); - let [m, err] = await r.readMIMEHeader(); + const m = assertNotEOF(await r.readMIMEHeader()); assertEquals(m.get("Accept"), "*/*"); assertEquals(m.get("Content-Disposition"), 'form-data; name="test"'); - assert(!err); } }); + +runIfMain(import.meta); |
