Карта соответствия RFC

На этой странице перечислены стандарты, которые важны для OxPHP как исходного сервера: HTTP, TLS, статические файлы и шлюз к PHP. Она описывает OxPHP 0.13.0. WebDAV, проксирование и разделяемые кэши сюда не входят.

Стандарт считается реализованным, если нужное поведение есть. Часть этого поведения OxPHP обеспечивает сам, а часть берётся из библиотек HTTP, TLS и сжатия, на которых построен OxPHP и которые он настраивает.

Реализовано полностью

  • RFC 9112, HTTP/1.1: keep-alive, передача тела по частям (chunked), Expect: 100-continue и конвейерная обработка запросов (pipelining). Таймаут ограничивает время, за которое клиент должен прислать заголовки.
  • RFC 9113, HTTP/2: поверх TLS, а также поверх обычного TCP для клиентов, которые подключаются с предварительным знанием. Число одновременных потоков и размер заголовков ограничены, атаки Rapid Reset и MadeYouReset блокируются, а при сливе соединений сервер сообщает об этом кадром GOAWAY.
  • RFC 7541, HPACK: сжатие заголовков HTTP/2 с лимитом на размер декодированных заголовков, который отсекает запросы с «HPACK-бомбой».
  • RFC 8446 и RFC 5246, TLS 1.3 и 1.2: обе версии, а минимальную версию можно поднять до 1.3. Ранние данные 0-RTT отключены, поэтому повтор ранних запросов исключён.
  • RFC 7301, ALPN: при рукопожатии TLS выбирается h2 или http/1.1.
  • RFC 9110, запросы Range: один диапазон байтов в GET и HEAD, ответ 206 или 416. На запрос нескольких диапазонов приходит весь файл с 200, и стандарт это допускает. Если ответ сжимается, диапазоны отключаются.
  • RFC 9110, If-Range: учитывается только с сильным валидатором, как требует стандарт.
  • RFC 9110, кодирование содержимого: Brotli, gzip и Zstandard. Веса в Accept-Encoding учитываются, и q=0 означает, что клиент отказывается от этой кодировки. Сжатые ответы несут Vary: Accept-Encoding и слабый ETag. Потоки событий никогда не сжимаются.
  • RFC 9110, Retry-After: отправляется с 429 (время, оставшееся до конца окна ограничения частоты), с 503, пока сервер сливает соединения или завершает работу, и с 529, когда он перегружен.
  • RFC 6585, 429 Too Many Requests: ограничение частоты запросов по IP отвечает 429 с Retry-After.
  • RFC 9110, HTTP-даты: даты в заголовках читаются и записываются в стандартном формате.
  • RFC 10008, метод QUERY: принимается вместе с телом, которое PHP читает так же, как тело POST. Для него действует собственный лимит размера тела. Запрос QUERY без Content-Type получает 400.
  • RFC 7578, multipart/form-data: загрузка файлов работает так же, как в любой конфигурации PHP.
  • RFC 9113 и RFC 6265, разделённые заголовки Cookie: если клиент присылает Cookie несколькими строками заголовка, как часто делают клиенты HTTP/2, OxPHP объединяет их в одну до того, как их увидит PHP.
  • RFC 8615, well-known URI: пути внутри /.well-known/ отдаются, хотя остальные dot-пути блокируются. PHP-файлы в этом каталоге никогда не выполняются.
  • RFC 1918, RFC 4193 и RFC 3927, частные сети: ключевое слово private в списке доверенных прокси покрывает все эти диапазоны. Диапазон операторского NAT (RFC 6598) в него не входит, его нужно указать вручную.
  • RFC 7034, X-Frame-Options: по умолчанию SAMEORIGIN, отправляется вместе с соответствующей директивой CSP frame-ancestors и X-Content-Type-Options: nosniff. Заголовки, заданные вашим приложением, имеют приоритет.

Поддерживаются и несколько стандартов вне серии RFC:

Реализовано частично

  • RFC 3875, CGI/1.1: стандартные CGI-переменные есть в $_SERVER, а каждый заголовок запроса приходит как HTTP_*. Чего нет: заголовок, присланный несколькими строками, не объединяется в одно значение, хотя стандарт этого требует. $_SERVER сохраняет последнюю строку, а API HTTP-запроса оставляет первую. REMOTE_HOST не задаётся.
  • RFC 7239, Forwarded: OxPHP читает Forwarded и X-Forwarded-* от доверенных прокси, а за Cloudflare ещё и CF-Connecting-IP. Чего нет: значение в кавычках, содержащее запятую или точку с запятой, разбивается не в том месте. X-Real-IP не поддерживается.
  • RFC 9110, условные запросы: статические файлы поддерживают If-None-Match и If-Modified-Since и отвечают 304. Чего нет: If-Match, If-Unmodified-Since и 412 Precondition Failed.
  • RFC 9111, HTTP-кэширование: статические файлы получают Cache-Control с настраиваемым max-age, а также ETag, Last-Modified и Vary. Чего нет: директивы immutable, а политика у всех файлов одна, независимо от их типа и пути.
  • RFC 9110, методы запроса: тела читаются для POST, PUT, PATCH, DELETE и QUERY, а слишком большое тело отклоняется с 413 ещё до чтения. Чего нет: статический файл отвечает на любой метод, включая POST и DELETE, кодом 200 и своим содержимым, тогда как nginx отвечает 405 с заголовком Allow.
  • RFC 7617, Basic-аутентификация: заголовок Authorization доходит до PHP как HTTP_AUTHORIZATION. Чего нет: PHP_AUTH_USER, PHP_AUTH_PW и AUTH_TYPE не заполняются.
  • RFC 3986, URI: процентное декодирование и разбор хоста работают, в том числе для адресов IPv6, а пути с сегментами . или .. получают 404. Чего нет: завершающий слеш отбрасывается до маршрутизации, поэтому /dir отдаёт индекс каталога без перенаправления на /dir/, а файл отвечает и по адресу /file/.
  • RFC 6265, cookie: cookie, которые плагины OxPHP ставят для себя, несут SameSite, HttpOnly, Secure и Max-Age. Cookie вашего приложения, как обычно, проходят через setcookie() в PHP. Чего нет: для некорректной пары cookie метод cookie() из API HTTP-запроса и $_COOKIE могут вернуть разные значения.

Дорожная карта

Это предложения, отсортированные по приоритету. Ни одно из них не запланировано на конкретный выпуск.

Высокий приоритет

  • RFC 3875: объединять заголовок, пришедший несколькими строками, в одно значение через запятую, чтобы PHP видел всю цепочку X-Forwarded-For, которую оставляют несколько прокси подряд.
  • RFC 7617: заполнять PHP_AUTH_USER и PHP_AUTH_PW из Basic-аутентификации. Сейчас приложения, которые их читают, получают пустые значения без какой-либо ошибки.
  • RFC 6797, HSTS: отправлять Strict-Transport-Security в каждом HTTPS-ответе, включая статические файлы и страницы ошибок. PHP не может добавить его к статическим файлам, потому что эти запросы до него не доходят.

Средний приоритет

  • RFC 7239: правильно разбирать значения в кавычках в Forwarded.
  • RFC 9110: отвечать 405 с Allow: GET, HEAD, когда к статическому файлу приходит любой другой метод, как это делает nginx.
  • RFC 3986: в режиме маршрутизации Traditional перенаправлять /dir на /dir/ с кодом 301, чтобы в старых приложениях работали относительные ссылки.
  • Заголовки RateLimit (черновик IETF): отправлять RateLimit и RateLimit-Policy, чтобы клиент видел свой лимит до того, как в него упрётся. Сейчас заголовки X-RateLimit-* появляются только в ответе 429.
  • W3C Server-Timing: сообщать время ожидания в очереди и время выполнения PHP в заголовке Server-Timing. OxPHP уже измеряет и то, и другое для метрик и трассировок.

Низкий приоритет

  • RFC 9110: If-Match, If-Unmodified-Since и 412 для статических файлов. Статические файлы доступны только для чтения, поэтому это редко имело бы значение.
  • RFC 6455 и RFC 8441, WebSocket: WebSocket поверх HTTP/1.1 и HTTP/2. Архитектура ещё прорабатывается.
  • RFC 8297, Early Hints: 103 Early Hints, чтобы браузеры начинали предзагрузку ресурсов до того, как готов ответ.
  • RFC 8446, клиентские сертификаты: взаимный TLS для сред с моделью нулевого доверия.
  • RFC 9114, HTTP/3, вместе с RFC 7838, Alt-Svc: большой объём работы, и неясно, окупится ли он.

Рассмотрено и отклонено

Граница проходит между обработкой HTTP, которая входит в задачи сервера, и содержимым конкретного сайта, которое в них не входит.

  • RFC 9116, security.txt: в этом файле перечислены контакты по вопросам безопасности того, кто управляет сайтом, а серверу они неизвестны. Встроенный файл по умолчанию был бы пустым или ошибочно указывал бы на разработчиков OxPHP. Положите файл в корень документов, и OxPHP отдаст его как любой другой статический файл. nginx, Apache и FrankenPHP такой файл тоже не создают.
  • RFC 3875, PATH_TRANSLATED: стандарт рекомендует задавать эту переменную, когда задан PATH_INFO. Она нужна CGI-скриптам, которые обрабатывают какой-то другой файл. В OxPHP выполняется всегда скрипт из SCRIPT_FILENAME, а привычная связка nginx с PHP-FPM и php -S эту переменную тоже не задают. Её значение строилось бы из PATH_INFO, присланного клиентом, поэтому старый код, который подключает $_SERVER['PATH_TRANSLATED'], загрузил бы файл, выбранный клиентом.
  • RFC 7540, переход на h2c через Upgrade: RFC 9113 исключил рукопожатие Upgrade: h2c. OxPHP обслуживает HTTP/2 без TLS для клиентов с предварительным знанием, и этого достаточно.

См. также

Нашли ошибку? Сообщите →