fix(mera/b2c): длинные адреса реально редиректят — redir без матчера не срабатывал
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 9s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Successful in 44s
CI Trade-In / frontend-checks (pull_request) Successful in 59s
CI Trade-In / backend-tests (pull_request) Successful in 4m38s

Проверка на живом 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` приезжают одним
слэшем. Ограничение оставлено как второй барьер, комментарий говорит ровно
это — а не то, что чинилась живая дыра.
This commit is contained in:
bot-backend 2026-08-16 09:46:46 +03:00
parent b1fb7bb055
commit 208173d816

View file

@ -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-префиксом (тот же