Amazon WebサービスにHTTP/1.1でアクセスするとゴミが出る
Zend_Http_Clientをincubatorバージョンに変えてテストしていたら、Zend_Service_Amazonの動作がおかしい*1。なんでかなーと原因をたどっていったら、Amazon WebサービスへのリクエストがHTTP/1.0からHTTP/1.1に変わったことが原因だった。
以下再現コード。HTTP/1.1でのリクエスト。
$socket = fsockopen('webservices.amazon.co.jp', 80);
fwrite($socket, "GET /onca/xml?ResponseGroup=Request&SubscriptionId=[Subscription ID]&Service=AWSECommerceService&Operation=ItemLookup&ItemId=4774128104 HTTP/1.1\r\n");
fwrite($socket, "Host: webservices.amazon.co.jp\r\n");
fwrite($socket, "Connection: close\r\n");
fwrite($socket, "\r\n");
while (!feof($socket)) {
echo fread($socket, 8192);
}
fclose($socket);
結果。
HTTP/1.1 200 OK Date: Thu, 22 Jun 2006 04:39:16 GMT Server: Server x-amz-id-1: 0TR0TFSQ68NG6TEF33NC x-amz-id-2: Qc8vxAunuvNVpdAORHM5YVP2pvxgSkOv Connection: close Transfer-Encoding: chunked Content-Type: text/xml; charset=UTF-8 36f <?xml version="1.0" encoding="UTF-8"?><ItemLookupResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05"><OperationRequest><HTTPHeaders><Header Name="UserAgent"></Header></HTTPHeaders><RequestId>0TR0TFSQ68NG6TEF33NC</RequestId><Arguments><Argument Name="SubscriptionId" Value="[Subscription ID]"></Argument><Argument Name="ResponseGroup" Value="Request"></Argument><ArgumentName="Operation" Value="ItemLookup"></Argument><Argument Name="Service" Value="AWSECommerceService"></Argument><Argument Name="ItemId" Value="4774128104"></Argument></Arguments><RequestProcessingTime>0.0139038562774658</RequestProcessingTime></OperationRequest><Items><Request><IsValid>True</IsValid><ItemLookupRequest><ItemId>4774128104</ItemId><ResponseGroup>Request</ResponseGroup></ItemLookupRequest></Request><Item><ASIN>4774128104</ASIN></Item></Items></ItemLookupResponse> 0
「36f」「0」などのゴミが混ざっている。上記を見るとボディ部の前後にゴミが混ざるように見えるけれども、もっと長い結果を返すリクエストの場合は、定期的に類似したゴミが混ざる。バッファ(最大0x2000バイト)から出力した文字数を16進数で出力しているっぽい。
続いてHTTP/1.0に変える。
$socket = fsockopen('webservices.amazon.co.jp', 80);
fwrite($socket, "GET /onca/xml?ResponseGroup=Request&SubscriptionId=[Subscription ID]&Service=AWSECommerceService&Operation=ItemLookup&ItemId=4774128104 HTTP/1.0\r\n");
fwrite($socket, "Host: webservices.amazon.co.jp\r\n");
fwrite($socket, "Connection: close\r\n");
fwrite($socket, "\r\n");
while (!feof($socket)) {
echo fread($socket, 8192);
}
fclose($socket);
以下、結果。
HTTP/1.1 200 OK Date: Thu, 22 Jun 2006 04:39:16 GMT Server: Server x-amz-id-1: 0TXZ0YSV0W5WA2TQGFCD x-amz-id-2: oew++LbGRDya+Ju9I49Vx7bXa6CAsn4V Connection: close Content-Type: text/xml; charset=UTF-8 <?xml version="1.0" encoding="UTF-8"?><ItemLookupResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05"><OperationRequest><HTTPHeaders><Header Name="UserAgent"></Header></HTTPHeaders><RequestId>0TXZ0YSV0W5WA2TQGFCD</RequestId><Arguments><Argument Name="SubscriptionId" Value="[Subscription ID]"></Argument><Argument Name="ResponseGroup" Value="Request"></Argument><ArgumentName="Operation" Value="ItemLookup"></Argument><Argument Name="Service" Value="AWSECommerceService"></Argument><Argument Name="ItemId" Value="4774128104"></Argument></Arguments><RequestProcessingTime>0.00991702079772949</RequestProcessingTime></OperationRequest><Items><Request><IsValid>True</IsValid><ItemLookupRequest><ItemId>4774128104</ItemId><ResponseGroup>Request</ResponseGroup></ItemLookupRequest></Request><Item><ASIN>4774128104</ASIN></Item></Items></ItemLookupResponse>
こっちは正常な結果が返ってくる。
Amazon WebサービスへのリクエストはHTTP/1.0で行わなければならない、とか決まっていたんだっけ? どこに報告するべき問題なのかいまいちよくわからない。ひとまずZend_Http_Clientのincubator版はHTTP/1.1がデフォルトになっちゃってるから、このままだと正式版に格上げされたときにトラブりそうだな。
ああ
Transfer-Encoding: chunkedだからか! これで正常なのね。っつーか、HTTP/1.1で送るならば受信側がちゃんと対応しないといけないのね。HTTP/1.1のRFCちゃんと読んでおこう。
一応資料
ハイパーテキスト転送プロトコル -- HTTP/1.1 3.6.1 チャンク形式転送エンコーディング
すべての HTTP/1.1 アプリケーションは、"chunked" 転送コーディングを受信しデコードできなければならないし、理解できない転送コーディング拡張は無視しなければならない。
※参照するRFCを2068から2616に変更しました。
*1 コンストラクタのインターフェースが変わっていたのは修正した
