Skip to content

fix(fetch): properly redirect non-ascii location header url#2971

Merged
mcollina merged 8 commits intonodejs:mainfrom
Xvezda:fix/redirect-non-ascii-location-header
Mar 21, 2024
Merged

fix(fetch): properly redirect non-ascii location header url#2971
mcollina merged 8 commits intonodejs:mainfrom
Xvezda:fix/redirect-non-ascii-location-header

Conversation

@Xvezda
Copy link
Copy Markdown
Contributor

@Xvezda Xvezda commented Mar 18, 2024

This relates to...

Rationale

The fetch function behaves differently from major web browsers(chrome, safari, firefox etc), and even CURL (with -L option).

Here is a minimal reproducible URL I made: https://non-ascii-location-header.sys.workers.dev/redirect

Worker code
export default {
	async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
		try {
			const url = new URL(request.url);
			if (url.pathname === '/redirect') {
				return new Response('', {
					status: 302,
					headers: {
						Location: '/안녕',
					},
				});
			}
			return new Response(`pathname ${url.pathname}`);
		} catch (e) {
			return new Response(`error: ${(e as Error).message}`, { status: 500 });
		}
	},
};

By accessing the address at https://non-ascii-location-header.sys.workers.dev/redirect directly
or https://non-ascii-location-header.sys.workers.dev/ first and then making a fetch request to the /redirect path using the developer tools leads to reaching https://non-ascii-location-header.sys.workers.dev/%EC%95%88%EB%85%95
which shows pathname /%EC%95%88%EB%85%95 as a result.

However, using undici fetch function does not behave in the same way.

> r = await fetch('https://non-ascii-location-header.sys.workers.dev/redirect')
... await r.text();
pathname /%C3%AC%C2%95%C2%88%C3%AB%C2%85%C2%95

This issue can also be observed at chrome web store: https://chromewebstore.google.com/detail/gbgmenmdglilmbmemagekpeaodajbeei

Welcome to Node.js v21.6.2.
Type ".help" for more information.
> await fetch('https://chromewebstore.google.com/detail/gbgmenmdglilmbmemagekpeaodajbeei')
Uncaught TypeError: fetch failed
    at node:internal/deps/undici/undici:12443:11
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async REPL1:1:33 {
  cause: Error: redirect count exceeded
      at makeNetworkError (node:internal/deps/undici/undici:5675:35)
      at httpRedirectFetch (node:internal/deps/undici/undici:10696:32)
      at httpFetch (node:internal/deps/undici/undici:10668:28)
      at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
      at async node:internal/deps/undici/undici:10440:20
      at async mainFetch (node:internal/deps/undici/undici:10430:20)
      at async httpFetch (node:internal/deps/undici/undici:10668:22)
      at async node:internal/deps/undici/undici:10440:20
      at async mainFetch (node:internal/deps/undici/undici:10430:20)
      at async httpFetch (node:internal/deps/undici/undici:10668:22)
}

I do not have an in-depth understanding of the fetch standard, so if this PR request violates the standard in any way, please feel free to close it.

Thank you.

Changes

Features

Bug Fixes

Breaking Changes and Deprecations

Status

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants