web-dev-qa-db-ja.com

「100 continue」HTTPメッセージの処理方法

私は主にcURLからのPUT要求をクライアントとして受け入れる単純なHTTPサーバーを書いていますが、Expect: 100-continueヘッダーの処理に少し問題があります。

私が理解しているように、サーバーはヘッダーを読み取り、接続でHTTP/1.1 100 Continue応答を返送し、Content-Lengthの値までストリームを読み取ってから、実際の応答コード(通常はHTTP/1.1 200 OKが、他の有効なHTTP応答はすべて実行する必要があります。

まあ、それはまさに私のサーバーが行うことです。問題は、明らかに、100 Continue回答を送信した場合、cURLが後続のHTTPエラーコードのレポートに失敗し、アップロードが成功したと想定することです。たとえば、コンテンツの性質が原因でアップロードが拒否された場合(基本的なデータチェックが行われている場合)、呼び出し元のクライアントが問題を検出し、それに応じて動作するようにします。

明らかな何かが欠けていますか?

編集:これは、エラーを含むセカンダリヘッダーを持つcURLからのサンプル出力です。

> PUT /test1%2Epdf HTTP/1.1
> Authorization: Basic xxxx
> User-Agent: curl/7.20.0 (i386-pc-win32) libcurl/7.20.0 OpenSSL/0.9.8l zlib/1.2.3
> Host: localhost
> Accept: */*
> Content-Length: 24
> Expect: 100-continue
>
< HTTP/1.1 100 Continue
< HTTP/1.1 415 Unsupported Media Type
< Connection: close
< Content-Type: text/xml
< Content-Length: 289
<
30
Stephane

LibcURLを使用してクライアント側プログラムを作成している場合は、CURLOPT_FAILONERRORオプションの1。たとえば、Cでは、次のようなことをします。

curl_easy_setopt (curl_handle, CURLOPT_FAILONERROR, 1L);

LibcURL documentation によれば、このオプションは「返されたHTTPコードが400以上の場合、サイレントに失敗するようにライブラリに指示します。」

さらに、ドキュメンテーションは、「デフォルトのアクションは、そのコードを無視して、通常ページを返すことであること」を明確にします。

Curlコマンドラインツールを使用している場合は、単に-fまたは--failをcurlコマンドに追加すると、上記と同様の動作が発生します。これはcurl manページ でも説明されています。

ドキュメントに明記されているように、これらの方法はどちらもフェイルセーフではないことに注意してください。

「この方法はフェイルセーフではありません。特に認証が関係している場合(応答コード401および407)、失敗した応答コードがすり抜ける場合があります。」

12
bloosh

私はこれが古いことを知っていますが、ここに「100 Continue」の私の理解があります

サーバーは、クライアントからのヘッダーのみに基づいてリクエストを検証することになっています。つまり、リクエストが無効な場合、do n't send "100 Continue" but send actual HTTP error代わりに。 403.これにより、クライアントがサーバーへのラウンドトリップの全ポイントであると理解しているデータ(つまり、「100 Continue」を待機しているクライアント)が最初に送信されるのを防ぐ必要があります。

実際に投稿されたデータを検証する場合は、ここで高レベルのプロトコルを適用する必要があります。つまり、有効なHTTP応答コンテンツにラップされたエラーを送信します。はい、制限のように思えますが、プロトコルの制限だとは思っていません。サーバーの応答を複数回処理しなければならない可能性が高いクライアントの混乱。

23
bronekk

実際には、100個のContinueヘッダーの後に実際のヘッダーがあるはずです

だから、私は通常クライアント側でこれを好きです。

$contents=curl_exec($ch);

list( $header, $contents ) = explode( "\r\n\r\n", $contents , 2);
if(strpos($header," 100 Continue")!==false){
    list( $header, $contents) = explode( "\r\n\r\n", $contents , 2);
}
6
YOU

あなたの答えを詳しく説明し、例としてPHPを使用しています:

複数の100 Continueヘッダーを受信できました。以下を使用して、ヘッダーをゆっくりと処理し、100 Continue応答がある場合:

<?php
// a little setup first
$ch = curl_init();
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_HEADER,1);
// etc...
$str = curl_exec($ch);

// the goods
$delimiter = "\r\n\r\n"; // HTTP header delimiter
// check if the 100 Continue header exists
while ( preg_match('#^HTTP/[0-9\\.]+\s+100\s+Continue#i',$str) ) {
    $tmp = explode($delimiter,$str,2); // grab the 100 Continue header
    $str = $tmp[1]; // update the response, purging the most recent 100 Continue header
} // repeat

// now we just have the normal header and the body
$parts = explode($delimiter,$str,2);
$header = $parts[0];
$body = $parts[1];
?>
4
zamnuts

100 Continue行の後に空行(CRLF)を追加してみてください( RFC 2616、セクション6 を参照)、

3
Julian Reschke