Карта соответствия 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, отправляется вместе с соответствующей директивой CSPframe-ancestorsиX-Content-Type-Options: nosniff. Заголовки, заданные вашим приложением, имеют приоритет.
Поддерживаются и несколько стандартов вне серии RFC:
- W3C Trace Context: распределённая трассировка продолжает входящие
traceparentиtracestateили начинает новую трассировку, если их нет. - WHATWG Server-Sent Events: ответ PHP с
Content-Type: text/event-streamпередаётся клиенту потоком по мере записи. - Текстовый формат Prometheus 0.0.4: внутренний сервер публикует метрики на
/metricsв этом формате, рядом с эндпоинтами проверки работоспособности. Можно ограничить адреса, с которых их разрешено читать.
Реализовано частично
- 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 для клиентов с предварительным знанием, и этого достаточно.
См. также
- TLS: сертификаты, версии и согласование HTTP/2
- Сжатие: как OxPHP выбирает Brotli, Zstandard или gzip
- Доверенные прокси: как получить реальный адрес клиента за прокси или CDN
- Суперглобальные переменные: что PHP находит в
$_SERVERи других суперглобальных переменных - Обзор архитектуры: как OxPHP обрабатывает запрос от начала до конца