I am writing an HTTP proxy and as I need to use Cloudflare Workers, my choice of libraries was very limited, so I decided to create it myself.
Here is the code, which works pretty well:
export default {
async fetch(request, env, ctx): Promise<Response> {
const { search, pathname } = new URL(request.url);
const url = pathname.slice(1);
if (!url) {
return new Response("Please specify a target URL.", { status: 400 });
}
let targetURL;
try {
targetURL = new URL(url);
} catch {
return new Response("Invalid URL.", { status: 400 });
}
const forwardedRequest = new Request(targetURL, request);
const res = await fetch(forwardedRequest);
const response = new Response(res.body, res);
return response;
},
} satisfies ExportedHandler<Env>;
The system is simple: the user makes a request to https://<domain>.workers.dev/<url>
and the request is sent to url
with the headers, method and body received by the proxy server.
Unfortunately, it does not handle relative redirects. If a relative redirect is encountered, the new path is simply appended to the proxy server's domain, resulting in an invalid URL. For example, when I forward a request to https://httpbin.dev/relative-redirect/2
, instead of the proxy server redirecting to https://<domain>.workers.dev/https://httpbin.dev/relative-redirect/1
, it goes to https://<domain>.workers.dev/relative-redirect/1
, which breaks the redirect.
However, it works as expected with https://httpbin.dev/absolute-redirect/2
.
Do you have any idea on how to fix this? I do not run into the same issue when using axios
.
The redirect location is in the response's Location
header. You will have to rewrite it. You can do so by changing this part of your code:
const response = new Response(res.body, res);
return response;
To something like:
const response = new Response(res.body, res);
let location = response.headers.get("Location");
if (location) {
response.headers.set("Location", rewriteLocation(location));
}
return response;
(You'll need to figure out what logit to put in rewriteLocation()
.)