Repository: awslabs/llrt
File: src/http/fetch.rs (Rust)

Code before:
                    let req = build_request(&ctx, &method, &uri, &options.headers, &options.body)?;

                    let res = if let Some(abort_receiver) = &abort_receiver {
                        select! {
                            res = client.request(req) => res.or_throw(&ctx)?,
                            reason = abort_receiver.recv() => return Err(ctx.throw(reason))
                        }
                    } else {
                        client.request(req).await.or_throw(&ctx)?
                    };

                    match res.headers().get(HeaderName::from_static("location")) {
                        Some(location_headers) => {
                            if let Ok(location_str) = location_headers.to_str() {
                                uri = location_str.parse().or_throw(&ctx)?;
                                ensure_url_access(&ctx, &uri)?;
                            }
                        },
                        None => break res,
                    };

                    if options.redirect == "manual" {
                        return Err(Exception::throw_type(&ctx, "Unsupported redirect option"));
                    } else if options.redirect == "error" {
                        // TODO: Return Response({type: “error”, status: 0}) to terminate fetch.
                        return Err(Exception::throw_message(&ctx, "TODO: Not Implemented options.redirect: errror"));
                    }

                    redirect_count += 1;
                    if redirect_count >= MAX_REDIRECT_COUNT {
                        // TODO: Return Response({type: “error”, status: 0}) to terminate fetch.
                        return Err(Exception::throw_message(&ctx, "Max retries exceeded"));
                    }
                };

                Response::from_incoming(ctx, res, method_string, options.url, start, abort_receiver)
            }
        })),
    )?;
    Ok(())
}

fn build_request(
    ctx: &Ctx<'_>,
    method: &hyper::Method,
    uri: &Uri,
    headers: &Option<Headers>,
    body: &Full<Bytes>,
) -> Result<Request<Full<Bytes>>> {
    let mut req = Request::builder()
        .method(method.clone())

Review comment (suggestion):
Its fine to just return exception here:
`Error: unexpected redirect`

Code after:
                let mut response_status = 0;
                let res = loop {
                    let req = build_request(
                        &ctx,
                        &method,
                        &uri,
                        &options.headers,
                        &options.body,
                        &response_status,
                        &initial_uri,
                    )?;

                    let res = if let Some(abort_receiver) = &abort_receiver {
                        select! {
                            res = client.request(req) => res.or_throw(&ctx)?,
                            reason = abort_receiver.recv() => return Err(ctx.throw(reason))
                        }
                    } else {
                        client.request(req).await.or_throw(&ctx)?
                    };

                    match res.headers().get(HeaderName::from_static("location")) {
                        Some(location_headers) => {
                            if let Ok(location_str) = location_headers.to_str() {
                                uri = location_str.parse().or_throw(&ctx)?;
                                ensure_url_access(&ctx, &uri)?;
                            }
                        },
                        None => break res,
                    };

                    if options.redirect == "manual" {
                        break res;
                    } else if options.redirect == "error" {
                        return Err(Exception::throw_message(&ctx, "Unexpected redirect"));
                    }

                    redirect_count += 1;
                    if redirect_count >= MAX_REDIRECT_COUNT {
                        return Err(Exception::throw_message(&ctx, "Max retries exceeded"));
                    }

                    response_status = res.status().as_u16();
                };

                Response::from_incoming(ctx, res, method_string, options.url, start, abort_receiver)
            }
        })),
    )?;
    Ok(())
}