Hacktoberfest 2026: as issues que os mantenedores marcaram para outubro, abertas e boas para iniciantes. Ver issues do Hacktoberfest

Angular SSR redirects can take healthy proxies upstreams out of rotation through an unbounded Location header

Fechada
#34,365 0 comentários 0 reações 0 responsáveis Ver no GitHub

Mantenedores costumam responder em até 1 dia

Ninguém assumiu esta issue ainda.

  • #34366 de @SkyZeroZx — fechado sem integrar

Avaliação

Dificuldade
3/5
Tempo estimado
Meio dia
Facilidade para iniciantes
30/100
Tipo de issue
Bug
Clareza
Razoavelmente clara
Status de atividade
Ativa
Stack de tecnologia
angular, nginx, nodejs, typescript
Domínio
backend

Direção de pesquisa

Start with createRedirectResponse() in the Angular SSR package, where resHeaders.set("Location", location) sets the header without a length check, and with the render-redirect path from #31497 that sends the Router's final URL. Linked PR #34366 is already open against this issue, so read it first. Reproduce with the lab repo linked in the issue, using a long query string. Done means the response no longer produces an oversized Location for such requests, with a test covering it.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

area: @angular/ssr
Description

createRedirectResponse() sets Location from request data without any length limit:

resHeaders.set("Location", location);

Route redirects copy request path segments into a relative redirectTo, and render redirects send the Router's final URL, query included, when it differs from the request (#31497). Both are intended, but nothing bounds the size. The header is at least as large as the request, and percent-encoding on the way makes it bigger: new URL() encodes " ' < > and the Router's query serializer encodes characters like / = ? |, so it is about 3x a raw request, and about 5x when a guard puts state.url in returnUrl and the % is encoded again. Both encodings are correct.

Behind nginx this affects other users. The response doesn't fit in nginx's default 4k proxy_buffer_size, so nginx answers 502 and counts it as a failed attempt for that backend (max_fails=1, fail_timeout=10s). With two backends and one worker, two unauthenticated GETs leave the upstream empty and every request gets 502 for about ten seconds, while both Node processes are fine.

I think this is bit similar as unpoly-rails GHSA-m875-3xf6-mf78.

A buffer sized for the app's largest redirect avoids it, but nothing tells the operator that size and it changes when someone adds a guard: for the plain returnUrl guard at nginx's 8 KB request line it is about 40 KB. max_fails=0 also avoids it, by turning passive health checks off.

The app doesn't need any redirect. With the server routes on RenderMode.Server, as in the SSR guide, this request gets a 302 with a 4,208 B Location:

GET /home/(x)?q=<1,400 raw ">     1,412 B

The ** route drops the unmatched (x) group, so the Router ends on /home?q=.... In the browser that is a replaceState; on the server #31497 turns it into a 302. Nothing in the Router needs to change.

Minimal Reproduction
// app.routes.ts
export const routes: Routes = [
  { path: "", component: Home },
  { path: "home", component: Home },
  { path: "**", component: NotFound },
];

// app.routes.server.ts
export const serverRoutes: ServerRoute[] = [
  { path: "**", renderMode: RenderMode.Server },
];
ng build
NG_ALLOWED_HOSTS=localhost PORT=4000 node dist/app/server/server.mjs &
NG_ALLOWED_HOSTS=localhost PORT=4001 node dist/app/server/server.mjs &

nginx with one worker and nothing else tuned:

worker_processes 1;
events {}
http {
  upstream ssr {
    server 127.0.0.1:4000;
    server 127.0.0.1:4001;
  }
  server {
    listen 8080;
    location / {
      proxy_pass http://ssr;
      proxy_set_header Host localhost;
    }
  }
}

The request has to go out raw, fetch and node:http percent-encode the quotes first. I sent one per second for 25 s while normal traffic hit /home, and counted until /home answered 200 again:

Setup /home OK
nginx, the config above 15.2%
nginx, Compose service with two replicas 9.5%
nginx image as shipped on 2 vCPUs (two workers) 25.2%
nginx, worker_processes auto with a shared zone 9.3%
OpenResty, plain upstream 4.8%
Kong 3.7, passive checks with 502 in unhealthy.http_statuses 1.3%
nginx, one backend 100%
Same setups without those requests 100%

I also reproduced it on a VPS with nginx behind Cloudflare.

See https://github.com/SkyZeroZx/angular-ssr-location-lab

Exception or Error
[error] upstream sent too big header while reading response header from upstream, request: "GET /home/(x)?q=..."
[warn] upstream server temporarily disabled while reading response header from upstream
[error] no live upstreams while connecting to upstream, request: "GET /home HTTP/1.1"
Your Environment
Angular CLI       22.2.2
@angular/ssr      22.2.2
@angular/core     22.2.2
@angular/router   22.2.2
Node.js           22.23.3
Build             production
Engine            AngularNodeAppEngine
Render mode       RenderMode.Server
nginx             1.27.5, 1.29.3, 1.30.4 and 1.31.2
Linguagem predominante
TypeScript
Estrelas
27k
Forks
11.8k
Merge médio
1d 3h
PRs com merge (30d)
193

Preparar o ambiente

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de angular/angular-cli

Todas as issues de angular/angular-cli

Issues semelhantes

Mais issues de TypeScript

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.