webhoster 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/HttpResponse.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/** @typedef {import('stream').Writable} Writable */
|
|
7
7
|
|
|
8
|
-
import { PassThrough,
|
|
8
|
+
import { PassThrough, pipeline } from 'node:stream';
|
|
9
9
|
|
|
10
10
|
import { isWritable } from '../utils/stream.js';
|
|
11
11
|
|
|
@@ -124,7 +124,7 @@ export default class HttpResponse {
|
|
|
124
124
|
async sendRaw(body) {
|
|
125
125
|
this.body = body;
|
|
126
126
|
await new Promise((resolve, reject) => {
|
|
127
|
-
this.stream.end(body, (
|
|
127
|
+
this.stream.end(body, (error) => (error ? reject(error) : resolve()));
|
|
128
128
|
});
|
|
129
129
|
return 0;
|
|
130
130
|
}
|
|
@@ -162,8 +162,8 @@ export default class HttpResponse {
|
|
|
162
162
|
// Called directly by user and needs finalizer calls
|
|
163
163
|
|
|
164
164
|
this.isStreaming = true;
|
|
165
|
-
for (let
|
|
166
|
-
const process = this.finalizers[
|
|
165
|
+
for (let index = 0; index < this.finalizers.length; index++) {
|
|
166
|
+
const process = this.finalizers[index];
|
|
167
167
|
const result = process(this);
|
|
168
168
|
if (result === false) {
|
|
169
169
|
break;
|
|
@@ -185,11 +185,11 @@ export default class HttpResponse {
|
|
|
185
185
|
|
|
186
186
|
this.#pipeline = array[0];
|
|
187
187
|
// @ts-ignore Bad typings
|
|
188
|
-
pipeline(array, (
|
|
188
|
+
pipeline(array, (error) => {
|
|
189
189
|
this.#pipelineComplete = true;
|
|
190
190
|
let nextCallback;
|
|
191
191
|
while ((nextCallback = this.#pipelineCallbacks.shift()) != null) {
|
|
192
|
-
nextCallback(
|
|
192
|
+
nextCallback(error);
|
|
193
193
|
}
|
|
194
194
|
});
|
|
195
195
|
return this.#pipeline;
|
|
@@ -209,7 +209,8 @@ export default class HttpResponse {
|
|
|
209
209
|
if (body !== undefined) {
|
|
210
210
|
this.body = body;
|
|
211
211
|
}
|
|
212
|
-
if (this.body
|
|
212
|
+
if (typeof this.body === 'object' && this.body !== null
|
|
213
|
+
&& (Symbol.asyncIterator in this.body)) {
|
|
213
214
|
this.isStreaming = true;
|
|
214
215
|
this.pipes.push(this.body);
|
|
215
216
|
}
|
|
@@ -234,8 +235,8 @@ export default class HttpResponse {
|
|
|
234
235
|
if (!isWritable(this.stream)) return 0;
|
|
235
236
|
if (this.isStreaming) {
|
|
236
237
|
await new Promise((resolve, reject) => {
|
|
237
|
-
this.getPipeline((
|
|
238
|
-
if (
|
|
238
|
+
this.getPipeline((error) => {
|
|
239
|
+
if (error) reject(error);
|
|
239
240
|
resolve();
|
|
240
241
|
});
|
|
241
242
|
});
|
|
@@ -268,7 +269,8 @@ export default class HttpResponse {
|
|
|
268
269
|
this.body = body;
|
|
269
270
|
}
|
|
270
271
|
|
|
271
|
-
if (this.body
|
|
272
|
+
if (typeof this.body === 'object' && this.body !== null
|
|
273
|
+
&& (Symbol.asyncIterator in this.body)) {
|
|
272
274
|
this.isStreaming = true;
|
|
273
275
|
this.pipes.push(this.body);
|
|
274
276
|
}
|
|
@@ -279,9 +281,9 @@ export default class HttpResponse {
|
|
|
279
281
|
let needsAsync = false;
|
|
280
282
|
/** @type {void|Promise<boolean|void>} */
|
|
281
283
|
let pendingPromise;
|
|
282
|
-
let
|
|
283
|
-
for (
|
|
284
|
-
const process = this.finalizers[
|
|
284
|
+
let index;
|
|
285
|
+
for (index = 0; index < this.finalizers.length; index++) {
|
|
286
|
+
const process = this.finalizers[index];
|
|
285
287
|
if (needsAsync) {
|
|
286
288
|
pendingProcessors.push(process);
|
|
287
289
|
continue;
|
|
@@ -301,8 +303,8 @@ export default class HttpResponse {
|
|
|
301
303
|
if (pendingPromise) {
|
|
302
304
|
pendingPromise.then(async (initialResult) => {
|
|
303
305
|
if (initialResult !== false) {
|
|
304
|
-
for (
|
|
305
|
-
const process = pendingProcessors[
|
|
306
|
+
for (index = 0; index < pendingProcessors.length; index++) {
|
|
307
|
+
const process = pendingProcessors[index];
|
|
306
308
|
const result = process(this);
|
|
307
309
|
if (result === true || result == null) {
|
|
308
310
|
continue;
|
package/package.json
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { PassThrough } from 'node:stream';
|
|
3
|
+
|
|
4
|
+
import HttpHandler from '../../../lib/HttpHandler.js';
|
|
5
|
+
import HttpResponse from '../../../lib/HttpResponse.js';
|
|
6
|
+
import HttpTransaction from '../../../lib/HttpTransaction.js';
|
|
7
|
+
|
|
8
|
+
test('middleware can return async iterable body', async (t) => {
|
|
9
|
+
const stream = new PassThrough();
|
|
10
|
+
const reader = new PassThrough();
|
|
11
|
+
stream.pipe(reader);
|
|
12
|
+
|
|
13
|
+
const response = new HttpResponse({ stream, onSendHeaders: () => {} });
|
|
14
|
+
const transaction = new HttpTransaction({ request: {}, response, socket: {}, httpVersion: '1.1' });
|
|
15
|
+
|
|
16
|
+
const handler = new HttpHandler();
|
|
17
|
+
|
|
18
|
+
// Middleware returns an async generator (async iterable)
|
|
19
|
+
const mw = async () => {
|
|
20
|
+
async function* gen() {
|
|
21
|
+
yield Buffer.from('m1-');
|
|
22
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
23
|
+
yield Buffer.from('m2');
|
|
24
|
+
}
|
|
25
|
+
return gen();
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const result = await handler.processMiddleware(transaction, mw);
|
|
29
|
+
t.truthy(result !== undefined);
|
|
30
|
+
|
|
31
|
+
let out = '';
|
|
32
|
+
for await (const chunk of reader) {
|
|
33
|
+
out += chunk.toString();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
t.is(out, 'm1-m2');
|
|
37
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { PassThrough } from 'node:stream';
|
|
3
|
+
|
|
4
|
+
import HttpHandler from '../../../lib/HttpHandler.js';
|
|
5
|
+
import HttpResponse from '../../../lib/HttpResponse.js';
|
|
6
|
+
|
|
7
|
+
test('HttpResponse.send() accepts async iterable body', async (t) => {
|
|
8
|
+
const stream = new PassThrough();
|
|
9
|
+
const reader = new PassThrough();
|
|
10
|
+
stream.pipe(reader);
|
|
11
|
+
|
|
12
|
+
const response = new HttpResponse({ stream, onSendHeaders: () => {} });
|
|
13
|
+
|
|
14
|
+
async function* gen() {
|
|
15
|
+
yield Buffer.from('chunk1-');
|
|
16
|
+
// allow microtask scheduling
|
|
17
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
18
|
+
yield Buffer.from('chunk2');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
response.body = gen();
|
|
22
|
+
|
|
23
|
+
const result = await response.send();
|
|
24
|
+
t.is(result, HttpHandler.END);
|
|
25
|
+
|
|
26
|
+
let out = '';
|
|
27
|
+
for await (const chunk of reader) {
|
|
28
|
+
out += chunk.toString();
|
|
29
|
+
}
|
|
30
|
+
t.is(out, 'chunk1-chunk2');
|
|
31
|
+
});
|