Cookie 管理

はじめに

HTTP 状態管理機構では、HTTP 要求および応答を使用してステートフルなセッションを確立するための方法を指定しています。仕様については、「RFC 2965: HTTP State Management Mechanism」(http://www.ietf.org/rfc/rfc2965.txt?number=2965) を参照してください。

Tiger 以前のサポート

Tiger 以前、Cookie 管理をアプリケーションに追加することは可能でした。ただし、API のサポートはやや不十分で、Cookie 管理につながる点はまったくありませんでした。各アプリケーションでは、java.net.URLConnection クラスから次の 2 つのメソッドを使用して、各 HTTP 要求/応答の Cookie を個別に処理する必要がありました。

setRequestProperty()
getHeaderFields()

1 つ目のメソッドは、HTTP 要求の送信前に呼び出す必要があります。これは、HTTP ヘッダーの現在の URL に適した Cookie を設定するためです。2 つ目のメソッドは、HTTP サーバーにより送信された応答ヘッダーから Cookie を取得するために使用します。

この方法で Cookie サポートを追加することは可能ですが、コードが断片化されることになります。これはエラーが発生しやすく、保守が大変です。

Tiger の新機能

abstract クラスを使用した新しいコールバック機構を導入しました。これは、HTTP 状態管理ポリシーの実装を HTTP プロトコルハンドラに接続することを目的としたものです。アプリケーションや Web コンテナでは、新しい API の具象サブクラスを用意すれば Cookie 管理の導入が可能です。

この新しい abstract クラスは java.net.CookieHandler と呼ばれ、これには、JVM の現在の CookieHandler の登録や取得を行う機構に加えて、特定 URI に対応する Cookie の取得や記録を行うためのメソッドが用意されています。

CookieHandler には、getDefault() および setDefault() の 2 つの static メソッドが含まれています。これは、VM においてデフォルトの CookieHandler の取得や登録を行うためのものです。さらに、Cookie リストを返すための 2 つのインスタンスメソッド、get() と put() は、URL をベースとし、それぞれ応答ヘッダーから Cookie リストを保存します。

Cookie は、Map<String,List<String>> として表されます。つまり、Cookie のヘッダーフィールド名から、String によって表される一連のリストまでの Map です。これまでに定義された「Set-Cookie2」と「Cookie」の 2 つの状態管理ヘッダーが用意されています。前者は応答ヘッダーで Cookie を返す場合に使用し、後者は HTTP 要求ヘッダーで Cookie の設定を行う場合に使用します。

RFC2965 からの例を次に示します。

1. User Agent -> Server

POST /acme/login HTTP/1.1
[form data]

2. Server -> User Agent

HTTP/1.1 200 OK
Set-Cookie2:Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"

3. User Agent -> Server

POST /acme/pickitem HTTP/1.1
Cookie:$Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
[form data]

簡単な例

次に、CookieHandler 実装の簡単な例を示します。基本的に 2 つのメソッドが用意されています。これらのメソッドでは、所定の要求 URI と要求ヘッダー (Cookie ヘッダーを除く) を実装し、Cookie キャッシュから関連する Cookie をすべて取得し、要求 URI と要求ヘッダーが与えられた Cookie キャッシュに対して適切な Cookie を記録します。

class MyCookieHandler extends CookieHandler {
	public Map<String, List<String>>
		get(URI uri, Map<String, List<String>> requestHeaders)
		throws IOException {
		// the cookies will be included in request
		Map<String, List<String>> map = new HashMap<String, List<String>>();
		List<String> l = retrieveCookies(uri, rqstHdrs);
		map.put("Cookie",l);
		return Collections.unmodifiableMap(map);
	}

	public void
		put(URI uri, Map responseHeaders)
		throws IOException {
	    // check response has cookies[1]
		List l = (List)responseHeaders.get("Set-Cookie2");
	    if (l != null) {
			// save the cookies in a cookie cache
		 storeCookies(uri, l);
	    }
	}
}

retrieveCookies()storeCookies() の各メソッドは、この例では省略されているバックエンドの Cookie 管理機能と対話するための「magic」機能です。

この機能が VM に登録されると、HTTP トランザクションを発行する時点で有効になります。

public static void main(String args[]) throws Exception {
	......
	CookieHandler.setDefault(new MyCookieHandler());
	HttpURLConnection http = (HttpURLConnection)url.openConnection();

	int respCode = http.getResponseCode();
	http.disconnect();
	......
}

J2SE には、Cookie マネージャーのデフォルトの実装が存在しません。しかし、この点は将来変更される可能性があります。Java Plug-in と Java WebStart では、それぞれの環境においてデフォルトの CookieHandler を提供します。