.NETはCookieContrainerクラスをHttpWebRequestとHttpWebResponseにバインドすることで、比較的簡単にWebサーバとやりとりするCookieの処理を実装できるのだが、それは自身で生成するか、サーバから受け取ったCookieだけが対象であり、Webブラウザにより生成、保存されたCookieを共有して利用することはできない。しかし、この処理は、過去にサイトにログインした際に生成、保存したCookieを初回のリクエスト時にWebサーバに送る等、アプリケーションではよくつかう手だ。
InternetExploler等で設定されたCookieを取得するためには、標題のAPIが用意されているのだが、残念ながらこのメソッドはwininetのAPIであり、.NET Framework 2.0のマネジドコードでは提供されていない。従って、マネジドコードから使うにはP/Invoke経由で使う必要がある。(私がメソッドの存在に気が付いていないだけかもしれない)
[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool InternetGetCookie(
string lpszUrlName,
string lpszCookieName,
StringBuilder lpszCookieData,
[MarshalAs(UnmanagedType.U4)]
ref int lpdwSize
);
//P/Invoke.NETでは以下のようにマッピングされていた
[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError=true)]
public static extern bool InternetGetCookie(
string lpszUrlName,
string lpszCookieName,
[Out] string lpszCookieData,
[MarshalAs(UnmanagedType.U4)]
out int lpdwSize
);
同じ第3パラメタをStringBuilderと[Out] stringマップしているのは、実際にどちらで使っても書ける。stringでマップした場合は取得した文字列が"\0\0"でターミネートされるので、トリムする必要があるだけだ。(これって、今後のことを考えるとどちらを使うのが良いのだろう。)
P/Invokeの記述が出来たら、後はマネジドコードから使うだけ。(第3パラメタに[Out]stringを使う例は省略)
public static string RetrieveIECookies(string url)
{
StringBuilder cookieHeader = new StringBuilder(new String(' ', 256), 256);
int datasize = cookieHeader.Length;
if (!InternetGetCookie(url, null, cookieHeader, ref datasize))
{
if (datasize < 0) return String.Empty;
new StringBuilder(datasize);
InternetGetCookie(url, null, cookieHeader, ref datasize);
}
return cookieHeader.ToString();
}
このメソッドで取得したCookieを今日の最初のエントリで紹介したSetCookiesメソッドでCookieContainerにセットして、HttpWebRequestにパインドしてやれば、既に存在しているCookieを初回のGETなりPOSTなりでWebサーバに送信できる。
Uri uri = new Uri("http://hoge.com/hogehoge"); HttpWebRequest httpRequest = (HttpWebRequest)HttpWebRequest.Create(uri); CookieContainer cookieContainer = new CookieContainer(); cookieContainer.SetCookies(uri, RetrieveIECookies(uri.AbsoluteUri)); httpRequest.CookieContainer = cookieContainer;