Windowsで作る - PHPプログラミングの開発環境
このページへのアクセス 今日: 0 / 昨日: 3 総計: 4220
文書の過去の版を表示しています。
— y2sunlight 2020-05-25
本章は、若干の補足を加筆してはいるものの単にPSRのサイトを翻訳したものに過ぎません。英語が堪能な方は原文をご参照下さい。翻訳に当たっては、基本的に機械翻訳を使い、理解できない部分は独断で意訳しております。拙い訳では御座いますが恥を忍んで投稿しておりますので、ご指摘など御座いましたらコメントを頂ければ幸いです。
関連記事
— // 原文より翻訳 PSR-7: HTTP message interfaces 2020-05-25 現在 //
このドキュメントでは、RFC 7230 および RFC 7231 で説明されているHTTPメッセージを表すための一般的なインターフェイスと、RFC 3986 で説明されているHTTPメッセージで使用するURIについて説明します。
HTTPメッセージはWeb開発の基礎です。WebブラウザーとcURLなどのHTTPクライアントは、HTTPレスポンスメッセージを提供するWebサーバーに送信されるHTTPリクエストメッセージを作成します。サーバー側コードは、HTTPリクエストメッセージを受信し、HTTPレスポンスメッセージを返します。
HTTPメッセージは通常、エンドユーザー(コンシューマー)からは抽象化されていますが、開発者は通常、HTTP APIにリクエストを送信する場合でも、または着信リクエストを処理する場合でも、タスクを実行するために、それらの構造とアクセスまたは操作の方法を知る必要があります。
原文では、コンシューマー(consumer)と言う表現が多く見られます。これはエンドユーザーと同じ意味で使用されていると思われます。
すべてのHTTPリクエストメッセージには特定の形式があります:
POST /path HTTP/1.1 Host: example.com foo=bar&baz=bat
リクエストの最初の行は「リクエストライン」であり、HTTPリクエストメソッド、リクエストターゲット(通常は絶対URIまたはWebサーバー上のパス)、HTTPプロトコルバージョンが順に含まれます。この後には、1行以上のHTTPヘッダー、空行、およびメッセージボディが続きます。
HTTPレスポンスメッセージも同様の構造を持っています:
HTTP/1.1 200 OK Content-Type: text/plain This is the response body
最初の行は「ステータスライン」で、HTTPプロトコルのバージョン、HTTPステータスコード、「理由フレーズ」が順に含まれます。「理由フレーズ」とは、ステータスコードの人間が読める説明のことです。 リクエストメッセージと同様に、この後に1行以上のHTTPヘッダー、空行、およびメッセージボディが続きます。
このドキュメントで説明されているインターフェースは、HTTPメッセージとそれらを構成する要素に関する抽象化です。
このドキュメントのキーワード MUST , MUST NOT , REQUIRED , SHALL , SHALL NOT , SHOULD , SHOULD NOT , RECOMMENDED , MAY 及び OPTIONAL は、 RFC 2119で説明されているように解釈して下さい。
MUST
MUST NOT
REQUIRED
SHALL
SHALL NOT
SHOULD
SHOULD NOT
RECOMMENDED
MAY
OPTIONAL
RFC 2119の説明 MUST, REQUIRED, SHALL — 絶対必要 MUST NOT, SHALL NOT — 絶対禁止 SHOULD, RECOMMENDED — 推奨(但し、無視できる特定の正当な理由が存在するかもしれない) SHOULD NOT — 推奨できない(但し、許可できる特定の正当な理由が存在するかもしれない) MAY, OPTIONAL — オプション
HTTPメッセージは、クライアントからサーバーへのリクエスト、またはサーバーからクライアントへのレスポンスです。この仕様は、HTTPメッセージ Psr\Http\Message\RequestInterfaceコード および Psr\Http\Message\ResponseInterface に対するインターフェースをそれぞれ定義します。
Psr\Http\Message\RequestInterface
コード
Psr\Http\Message\ResponseInterface
Psr\Http\Message\RequestInterface と Psr\Http\Message\ResponseInterface はどちらも Psr\Http\Message\MessageInterface を拡張(extends)します。Psr\Http\Message\MessageInterface を直接実装(implements)してもかまいませんが( MAY )、実装者は Psr\Http\Message\RequestInterface と Psr\Http\Message\ResponseInterface を実装する必要があります ( SHOULD )。
Psr\Http\Message\MessageInterface
これ以降、これらのインターフェースを参照する場合、名前空間 Psr\Http\Message は省略されます。
Psr\Http\Message
HTTPメッセージには、Case-insensitiveな(大文字と小文字を区別しない)ヘッダーフィールド名が含まれます。ヘッダーは、Case-insensitiveな方法で MessageInterface を実装しているクラスから名前で取得されます。たとえば、fooヘッダーを取得する場合、FoOコードヘッダーを取得した場合と同じ結果が返されます。 同様に、Fooヘッダーを設定すると、先に設定されたfooヘッダー値が上書きされます。
MessageInterface
foo
FoO
Foo
$message = $message->withHeader('foo', 'bar'); echo $message->getHeaderLine('foo'); // Outputs: bar echo $message->getHeaderLine('FOO'); // Outputs: bar $message = $message->withHeader('fOO', 'baz'); echo $message->getHeaderLine('foo'); // Outputs: baz
ヘッダーは大文字と小文字を区別せずに取得できますが、特に getHeaders() を使用して取得する場合は、実装によって元の大文字と小文字を維持する必要があります( MUST )。
getHeaders()
非準拠のHTTPアプリケーションはある特定のケースに依存するかもしれません。従って、ユーザーがリクエストまたはレスポンスを作成する時に、そのケースのHTTPヘッダーを指定できることは有益です。
複数の値を持つヘッダーに対応しつつ、ヘッダーを文字列として操作する便利さを提供するために、ヘッダーは MessageInterface のインスタンスから配列または文字列として取得できます。getHeaderLine() メソッドを使用して、名前によってCase-insensitiveなヘッダーに対するヘッダー値を文字列として取得して下さい。その文字列には、カンマで連結されたすべてのヘッダー値が含まれています。getHeader() を使用して、名前によって特定のCase-insensitiveなヘッダーに対するすべてのヘッダー値を配列で取得して下さい。
getHeaderLine()
getHeader()
$message = $message ->withHeader('foo', 'bar') ->withAddedHeader('foo', 'baz'); $header = $message->getHeaderLine('foo'); // $header contains: 'bar,baz' $header = $message->getHeader('foo'); // ['bar', 'baz']
注意:すべてのヘッダー値をカンマを使用して連結できるわけではありません(例えば、Set-Cookie)。このようなヘッダーを操作する場合、MessageInterface ベースのクラスのコンシューマーは、そのような複数値のヘッダーを取得するために getHeader() メソッドに頼るべきです ( SHOULD )。
Set-Cookie
リクエストでは、Hostヘッダーは通常、URIのホストコンポーネントと、TCP接続を確立するときに使用されたホストをミラーリングします。 ただし、HTTP仕様では、Hostヘッダーが2つのそれぞれのヘッダーと異なることを許可しています。
Host
(リクエストオブジェクトの)構築中、'Hostヘッダーが提供されていない場合、実装は提供されたURIから'Hostヘッダーを設定しようと試みる必要があります( MUST )。
ヘッダーが提供されていない場合、実装は提供されたURIから'Host
RequestInterface::withUri() は、デフォルトでは、返すべきリクエストのHostヘッダーを、(引数で)渡された UriInterface のホストコンポーネントと一致するHostヘッダーに置き換えます。
RequestInterface::withUri()
UriInterface
withUri() の2番目の( $preserveHost )引数に true を渡すことで、Hostヘッダーの元の状態を保持するように選択できます。この引数が true に設定されている場合、返すべきリクエストは返されたメッセージのホストヘッダーを更新しません(メッセージにHostヘッダーが含まれていない場合を除きます)。
withUri()
$preserveHost
true
上記の原文 You can opt-in to preserving the original state of the Host header by passing true for the second ($preserveHost) argument. When this argument is set to true, the returned request will not update the Host header of the returned message – unless the message contains no Host header.
この表は、様々な初期リクエストとURIに対して $preserveHost 引数を true に設定して、withUri() によって返されたリクエストに対して getHeaderLine('Host') が返すものを示しています。
getHeaderLine('Host')
※1 操作前のホストヘッダ値 ※2 操作前のリクエストに含まれるURIのホストコンポーネント ※3 withUri()を介して注入されるURIのホストコンポーネント
HTTPメッセージは、開始行、ヘッダー、および本文で構成されます。HTTPメッセージの本文は、非常に小さい場合と非常に大きい場合があります。メッセージの本文を完全にメモリに格納する必要があるため、メッセージの本文を文字列として表現しようとすると、意図したよりも多くのメモリが消費されます。リクエストまたはレスポンスの本文をメモリに保存しようとすると、その実装を使用して大きなメッセージ本文を処理できなくなります。StreamInterface は、データストリームの読み取りまたは書き込み時、実装の詳細を隠蔽するために使用されます。文字列が適切なメッセージ実装である状況では、php://memory や php:php://temp などの組み込みストリームを使用できます。
StreamInterface
php://memory
php:php://temp
StreamInterface は、ストリームの読み取り、書き込み、および効率的なトラバース(通過)を可能にするいくつかのメソッドを公開しています。
ストリームは、isReadable()、isWritable()、isSeekable() の3つのメソッドを使用してその機能を公開します。ストリームの共同作業者はこれらのメソッドを使用して、ストリームが要件を満たしているかどうかを判断できます。
isReadable()
isWritable()
isSeekable()
各ストリームのインスタンスには様々な機能があります。読み取り専用、書き込み専用、または読み書き可能です。 また、任意のランダムアクセス(任意の場所への前方または後方へのシーク)またはシーケンシャルアクセス(たとえば、ソケット、パイプ、またはコールバックベースのストリームの場合)のみを許可することもできます。
最後に、StreamInterface は __toString() メソッドを定義して、ボディコンテンツ全体を一度に取得(読み込み)または送出(書き込み)することを簡素化します。
__toString()
リクエストおよびレスポンスインターフェイスとは異なり、StreamInterface は不変性(immutability)をモデル化していません。 実際のPHPストリームがラップされている状況では、リソースとやり取りするコードがその状態(カーソルの位置、内容など)を変更する可能性があるため、不変性を強制することは不可能です。実装では、サーバー側の(HTTP)要求とクライアント側の(HTTP)応答に読み取り専用ストリームを使用することをお勧めします。コンシューマーは、ストリームのインスタンスが変更可能であり、メッセージの状態を変更する可能性があることを認識しておく必要があります。不確かな場合は、新しいストリームのインスタンスを作成し、それをメッセージにアタッチして状態を強制します。
RFC 7230に従い、リクエストメッセージには、リクエストラインの2番目のセグメントとして「リクエストターゲット」が含まれています。 リクエストターゲットは、次のいずれかの形式になります。
*
これらのリクエストターゲットとは別に、リクエストターゲットとは異なる「有効なURL」が存在することがよくあります。有効なURLはHTTPメッセージ内では送信されませんが、リクエストを行うためにプロトコル (http/https)、ポート、およびホスト名を決定するために使用されます。
有効なURLは UriInterface で表されます。UriInterface は、RFC 3986(the primary use case)で指定されているHTTPおよびHTTPS URIをモデル化します。このインターフェースは、さまざまなURI部分と対話するためのメソッドを提供します。これにより、URIを繰り返し解析する必要がなくなります。また、モデル化されたURIをその文字列表現にキャストするための__toString() メソッドも仕様に含んでいます。
getRequestTarget() を使用してリクエストターゲットを取得する場合、デフォルトでは、このメソッドはURIオブジェクトを使用し、必要なすべてのコンポーネントを抽出して origin-form を構築します。origin-form は、最も一般的なリクエストターゲットです。
getRequestTarget()
エンドユーザーが他の3つの形式(origin-form以外)のいずれかを使用したい場合、またはユーザーがリクエストターゲットを明示的にオーバーライドしたい場合は、withRequestTarget() を使用してこれを行うことができます。
withRequestTarget()
このメソッドを呼び出しは、getUri() から返されるURIには影響しません。
getUri()
たとえば、ユーザーがサーバーに asterisk-form のリクエストを行う場合があります:
$request = $request ->withMethod('OPTIONS') ->withRequestTarget('*') ->withUri(new Uri('https://example.org/'));
この例では、最終的に次のようなHTTPリクエストになります:
OPTIONS * HTTP/1.1
しかし、HTTPクライアントは、( getUri() からの ) 有効なURLを使用して、プロトコル、ホスト名、およびTCPポートを決定することができます。
HTTPクライアントは、Uri::getPath() および Uri::getQuery() の値を無視し、代わりに getRequestTarget() によって返される値を使用する必要があります ( MUST )。getRequestTarget() はデフォルトでは、これら2つの値が連結されます。
Uri::getPath()
Uri::getQuery()
4つのリクエストターゲット形式の1つ以上を実装しないことを選択したクライアントは、引き続き getRequestTarget() を使用する必要があります ( MUST )。これらのクライアントは、サポートしていないリクエストターゲットを拒否する必要があり( MUST )、getUri() からの値にフォールバックしてはなりません ( MUST NOT )。
上記の原文 Clients that choose to not implement 1 or more of the 4 request-target forms, MUST still use getRequestTarget(). These clients MUST reject request-targets they do not support, and MUST NOT fall back on the values from getUri().
上記の原文
RequestInterface は、リクエストターゲットを取得するメソッド、または指定されたリクエストターゲットを使用して新しいインスタンスを作成するメソッドを提供します。デフォルトでは、リクエストターゲットがインスタンス内で具体的に構成されていない場合、getRequestTarget() は、構成されたURIの origin-form(または構成されていない場合は「/」)を返します。
RequestInterface
withRequestTarget($requestTarget) は、指定されたリクエストターゲットを使用して新しいインスタンスを作成するので、開発者は他の3つのリクエストターゲット形式 ( absolute-form、authority-form、およびasterisk-form ) を表すリクエストメッセージを作成できます。これが使用された場合、構成されたURIインスタンスは、特にクライアント引き続き使用でき、サーバーへの接続を作成するために使用できます。
withRequestTarget($requestTarget)
RequestInterface は、HTTPリクエストメッセージの一般的な表現を提供します。ただし、サーバー側の環境の性質上、サーバー側のリクエストには追加の処理が必要です。サーバー側の処理では、Common Gateway Interface(CGI)と、さらに具体的には、PHPのサーバーAPI(SAPI)を介したCGIの抽象化と拡張を考慮する必要があります。PHPは、次のようなスーパーグローバル変数を経由して入力のマーシャリングを簡素化しました。
ServerRequestInterface は RequestInterface を拡張して、これらのさまざまなスーパーグローバル変数に関する抽象化を提供します。このプラクティスは、コンシューマーによるスーパーグローバル変数への結合を減らすのに役立ち、リクエストコンシューマーをテストする為の能力を奨励し促進します。
ServerRequestInterface
サーバーリクエストは、「attributes」という1つの追加プロパティを提供して、コンシューマーがアプリケーション固有のルール(パスマッチング、スキームマッチング、ホストマッチングなど)に対してリクエストを内省(introspect)、分解(decompose)、および照合(match)できるようにします。従って、サーバーリクエストは、複数のリクエストコンシューマー間のメッセージングを提供することもできます。
ServerRequestInterface は、正規化された構造でアップロードファイルのツリーを取得するメソッドを規定します。そのツリーの各リーフには UploadedFileInterface のインスタンスがあります。
UploadedFileInterface
$_FILES スーパーグローバル変数には、ファイル入力の配列を処理するときによく知られた問題がいくつかあります。例として、ファイルの配列を送信するフォームがある場合(例えば入力名を「files」とする)、files[0] と files[1] を送信すると、PHPはこれを次のように表します:
$_FILES
files[0]
files[1]
array( 'files' => array( 'name' => array( 0 => 'file0.txt', 1 => 'file1.html', ), 'type' => array( 0 => 'text/plain', 1 => 'text/html', ), /* etc. */ ), )
期待されるのは次のようです:
array( 'files' => array( 0 => array( 'name' => 'file0.txt', 'type' => 'text/plain', /* etc. */ ), 1 => array( 'name' => 'file1.html', 'type' => 'text/html', /* etc. */ ), ), )
その結果、コンシューマーはこの言語実装(PHP)の詳細を知って、与えられたアップロードのデータを収集するためのコードを書く必要があります。
さらに、ファイルのアップロードが発生したときに $_FILES が設定されない状況があります:
POST
そのような場合、データを別の方法でシード(特別な処理)する必要があります。例としては:
getUploadedFiles() は、コンシューマに正規化された構造を提供します。実装では、次のことが期待されます:
getUploadedFiles()
Psr\Http\Message\UploadedFileInterface
参照されるツリー構造は、ファイルが送信されたときのネーミング構造を模倣する必要があります。
最も単純な例では、これは次のように送信された単一の名前付きフォーム要素でしょう:
<input type="file" name="avatar" />
この場合、$_FILES の構造は次のようになります:
array( 'avatar' => array( 'tmp_name' => 'phpUxcOty', 'name' => 'my-avatar.png', 'size' => 90996, 'type' => 'image/png', 'error' => 0, ), )
getUploadedFiles() によって返される正規化された形式は次のようになります:
array( 'avatar' => /* UploadedFileInterface instance */ )
名前に配列表記を使用した入力の場合:
<input type="file" name="my-form[details][avatar]" />
$_FILESは次のようになります:
array ( 'my-form' => array ( 'name' => array ( 'details' => array ( 'avatar' => 'my-avatar.png', ), ), 'type' => array ( 'details' => array ( 'avatar' => 'image/png', ), ), 'tmp_name' => array ( 'details' => array ( 'avatar' => 'phpmFLrzD', ), ), 'error' => array ( 'details' => array ( 'avatar' => 0, ), ), 'size' => array ( 'details' => array ( 'avatar' => 90996, ), ), ), )
そして、getUploadedFiles() によって返される対応するツリーは次のようになります:
array( 'my-form' => array( 'details' => array( 'avatar' => /* UploadedFileInterface instance */ ), ), )
場合によっては、ファイルの配列を指定できます:
Upload an avatar: <input type="file" name="my-form[details][avatars][]" /> Upload an avatar: <input type="file" name="my-form[details][avatars][]" />
(例として、JavaScriptコントロールは、複数のファイルを一度にアップロードできるように、追加のファイルアップロード入力を生成する場合があります。)
このような場合、仕様の実装では、指定されたインデックスにあるファイルに関連するすべての情報を集約する必要があります。その理由は、$_FILES は通常の構造から逸脱しているためです。それは、次のような場合です:
array ( 'my-form' => array ( 'name' => array ( 'details' => array ( 'avatar' => array ( 0 => 'my-avatar.png', 1 => 'my-avatar2.png', 2 => 'my-avatar3.png', ), ), ), 'type' => array ( 'details' => array ( 'avatar' => array ( 0 => 'image/png', 1 => 'image/png', 2 => 'image/png', ), ), ), 'tmp_name' => array ( 'details' => array ( 'avatar' => array ( 0 => 'phpmFLrzD', 1 => 'phpV2pBil', 2 => 'php8RUG8v', ), ), ), 'error' => array ( 'details' => array ( 'avatar' => array ( 0 => 0, 1 => 0, 2 => 0, ), ), ), 'size' => array ( 'details' => array ( 'avatar' => array ( 0 => 90996, 1 => 90996, 3 => 90996, ), ), ), ), )
上記の $_FILES 配列は、getUploadedFiles() によって返される次の構造に対応します:
array( 'my-form' => array( 'details' => array( 'avatars' => array( 0 => /* UploadedFileInterface instance */, 1 => /* UploadedFileInterface instance */, 2 => /* UploadedFileInterface instance */, ), ), ), )
コンシューマーは、ネストされた配列のインデックス1に次のようにしてアクセスします:
$request->getUploadedFiles()['my-form']['details']['avatars'][1];
アップロードされたファイルデータは派生型($_FILES またはリクエストボディからの派生)であるため、インターフェイスにはミューテーターメソッド(mutator method) として withUploadedFiles() も存在し、正規化を別のプロセスに委譲できます。
withUploadedFiles()
冒頭の例の場合、使用方法は次のようになります:
$file0 = $request->getUploadedFiles()['files'][0]; $file1 = $request->getUploadedFiles()['files'][1]; printf( "Received the files %s and %s", $file0->getClientFilename(), $file1->getClientFilename() ); // "Received the files file0.txt and file1.html"
この提案は、実装が非SAPI環境で動作する可能性があることも認識しています。従って、UploadedFileInterface は、環境に関係なく操作が確実に機能するためのメソッドを提供します。 特に:
moveTo($targetPath)
move_uploaded_file()
getStream()
php://temp
例として:
// Move a file to an upload directory // ファイルをアップロードディレクトリに移動する $filename = sprintf( '%s.%s', create_uuid(), pathinfo($file0->getClientFilename(), PATHINFO_EXTENSION) ); $file0->moveTo(DATA_DIR . '/' . $filename); // Stream a file to Amazon S3. // Assume $s3wrapper is a PHP stream that will write to S3, and that // Psr7StreamWrapper is a class that will decorate a StreamInterface as a PHP // StreamWrapper. // // ファイルを Amazon S3 にストリーミングします。 // $s3wrapper が S3 に書き込むPHPストリームであり、 // Psr7StreamWrapper が StreamInterface を // PHP StreamWrapper として装飾するクラスであると仮定します。 $stream = new Psr7StreamWrapper($file1->getStream()); stream_copy_to_stream($stream, $s3wrapper);
説明されているインターフェースとクラスは、psr/http-message パッケージの一部として提供されます。
ここでは、原本に記載されているインターフェースの要約とメソッド一覧を示します。詳細はphp-fig.orgを参照してください。
完全クラス名
要約
HTTPメッセージは、クライアントからサーバーへの要求と、サーバーからクライアントへの応答で構成されます。 このインターフェースは、それぞれに共通するメソッドを定義します。
メッセージは不変と見なされます。 状態を変更する可能性のあるすべてのメソッドは、現在のメッセージの内部状態を保持し、変更された状態を含むインスタンスを返すように実装する必要があります。
参照
クライアント側(発信側)のリクエストの表現
HTTP仕様に従って、このインターフェイスには次の各プロパティが含まれています:
インスタンス構築時、Hostヘッダーが提供されていない場合、実装は提供されたURIからHostヘッダーを設定しようとする必要があります( MUST )。
リクエストは不変と見なされます。状態を変更する可能性のあるすべてのメソッドは、現在のメッセージの内部状態を保持し、変更された状態を含むインスタンスを返すように実装する必要があります( MUST )。
Psr\Http\Message\ServerRequestInterface
サーバー側(受信側)のHTTPリクエストの表現
さらに、CGIやPHP環境からアプリケーションに到達したすべてのデータをカプセル化します:
$_SERVERの値は、リクエスト時のアプリケーションの状態を表すため、不変として扱う必要があります( MUST )。 そのため、これらの値を変更できるメソッドは提供されていません。 他の値は、$_SERVER またはリクエストボディから復元できるので、このようなメソッドを提供し、アプリケーション中の処理が必要になる場合があります(たとえば、本文のパラメーターはコンテンツタイプに基づいてデシリアル化される場合があります)。
さらに、このインターフェイスは、追加のパラメータを取得して照合するリクエストを内省(イントロスペクト)するユーティリティを認識します(例えば、URIパスマッチング、Cookie値の復号、フォームエンコードされていない本文コンテンツのデシリル化、認証ヘッダーとユーザーの照合など)。 これらのパラメーターは attributes プロパティーに保管されます。
attributes
上記の原文 Additionally, this interface recognizes the utility of introspecting a request to derive and match additional parameters (e.g., via URI path matching, decrypting cookie values, deserializing non-form-encoded body content, matching authorization headers to users, etc). These parameters are stored in an “attributes” property.
サーバー側(送信側)のレスポンスの表現
レスポンスは不変と見なされます。状態を変更する可能性のあるすべてのメソッドは、現在のメッセージの内部状態を保持し、変更された状態を含むインスタンスを返すように実装する必要があります( MUST )。
Psr\Http\Message\StreamInterface
データストリームを表します。
通常、インスタンスはPHPストリームをラップします。このインターフェイスは、ストリーム全体の文字列へのシリアル化を含む、最も一般的な操作のラッパーを提供します。
Psr\Http\Message\UriInterface
URIを表す値オブジェクト(Value Object)です。
このインターフェースは、RFC 3986 に従ってURIを表し、最も一般的な操作のメソッドを提供することを目的としています。 URIを操作するための追加機能は、インターフェースの上部または外部で提供できます。 その主な用途はHTTPリクエストですが、他のコンテキストでも使用できます。
このインターフェースのインスタンスは不変と見なされます。状態を変更する可能性のあるすべてのメソッドは、現在のインスタンスの内部状態を保持し、変更された状態を含むインスタンスを返すように実装する必要があります( MUST )。
通常、Hostヘッダーはリクエストメッセージにも含まれます。サーバー側のリクエストの場合、通常、スキームはサーバーパラメータで検出できます。
HTTPリクエストによるアップロードファイルを表す値オブジェクト(Value object)です。