1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-12 00:54:02 -05:00

BREAKING: Remove Deno.EOF, use null instead (#4953)

This commit is contained in:
Nayeem Rahman 2020-04-28 17:40:43 +01:00 committed by GitHub
parent 47c2f034e9
commit 678313b176
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 329 additions and 325 deletions

View file

@ -4,7 +4,7 @@
// Copyright 2009 The Go Authors. All rights reserved. BSD license.
// https://github.com/golang/go/blob/master/LICENSE
import { Reader, Writer, EOF, ReaderSync, WriterSync } from "./io.ts";
import { Reader, Writer, ReaderSync, WriterSync } from "./io.ts";
import { assert } from "./util.ts";
import { TextDecoder } from "./web/text_encoding.ts";
@ -91,7 +91,7 @@ export class Buffer implements Reader, ReaderSync, Writer, WriterSync {
this.#buf = new Uint8Array(this.#buf.buffer, 0, len);
};
readSync(p: Uint8Array): number | EOF {
readSync(p: Uint8Array): number | null {
if (this.empty()) {
// Buffer is empty, reset to recover space.
this.reset();
@ -99,14 +99,14 @@ export class Buffer implements Reader, ReaderSync, Writer, WriterSync {
// this edge case is tested in 'bufferReadEmptyAtEOF' test
return 0;
}
return EOF;
return null;
}
const nread = copyBytes(p, this.#buf.subarray(this.#off));
this.#off += nread;
return nread;
}
read(p: Uint8Array): Promise<number | EOF> {
read(p: Uint8Array): Promise<number | null> {
const rr = this.readSync(p);
return Promise.resolve(rr);
}
@ -169,7 +169,7 @@ export class Buffer implements Reader, ReaderSync, Writer, WriterSync {
this.#reslice(i);
const fub = new Uint8Array(this.#buf.buffer, i);
const nread = await r.read(fub);
if (nread === EOF) {
if (nread === null) {
return n;
}
this.#reslice(i + nread);
@ -188,7 +188,7 @@ export class Buffer implements Reader, ReaderSync, Writer, WriterSync {
this.#reslice(i);
const fub = new Uint8Array(this.#buf.buffer, i);
const nread = r.readSync(fub);
if (nread === EOF) {
if (nread === null) {
return n;
}
this.#reslice(i + nread);

View file

@ -40,7 +40,6 @@ export { read, readSync, write, writeSync } from "./ops/io.ts";
export { FsEvent, watchFs } from "./ops/fs_events.ts";
export { internalSymbol as internal } from "./internals.ts";
export {
EOF,
copy,
iter,
iterSync,

View file

@ -1,6 +1,5 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import {
EOF,
Reader,
Writer,
Seeker,
@ -76,11 +75,11 @@ export class File
return writeSync(this.rid, p);
}
read(p: Uint8Array): Promise<number | EOF> {
read(p: Uint8Array): Promise<number | null> {
return read(this.rid, p);
}
readSync(p: Uint8Array): number | EOF {
readSync(p: Uint8Array): number | null {
return readSync(this.rid, p);
}
@ -103,11 +102,11 @@ class Stdin implements Reader, ReaderSync, Closer {
this.rid = 0;
}
read(p: Uint8Array): Promise<number | EOF> {
read(p: Uint8Array): Promise<number | null> {
return read(this.rid, p);
}
readSync(p: Uint8Array): number | EOF {
readSync(p: Uint8Array): number | null {
return readSync(this.rid, p);
}

View file

@ -3,9 +3,6 @@
// Documentation liberally lifted from them too.
// Thank you! We love Go!
export const EOF: unique symbol = Symbol("EOF");
export type EOF = typeof EOF;
const DEFAULT_BUFFER_SIZE = 32 * 1024;
// Seek whence values.
@ -19,11 +16,11 @@ export enum SeekMode {
// Reader is the interface that wraps the basic read() method.
// https://golang.org/pkg/io/#Reader
export interface Reader {
read(p: Uint8Array): Promise<number | EOF>;
read(p: Uint8Array): Promise<number | null>;
}
export interface ReaderSync {
readSync(p: Uint8Array): number | EOF;
readSync(p: Uint8Array): number | null;
}
// Writer is the interface that wraps the basic write() method.
@ -65,7 +62,7 @@ export async function copy(
let gotEOF = false;
while (gotEOF === false) {
const result = await src.read(b);
if (result === EOF) {
if (result === null) {
gotEOF = true;
} else {
n += await dst.write(b.subarray(0, result));
@ -84,7 +81,7 @@ export async function* iter(
const b = new Uint8Array(bufSize);
while (true) {
const result = await r.read(b);
if (result === EOF) {
if (result === null) {
break;
}
@ -102,7 +99,7 @@ export function* iterSync(
const b = new Uint8Array(bufSize);
while (true) {
const result = r.readSync(b);
if (result === EOF) {
if (result === null) {
break;
}

View file

@ -361,10 +361,6 @@ declare namespace Deno {
*/
export function umask(mask?: number): number;
/** **UNSTABLE**: might be removed in favor of `null` (#3932). */
export const EOF: unique symbol;
export type EOF = typeof EOF;
export enum SeekMode {
Start = 0,
Current = 1,
@ -379,20 +375,21 @@ declare namespace Deno {
* available but not `p.byteLength` bytes, `read()` conventionally resolves
* to what is available instead of waiting for more.
*
* When `read()` encounters end-of-file condition, it resolves to
* `Deno.EOF` symbol.
* When `read()` encounters end-of-file condition, it resolves to EOF
* (`null`).
*
* When `read()` encounters an error, it rejects with an error.
*
* Callers should always process the `n` > `0` bytes returned before
* considering the `EOF`. Doing so correctly handles I/O errors that happen
* after reading some bytes and also both of the allowed EOF behaviors.
* considering the EOF (`null`). Doing so correctly handles I/O errors that
* happen after reading some bytes and also both of the allowed EOF
* behaviors.
*
* Implementations should not retain a reference to `p`.
*
* Use Deno.iter() to turn a Reader into an AsyncIterator.
*/
read(p: Uint8Array): Promise<number | EOF>;
read(p: Uint8Array): Promise<number | null>;
}
export interface ReaderSync {
@ -403,20 +400,20 @@ declare namespace Deno {
* but not `p.byteLength` bytes, `read()` conventionally returns what is
* available instead of waiting for more.
*
* When `readSync()` encounters end-of-file condition, it returns `Deno.EOF`
* symbol.
* When `readSync()` encounters end-of-file condition, it returns EOF
* (`null`).
*
* When `readSync()` encounters an error, it throws with an error.
*
* Callers should always process the `n` > `0` bytes returned before
* considering the `EOF`. Doing so correctly handles I/O errors that happen
* considering the EOF (`null`). Doing so correctly handles I/O errors that happen
* after reading some bytes and also both of the allowed EOF behaviors.
*
* Implementations should not retain a reference to `p`.
*
* Use Deno.iterSync() to turn a ReaderSync into an Iterator.
*/
readSync(p: Uint8Array): number | EOF;
readSync(p: Uint8Array): number | null;
}
export interface Writer {
@ -477,8 +474,8 @@ declare namespace Deno {
seekSync(offset: number, whence: SeekMode): number;
}
/** Copies from `src` to `dst` until either `EOF` is reached on `src` or an
* error occurs. It resolves to the number of bytes copied or rejects with
/** Copies from `src` to `dst` until either EOF (`null`) is read from `src` or
* an error occurs. It resolves to the number of bytes copied or rejects with
* the first error encountered while copying.
*
* const source = await Deno.open("my_file.txt");
@ -486,9 +483,6 @@ declare namespace Deno {
* const bytesCopied1 = await Deno.copy(source, Deno.stdout);
* const bytesCopied2 = await Deno.copy(source, buffer);
*
* Because `copy()` is defined to read from `src` until `EOF`, it does not
* treat an `EOF` from `read()` as an error to be reported.
*
* @param src The source to copy from
* @param dst The destination to copy to
* @param options Can be used to tune size of the buffer. Default size is 32kB
@ -611,8 +605,11 @@ declare namespace Deno {
/** Synchronously read from a resource ID (`rid`) into an array buffer (`buffer`).
*
* Returns either the number of bytes read during the operation or End Of File
* (`Symbol(EOF)`) if there was nothing to read.
* Returns either the number of bytes read during the operation or EOF
* (`null`) if there was nothing more to read.
*
* It is possible for a read to successfully return with `0` bytes. This does
* not indicate EOF.
*
* // if "/foo/bar.txt" contains the text "hello world":
* const file = Deno.openSync("/foo/bar.txt");
@ -621,12 +618,15 @@ declare namespace Deno {
* const text = new TextDecoder().decode(buf); // "hello world"
* Deno.close(file.rid);
*/
export function readSync(rid: number, buffer: Uint8Array): number | EOF;
export function readSync(rid: number, buffer: Uint8Array): number | null;
/** Read from a resource ID (`rid`) into an array buffer (`buffer`).
*
* Resolves to either the number of bytes read during the operation or End Of
* File (`Symbol(EOF)`) if there was nothing to read.
* Resolves to either the number of bytes read during the operation or EOF
* (`null`) if there was nothing more to read.
*
* It is possible for a read to successfully return with `0` bytes. This does
* not indicate EOF.
*
* // if "/foo/bar.txt" contains the text "hello world":
* const file = await Deno.open("/foo/bar.txt");
@ -635,7 +635,7 @@ declare namespace Deno {
* const text = new TextDecoder().decode(buf); // "hello world"
* Deno.close(file.rid);
*/
export function read(rid: number, buffer: Uint8Array): Promise<number | EOF>;
export function read(rid: number, buffer: Uint8Array): Promise<number | null>;
/** Synchronously write to the resource ID (`rid`) the contents of the array
* buffer (`data`).
@ -743,8 +743,8 @@ declare namespace Deno {
constructor(rid: number);
write(p: Uint8Array): Promise<number>;
writeSync(p: Uint8Array): number;
read(p: Uint8Array): Promise<number | EOF>;
readSync(p: Uint8Array): number | EOF;
read(p: Uint8Array): Promise<number | null>;
readSync(p: Uint8Array): number | null;
seek(offset: number, whence: SeekMode): Promise<number>;
seekSync(offset: number, whence: SeekMode): number;
close(): void;
@ -863,12 +863,12 @@ declare namespace Deno {
reset(): void;
/** Reads the next `p.length` bytes from the buffer or until the buffer is
* drained. Returns the number of bytes read. If the buffer has no data to
* return, the return is `Deno.EOF`. */
readSync(p: Uint8Array): number | EOF;
* return, the return is EOF (`null`). */
readSync(p: Uint8Array): number | null;
/** Reads the next `p.length` bytes from the buffer or until the buffer is
* drained. Resolves to the number of bytes read. If the buffer has no
* data to return, resolves to `Deno.EOF`. */
read(p: Uint8Array): Promise<number | EOF>;
* data to return, resolves to EOF (`null`). */
read(p: Uint8Array): Promise<number | null>;
writeSync(p: Uint8Array): number;
write(p: Uint8Array): Promise<number>;
/** Grows the buffer's capacity, if necessary, to guarantee space for
@ -879,14 +879,14 @@ declare namespace Deno {
* Based on Go Lang's
* [Buffer.Grow](https://golang.org/pkg/bytes/#Buffer.Grow). */
grow(n: number): void;
/** Reads data from `r` until `Deno.EOF` and appends it to the buffer,
/** Reads data from `r` until EOF (`null`) and appends it to the buffer,
* growing the buffer as needed. It resolves to the number of bytes read.
* If the buffer becomes too large, `.readFrom()` will reject with an error.
*
* Based on Go Lang's
* [Buffer.ReadFrom](https://golang.org/pkg/bytes/#Buffer.ReadFrom). */
readFrom(r: Reader): Promise<number>;
/** Reads data from `r` until `Deno.EOF` and appends it to the buffer,
/** Reads data from `r` until EOF (`null`) and appends it to the buffer,
* growing the buffer as needed. It returns the number of bytes read. If the
* buffer becomes too large, `.readFromSync()` will throw an error.
*
@ -895,8 +895,8 @@ declare namespace Deno {
readFromSync(r: ReaderSync): number;
}
/** Read Reader `r` until end of file (`Deno.EOF`) and resolve to the content
* as `Uint8Array`.
/** Read Reader `r` until EOF (`null`) and resolve to the content as
* Uint8Array`.
*
* // Example from stdin
* const stdinContent = await Deno.readAll(Deno.stdin);
@ -914,8 +914,8 @@ declare namespace Deno {
*/
export function readAll(r: Reader): Promise<Uint8Array>;
/** Synchronously reads Reader `r` until end of file (`Deno.EOF`) and returns
* the content as `Uint8Array`.
/** Synchronously reads Reader `r` until EOF (`null`) and returns the content
* as `Uint8Array`.
*
* // Example from stdin
* const stdinContent = Deno.readAllSync(Deno.stdin);
@ -2183,13 +2183,13 @@ declare namespace Deno {
readonly stderr?: Reader & Closer;
/** Resolves to the current status of the process. */
status(): Promise<ProcessStatus>;
/** Buffer the stdout and return it as `Uint8Array` after `Deno.EOF`.
/** Buffer the stdout until EOF and return it as `Uint8Array`.
*
* You must set stdout to `"piped"` when creating the process.
*
* This calls `close()` on stdout after its done. */
output(): Promise<Uint8Array>;
/** Buffer the stderr and return it as `Uint8Array` after `Deno.EOF`.
/** Buffer the stderr until EOF and return it as `Uint8Array`.
*
* You must set stderr to `"piped"` when creating the process.
*

View file

@ -1,6 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { errors } from "./errors.ts";
import { EOF, Reader, Writer, Closer } from "./io.ts";
import { Reader, Writer, Closer } from "./io.ts";
import { read, write } from "./ops/io.ts";
import { close } from "./ops/resources.ts";
import * as netOps from "./ops/net.ts";
@ -40,7 +40,7 @@ export class ConnImpl implements Conn {
return write(this.rid, p);
}
read(p: Uint8Array): Promise<number | EOF> {
read(p: Uint8Array): Promise<number | null> {
return read(this.rid, p);
}

View file

@ -1,7 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendAsyncMinimal, sendSyncMinimal } from "./dispatch_minimal.ts";
import { EOF } from "../io.ts";
// TODO(bartlomieju): remove this import and maybe lazy-initialize
// OPS_CACHE that belongs only to this module
import { OPS_CACHE } from "../runtime.ts";
@ -10,7 +9,7 @@ import { OPS_CACHE } from "../runtime.ts";
let OP_READ = -1;
let OP_WRITE = -1;
export function readSync(rid: number, buffer: Uint8Array): number | EOF {
export function readSync(rid: number, buffer: Uint8Array): number | null {
if (buffer.length == 0) {
return 0;
}
@ -21,7 +20,7 @@ export function readSync(rid: number, buffer: Uint8Array): number | EOF {
if (nread < 0) {
throw new Error("read error");
} else if (nread == 0) {
return EOF;
return null;
} else {
return nread;
}
@ -30,7 +29,7 @@ export function readSync(rid: number, buffer: Uint8Array): number | EOF {
export async function read(
rid: number,
buffer: Uint8Array
): Promise<number | EOF> {
): Promise<number | null> {
if (buffer.length == 0) {
return 0;
}
@ -41,7 +40,7 @@ export async function read(
if (nread < 0) {
throw new Error("read error");
} else if (nread == 0) {
return EOF;
return null;
} else {
return nread;
}

View file

@ -65,7 +65,7 @@ async function empty(buf: Buffer, s: string, fub: Uint8Array): Promise<void> {
check(buf, s);
while (true) {
const r = await buf.read(fub);
if (r === Deno.EOF) {
if (r === null) {
break;
}
s = s.slice(r);
@ -231,8 +231,7 @@ unitTest(async function bufferTestGrow(): Promise<void> {
for (const growLen of [0, 100, 1000, 10000, 100000]) {
const buf = new Buffer(xBytes.buffer as ArrayBuffer);
// If we read, this affects buf.off, which is good to test.
const result = await buf.read(tmp);
const nread = result === Deno.EOF ? 0 : result;
const nread = (await buf.read(tmp)) ?? 0;
buf.grow(growLen);
const yBytes = repeat("y", growLen);
await buf.write(yBytes);

View file

@ -101,13 +101,13 @@ unitTest(async function readerIter(): Promise<void> {
this.#buf = new Uint8Array(encoder.encode(s));
}
read(p: Uint8Array): Promise<number | Deno.EOF> {
read(p: Uint8Array): Promise<number | null> {
const n = Math.min(p.byteLength, this.#buf.byteLength - this.#offset);
p.set(this.#buf.slice(this.#offset, this.#offset + n));
this.#offset += n;
if (n === 0) {
return Promise.resolve(Deno.EOF);
return Promise.resolve(null);
}
return Promise.resolve(n);
@ -136,13 +136,13 @@ unitTest(async function readerIterSync(): Promise<void> {
this.#buf = new Uint8Array(encoder.encode(s));
}
readSync(p: Uint8Array): number | Deno.EOF {
readSync(p: Uint8Array): number | null {
const n = Math.min(p.byteLength, this.#buf.byteLength - this.#offset);
p.set(this.#buf.slice(this.#offset, this.#offset + n));
this.#offset += n;
if (n === 0) {
return Deno.EOF;
return null;
}
return n;

View file

@ -19,7 +19,7 @@ function spyRead(obj: Deno.Buffer): Spy {
const orig = obj.read.bind(obj);
obj.read = (p: Uint8Array): Promise<number | Deno.EOF> => {
obj.read = (p: Uint8Array): Promise<number | null> => {
spy.calls++;
return orig(p);
};

View file

@ -179,10 +179,10 @@ unitTest({ perms: { net: true } }, async function netTcpDialListen(): Promise<
assertEquals(3, buf[2]);
assert(conn.rid > 0);
assert(readResult !== Deno.EOF);
assert(readResult !== null);
const readResult2 = await conn.read(buf);
assertEquals(Deno.EOF, readResult2);
assertEquals(readResult2, null);
listener.close();
conn.close();
@ -214,10 +214,10 @@ unitTest(
assertEquals(3, buf[2]);
assert(conn.rid > 0);
assert(readResult !== Deno.EOF);
assert(readResult !== null);
const readResult2 = await conn.read(buf);
assertEquals(Deno.EOF, readResult2);
assertEquals(readResult2, null);
listener.close();
conn.close();
@ -358,10 +358,10 @@ unitTest(
assertEquals(3, buf[2]);
assert(conn.rid > 0);
assert(readResult !== Deno.EOF);
assert(readResult !== null);
const readResult2 = await conn.read(buf);
assertEquals(Deno.EOF, readResult2);
assertEquals(readResult2, null);
listener.close();
conn.close();
@ -396,7 +396,7 @@ unitTest(
closeReadDeferred.resolve();
const buf = new Uint8Array(1024);
const readResult = await conn.read(buf);
assertEquals(Deno.EOF, readResult); // with immediate EOF
assertEquals(readResult, null); // with immediate EOF
// Ensure closeRead does not impact write
await conn.write(new Uint8Array([4, 5, 6]));
await closeDeferred;
@ -523,7 +523,7 @@ unitTest(
try {
while (true) {
const nread = await conn.read(p);
if (nread === Deno.EOF) {
if (nread === null) {
break;
}
await conn.write(new Uint8Array([1, 2, 3]));

View file

@ -154,14 +154,14 @@ unitTest({ perms: { run: true } }, async function runStdoutPiped(): Promise<
const data = new Uint8Array(10);
let r = await p.stdout!.read(data);
if (r === Deno.EOF) {
throw new Error("p.stdout.read(...) should not be EOF");
if (r === null) {
throw new Error("p.stdout.read(...) should not be null");
}
assertEquals(r, 5);
const s = new TextDecoder().decode(data.subarray(0, r));
assertEquals(s, "hello");
r = await p.stdout!.read(data);
assertEquals(r, Deno.EOF);
assertEquals(r, null);
p.stdout!.close();
const status = await p.status();
@ -183,14 +183,14 @@ unitTest({ perms: { run: true } }, async function runStderrPiped(): Promise<
const data = new Uint8Array(10);
let r = await p.stderr!.read(data);
if (r === Deno.EOF) {
throw new Error("p.stderr.read should not return EOF here");
if (r === null) {
throw new Error("p.stderr.read should not return null here");
}
assertEquals(r, 5);
const s = new TextDecoder().decode(data.subarray(0, r));
assertEquals(s, "hello");
r = await p.stderr!.read(data);
assertEquals(r, Deno.EOF);
assertEquals(r, null);
p.stderr!.close();
const status = await p.status();
@ -313,7 +313,7 @@ unitTest({ perms: { run: true } }, async function runClose(): Promise<void> {
const data = new Uint8Array(10);
const r = await p.stderr!.read(data);
assertEquals(r, Deno.EOF);
assertEquals(r, null);
p.stderr!.close();
});

View file

@ -191,7 +191,7 @@ unitTest(
await w.flush();
const tpr = new TextProtoReader(r);
const statusLine = await tpr.readLine();
assert(statusLine !== Deno.EOF, `line must be read: ${String(statusLine)}`);
assert(statusLine !== null, `line must be read: ${String(statusLine)}`);
const m = statusLine.match(/^(.+?) (.+?) (.+?)$/);
assert(m !== null, "must be matched");
const [_, proto, status, ok] = m;
@ -199,7 +199,7 @@ unitTest(
assertEquals(status, "200");
assertEquals(ok, "OK");
const headers = await tpr.readMIMEHeader();
assert(headers !== Deno.EOF);
assert(headers !== null);
const contentLength = parseInt(headers.get("content-length")!);
const bodyBuf = new Uint8Array(contentLength);
await r.readFull(bodyBuf);
@ -225,7 +225,7 @@ unitTest(
let writer = new BufWriter(conn);
let reader = new TextProtoReader(new BufReader(conn));
let line: string | Deno.EOF = (await reader.readLine()) as string;
let line: string | null = (await reader.readLine()) as string;
assert(line.startsWith("220"));
await writer.write(encoder.encode(`EHLO ${hostname}\r\n`));

View file

@ -220,7 +220,7 @@ class Body
return decoder.decode(ab);
}
read(p: Uint8Array): Promise<number | io.EOF> {
read(p: Uint8Array): Promise<number | null> {
this.#bodyUsed = true;
return read(this.#rid, p);
}

View file

@ -6,7 +6,7 @@ Deno.stdout.writeSync(new TextEncoder().encode("S"));
const buf = new Uint8Array(3);
for (let i = 0; i < 3; i++) {
const nread = await Deno.stdin.read(buf);
if (nread === Deno.EOF) {
if (nread === null) {
break;
} else {
const data = new TextDecoder().decode(buf.subarray(0, nread));

View file

@ -41,12 +41,12 @@ class FileReader implements Deno.Reader {
constructor(private filePath: string) {}
public async read(p: Uint8Array): Promise<number | Deno.EOF> {
public async read(p: Uint8Array): Promise<number | null> {
if (!this.file) {
this.file = await Deno.open(this.filePath, { read: true });
}
const res = await Deno.read(this.file.rid, p);
if (res === Deno.EOF) {
if (res === null) {
Deno.close(this.file.rid);
this.file = undefined;
}

View file

@ -17,8 +17,8 @@ Available Functions:
```typescript
sizeof(dataType: RawTypes): number
getNBytes(r: Deno.Reader, n: number): Promise<Uint8Array>
varnum(b: Uint8Array, o: VarnumOptions = {}): number | Deno.EOF
varbig(b: Uint8Array, o: VarbigOptions = {}): bigint | Deno.EOF
varnum(b: Uint8Array, o: VarnumOptions = {}): number | null
varbig(b: Uint8Array, o: VarbigOptions = {}): bigint | null
putVarnum(b: Uint8Array, x: number, o: VarnumOptions = {}): number
putVarbig(b: Uint8Array, x: bigint, o: VarbigOptions = {}): number
readVarnum(r: Deno.Reader, o: VarnumOptions = {}): Promise<number>

View file

@ -51,19 +51,16 @@ export async function getNBytes(
): Promise<Uint8Array> {
const scratch = new Uint8Array(n);
const nRead = await r.read(scratch);
if (nRead === Deno.EOF || nRead < n) throw new Deno.errors.UnexpectedEof();
if (nRead === null || nRead < n) throw new Deno.errors.UnexpectedEof();
return scratch;
}
/** Decode a number from `b`, and return it as a `number`. Data-type defaults to `int32`.
* Returns `EOF` if `b` is too short for the data-type given in `o`. */
export function varnum(
b: Uint8Array,
o: VarnumOptions = {}
): number | Deno.EOF {
* Returns `null` if `b` is too short for the data-type given in `o`. */
export function varnum(b: Uint8Array, o: VarnumOptions = {}): number | null {
o.dataType = o.dataType ?? "int32";
const littleEndian = (o.endian ?? "big") === "little" ? true : false;
if (b.length < sizeof(o.dataType)) return Deno.EOF;
if (b.length < sizeof(o.dataType)) return null;
const view = new DataView(b.buffer);
switch (o.dataType) {
case "int8":
@ -86,14 +83,11 @@ export function varnum(
}
/** Decode an integer from `b`, and return it as a `bigint`. Data-type defaults to `int64`.
* Returns `EOF` if `b` is too short for the data-type given in `o`. */
export function varbig(
b: Uint8Array,
o: VarbigOptions = {}
): bigint | Deno.EOF {
* Returns `null` if `b` is too short for the data-type given in `o`. */
export function varbig(b: Uint8Array, o: VarbigOptions = {}): bigint | null {
o.dataType = o.dataType ?? "int64";
const littleEndian = (o.endian ?? "big") === "little" ? true : false;
if (b.length < sizeof(o.dataType)) return Deno.EOF;
if (b.length < sizeof(o.dataType)) return null;
const view = new DataView(b.buffer);
switch (o.dataType) {
case "int8":

View file

@ -64,12 +64,12 @@ async function readRecord(
Startline: number,
reader: BufReader,
opt: ReadOptions = { comma: ",", trimLeadingSpace: false }
): Promise<string[] | Deno.EOF> {
): Promise<string[] | null> {
const tp = new TextProtoReader(reader);
const lineIndex = Startline;
let line = await readLine(tp);
if (line === Deno.EOF) return Deno.EOF;
if (line === null) return null;
if (line.length === 0) {
return [];
}
@ -147,7 +147,7 @@ async function readRecord(
// Hit end of line (copy all data so far).
recordBuffer += line;
const r = await readLine(tp);
if (r === Deno.EOF) {
if (r === null) {
if (!opt.lazyQuotes) {
quoteError = ERR_QUOTE;
break parseField;
@ -182,13 +182,13 @@ async function readRecord(
}
async function isEOF(tp: TextProtoReader): Promise<boolean> {
return (await tp.r.peek(0)) === Deno.EOF;
return (await tp.r.peek(0)) === null;
}
async function readLine(tp: TextProtoReader): Promise<string | Deno.EOF> {
async function readLine(tp: TextProtoReader): Promise<string | null> {
let line: string;
const r = await tp.readLine();
if (r === Deno.EOF) return Deno.EOF;
if (r === null) return null;
line = r;
// For backwards compatibility, drop trailing \r before EOF.
@ -226,7 +226,7 @@ export async function readMatrix(
for (;;) {
const r = await readRecord(lineIndex, reader, opt);
if (r === Deno.EOF) break;
if (r === null) break;
lineResult = r;
lineIndex++;
// If fieldsPerRecord is 0, Read sets it to

View file

@ -17,7 +17,7 @@ async function startServer(): Promise<Deno.Process> {
assert(server.stdout != null);
const r = new TextProtoReader(new BufReader(server.stdout));
const s = await r.readLine();
assert(s !== Deno.EOF && s.includes("chat server starting"));
assert(s !== null && s.includes("chat server starting"));
} catch (err) {
server.stdout!.close();
server.close();

View file

@ -1,6 +1,6 @@
#!/usr/bin/env -S deno --allow-net --allow-env
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { parse } from "https://deno.land/std/flags/mod.ts";
import { parse } from "../flags/mod.ts";
function pathBase(p: string): string {
const parts = p.split("/");

View file

@ -16,7 +16,7 @@ Deno.test("[examples/echo_server]", async () => {
const processReader = new BufReader(process.stdout!);
const message = await processReader.readLine();
assertNotEquals(message, Deno.EOF);
assertNotEquals(message, null);
assertStrictEq(
decoder.decode((message as ReadLineResult).line).trim(),
"Listening on 0.0.0.0:8080"
@ -28,7 +28,7 @@ Deno.test("[examples/echo_server]", async () => {
await conn.write(encoder.encode("Hello echo_server\n"));
const result = await connReader.readLine();
assertNotEquals(result, Deno.EOF);
assertNotEquals(result, null);
const actualResponse = decoder
.decode((result as ReadLineResult).line)

View file

@ -25,7 +25,7 @@ async function startFileServer(): Promise<void> {
assert(fileServer.stdout != null);
const r = new TextProtoReader(new BufReader(fileServer.stdout));
const s = await r.readLine();
assert(s !== Deno.EOF && s.includes("server listening"));
assert(s !== null && s.includes("server listening"));
}
function killFileServer(): void {
@ -114,7 +114,7 @@ test("servePermissionDenied", async function (): Promise<void> {
assert(deniedServer.stderr != null);
const errReader = new TextProtoReader(new BufReader(deniedServer.stderr));
const s = await reader.readLine();
assert(s !== Deno.EOF && s.includes("server listening"));
assert(s !== null && s.includes("server listening"));
try {
const res = await fetch("http://localhost:4500/");
@ -138,7 +138,7 @@ test("printHelp", async function (): Promise<void> {
assert(helpProcess.stdout != null);
const r = new TextProtoReader(new BufReader(helpProcess.stdout));
const s = await r.readLine();
assert(s !== Deno.EOF && s.includes("Deno File Server"));
assert(s !== null && s.includes("Deno File Server"));
helpProcess.close();
helpProcess.stdout.close();
});

View file

@ -7,8 +7,8 @@ import { STATUS_TEXT } from "./http_status.ts";
export function emptyReader(): Deno.Reader {
return {
read(_: Uint8Array): Promise<number | Deno.EOF> {
return Promise.resolve(Deno.EOF);
read(_: Uint8Array): Promise<number | null> {
return Promise.resolve(null);
},
};
}
@ -16,9 +16,9 @@ export function emptyReader(): Deno.Reader {
export function bodyReader(contentLength: number, r: BufReader): Deno.Reader {
let totalRead = 0;
let finished = false;
async function read(buf: Uint8Array): Promise<number | Deno.EOF> {
if (finished) return Deno.EOF;
let result: number | Deno.EOF;
async function read(buf: Uint8Array): Promise<number | null> {
if (finished) return null;
let result: number | null;
const remaining = contentLength - totalRead;
if (remaining >= buf.byteLength) {
result = await r.read(buf);
@ -26,7 +26,7 @@ export function bodyReader(contentLength: number, r: BufReader): Deno.Reader {
const readBuf = buf.subarray(0, remaining);
result = await r.read(readBuf);
}
if (result !== Deno.EOF) {
if (result !== null) {
totalRead += result;
}
finished = totalRead === contentLength;
@ -43,8 +43,8 @@ export function chunkedBodyReader(h: Headers, r: BufReader): Deno.Reader {
offset: number;
data: Uint8Array;
}> = [];
async function read(buf: Uint8Array): Promise<number | Deno.EOF> {
if (finished) return Deno.EOF;
async function read(buf: Uint8Array): Promise<number | null> {
if (finished) return null;
const [chunk] = chunks;
if (chunk) {
const chunkRemaining = chunk.data.byteLength - chunk.offset;
@ -56,14 +56,14 @@ export function chunkedBodyReader(h: Headers, r: BufReader): Deno.Reader {
if (chunk.offset === chunk.data.byteLength) {
chunks.shift();
// Consume \r\n;
if ((await tp.readLine()) === Deno.EOF) {
if ((await tp.readLine()) === null) {
throw new Deno.errors.UnexpectedEof();
}
}
return readLength;
}
const line = await tp.readLine();
if (line === Deno.EOF) throw new Deno.errors.UnexpectedEof();
if (line === null) throw new Deno.errors.UnexpectedEof();
// TODO: handle chunk extension
const [chunkSizeString] = line.split(";");
const chunkSize = parseInt(chunkSizeString, 16);
@ -73,12 +73,12 @@ export function chunkedBodyReader(h: Headers, r: BufReader): Deno.Reader {
if (chunkSize > 0) {
if (chunkSize > buf.byteLength) {
let eof = await r.readFull(buf);
if (eof === Deno.EOF) {
if (eof === null) {
throw new Deno.errors.UnexpectedEof();
}
const restChunk = new Uint8Array(chunkSize - buf.byteLength);
eof = await r.readFull(restChunk);
if (eof === Deno.EOF) {
if (eof === null) {
throw new Deno.errors.UnexpectedEof();
} else {
chunks.push({
@ -90,11 +90,11 @@ export function chunkedBodyReader(h: Headers, r: BufReader): Deno.Reader {
} else {
const bufToFill = buf.subarray(0, chunkSize);
const eof = await r.readFull(bufToFill);
if (eof === Deno.EOF) {
if (eof === null) {
throw new Deno.errors.UnexpectedEof();
}
// Consume \r\n
if ((await tp.readLine()) === Deno.EOF) {
if ((await tp.readLine()) === null) {
throw new Deno.errors.UnexpectedEof();
}
return chunkSize;
@ -102,12 +102,12 @@ export function chunkedBodyReader(h: Headers, r: BufReader): Deno.Reader {
} else {
assert(chunkSize === 0);
// Consume \r\n
if ((await r.readLine()) === Deno.EOF) {
if ((await r.readLine()) === null) {
throw new Deno.errors.UnexpectedEof();
}
await readTrailers(h, r);
finished = true;
return Deno.EOF;
return null;
}
}
return { read };
@ -131,7 +131,7 @@ export async function readTrailers(
if (!keys) return;
const tp = new TextProtoReader(r);
const result = await tp.readMIMEHeader();
assert(result != Deno.EOF, "trailer must be set");
assert(result !== null, "trailer must be set");
for (const [k, v] of result) {
if (!keys.has(k)) {
throw new Error("Undeclared trailer field");
@ -332,12 +332,12 @@ export function parseHTTPVersion(vers: string): [number, number] {
export async function readRequest(
conn: Deno.Conn,
bufr: BufReader
): Promise<ServerRequest | Deno.EOF> {
): Promise<ServerRequest | null> {
const tp = new TextProtoReader(bufr);
const firstLine = await tp.readLine(); // e.g. GET /index.html HTTP/1.0
if (firstLine === Deno.EOF) return Deno.EOF;
if (firstLine === null) return null;
const headers = await tp.readMIMEHeader();
if (headers === Deno.EOF) throw new Deno.errors.UnexpectedEof();
if (headers === null) throw new Deno.errors.UnexpectedEof();
const req = new ServerRequest();
req.conn = conn;

View file

@ -3,7 +3,6 @@ import {
assertThrowsAsync,
assertEquals,
assert,
assertNotEOF,
assertNotEquals,
} from "../testing/asserts.ts";
import {
@ -43,11 +42,11 @@ test("chunkedBodyReader", async () => {
].join("");
const h = new Headers();
const r = chunkedBodyReader(h, new BufReader(new Buffer(encode(body))));
let result: number | Deno.EOF;
let result: number | null;
// Use small buffer as some chunks exceed buffer size
const buf = new Uint8Array(5);
const dest = new Buffer();
while ((result = await r.read(buf)) !== Deno.EOF) {
while ((result = await r.read(buf)) !== null) {
const len = Math.min(buf.byteLength, result);
await dest.write(buf.subarray(0, len));
}
@ -223,25 +222,28 @@ test("writeUint8ArrayResponse", async function (): Promise<void> {
const decoder = new TextDecoder("utf-8");
const reader = new BufReader(buf);
let r: ReadLineResult;
r = assertNotEOF(await reader.readLine());
let r: ReadLineResult | null = await reader.readLine();
assert(r !== null);
assertEquals(decoder.decode(r.line), "HTTP/1.1 200 OK");
assertEquals(r.more, false);
r = assertNotEOF(await reader.readLine());
r = await reader.readLine();
assert(r !== null);
assertEquals(decoder.decode(r.line), `content-length: ${shortText.length}`);
assertEquals(r.more, false);
r = assertNotEOF(await reader.readLine());
r = await reader.readLine();
assert(r !== null);
assertEquals(r.line.byteLength, 0);
assertEquals(r.more, false);
r = assertNotEOF(await reader.readLine());
r = await reader.readLine();
assert(r !== null);
assertEquals(decoder.decode(r.line), shortText);
assertEquals(r.more, false);
const eof = await reader.readLine();
assertEquals(eof, Deno.EOF);
assertEquals(eof, null);
});
test("writeStringResponse", async function (): Promise<void> {
@ -255,25 +257,28 @@ test("writeStringResponse", async function (): Promise<void> {
const decoder = new TextDecoder("utf-8");
const reader = new BufReader(buf);
let r: ReadLineResult;
r = assertNotEOF(await reader.readLine());
let r: ReadLineResult | null = await reader.readLine();
assert(r !== null);
assertEquals(decoder.decode(r.line), "HTTP/1.1 200 OK");
assertEquals(r.more, false);
r = assertNotEOF(await reader.readLine());
r = await reader.readLine();
assert(r !== null);
assertEquals(decoder.decode(r.line), `content-length: ${body.length}`);
assertEquals(r.more, false);
r = assertNotEOF(await reader.readLine());
r = await reader.readLine();
assert(r !== null);
assertEquals(r.line.byteLength, 0);
assertEquals(r.more, false);
r = assertNotEOF(await reader.readLine());
r = await reader.readLine();
assert(r !== null);
assertEquals(decoder.decode(r.line), body);
assertEquals(r.more, false);
const eof = await reader.readLine();
assertEquals(eof, Deno.EOF);
assertEquals(eof, null);
});
test("writeStringReaderResponse", async function (): Promise<void> {
@ -288,28 +293,33 @@ test("writeStringReaderResponse", async function (): Promise<void> {
const decoder = new TextDecoder("utf-8");
const reader = new BufReader(buf);
let r: ReadLineResult;
r = assertNotEOF(await reader.readLine());
let r: ReadLineResult | null = await reader.readLine();
assert(r !== null);
assertEquals(decoder.decode(r.line), "HTTP/1.1 200 OK");
assertEquals(r.more, false);
r = assertNotEOF(await reader.readLine());
r = await reader.readLine();
assert(r !== null);
assertEquals(decoder.decode(r.line), "transfer-encoding: chunked");
assertEquals(r.more, false);
r = assertNotEOF(await reader.readLine());
r = await reader.readLine();
assert(r !== null);
assertEquals(r.line.byteLength, 0);
assertEquals(r.more, false);
r = assertNotEOF(await reader.readLine());
r = await reader.readLine();
assert(r !== null);
assertEquals(decoder.decode(r.line), shortText.length.toString());
assertEquals(r.more, false);
r = assertNotEOF(await reader.readLine());
r = await reader.readLine();
assert(r !== null);
assertEquals(decoder.decode(r.line), shortText);
assertEquals(r.more, false);
r = assertNotEOF(await reader.readLine());
r = await reader.readLine();
assert(r !== null);
assertEquals(decoder.decode(r.line), "0");
assertEquals(r.more, false);
});
@ -372,7 +382,7 @@ test("testReadRequestError", async function (): Promise<void> {
in: "GET / HTTP/1.1\r\nheader:foo\r\n",
err: Deno.errors.UnexpectedEof,
},
{ in: "", err: Deno.EOF },
{ in: "", eof: true },
{
in: "HEAD / HTTP/1.1\r\nContent-Length:4\r\n\r\n",
err: "http: method cannot contain a Content-Length",
@ -427,14 +437,14 @@ test("testReadRequestError", async function (): Promise<void> {
for (const test of testCases) {
const reader = new BufReader(new StringReader(test.in));
let err;
let req: ServerRequest | Deno.EOF | undefined;
let req: ServerRequest | null = null;
try {
req = await readRequest(mockConn(), reader);
} catch (e) {
err = e;
}
if (test.err === Deno.EOF) {
assertEquals(req, Deno.EOF);
if (test.eof) {
assertEquals(req, null);
} else if (typeof test.err === "string") {
assertEquals(err.message, test.err);
} else if (test.err) {
@ -443,7 +453,7 @@ test("testReadRequestError", async function (): Promise<void> {
assert(req instanceof ServerRequest);
assert(test.headers);
assertEquals(err, undefined);
assertNotEquals(req, Deno.EOF);
assertNotEquals(req, null);
for (const h of test.headers) {
assertEquals(req.headers.get(h.key), h.value);
}

View file

@ -14,7 +14,7 @@ export function mockConn(base: Partial<Deno.Conn> = {}): Deno.Conn {
rid: -1,
closeRead: (): void => {},
closeWrite: (): void => {},
read: (): Promise<number | Deno.EOF> => {
read: (): Promise<number | null> => {
return Promise.resolve(0);
},
write: (): Promise<number> => {

View file

@ -13,7 +13,7 @@ async function startServer(): Promise<void> {
assert(server.stdout != null);
const r = new TextProtoReader(new BufReader(server.stdout));
const s = await r.readLine();
assert(s !== Deno.EOF && s.includes("Racing server listening..."));
assert(s !== null && s.includes("Racing server listening..."));
}
function killServer(): void {
server.close();

View file

@ -60,7 +60,7 @@ export class ServerRequest {
* let totRead = 0;
* while (true) {
* const nread = await req.body.read(bufSlice);
* if (nread === Deno.EOF) break;
* if (nread === null) break;
* totRead += nread;
* if (totRead >= req.contentLength) break;
* bufSlice = bufSlice.subarray(nread);
@ -117,7 +117,7 @@ export class ServerRequest {
// Consume unread body
const body = this.body;
const buf = new Uint8Array(1024);
while ((await body.read(buf)) !== Deno.EOF) {}
while ((await body.read(buf)) !== null) {}
this.finalized = true;
}
}
@ -151,7 +151,7 @@ export class Server implements AsyncIterable<ServerRequest> {
const writer = new BufWriter(conn);
while (!this.closing) {
let request: ServerRequest | Deno.EOF;
let request: ServerRequest | null;
try {
request = await readRequest(conn, reader);
} catch (error) {
@ -167,7 +167,7 @@ export class Server implements AsyncIterable<ServerRequest> {
}
break;
}
if (request == Deno.EOF) {
if (request === null) {
break;
}

View file

@ -10,7 +10,6 @@ import {
assert,
assertEquals,
assertMatch,
assertNotEOF,
assertStrContains,
assertThrowsAsync,
} from "../testing/asserts.ts";
@ -108,7 +107,7 @@ interface TotalReader extends Deno.Reader {
}
function totalReader(r: Deno.Reader): TotalReader {
let _total = 0;
async function read(p: Uint8Array): Promise<number | Deno.EOF> {
async function read(p: Uint8Array): Promise<number | null> {
const result = await r.read(p);
if (typeof result === "number") {
_total += result;
@ -252,13 +251,13 @@ test("requestBodyReaderWithContentLength", async function (): Promise<void> {
let offset = 0;
while (offset < shortText.length) {
const nread = await req.body.read(readBuf);
assertNotEOF(nread);
assert(nread !== null);
const s = decode(readBuf.subarray(0, nread as number));
assertEquals(shortText.substr(offset, nread as number), s);
offset += nread as number;
}
const nread = await req.body.read(readBuf);
assertEquals(nread, Deno.EOF);
assertEquals(nread, null);
}
// Larger than given buf
@ -273,13 +272,13 @@ test("requestBodyReaderWithContentLength", async function (): Promise<void> {
let offset = 0;
while (offset < longText.length) {
const nread = await req.body.read(readBuf);
assertNotEOF(nread);
assert(nread !== null);
const s = decode(readBuf.subarray(0, nread as number));
assertEquals(longText.substr(offset, nread as number), s);
offset += nread as number;
}
const nread = await req.body.read(readBuf);
assertEquals(nread, Deno.EOF);
assertEquals(nread, null);
}
});
@ -307,13 +306,13 @@ test("requestBodyReaderWithTransferEncoding", async function (): Promise<void> {
let offset = 0;
while (offset < shortText.length) {
const nread = await req.body.read(readBuf);
assertNotEOF(nread);
assert(nread !== null);
const s = decode(readBuf.subarray(0, nread as number));
assertEquals(shortText.substr(offset, nread as number), s);
offset += nread as number;
}
const nread = await req.body.read(readBuf);
assertEquals(nread, Deno.EOF);
assertEquals(nread, null);
}
// Larger than internal buf
@ -340,13 +339,13 @@ test("requestBodyReaderWithTransferEncoding", async function (): Promise<void> {
let offset = 0;
while (offset < longText.length) {
const nread = await req.body.read(readBuf);
assertNotEOF(nread);
assert(nread !== null);
const s = decode(readBuf.subarray(0, nread as number));
assertEquals(longText.substr(offset, nread as number), s);
offset += nread as number;
}
const nread = await req.body.read(readBuf);
assertEquals(nread, Deno.EOF);
assertEquals(nread, null);
}
});
@ -372,7 +371,7 @@ test({
try {
const r = new TextProtoReader(new BufReader(p.stdout!));
const s = await r.readLine();
assert(s !== Deno.EOF && s.includes("server listening"));
assert(s !== null && s.includes("server listening"));
await delay(100);
// Reqeusts to the server and immediately closes the connection
const conn = await Deno.connect({ port: 4502 });
@ -419,7 +418,7 @@ test({
const r = new TextProtoReader(new BufReader(p.stdout!));
const s = await r.readLine();
assert(
s !== Deno.EOF && s.includes("server listening"),
s !== null && s.includes("server listening"),
"server must be started"
);
// Requests to the server and immediately closes the connection
@ -433,7 +432,8 @@ test({
new TextEncoder().encode("GET / HTTP/1.0\r\n\r\n")
);
const res = new Uint8Array(100);
const nread = assertNotEOF(await conn.read(res));
const nread = await conn.read(res);
assert(nread !== null);
conn.close();
const resStr = new TextDecoder().decode(res.subarray(0, nread));
assert(resStr.includes("Hello HTTPS"));
@ -476,7 +476,7 @@ test({
);
const res = new Uint8Array(100);
const nread = await conn.read(res);
assert(nread !== Deno.EOF);
assert(nread !== null);
const resStr = new TextDecoder().decode(res.subarray(0, nread));
assertStrContains(resStr, "/hello");
server.close();

View file

@ -83,7 +83,7 @@ export class BufReader implements Reader {
// Read new data: try a limited number of times.
for (let i = MAX_CONSECUTIVE_EMPTY_READS; i > 0; i--) {
const rr = await this.rd.read(this.buf.subarray(this.w));
if (rr === Deno.EOF) {
if (rr === null) {
this.eof = true;
return;
}
@ -120,8 +120,8 @@ export class BufReader implements Reader {
* hence n may be less than len(p).
* To read exactly len(p) bytes, use io.ReadFull(b, p).
*/
async read(p: Uint8Array): Promise<number | Deno.EOF> {
let rr: number | Deno.EOF = p.byteLength;
async read(p: Uint8Array): Promise<number | null> {
let rr: number | null = p.byteLength;
if (p.byteLength === 0) return rr;
if (this.r === this.w) {
@ -129,7 +129,7 @@ export class BufReader implements Reader {
// Large read, empty buffer.
// Read directly into p to avoid copy.
const rr = await this.rd.read(p);
const nread = rr === Deno.EOF ? 0 : rr;
const nread = rr ?? 0;
assert(nread >= 0, "negative read");
// if (rr.nread > 0) {
// this.lastByte = p[rr.nread - 1];
@ -143,7 +143,7 @@ export class BufReader implements Reader {
this.r = 0;
this.w = 0;
rr = await this.rd.read(this.buf);
if (rr === 0 || rr === Deno.EOF) return rr;
if (rr === 0 || rr === null) return rr;
assert(rr >= 0, "negative read");
this.w += rr;
}
@ -161,7 +161,7 @@ export class BufReader implements Reader {
* If successful, `p` is returned.
*
* If the end of the underlying stream has been reached, and there are no more
* bytes available in the buffer, `readFull()` returns `EOF` instead.
* bytes available in the buffer, `readFull()` returns `null` instead.
*
* An error is thrown if some bytes could be read, but not enough to fill `p`
* entirely before the underlying stream reported an error or EOF. Any error
@ -170,14 +170,14 @@ export class BufReader implements Reader {
*
* Ported from https://golang.org/pkg/io/#ReadFull
*/
async readFull(p: Uint8Array): Promise<Uint8Array | Deno.EOF> {
async readFull(p: Uint8Array): Promise<Uint8Array | null> {
let bytesRead = 0;
while (bytesRead < p.length) {
try {
const rr = await this.read(p.subarray(bytesRead));
if (rr === Deno.EOF) {
if (rr === null) {
if (bytesRead === 0) {
return Deno.EOF;
return null;
} else {
throw new PartialReadError();
}
@ -191,10 +191,10 @@ export class BufReader implements Reader {
return p;
}
/** Returns the next byte [0, 255] or `EOF`. */
async readByte(): Promise<number | Deno.EOF> {
/** Returns the next byte [0, 255] or `null`. */
async readByte(): Promise<number | null> {
while (this.r === this.w) {
if (this.eof) return Deno.EOF;
if (this.eof) return null;
await this._fill(); // buffer is empty.
}
const c = this.buf[this.r];
@ -207,17 +207,17 @@ export class BufReader implements Reader {
* returning a string containing the data up to and including the delimiter.
* If ReadString encounters an error before finding a delimiter,
* it returns the data read before the error and the error itself
* (often io.EOF).
* (often `null`).
* ReadString returns err != nil if and only if the returned data does not end
* in delim.
* For simple uses, a Scanner may be more convenient.
*/
async readString(delim: string): Promise<string | Deno.EOF> {
async readString(delim: string): Promise<string | null> {
if (delim.length !== 1) {
throw new Error("Delimiter should be a single character");
}
const buffer = await this.readSlice(delim.charCodeAt(0));
if (buffer == Deno.EOF) return Deno.EOF;
if (buffer === null) return null;
return new TextDecoder().decode(buffer);
}
@ -237,14 +237,14 @@ export class BufReader implements Reader {
* When the end of the underlying stream is reached, the final bytes in the
* stream are returned. No indication or error is given if the input ends
* without a final line end. When there are no more trailing bytes to read,
* `readLine()` returns the `EOF` symbol.
* `readLine()` returns `null`.
*
* Calling `unreadByte()` after `readLine()` will always unread the last byte
* read (possibly a character belonging to the line end) even if that byte is
* not part of the line returned by `readLine()`.
*/
async readLine(): Promise<ReadLineResult | Deno.EOF> {
let line: Uint8Array | Deno.EOF;
async readLine(): Promise<ReadLineResult | null> {
let line: Uint8Array | null;
try {
line = await this.readSlice(LF);
@ -277,8 +277,8 @@ export class BufReader implements Reader {
return { line: partial, more: !this.eof };
}
if (line === Deno.EOF) {
return Deno.EOF;
if (line === null) {
return null;
}
if (line.byteLength === 0) {
@ -306,12 +306,12 @@ export class BufReader implements Reader {
* If `readSlice()` encounters the end of the underlying stream and there are
* any bytes left in the buffer, the rest of the buffer is returned. In other
* words, EOF is always treated as a delimiter. Once the buffer is empty,
* it returns `EOF`.
* it returns `null`.
*
* Because the data returned from `readSlice()` will be overwritten by the
* next I/O operation, most clients should use `readString()` instead.
*/
async readSlice(delim: number): Promise<Uint8Array | Deno.EOF> {
async readSlice(delim: number): Promise<Uint8Array | null> {
let s = 0; // search start index
let slice: Uint8Array | undefined;
@ -328,7 +328,7 @@ export class BufReader implements Reader {
// EOF?
if (this.eof) {
if (this.r === this.w) {
return Deno.EOF;
return null;
}
slice = this.buf.subarray(this.r, this.w);
this.r = this.w;
@ -367,13 +367,13 @@ export class BufReader implements Reader {
*
* When the end of the underlying stream is reached, but there are unread
* bytes left in the buffer, those bytes are returned. If there are no bytes
* left in the buffer, it returns `EOF`.
* left in the buffer, it returns `null`.
*
* If an error is encountered before `n` bytes are available, `peek()` throws
* an error with the `partial` property set to a slice of the buffer that
* contains the bytes that were available before the error occurred.
*/
async peek(n: number): Promise<Uint8Array | Deno.EOF> {
async peek(n: number): Promise<Uint8Array | null> {
if (n < 0) {
throw Error("negative count");
}
@ -390,7 +390,7 @@ export class BufReader implements Reader {
}
if (avail === 0 && this.eof) {
return Deno.EOF;
return null;
} else if (avail < n && this.eof) {
return this.buf.subarray(this.r, this.r + avail);
} else if (avail < n) {
@ -656,7 +656,7 @@ export async function* readDelim(
let matchIndex = 0;
while (true) {
const result = await reader.read(inspectArr);
if (result === Deno.EOF) {
if (result === null) {
// Yield last chunk.
yield inputBuffer.bytes();
return;

View file

@ -5,12 +5,7 @@
const { Buffer } = Deno;
type Reader = Deno.Reader;
import {
assert,
assertEquals,
fail,
assertNotEOF,
} from "../testing/asserts.ts";
import { assert, assertEquals, fail } from "../testing/asserts.ts";
import {
BufReader,
BufWriter,
@ -30,7 +25,7 @@ async function readBytes(buf: BufReader): Promise<string> {
let nb = 0;
while (true) {
const c = await buf.readByte();
if (c === Deno.EOF) {
if (c === null) {
break; // EOF
}
b[nb] = c;
@ -69,7 +64,7 @@ async function reads(buf: BufReader, m: number): Promise<string> {
let nb = 0;
while (true) {
const result = await buf.read(b.subarray(nb, nb + m));
if (result === Deno.EOF) {
if (result === null) {
break;
}
nb += result;
@ -152,7 +147,8 @@ Deno.test("bufioBufferFull", async function (): Promise<void> {
assertEquals(decoder.decode(err.partial), "And now, hello, ");
}
const line = assertNotEOF(await buf.readSlice(charCode("!")));
const line = await buf.readSlice(charCode("!"));
assert(line !== null);
const actual = decoder.decode(line);
assertEquals(actual, "world!");
});
@ -161,14 +157,16 @@ Deno.test("bufioReadString", async function (): Promise<void> {
const string = "And now, hello world!";
const buf = new BufReader(stringsReader(string), MIN_READ_BUFFER_SIZE);
const line = assertNotEOF(await buf.readString(","));
const line = await buf.readString(",");
assert(line !== null);
assertEquals(line, "And now,");
assertEquals(line.length, 8);
const line2 = assertNotEOF(await buf.readString(","));
const line2 = await buf.readString(",");
assert(line2 !== null);
assertEquals(line2, " hello world!");
assertEquals(await buf.readString(","), Deno.EOF);
assertEquals(await buf.readString(","), null);
try {
await buf.readString("deno");
@ -192,7 +190,7 @@ const testOutput = encoder.encode("0123456789abcdefghijklmnopqrstuvwxy");
class TestReader implements Reader {
constructor(private data: Uint8Array, private stride: number) {}
read(buf: Uint8Array): Promise<number | Deno.EOF> {
read(buf: Uint8Array): Promise<number | null> {
let nread = this.stride;
if (nread > this.data.byteLength) {
nread = this.data.byteLength;
@ -201,7 +199,7 @@ class TestReader implements Reader {
nread = buf.byteLength;
}
if (nread === 0) {
return Promise.resolve(Deno.EOF);
return Promise.resolve(null);
}
copyBytes(buf as Uint8Array, this.data);
this.data = this.data.subarray(nread);
@ -216,7 +214,7 @@ async function testReadLine(input: Uint8Array): Promise<void> {
const l = new BufReader(reader, input.byteLength + 1);
while (true) {
const r = await l.readLine();
if (r === Deno.EOF) {
if (r === null) {
break;
}
const { line, more } = r;
@ -253,10 +251,12 @@ Deno.test("bufioPeek", async function (): Promise<void> {
MIN_READ_BUFFER_SIZE
);
let actual = assertNotEOF(await buf.peek(1));
let actual = await buf.peek(1);
assert(actual !== null);
assertEquals(decoder.decode(actual), "a");
actual = assertNotEOF(await buf.peek(4));
actual = await buf.peek(4);
assert(actual !== null);
assertEquals(decoder.decode(actual), "abcd");
try {
@ -271,33 +271,39 @@ Deno.test("bufioPeek", async function (): Promise<void> {
await buf.read(p.subarray(0, 3));
assertEquals(decoder.decode(p.subarray(0, 3)), "abc");
actual = assertNotEOF(await buf.peek(1));
actual = await buf.peek(1);
assert(actual !== null);
assertEquals(decoder.decode(actual), "d");
actual = assertNotEOF(await buf.peek(1));
actual = await buf.peek(1);
assert(actual !== null);
assertEquals(decoder.decode(actual), "d");
actual = assertNotEOF(await buf.peek(1));
actual = await buf.peek(1);
assert(actual !== null);
assertEquals(decoder.decode(actual), "d");
actual = assertNotEOF(await buf.peek(2));
actual = await buf.peek(2);
assert(actual !== null);
assertEquals(decoder.decode(actual), "de");
const res = await buf.read(p.subarray(0, 3));
assertEquals(decoder.decode(p.subarray(0, 3)), "def");
assert(res !== Deno.EOF);
assert(res !== null);
actual = assertNotEOF(await buf.peek(4));
actual = await buf.peek(4);
assert(actual !== null);
assertEquals(decoder.decode(actual), "ghij");
await buf.read(p);
assertEquals(decoder.decode(p), "ghijklmnop");
actual = assertNotEOF(await buf.peek(0));
actual = await buf.peek(0);
assert(actual !== null);
assertEquals(decoder.decode(actual), "");
const r = await buf.peek(1);
assert(r === Deno.EOF);
assert(r === null);
/* TODO
Test for issue 3022, not exposing a reader's error on a successful Peek.
buf = NewReaderSize(dataAndEOFReader("abcd"), 32)
@ -396,7 +402,8 @@ Deno.test("bufReaderReadFull", async function (): Promise<void> {
const bufr = new BufReader(data, 3);
{
const buf = new Uint8Array(6);
const r = assertNotEOF(await bufr.readFull(buf));
const r = await bufr.readFull(buf);
assert(r !== null);
assertEquals(r, buf);
assertEquals(dec.decode(buf), "Hello ");
}

View file

@ -10,7 +10,7 @@ type Reader = Deno.Reader;
export class OneByteReader implements Reader {
constructor(readonly r: Reader) {}
read(p: Uint8Array): Promise<number | Deno.EOF> {
read(p: Uint8Array): Promise<number | null> {
if (p.byteLength === 0) {
return Promise.resolve(0);
}
@ -27,7 +27,7 @@ export class OneByteReader implements Reader {
export class HalfReader implements Reader {
constructor(readonly r: Reader) {}
read(p: Uint8Array): Promise<number | Deno.EOF> {
read(p: Uint8Array): Promise<number | null> {
if (!(p instanceof Uint8Array)) {
throw Error("expected Uint8Array");
}
@ -43,7 +43,7 @@ export class TimeoutReader implements Reader {
count = 0;
constructor(readonly r: Reader) {}
read(p: Uint8Array): Promise<number | Deno.EOF> {
read(p: Uint8Array): Promise<number | null> {
this.count++;
if (this.count === 2) {
throw new Deno.errors.TimedOut();

View file

@ -21,13 +21,13 @@ export async function copyN(
buf = new Uint8Array(size - bytesRead);
}
const result = await r.read(buf);
const nread = result === Deno.EOF ? 0 : result;
const nread = result ?? 0;
bytesRead += nread;
if (nread > 0) {
const n = await dest.write(buf.slice(0, nread));
assert(n === nread, "could not write");
}
if (result === Deno.EOF) {
if (result === null) {
break;
}
}
@ -35,31 +35,31 @@ export async function copyN(
}
/** Read big endian 16bit short from BufReader */
export async function readShort(buf: BufReader): Promise<number | Deno.EOF> {
export async function readShort(buf: BufReader): Promise<number | null> {
const high = await buf.readByte();
if (high === Deno.EOF) return Deno.EOF;
if (high === null) return null;
const low = await buf.readByte();
if (low === Deno.EOF) throw new Deno.errors.UnexpectedEof();
if (low === null) throw new Deno.errors.UnexpectedEof();
return (high << 8) | low;
}
/** Read big endian 32bit integer from BufReader */
export async function readInt(buf: BufReader): Promise<number | Deno.EOF> {
export async function readInt(buf: BufReader): Promise<number | null> {
const high = await readShort(buf);
if (high === Deno.EOF) return Deno.EOF;
if (high === null) return null;
const low = await readShort(buf);
if (low === Deno.EOF) throw new Deno.errors.UnexpectedEof();
if (low === null) throw new Deno.errors.UnexpectedEof();
return (high << 16) | low;
}
const MAX_SAFE_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);
/** Read big endian 64bit long from BufReader */
export async function readLong(buf: BufReader): Promise<number | Deno.EOF> {
export async function readLong(buf: BufReader): Promise<number | null> {
const high = await readInt(buf);
if (high === Deno.EOF) return Deno.EOF;
if (high === null) return null;
const low = await readInt(buf);
if (low === Deno.EOF) throw new Deno.errors.UnexpectedEof();
if (low === null) throw new Deno.errors.UnexpectedEof();
const big = (BigInt(high) << 32n) | BigInt(low);
// We probably should provide a similar API that returns BigInt values.
if (big > MAX_SAFE_INTEGER) {

View file

@ -17,7 +17,7 @@ class BinaryReader implements Reader {
constructor(private bytes: Uint8Array = new Uint8Array(0)) {}
read(p: Uint8Array): Promise<number | Deno.EOF> {
read(p: Uint8Array): Promise<number | null> {
p.set(this.bytes.subarray(this.index, p.byteLength));
this.index += p.byteLength;
return Promise.resolve(p.byteLength);

View file

@ -9,12 +9,12 @@ export class StringReader implements Reader {
constructor(private readonly s: string) {}
read(p: Uint8Array): Promise<number | Deno.EOF> {
read(p: Uint8Array): Promise<number | null> {
const n = Math.min(p.byteLength, this.buf.byteLength - this.offs);
p.set(this.buf.slice(this.offs, this.offs + n));
this.offs += n;
if (n === 0) {
return Promise.resolve(Deno.EOF);
return Promise.resolve(null);
}
return Promise.resolve(n);
}
@ -29,11 +29,11 @@ export class MultiReader implements Reader {
this.readers = readers;
}
async read(p: Uint8Array): Promise<number | Deno.EOF> {
async read(p: Uint8Array): Promise<number | null> {
const r = this.readers[this.currentIndex];
if (!r) return Deno.EOF;
if (!r) return null;
const result = await r.read(p);
if (result === Deno.EOF) {
if (result === null) {
this.currentIndex++;
return 0;
}

View file

@ -10,7 +10,7 @@ test("ioStringReader", async function (): Promise<void> {
const res0 = await r.read(new Uint8Array(6));
assertEquals(res0, 6);
const res1 = await r.read(new Uint8Array(6));
assertEquals(res1, Deno.EOF);
assertEquals(res1, null);
});
test("ioStringReader", async function (): Promise<void> {
@ -23,7 +23,7 @@ test("ioStringReader", async function (): Promise<void> {
assertEquals(res2, 3);
assertEquals(decode(buf), "def");
const res3 = await r.read(buf);
assertEquals(res3, Deno.EOF);
assertEquals(res3, null);
assertEquals(decode(buf), "def");
});

View file

@ -105,7 +105,7 @@ export function scanUntilBoundary(
newLineDashBoundary: Uint8Array,
total: number,
eof: boolean
): number | Deno.EOF {
): number | null {
if (total === 0) {
// At beginning of body, allow dashBoundary.
if (hasPrefix(buf, dashBoundary)) {
@ -115,7 +115,7 @@ export function scanUntilBoundary(
case 0:
return 0;
case 1:
return Deno.EOF;
return null;
}
}
if (hasPrefix(dashBoundary, buf)) {
@ -132,7 +132,7 @@ export function scanUntilBoundary(
case 0:
return i;
case 1:
return i > 0 ? i : Deno.EOF;
return i > 0 ? i : null;
}
}
if (hasPrefix(newLineDashBoundary, buf)) {
@ -151,12 +151,12 @@ export function scanUntilBoundary(
}
class PartReader implements Reader, Closer {
n: number | Deno.EOF = 0;
n: number | null = 0;
total = 0;
constructor(private mr: MultipartReader, public readonly headers: Headers) {}
async read(p: Uint8Array): Promise<number | Deno.EOF> {
async read(p: Uint8Array): Promise<number | null> {
const br = this.mr.bufReader;
// Read into buffer until we identify some data to return,
@ -165,7 +165,7 @@ class PartReader implements Reader, Closer {
while (this.n === 0) {
peekLength = max(peekLength, br.buffered());
const peekBuf = await br.peek(peekLength);
if (peekBuf === Deno.EOF) {
if (peekBuf === null) {
throw new Deno.errors.UnexpectedEof();
}
const eof = peekBuf.length < peekLength;
@ -183,8 +183,8 @@ class PartReader implements Reader, Closer {
}
}
if (this.n === Deno.EOF) {
return Deno.EOF;
if (this.n === null) {
return null;
}
const nread = min(p.length, this.n);
@ -288,7 +288,7 @@ export class MultipartReader {
const buf = new Buffer(new Uint8Array(maxValueBytes));
for (;;) {
const p = await this.nextPart();
if (p === Deno.EOF) {
if (p === null) {
break;
}
if (p.formName === "") {
@ -354,7 +354,7 @@ export class MultipartReader {
private currentPart: PartReader | undefined;
private partsRead = 0;
private async nextPart(): Promise<PartReader | Deno.EOF> {
private async nextPart(): Promise<PartReader | null> {
if (this.currentPart) {
this.currentPart.close();
}
@ -364,14 +364,14 @@ export class MultipartReader {
let expectNewPart = false;
for (;;) {
const line = await this.bufReader.readSlice("\n".charCodeAt(0));
if (line === Deno.EOF) {
if (line === null) {
throw new Deno.errors.UnexpectedEof();
}
if (this.isBoundaryDelimiterLine(line)) {
this.partsRead++;
const r = new TextProtoReader(this.bufReader);
const headers = await r.readMIMEHeader();
if (headers === Deno.EOF) {
if (headers === null) {
throw new Deno.errors.UnexpectedEof();
}
const np = new PartReader(this, headers);
@ -379,7 +379,7 @@ export class MultipartReader {
return np;
}
if (this.isFinalBoundary(line)) {
return Deno.EOF;
return null;
}
if (expectNewPart) {
throw new Error(`expecting a new Part; got line ${line}`);

View file

@ -31,7 +31,7 @@ test("multipartScanUntilBoundary1", function (): void {
0,
true
);
assertEquals(n, Deno.EOF);
assertEquals(n, null);
});
test("multipartScanUntilBoundary2", function (): void {

View file

@ -379,8 +379,3 @@ export function unimplemented(msg?: string): never {
export function unreachable(): never {
throw new AssertionError("unreachable");
}
export function assertNotEOF<T extends {}>(val: T | Deno.EOF): T {
assertNotEquals(val, Deno.EOF);
return val as T;
}

View file

@ -22,9 +22,9 @@ 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 | Deno.EOF> {
async readLine(): Promise<string | null> {
const s = await this.readLineSlice();
if (s === Deno.EOF) return Deno.EOF;
if (s === null) return null;
return str(s);
}
@ -48,20 +48,20 @@ export class TextProtoReader {
* "Long-Key": {"Even Longer Value"},
* }
*/
async readMIMEHeader(): Promise<Headers | Deno.EOF> {
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 === Deno.EOF) {
return Deno.EOF;
if (buf === null) {
return null;
} else if (buf[0] == charCode(" ") || buf[0] == charCode("\t")) {
line = (await this.readLineSlice()) as Uint8Array;
}
buf = await this.r.peek(1);
if (buf === Deno.EOF) {
if (buf === null) {
throw new Deno.errors.UnexpectedEof();
} else if (buf[0] == charCode(" ") || buf[0] == charCode("\t")) {
throw new Deno.errors.InvalidData(
@ -71,7 +71,7 @@ export class TextProtoReader {
while (true) {
const kv = await this.readLineSlice(); // readContinuedLineSlice
if (kv === Deno.EOF) throw new Deno.errors.UnexpectedEof();
if (kv === null) throw new Deno.errors.UnexpectedEof();
if (kv.byteLength === 0) return m;
// Key ends at first colon
@ -112,12 +112,12 @@ export class TextProtoReader {
}
}
async readLineSlice(): Promise<Uint8Array | Deno.EOF> {
async readLineSlice(): Promise<Uint8Array | null> {
// this.closeDot();
let line: Uint8Array | undefined;
while (true) {
const r = await this.r.readLine();
if (r === Deno.EOF) return Deno.EOF;
if (r === null) return null;
const { line: l, more } = r;
// Avoid the copy if the first call produced a full line.

View file

@ -6,12 +6,7 @@
import { BufReader } from "../io/bufio.ts";
import { TextProtoReader } from "./mod.ts";
import { stringsReader } from "../io/util.ts";
import {
assert,
assertEquals,
assertThrows,
assertNotEOF,
} from "../testing/asserts.ts";
import { assert, assertEquals, assertThrows } from "../testing/asserts.ts";
const { test } = Deno;
function reader(s: string): TextProtoReader {
@ -31,7 +26,7 @@ test({
test("[textproto] ReadEmpty", async () => {
const r = reader("");
const m = await r.readMIMEHeader();
assertEquals(m, Deno.EOF);
assertEquals(m, null);
});
test("[textproto] Reader", async () => {
@ -43,7 +38,7 @@ test("[textproto] Reader", async () => {
assertEquals(s, "line2");
s = await r.readLine();
assert(s === Deno.EOF);
assert(s === null);
});
test({
@ -53,7 +48,8 @@ test({
"my-key: Value 1 \r\nLong-key: Even Longer Value\r\nmy-Key: " +
"Value 2\r\n\n";
const r = reader(input);
const m = assertNotEOF(await r.readMIMEHeader());
const m = await r.readMIMEHeader();
assert(m !== null);
assertEquals(m.get("My-Key"), "Value 1, Value 2");
assertEquals(m.get("Long-key"), "Even Longer Value");
},
@ -64,7 +60,8 @@ test({
async fn(): Promise<void> {
const input = "Foo: bar\n\n";
const r = reader(input);
const m = assertNotEOF(await r.readMIMEHeader());
const m = await r.readMIMEHeader();
assert(m !== null);
assertEquals(m.get("Foo"), "bar");
},
});
@ -74,7 +71,8 @@ test({
async fn(): Promise<void> {
const input = ": bar\ntest-1: 1\n\n";
const r = reader(input);
const m = assertNotEOF(await r.readMIMEHeader());
const m = await r.readMIMEHeader();
assert(m !== null);
assertEquals(m.get("Test-1"), "1");
},
});
@ -89,7 +87,8 @@ test({
}
const sdata = data.join("");
const r = reader(`Cookie: ${sdata}\r\n\r\n`);
const m = assertNotEOF(await r.readMIMEHeader());
const m = await r.readMIMEHeader();
assert(m !== null);
assertEquals(m.get("Cookie"), sdata);
},
});
@ -106,7 +105,8 @@ test({
"Audio Mode : None\r\n" +
"Privilege : 127\r\n\r\n";
const r = reader(input);
const m = assertNotEOF(await r.readMIMEHeader());
const m = await r.readMIMEHeader();
assert(m !== null);
assertEquals(m.get("Foo"), "bar");
assertEquals(m.get("Content-Language"), "en");
// Make sure we drop headers with trailing whitespace
@ -174,7 +174,8 @@ test({
"------WebKitFormBoundaryimeZ2Le9LjohiUiG--\r\n\n",
];
const r = reader(input.join(""));
const m = assertNotEOF(await r.readMIMEHeader());
const m = await r.readMIMEHeader();
assert(m !== null);
assertEquals(m.get("Accept"), "*/*");
assertEquals(m.get("Content-Disposition"), 'form-data; name="test"');
},

View file

@ -102,7 +102,7 @@ const tpr = new TextProtoReader(new BufReader(Deno.stdin));
while (true) {
await Deno.stdout.write(encode("> "));
const line = await tpr.readLine();
if (line === Deno.EOF) {
if (line === null) {
break;
}
if (line === "close") {

View file

@ -31,7 +31,7 @@ const tpr = new TextProtoReader(new BufReader(Deno.stdin));
while (true) {
await Deno.stdout.write(encode("> "));
const line = await tpr.readLine();
if (line === Deno.EOF) {
if (line === null) {
break;
}
if (line === "close") {

View file

@ -8,7 +8,7 @@ import { Sha1 } from "../util/sha1.ts";
import { writeResponse } from "../http/io.ts";
import { TextProtoReader } from "../textproto/mod.ts";
import { Deferred, deferred } from "../util/async.ts";
import { assertNotEOF } from "../testing/asserts.ts";
import { assert } from "../testing/asserts.ts";
import { concat } from "../bytes/mod.ts";
import Conn = Deno.Conn;
import Writer = Deno.Writer;
@ -149,7 +149,8 @@ export async function writeFrame(
* @throws `Error` Frame is invalid
*/
export async function readFrame(buf: BufReader): Promise<WebSocketFrame> {
let b = assertNotEOF(await buf.readByte());
let b = await buf.readByte();
assert(b !== null);
let isLastFrame = false;
switch (b >>> 4) {
case 0b1000:
@ -163,25 +164,28 @@ export async function readFrame(buf: BufReader): Promise<WebSocketFrame> {
}
const opcode = b & 0x0f;
// has_mask & payload
b = assertNotEOF(await buf.readByte());
b = await buf.readByte();
assert(b !== null);
const hasMask = b >>> 7;
let payloadLength = b & 0b01111111;
if (payloadLength === 126) {
const l = assertNotEOF(await readShort(buf));
const l = await readShort(buf);
assert(l !== null);
payloadLength = l;
} else if (payloadLength === 127) {
const l = assertNotEOF(await readLong(buf));
const l = await readLong(buf);
assert(l !== null);
payloadLength = Number(l);
}
// mask
let mask: Uint8Array | undefined;
if (hasMask) {
mask = new Uint8Array(4);
assertNotEOF(await buf.readFull(mask));
assert((await buf.readFull(mask)) !== null);
}
// payload
const payload = new Uint8Array(payloadLength);
assertNotEOF(await buf.readFull(payload));
assert((await buf.readFull(payload)) !== null);
return {
isLastFrame,
opcode,
@ -479,7 +483,7 @@ export async function handshake(
const tpReader = new TextProtoReader(bufReader);
const statusLine = await tpReader.readLine();
if (statusLine === Deno.EOF) {
if (statusLine === null) {
throw new Deno.errors.UnexpectedEof();
}
const m = statusLine.match(/^(?<version>\S+) (?<statusCode>\S+) /);
@ -497,7 +501,7 @@ export async function handshake(
}
const responseHeaders = await tpReader.readMIMEHeader();
if (responseHeaders === Deno.EOF) {
if (responseHeaders === null) {
throw new Deno.errors.UnexpectedEof();
}

View file

@ -278,7 +278,7 @@ function dummyConn(r: Reader, w: Writer): Conn {
rid: -1,
closeRead: (): void => {},
closeWrite: (): void => {},
read: (x): Promise<number | Deno.EOF> => r.read(x),
read: (x): Promise<number | null> => r.read(x),
write: (x): Promise<number> => w.write(x),
close: (): void => {},
localAddr: { transport: "tcp", hostname: "0.0.0.0", port: 0 },
@ -335,8 +335,8 @@ test("[ws] createSecKeyHasCorrectLength", () => {
test("[ws] WebSocket should throw `Deno.errors.ConnectionReset` when peer closed connection without close frame", async () => {
const buf = new Buffer();
const eofReader: Deno.Reader = {
read(_: Uint8Array): Promise<number | Deno.EOF> {
return Promise.resolve(Deno.EOF);
read(_: Uint8Array): Promise<number | null> {
return Promise.resolve(null);
},
};
const conn = dummyConn(eofReader, buf);
@ -353,8 +353,8 @@ test("[ws] WebSocket should throw `Deno.errors.ConnectionReset` when peer closed
test("[ws] WebSocket shouldn't throw `Deno.errors.UnexpectedEof` on recive()", async () => {
const buf = new Buffer();
const eofReader: Deno.Reader = {
read(_: Uint8Array): Promise<number | Deno.EOF> {
return Promise.resolve(Deno.EOF);
read(_: Uint8Array): Promise<number | null> {
return Promise.resolve(null);
},
};
const conn = dummyConn(eofReader, buf);

View file

@ -13,7 +13,7 @@ async function handle(conn: Deno.Conn): Promise<void> {
try {
while (true) {
const r = await conn.read(buffer);
if (r === Deno.EOF) {
if (r === null) {
break;
}
await conn.write(response);