トップ回答者
HttpWebResponseで取得したHTTPレスポンスヘッダ値が「,(カンマ)」で分割される。

質問
-
初めて質問させていただきます。
お手数ですが、宜しくお願い致します。
C#でHTTPクライアントアプリを作っております。HTTPリクエスト/レスポンスの送受信には「HttpWebRequest」「HttpWebResponse」を使っていますが、
下記コード例に示す通り、WebHeaderCollection.GetValues(string)を使用して受信したHTTPレスポンスのヘッダ値を取得すると、
ヘッダ値に「,(カンマ)」が含まれている場合、カンマでレスポンスヘッダが分割されてしまいます。
•コード例
HttpWebResponse response = (HttpWebResponse)request.GetResponse() WebHeaderCollection headers = response.Headers; foreach (string key in headers.Keys) { foreach (string value in headers.GetValues(key)) { Console.WriteLine("{0}: {1}", key, value); } }
•実行結果
Pragma: no-cache Vary: Accept-Encoding Content-Encoding: gzip Content-Length: 3855 Cache-Control: no-store Cache-Control: no-cache Cache-Control: must-revalidate Cache-Control: post-check=0 Cache-Control: pre-check=0 Content-Type: text/html Date: Thu, 25 Jun 2015 07:34:18 GMT Expires: Thu, 19 Nov 1981 08:52:00 GMT Location: ./login.php Set-Cookie: Loggedin=deleted; expires=Wed Set-Cookie: 25-Jun-2014 07:34:17 GMT; path=/ Server: Apache/2.2.14 (Ubuntu) mod_mono/2.4.3 PHP/5.3.2-1ubuntu4.5 with Suhosin-Patch proxy_html/3.0.1 mod_python/3.3.1 Python/2.6.5 mod_ssl/2.2.14 OpenSSL/0.9.8k Phusion_Passenger/3.0.17 mod_perl/2.0.4 Perl/v5.10.1 X-Powered-By: PHP/5.3.2-1ubuntu4.5
上記例では、Cache-ControlとSet-Cookieの値がカンマで分割され、複数のヘッダとして取得されています。
ちなみに、このHTTPレスポンスのRawデータは以下の通りです。
当然ですが、Cache-ControlとSet-Cookieはカンマで分割されておりません。
HTTP/1.1 302 Found Pragma: no-cache Vary: Accept-Encoding Content-Encoding: gzip Content-Length: 3855 Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Content-Type: text/html Date: Thu, 25 Jun 2015 07:34:18 GMT Expires: Thu, 19 Nov 1981 08:52:00 GMT Location: ./login.php Set-Cookie: Loggedin=deleted; expires=Wed, 25-Jun-2014 06:26:18 GMT; path=/ Server: Apache/2.2.14 (Ubuntu) mod_mono/2.4.3 PHP/5.3.2-1ubuntu4.5 with Suhosin-Patch proxy_html/3.0.1 mod_python/3.3.1 Python/2.6.5 mod_ssl/2.2.14 OpenSSL/0.9.8k Phusion_Passenger/3.0.17 mod_perl/2.0.4 Perl/v5.10.1 X-Powered-By: PHP/5.3.2-1ubuntu4.5
この事象をクリアする方法があれば、ご教授いただけないでしょうか。
ちなみに、.NET Framework 4.5.51650を使用しております。
開発はVisual Studio 2013 Express Editionです。
お手数お掛けしますが、宜しくお願い致します。
以上です。- 移動 星 睦美 2015年7月10日 0:39 .NET Micro Framework
回答
-
WebHeaderCollection::GetValues(String)使えばそりゃそうなるでしょう。そう言うメソッドなので。
WebHeaderCollection::this[String]、つまりheaders[key]でアクセスすれば、Addしたときのがそのまま返されます。
- 回答としてマーク secscan2015 2015年6月29日 6:11
すべての返信
-
WebHeaderCollection::GetValues(String)使えばそりゃそうなるでしょう。そう言うメソッドなので。
WebHeaderCollection::this[String]、つまりheaders[key]でアクセスすれば、Addしたときのがそのまま返されます。
- 回答としてマーク secscan2015 2015年6月29日 6:11
-
-
ご回答ありがとうございます。
また、返信が遅くなり申し訳ありません。
ご教授頂いた方法も確認致しましたが、同名のヘッダが複数存在する場合、下記の様に1行に纏められます。
- 期待するレスポンスデータ
Set-Cookie: A Set-Cookie: B
- 上記方法で取得したレスポンスデータ
Set-Cookie: A, B
事前にローカルProxy(Burp Suiteなど)で取得したレスポンス(上記の期待するレスポンスデータ)と、HttpWebResponseで取得したレスポンスデータの差分比較を行う必要がありますので、上記の違いが大きな差分となっています。
現在はレスポンスヘッダ値をチェックし、差分が生じないようにレスポンスヘッダを組み直す方法を採用しています。
以上
-
-
質問者さんは Set-Cookie: A, B という形で取得したいのだと思っていましたが、勘違いだったようですみません。
以下のような形で取得し、かつ、例えば expires=Wed, 16-Sep-2015 16:51:30 GMT というように期限が設定されていても、Wed の後のカンマで分割されることがないようにしたいということですね。
Set-Cookie: A
Set-Cookie: BGetValues メソッドを使うとカンマ ( , ) で分割されるのは、GetValues メソッドは文字列の中身を見てパースしている訳ではなく、単純に何も考えずにカンマでデリミティングしているからだそうです。
Set-Cookie header broken in WebHeaderCollection
http://bytes.com/topic/asp-net/answers/309751-set-cookie-header-broken-webheadercollectionなので、GetValues メソッドではうまく行きません。先の私のレスで書いた方法で Set-Cookie: A, B の形で取得して、曜日の後のカンマは無視するようにしてパースしてはいかがでしょう。
どうしても Set-Cookie: A という形で取得したいというわけではなく、Cookie の中の情報を取得できればいいのであれば、上の記事に書いてあるように、CookieContainer, CookieCollection, Cookie クラスを利用すれば必要な情報を取得できるはずです。
使い方のサンプルは以下のページにありますので見てください。
Cookie クラス
https://msdn.microsoft.com/ja-jp/library/system.net.cookie(v=vs.110).aspx- 編集済み SurferOnWww 2015年7月9日 7:34 タイポ訂正
-
# .NET Micro Frameworkフォーラムではなく、.NET Frameworkフォーラム等(C#やExpressでもいいかなと)が適切に思います。モデレーターさん移動をお願いします。
Hongliangさんの回答のようにGetValue(int)を使うことになると思います。
ちなみに.NET Framework 4.5からHttpWebRequest / HttpWebResponseに代わるHttpClientクラスが用意されています。
static async Task RunAsync(Uri uri) { using (var client = new HttpClient()) using (var response = await client.GetAsync(uri)) foreach (var pair in response.Headers) { var key = pair.Key; foreach (var value in pair.Value) Console.WriteLine("{0}: {1}", key, value); } } static void Main() { var uri = new Uri("http://www.example.com"); RunAsync(uri).Wait(); }
-
> Hongliangさんの回答のようにGetValue(int)を使うことになると思います。
実際に .NET 4 で試してみましたが、GetValues(string) は単純にカンマ・デリミティング、GetValues(int) の方はきちんとパースしました。
実装が違うようですね。
- 編集済み SurferOnWww 2015年7月9日 8:48 Typo 訂正
-
WebHeaderCollectionの元となっているNameValueCollectionの動作仕様です。
Item[string]インデクサなどにもその片鱗を見ることができ、同一のキーはコンマ区切りで結合できるものと見なされています。intによるインデックスアクセス(Item[int]、GetKey(int)、GetValues(int)など)はそれらの影響を受けずにアクセスできます。
この辺りはもうソースコードを見て実際の動作を把握するしかありません。
-
おかげさまで、そういうことがあることを知ることができ、一つ利口になりました。
さらに試してみましたが、GetValues(int) の方は、曜日の後のカンマだけでなく、以下のような Cookie(最後に注目)でもカンマがデリミタかそうでないかの見分けが付くようです。
Set-Cookie: .ASPXANONYMOUS=Hd_V47vw0AEk...; expires=Wed, 16-Sep-2015 20:11:36 GMT; path=/; HttpOnly Set-Cookie: ASP.NET_SessionId=nvd2cdexbtjwxvxjw5x0msja; path=/; HttpOnly Set-Cookie: DateTimeCookie=2015/07/09 18:31:36; path=/ Set-Cookie: RandomNumber=1408121466; path=/ Set-Cookie: session_cache={"Cache":"XZ9","Time":"6351258293015444647","SessionID":"ls4e3hz2yv4hnhxfn4d2xqhm"}; path=/
GetValues(string) の方はもちろんダメでした。
ソースを見たわけではないですが、結果からすると、GetValues(int) の方はヘッダの種類、Cookie であればカンマがデリミタかそうでないかを見分けるというパース機能が実装されているということでしょうか。もしそうであれば、そういうことは MSDN ライブラリに書いておいて欲しいと思うのですが・・・
- 編集済み SurferOnWww 2015年7月9日 9:56 誤字脱字訂正
-
フォーラム オペレーターの星 睦美です。
こちらのスレッドは.NET Micro Framework に関する話題を扱うフォーラムに投稿いただいていますが、質問の内容から Visual C# フォーラムに移動しました。投稿した質問はフォーラム ページの左上、[クイック アクセス] > マイ スレッドから確認できます。フォーラム オペレーター 星 睦美 - MSDN Community Support
-
Hongliang様、SurferOnWww様、佐祐理様、なちゃ様
御礼が遅くなり申し訳ございません。
また貴重な情報をご提供いただき、ありがとうございます。
Hongliang様にご教授いただいた方法(GetValue(int)を使用)により、期待していた結果を得ることができました。
Set-CookieやCache-Controlなどのヘッダ値をRawデータと同じ形式で取り出すことができました。
改めて御礼申し上げます。