RFC 準拠マップ
このページでは、オリジンサーバーとしての OxPHP に関わる標準を一覧にします。対象は HTTP、TLS、静的ファイル、そして PHP へのゲートウェイです。記載内容は OxPHP 0.13.0 のものです。WebDAV、プロキシ機能、共有キャッシュは対象外です。
ここでは、その動作が実際に備わっていれば実装済みとみなします。OxPHP 自身が実装している部分もあれば、OxPHP が土台とし、設定して使っている HTTP、TLS、圧縮のライブラリが担っている部分もあります。
完全に実装済み
- RFC 9112、HTTP/1.1: keep-alive、チャンク形式のボディ、
Expect: 100-continue、パイプライン処理に対応します。クライアントがヘッダーを送り終えるまでの時間は、タイムアウトで制限されます。 - RFC 9113、HTTP/2: TLS 上で動作し、事前知識(prior knowledge)で接続するクライアントには平文の 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 値を尊重し、q=0はクライアントがそのエンコーディングを拒否しているものとして扱います。圧縮されたレスポンスにはVary: Accept-Encodingと弱い ETag が付きます。イベントストリームは圧縮しません。 - RFC 9110、
Retry-After:429(レート制限ウィンドウの残り時間)、サーバーのドレイン中またはシャットダウン中の503、過負荷時の529に付けて送ります。 - RFC 6585、
429 Too Many Requests: IP 単位のレート制限はRetry-After付きの429で応答します。 - RFC 9110、HTTP の日付: ヘッダー内の日付は標準の形式で読み書きします。
- RFC 10008、
QUERYメソッド: ボディ付きで受け付け、PHP はそのボディを POST のボディと同じ方法で読み取ります。ボディサイズには専用の上限があります。Content-TypeのないQUERYリクエストには400を返します。 - RFC 7578、
multipart/form-data: ファイルアップロードは、一般的な PHP 環境と同じように動作します。 - RFC 9113 と RFC 6265、分割された
Cookieヘッダー: クライアントがCookieを複数のヘッダー行に分けて送った場合(HTTP/2 クライアントによくあります)、OxPHP は PHP に渡す前にそれらを 1 つにまとめます。 - RFC 8615、Well-Known URI: 他のドットパスはブロックしますが、
/.well-known/配下のパスは配信します。このディレクトリ内の 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 以外の標準にもいくつか対応しています。
- W3C Trace Context: 分散トレーシングは、受信した
traceparentとtracestateを引き継ぎます。どちらもない場合は新しいトレースを開始します。 - WHATWG Server-Sent Events:
Content-Type: text/event-streamを持つ PHP のレスポンスは、書き出されるそばからクライアントへストリーミングされます。 - Prometheus テキスト形式 0.0.4: 内部サーバーがヘルスエンドポイントと並べて、この形式のメトリクスを
/metricsで公開します。読み取りを許可するアドレスは制限できます。
一部実装済み
- RFC 3875、CGI/1.1: 標準の CGI 変数は
$_SERVERに入り、すべてのリクエストヘッダーはHTTP_*として届きます。未対応: 複数行で送られたヘッダーが 1 つの値にまとめられません。標準ではまとめることが求められています。$_SERVERには最後の行が、リクエスト API には最初の行が残ります。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 キャッシュ: 静的ファイルには、
max-ageを設定できるCache-Controlと、ETag、Last-Modified、Varyが付きます。未対応:immutableはなく、種類やパスに関係なくすべてのファイルに同じポリシーが適用されます。 - RFC 9110、リクエストメソッド: POST、PUT、PATCH、DELETE、QUERY ではボディを読み取り、大きすぎるボディは読み取る前に
413で拒否します。未対応: 静的ファイルは POST や DELETE を含むすべてのメソッドに、200とその内容で応答します。nginx の場合はAllowヘッダー付きの405で応答します。 - RFC 7617、Basic 認証:
AuthorizationヘッダーはHTTP_AUTHORIZATIONとして PHP に届きます。未対応:PHP_AUTH_USER、PHP_AUTH_PW、AUTH_TYPEは設定されません。 - RFC 3986、URI: パーセントデコードとホストの解析は IPv6 アドレスも含めて動作し、
.や..のセグメントを含むパスには404を返します。未対応: ルーティングの前に末尾のスラッシュが取り除かれるため、/dirは/dir/へリダイレクトせずにディレクトリインデックスを返し、ファイルは/file/でも応答します。 - RFC 6265、Cookie: OxPHP のプラグインが自分用に設定する Cookie には
SameSite、HttpOnly、Secure、Max-Ageが付きます。アプリケーションの Cookie は、通常どおり PHP のsetcookie()を通ります。未対応: 不正な形式の Cookie ペアに対して、リクエスト API のcookie()と$_COOKIEが異なる値を返すことがあります。
ロードマップ
以下は提案で、優先度順に並べています。どれも特定のリリースには予定されていません。
高優先度
- RFC 3875: 複数行で届いたヘッダーを、カンマ区切りの 1 つの値にまとめます。これにより、複数のプロキシを経由した
X-Forwarded-Forのチェーン全体が PHP から見えるようになります。 - RFC 7617: Basic 認証から
PHP_AUTH_USERとPHP_AUTH_PWを設定します。現在、これらを読み取るアプリケーションは、エラーもなく空の値を受け取ります。 - RFC 6797、HSTS: 静的ファイルやエラーページも含め、すべての HTTPS レスポンスで
Strict-Transport-Securityを送ります。静的ファイルへのリクエストは PHP に届かないため、PHP 側では静的ファイルにこのヘッダーを付けられません。
中優先度
- RFC 7239:
Forwarded内の引用符付きの値を正しく解析します。 - RFC 9110: 静的ファイルがそれ以外のメソッドを受けたときに、nginx と同じく
Allow: GET, HEAD付きの405で応答します。 - RFC 3986: 従来型モードのルーティングで
/dirを301で/dir/へリダイレクトし、古いアプリケーションの相対リンクが解決されるようにします。 - 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: HTTP/1.1 と HTTP/2 上の WebSocket。設計はまだ検討中です。
- 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']のファイルを include する古いコードは、クライアントが選んだファイルを読み込んでしまいます。 - RFC 7540、h2c アップグレード: RFC 9113 で
Upgrade: h2cハンドシェイクは廃止されました。OxPHP は事前知識を持つクライアントに TLS なしの HTTP/2 を提供しており、それで十分です。