kit-sub: на мусорную строку запроса – «HTTP/1.1 400 Bad Request», как у nginx

Python считал такой запрос HTTP/0.9 и отвечал одним телом, без строки статуса и
заголовков. Теперь ошибки разбора запроса идут со строкой статуса HTTP/1.1,
Server: nginx и Connection: close. Тесты – в tools/test/kitsub_http_test.py.
This commit is contained in:
maxdmitrov
2026-10-06 17:02:34 +03:00
parent 1aa9a84e96
commit 220d82c01e
3 changed files with 17 additions and 1 deletions
+1 -1
View File
@@ -12,7 +12,7 @@
* Исправил `--restore` на сервер с другим IP: ссылки части протоколов (адреса в таблице `hosts` панели и в настройках kit-sub) оставались со старым IP, а проверка панели после запуска могла ложно сообщить «Панель не отвечает», если панель стартует не сразу. А файлы настроек из копии `--restore` теперь читает строго по списку, как охранник на входе: лишнее имя – и копия не принимается, ничего не меняется.
* Исправил `kit backup`: из `/root` он падал с «No such file or directory», работал только из `/`. Теперь работает откуда угодно. Если токен API панели в `/etc/x-ui/install-result.env` не подошёл (так бывает после обновления с 1.0), `kit` сам выпускает новый и сохраняет его, а если панель всё же не отвечает – говорит по-человечески (код ответа и вероятная причина), а не «Unsupported HTTP version in response».
* Сайт-заглушка теперь у каждого сервера своя: при установке она собирается из двадцати тем и пяти вёрсток со случайным названием, текстами и цветами. Пекарня, переводчик или мастерская по велосипедам – как повезёт. Раньше у многих серверов был один и тот же «облачный» сосед.
* `kit-sub` на своём порту (`--multi-port`) отвечает по HTTP/1.1 и с `Server: nginx` без лишнего пробела – как настоящий nginx, а не его двоюродный брат.
* `kit-sub` на своём порту (`--multi-port`) отвечает по HTTP/1.1 и с `Server: nginx` без лишнего пробела, а на бессмыслицу вместо запроса – честным `400 Bad Request` со строкой статуса. Как настоящий nginx, а не его двоюродный брат.
* Исправил `kit net masq on`: Hysteria2 после него переставала слушать порт до перезапуска панели, а `kit net fp` и `kit net on` спотыкались о то же. Панель меняет подключение на ходу, а ядро такую правку не принимает. Теперь `kit` проверяет порты после каждой правки и, если что-то закрылось, перезапускает ядро и честно об этом говорит. А `kit check` научился смотреть, запущено ли ядро Xray и слушает ли каждое подключение свой порт, TCP и UDP отдельно: nginx на 443/tcp больше не выдаёт себя за Hysteria2 на 443/udp.
* `--restore` на новый IP, где Let's Encrypt не выдал сертификат (лимит или закрытый порт 80), раньше говорил «Готово», а ядро Xray не запускалось: подключения ждали сертификат, которого нет. Теперь я ставлю самоподписанный, закрепляю его отпечаток в ссылках и прямо говорю об этом. А если ядро всё же не поднялось, «Готово» не будет: покажу, где смотреть. Копию с пустой папкой сертификата `--restore` теперь отклоняет сразу, а не на полпути установки.
* JSON-подписка снова открывается в приложениях на Xray: там, где у vless не было `encryption`, подписка теперь дописывает `none`.
+3
View File
@@ -372,6 +372,9 @@ class Handler(http.server.BaseHTTPRequestHandler):
def send_error(self, code, message=None, explain=None):
# Свои ответы вместо страницы ошибок Python, в том же виде, что у обычного nginx.
# На мусорную строку запроса Python считает запрос HTTP/0.9 и пишет одно тело, без строки статуса;
# nginx отвечает «HTTP/1.1 400 Bad Request» с заголовками.
self.request_version = "HTTP/1.1"
self.close_connection = True
self.send_html_error(code)
+13
View File
@@ -45,6 +45,19 @@ class Http(unittest.TestCase):
self.assertIn("Connection: close", r)
self.assertNotIn("<open>", r)
def test_garbage_request_line(self):
for req in (b"GARBAGE\r\n\r\n", b"GET\r\n\r\n", b"GET / HTTP/1.1 x\r\n\r\n", b"POST /\r\n\r\n"):
r = raw(req)
self.assertTrue(r.startswith("HTTP/1.1 400 Bad Request\r\n"), (req, r[:60]))
self.assertIn("\r\nServer: nginx\r\n", r)
self.assertIn("Connection: close", r)
self.assertIn("<center><h1>400 Bad Request</h1></center>", r)
self.assertNotIn("<open>", r)
def test_bad_version(self):
r = raw(b"GET / HTTP/9.9\r\n\r\n")
self.assertTrue(r.startswith("HTTP/1.1 505"), r[:40])
if __name__ == "__main__":
unittest.main()