Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

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

クローズ
#34,365 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

  • #34366 @SkyZeroZx による — マージされずにクローズ

評価

難易度
3/5
見積もり時間
半日
初心者へのやさしさ
30/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
angular, nginx, nodejs, typescript
領域
backend

調査の方向性

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.

索引モデルが issue の本文から書いたものです。

説明

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
主要言語
TypeScript
スター
27k
フォーク
11.8k
平均マージ
1日 3時間
マージ済み PR(30日)
193

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

angular/angular-cli のほかの issue

angular/angular-cli の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。