UNPKG

5.66 kBJavaScriptView Raw
1"use strict";
2/*---------------------------------------------------------------------------------------------
3 * Copyright (c) Microsoft Corporation. All rights reserved.
4 * Licensed under the MIT License. See License.txt in the project root for license information.
5 *--------------------------------------------------------------------------------------------*/
6Object.defineProperty(exports, "__esModule", { value: true });
7exports.AbstractMessageBuffer = void 0;
8const CR = 13;
9const LF = 10;
10const CRLF = '\r\n';
11class AbstractMessageBuffer {
12 constructor(encoding = 'utf-8') {
13 this._encoding = encoding;
14 this._chunks = [];
15 this._totalLength = 0;
16 }
17 get encoding() {
18 return this._encoding;
19 }
20 append(chunk) {
21 const toAppend = typeof chunk === 'string' ? this.fromString(chunk, this._encoding) : chunk;
22 this._chunks.push(toAppend);
23 this._totalLength += toAppend.byteLength;
24 }
25 tryReadHeaders(lowerCaseKeys = false) {
26 if (this._chunks.length === 0) {
27 return undefined;
28 }
29 let state = 0;
30 let chunkIndex = 0;
31 let offset = 0;
32 let chunkBytesRead = 0;
33 row: while (chunkIndex < this._chunks.length) {
34 const chunk = this._chunks[chunkIndex];
35 offset = 0;
36 column: while (offset < chunk.length) {
37 const value = chunk[offset];
38 switch (value) {
39 case CR:
40 switch (state) {
41 case 0:
42 state = 1;
43 break;
44 case 2:
45 state = 3;
46 break;
47 default:
48 state = 0;
49 }
50 break;
51 case LF:
52 switch (state) {
53 case 1:
54 state = 2;
55 break;
56 case 3:
57 state = 4;
58 offset++;
59 break row;
60 default:
61 state = 0;
62 }
63 break;
64 default:
65 state = 0;
66 }
67 offset++;
68 }
69 chunkBytesRead += chunk.byteLength;
70 chunkIndex++;
71 }
72 if (state !== 4) {
73 return undefined;
74 }
75 // The buffer contains the two CRLF at the end. So we will
76 // have two empty lines after the split at the end as well.
77 const buffer = this._read(chunkBytesRead + offset);
78 const result = new Map();
79 const headers = this.toString(buffer, 'ascii').split(CRLF);
80 if (headers.length < 2) {
81 return result;
82 }
83 for (let i = 0; i < headers.length - 2; i++) {
84 const header = headers[i];
85 const index = header.indexOf(':');
86 if (index === -1) {
87 throw new Error(`Message header must separate key and value using ':'\n${header}`);
88 }
89 const key = header.substr(0, index);
90 const value = header.substr(index + 1).trim();
91 result.set(lowerCaseKeys ? key.toLowerCase() : key, value);
92 }
93 return result;
94 }
95 tryReadBody(length) {
96 if (this._totalLength < length) {
97 return undefined;
98 }
99 return this._read(length);
100 }
101 get numberOfBytes() {
102 return this._totalLength;
103 }
104 _read(byteCount) {
105 if (byteCount === 0) {
106 return this.emptyBuffer();
107 }
108 if (byteCount > this._totalLength) {
109 throw new Error(`Cannot read so many bytes!`);
110 }
111 if (this._chunks[0].byteLength === byteCount) {
112 // super fast path, precisely first chunk must be returned
113 const chunk = this._chunks[0];
114 this._chunks.shift();
115 this._totalLength -= byteCount;
116 return this.asNative(chunk);
117 }
118 if (this._chunks[0].byteLength > byteCount) {
119 // fast path, the reading is entirely within the first chunk
120 const chunk = this._chunks[0];
121 const result = this.asNative(chunk, byteCount);
122 this._chunks[0] = chunk.slice(byteCount);
123 this._totalLength -= byteCount;
124 return result;
125 }
126 const result = this.allocNative(byteCount);
127 let resultOffset = 0;
128 let chunkIndex = 0;
129 while (byteCount > 0) {
130 const chunk = this._chunks[chunkIndex];
131 if (chunk.byteLength > byteCount) {
132 // this chunk will survive
133 const chunkPart = chunk.slice(0, byteCount);
134 result.set(chunkPart, resultOffset);
135 resultOffset += byteCount;
136 this._chunks[chunkIndex] = chunk.slice(byteCount);
137 this._totalLength -= byteCount;
138 byteCount -= byteCount;
139 }
140 else {
141 // this chunk will be entirely read
142 result.set(chunk, resultOffset);
143 resultOffset += chunk.byteLength;
144 this._chunks.shift();
145 this._totalLength -= chunk.byteLength;
146 byteCount -= chunk.byteLength;
147 }
148 }
149 return result;
150 }
151}
152exports.AbstractMessageBuffer = AbstractMessageBuffer;