diff options
Diffstat (limited to 'js/fetch.ts')
-rw-r--r-- | js/fetch.ts | 106 |
1 files changed, 80 insertions, 26 deletions
diff --git a/js/fetch.ts b/js/fetch.ts index d5f01b870..3659710c5 100644 --- a/js/fetch.ts +++ b/js/fetch.ts @@ -247,7 +247,7 @@ export class Response implements domTypes.Response { readonly url: string = ""; statusText = "FIXME"; // TODO readonly type = "basic"; // TODO - redirected = false; // TODO + readonly redirected: boolean; headers: domTypes.Headers; readonly trailer: Promise<domTypes.Headers>; bodyUsed = false; @@ -257,6 +257,7 @@ export class Response implements domTypes.Response { readonly status: number, headersList: Array<[string, string]>, rid: number, + redirected_: boolean, body_: null | Body = null ) { this.trailer = createResolvable(); @@ -268,6 +269,8 @@ export class Response implements domTypes.Response { } else { this.body = body_; } + + this.redirected = redirected_; } async arrayBuffer(): Promise<ArrayBuffer> { @@ -308,7 +311,13 @@ export class Response implements domTypes.Response { headersList.push(header); } - return new Response(this.status, headersList, -1, this.body); + return new Response( + this.status, + headersList, + -1, + this.redirected, + this.body + ); } } @@ -352,6 +361,29 @@ function deserializeHeaderFields(m: msg.HttpHeader): Array<[string, string]> { return out; } +async function getFetchRes( + url: string, + method: string | null, + headers: domTypes.Headers | null, + body: ArrayBufferView | undefined +): Promise<msg.FetchRes> { + // Send Fetch message + const builder = flatbuffers.createBuilder(); + const headerOff = msgHttpRequest(builder, url, method, headers); + const resBase = await sendAsync( + builder, + msg.Any.Fetch, + msg.Fetch.createFetch(builder, headerOff), + body + ); + + // Decode FetchRes + assert(msg.Any.FetchRes === resBase.innerType()); + const inner = new msg.FetchRes(); + assert(resBase.inner(inner) != null); + return inner; +} + /** Fetch a resource from the network. */ export async function fetch( input: domTypes.Request | string, @@ -361,6 +393,8 @@ export async function fetch( let method: string | null = null; let headers: domTypes.Headers | null = null; let body: ArrayBufferView | undefined; + let redirected = false; + let remRedirectCount = 20; // TODO: use a better way to handle if (typeof input === "string") { url = input; @@ -414,28 +448,48 @@ export async function fetch( } } - // Send Fetch message - const builder = flatbuffers.createBuilder(); - const headerOff = msgHttpRequest(builder, url, method, headers); - const resBase = await sendAsync( - builder, - msg.Any.Fetch, - msg.Fetch.createFetch(builder, headerOff), - body - ); - - // Decode FetchRes - assert(msg.Any.FetchRes === resBase.innerType()); - const inner = new msg.FetchRes(); - assert(resBase.inner(inner) != null); - - const header = inner.header()!; - const bodyRid = inner.bodyRid(); - assert(!header.isRequest()); - const status = header.status(); - - const headersList = deserializeHeaderFields(header); - - const response = new Response(status, headersList, bodyRid); - return response; + while (remRedirectCount) { + const inner = await getFetchRes(url, method, headers, body); + + const header = inner.header()!; + const bodyRid = inner.bodyRid(); + assert(!header.isRequest()); + const status = header.status(); + + const headersList = deserializeHeaderFields(header); + + const response = new Response(status, headersList, bodyRid, redirected); + if ([301, 302, 303, 307, 308].includes(response.status)) { + // We're in a redirect status + switch ((init && init.redirect) || "follow") { + case "error": + throw notImplemented(); + case "manual": + throw notImplemented(); + case "follow": + default: + let redirectUrl = response.headers.get("Location"); + if (redirectUrl == null) { + return response; // Unspecified + } + if ( + !redirectUrl.startsWith("http://") && + !redirectUrl.startsWith("https://") + ) { + redirectUrl = + url.split("//")[0] + + "//" + + url.split("//")[1].split("/")[0] + + redirectUrl; // TODO: handle relative redirection more gracefully + } + url = redirectUrl; + redirected = true; + remRedirectCount--; + } + } else { + return response; + } + } + // Return a network error due to too many redirections + throw notImplemented(); } |