Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/shared-fetch-utils/common/httpResponse.ts
13397 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import type { HttpHeaders, HttpResponse } from './fetchTypes';
7
8
/**
9
* An HTTP response whose body may be a {@link ReadableStream} or a
10
* `DestroyableStream` (from the platform `Response` class).
11
*/
12
export interface CloneableResponse {
13
readonly status: number;
14
readonly headers: HttpHeaders;
15
readonly body: ReadableStream<Uint8Array> | { toReadableStream(): ReadableStream<Uint8Array> } | null;
16
}
17
18
/**
19
* Clones a response by teeing its body stream, returning two independent
20
* {@link HttpResponse} objects that can each be consumed separately.
21
*
22
* Both returned responses have fully functional `text()` and `json()`
23
* methods backed by their own stream branch.
24
*
25
* Accepts either an {@link HttpResponse} (with `ReadableStream` body) or a
26
* platform `Response` (with `DestroyableStream` body) transparently.
27
*/
28
export function cloneResponse(response: CloneableResponse): [HttpResponse, HttpResponse] {
29
const { status, headers } = response;
30
31
if (!response.body) {
32
return [makeHttpResponse(status, headers, null), makeHttpResponse(status, headers, null)];
33
}
34
35
const readable: ReadableStream<Uint8Array> = 'toReadableStream' in response.body
36
? response.body.toReadableStream()
37
: response.body;
38
39
const [a, b] = readable.tee();
40
return [makeHttpResponse(status, headers, a), makeHttpResponse(status, headers, b)];
41
}
42
43
function makeHttpResponse(status: number, headers: HttpHeaders, body: ReadableStream<Uint8Array> | null): HttpResponse {
44
return {
45
status,
46
headers,
47
body,
48
async text() {
49
if (!body) {
50
return '';
51
}
52
const reader = body.getReader();
53
const chunks: Uint8Array[] = [];
54
while (true) {
55
const { done, value } = await reader.read();
56
if (done) {
57
break;
58
}
59
chunks.push(value);
60
}
61
const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);
62
const merged = new Uint8Array(totalLength);
63
let offset = 0;
64
for (const chunk of chunks) {
65
merged.set(chunk, offset);
66
offset += chunk.length;
67
}
68
return new TextDecoder().decode(merged);
69
},
70
async json() {
71
return JSON.parse(await this.text());
72
},
73
};
74
}
75
76