Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/mono/wasm/runtime/http.ts')
-rw-r--r--src/mono/wasm/runtime/http.ts150
1 files changed, 150 insertions, 0 deletions
diff --git a/src/mono/wasm/runtime/http.ts b/src/mono/wasm/runtime/http.ts
new file mode 100644
index 00000000000..d8249fad0b9
--- /dev/null
+++ b/src/mono/wasm/runtime/http.ts
@@ -0,0 +1,150 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+import { wrap_as_cancelable_promise } from "./cancelable-promise";
+import { MemoryViewType, Span } from "./marshal";
+import { mono_assert } from "./types";
+import { VoidPtr } from "./types/emscripten";
+
+export function http_wasm_supports_streaming_response(): boolean {
+ return typeof Response !== "undefined" && "body" in Response.prototype && typeof ReadableStream === "function";
+}
+
+export function http_wasm_create_abort_controler(): AbortController {
+ return new AbortController();
+}
+
+export function http_wasm_abort_request(abort_controller: AbortController): void {
+ abort_controller.abort();
+}
+
+export function http_wasm_abort_response(res: ResponseExtension): void {
+ res.__abort_controller.abort();
+ if (res.__reader) {
+ res.__reader.cancel();
+ }
+}
+
+export function http_wasm_fetch_bytes(url: string, header_names: string[], header_values: string[], option_names: string[], option_values: any[], abort_controller: AbortController, bodyPtr: VoidPtr, bodyLength: number): Promise<ResponseExtension> {
+ // the bufferPtr is pinned by the caller
+ const view = new Span(bodyPtr, bodyLength, MemoryViewType.Byte);
+ const copy = view.slice() as Uint8Array;
+ return http_wasm_fetch(url, header_names, header_values, option_names, option_values, abort_controller, copy);
+}
+
+export function http_wasm_fetch(url: string, header_names: string[], header_values: string[], option_names: string[], option_values: any[], abort_controller: AbortController, body: string | Uint8Array | null): Promise<ResponseExtension> {
+ mono_assert(url && typeof url === "string", "expected url string");
+ mono_assert(header_names && header_values && Array.isArray(header_names) && Array.isArray(header_values) && header_names.length === header_values.length, "expected headerNames and headerValues arrays");
+ mono_assert(option_names && option_values && Array.isArray(option_names) && Array.isArray(option_values) && option_names.length === option_values.length, "expected headerNames and headerValues arrays");
+ const headers = new Headers();
+ for (let i = 0; i < header_names.length; i++) {
+ headers.append(header_names[i], header_values[i]);
+ }
+ const options: any = {
+ body,
+ headers,
+ signal: abort_controller.signal
+ };
+ for (let i = 0; i < option_names.length; i++) {
+ options[option_names[i]] = option_values[i];
+ }
+
+ return wrap_as_cancelable_promise(async () => {
+ const res = await fetch(url, options) as ResponseExtension;
+ res.__abort_controller = abort_controller;
+ return res;
+ });
+}
+
+function get_response_headers(res: ResponseExtension): void {
+ if (!res.__headerNames) {
+ res.__headerNames = [];
+ res.__headerValues = [];
+ const entries: Iterable<string[]> = (<any>res.headers).entries();
+
+ for (const pair of entries) {
+ res.__headerNames.push(pair[0]);
+ res.__headerValues.push(pair[1]);
+ }
+ }
+}
+
+export function http_wasm_get_response_header_names(res: ResponseExtension): string[] {
+ get_response_headers(res);
+ return res.__headerNames;
+}
+
+export function http_wasm_get_response_header_values(res: ResponseExtension): string[] {
+ get_response_headers(res);
+ return res.__headerValues;
+}
+
+export function http_wasm_get_response_length(res: ResponseExtension): Promise<number> {
+ return wrap_as_cancelable_promise(async () => {
+ const buffer = await res.arrayBuffer();
+ res.__buffer = buffer;
+ res.__source_offset = 0;
+ return buffer.byteLength;
+ });
+}
+
+export function http_wasm_get_response_bytes(res: ResponseExtension, view: Span): number {
+ mono_assert(res.__buffer, "expected resoved arrayBuffer");
+ if (res.__source_offset == res.__buffer!.byteLength) {
+ return 0;
+ }
+ const source_view = new Uint8Array(res.__buffer!, res.__source_offset);
+ view.set(source_view, 0);
+ const bytes_read = Math.min(view.byteLength, source_view.byteLength);
+ res.__source_offset += bytes_read;
+ return bytes_read;
+}
+
+export async function http_wasm_get_streamed_response_bytes(res: ResponseExtension, bufferPtr: VoidPtr, bufferLength: number): Promise<number> {
+ // the bufferPtr is pinned by the caller
+ const view = new Span(bufferPtr, bufferLength, MemoryViewType.Byte);
+ return wrap_as_cancelable_promise(async () => {
+ if (!res.__chunk && res.body) {
+ res.__reader = res.body.getReader();
+ res.__chunk = await res.__reader.read();
+ res.__source_offset = 0;
+ }
+
+ let target_offset = 0;
+ let bytes_read = 0;
+ // loop until end of browser stream or end of C# buffer
+ while (res.__reader && res.__chunk && !res.__chunk.done) {
+ const remaining_source = res.__chunk.value.byteLength - res.__source_offset;
+ if (remaining_source === 0) {
+ res.__chunk = await res.__reader.read();
+ res.__source_offset = 0;
+ continue;// are we done yet
+ }
+
+ const remaining_target = view.byteLength - target_offset;
+ const bytes_copied = Math.min(remaining_source, remaining_target);
+ const source_view = res.__chunk.value.subarray(res.__source_offset, res.__source_offset + bytes_copied);
+
+ // copy available bytes
+ view.set(source_view, target_offset);
+ target_offset += bytes_copied;
+ bytes_read += bytes_copied;
+ res.__source_offset += bytes_copied;
+
+ if (target_offset == view.byteLength) {
+ return bytes_read;
+ }
+ }
+ return bytes_read;
+ });
+}
+
+interface ResponseExtension extends Response {
+ __buffer?: ArrayBuffer
+ __reader?: ReadableStreamDefaultReader<Uint8Array>
+ __chunk?: ReadableStreamDefaultReadResult<Uint8Array>
+ __source_offset: number
+ __abort_controller: AbortController
+ __headerNames: string[];
+ __headerValues: string[];
+} \ No newline at end of file