-
-
Notifications
You must be signed in to change notification settings - Fork 38
/
readers.ts
111 lines (99 loc) 路 2.84 KB
/
readers.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Copyright 2019 Yusuke Sakurai. All rights reserved. MIT license.
import { BufReader } from "./vendor/https/deno.land/std/io/bufio.ts";
import { TextProtoReader } from "./vendor/https/deno.land/std/textproto/mod.ts";
import { promiseInterrupter } from "./promises.ts";
import Reader = Deno.Reader;
import EOF = Deno.EOF;
const nullBuffer = new Uint8Array(1024);
export async function readUntilEof(reader: Reader): Promise<number> {
let total = 0;
while (true) {
const result = await reader.read(nullBuffer);
if (result === EOF) {
break;
}
total += result;
}
return total;
}
export class BodyReader implements Reader {
total: number;
constructor(readonly reader: Reader, readonly contentLength: number) {
this.total = 0;
}
async read(p: Uint8Array): Promise<number | EOF> {
const remaining = this.contentLength - this.total;
let buf = p;
if (p.byteLength > remaining) {
buf = new Uint8Array(remaining);
}
let result = await this.reader.read(buf);
if (buf !== p) {
p.set(buf);
}
let eof = result === EOF || this.total === this.contentLength;
if (result !== EOF) {
this.total += result;
}
return eof ? EOF : result;
}
}
export class ChunkedBodyReader implements Reader {
bufReader: BufReader;
tpReader: TextProtoReader;
constructor(private reader: Reader) {
this.bufReader =
reader instanceof BufReader ? reader : new BufReader(reader);
this.tpReader = new TextProtoReader(this.bufReader);
}
chunks: Uint8Array[] = [];
crlfBuf = new Uint8Array(2);
finished: boolean = false;
async read(p: Uint8Array): Promise<number | EOF> {
if (this.finished) {
return EOF;
}
const line = await this.tpReader.readLine();
if (line === EOF) {
return EOF;
}
const len = parseInt(line, 16);
if (len === 0) {
this.finished = true;
await this.bufReader.readFull(this.crlfBuf);
return EOF;
} else {
const buf = new Uint8Array(len + 2);
const res = await this.bufReader.readFull(buf);
if (res === EOF) {
return EOF;
}
this.chunks.push(buf.slice(0, len));
}
const buf = this.chunks[0];
if (buf.byteLength <= p.byteLength) {
p.set(buf);
this.chunks.shift();
return buf.byteLength;
} else {
p.set(buf.slice(0, p.byteLength));
this.chunks[0] = buf.slice(p.byteLength, buf.byteLength);
return p.byteLength;
}
}
}
export class TimeoutReader implements Reader {
timeoutOrCancel: (p: Promise<number | EOF>) => Promise<number | EOF>;
constructor(
private readonly r: Reader,
opts: {
timeout: number;
cancel?: Promise<void>;
}
) {
this.timeoutOrCancel = promiseInterrupter(opts);
}
async read(p: Uint8Array): Promise<number | EOF> {
return await this.timeoutOrCancel(this.r.read(p));
}
}