From 208173d816648932d3beaf022343416e9d2a5b78 Mon Sep 17 00:00:00 2001 From: bot-backend Date: Sun, 16 Aug 2026 09:46:46 +0300 Subject: [PATCH] =?UTF-8?q?fix(mera/b2c):=20=D0=B4=D0=BB=D0=B8=D0=BD=D0=BD?= =?UTF-8?q?=D1=8B=D0=B5=20=D0=B0=D0=B4=D1=80=D0=B5=D1=81=D0=B0=20=D1=80?= =?UTF-8?q?=D0=B5=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE=20=D1=80=D0=B5=D0=B4=D0=B8?= =?UTF-8?q?=D1=80=D0=B5=D0=BA=D1=82=D1=8F=D1=82=20=E2=80=94=20`redir`=20?= =?UTF-8?q?=D0=B1=D0=B5=D0=B7=20=D0=BC=D0=B0=D1=82=D1=87=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=20=D0=BD=D0=B5=20=D1=81=D1=80=D0=B0=D0=B1=D0=B0=D1=82=D1=8B?= =?UTF-8?q?=D0=B2=D0=B0=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проверка на живом Caddy (локальный стенд: реальный site-блок + заглушка вместо фронта) показала, что 301 не работал вовсе: длинные адреса отдавали пустой 200. Причина — разбор Caddyfile: первый аргумент директивы, начинающийся со слэша, читается как inline path-matcher. То есть `redir / permanent` означает «для пути / редиректить на permanent», а не «редиректить на /»; матчер не совпадал, директива молча не срабатывала, наружу уходило пустое тело. Пустая страница с кодом 200 хуже 404: выглядит рабочей и не ловится ни смоуком по коду ответа, ни глазом. Замер после правки (`redir * <куда>`): /trade-in/mera-public 301 → / /trade-in/mera-public/ 301 → / /trade-in/mera-public/oferta 301 → /oferta /trade-in/mera-public/v3 301 → /v3 / 200 upstream /trade-in/mera-public /estimate 200 upstream /trade-in/mera-public/estimate /trade-in/api/public/mera/coverage 200 upstream /api/public/mera/coverage /trade-in/api/v1/me 404 /trade-in/v2 404 Заодно захват сужен до `([^/].*)` — страховка от протокол-относительной цели (`//evil.example` резолвится браузером как чужой хост). Тем же замером проверено, что сегодня это недостижимо и без ограничения: Caddy нормализует путь до матчинга, и `//evil.example` / `/%2Fevil.example` приезжают одним слэшем. Ограничение оставлено как второй барьер, комментарий говорит ровно это — а не то, что чинилась живая дыра. --- Caddyfile | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/Caddyfile b/Caddyfile index e02a49d7..b54f530c 100644 --- a/Caddyfile +++ b/Caddyfile @@ -304,14 +304,29 @@ meraocenka.ru { # параметров не принимает (форма проверки шлёт данные телом POST, а # черновик с лэндинга едет через sessionStorage — специально чтобы адрес # квартиры не попал в access-лог). + # `redir * <куда>`, а НЕ `redir <куда>`. Первый аргумент директивы, если он + # начинается со слэша, Caddy разбирает как inline path-matcher — то есть + # `redir / permanent` означает «для пути / редиректить на permanent», а не + # «редиректить на /». Проверено на живом Caddy: без `*` длинные адреса + # отдавали пустой 200 (матчер не совпадал, директива не срабатывала, тело + # пустое) — хуже, чем 404, потому что выглядит как рабочая пустая страница. @meraLongRoot path /trade-in/mera-public /trade-in/mera-public/ handle @meraLongRoot { - redir / permanent + redir * / permanent } - @meraLongSub path_regexp meralong ^/trade-in/mera-public/(.+)$ + # `([^/].*)`, а не `(.+)` — страховка от протокол-относительной цели. + # Захват, начинающийся со слэша, дал бы `redir` цель вида `//evil.example`, + # которую браузер резолвит как ЧУЖОЙ ХОСТ (открытый редирект с нашего + # домена). Проверено на живом Caddy: сегодня это недостижимо и без + # ограничения — Caddy нормализует путь ДО матчинга, схлопывая повторные + # слэши, и `//evil.example` (как и `/%2Fevil.example`) уже приезжает сюда + # одним слэшем, то есть редирект остаётся на нашем хосте. Ограничение + # оставлено намеренно: оно стоит ноль, а полагаться на нормализацию как на + # единственный барьер для дыры такого класса не хочется. + @meraLongSub path_regexp meralong ^/trade-in/mera-public/([^/].*)$ handle @meraLongSub { - redir /{re.meralong.1} permanent + redir * /{re.meralong.1} permanent } # Next.js уже эмитит ссылки на статику с /trade-in-префиксом (тот же