ページ

2009年8月25日火曜日

NSHTTPCookieStorage相当のクラスを自前で実装する (2)クッキーの受け取り

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

最初から保存やら同期やらすべてを実装すると大変なので、まずはメモリ上だけでクッキーのやりとりを行う実装から始めよう。当面はラフな実装で動作確認を先行して行い、徐々に精度を高めていくやり方で進める。

今回はクッキーの受け取り処理を実装する。


(1) クライアント側の用意

まず WebView の WebResourceLoadDelegate として AppController を指定し、必要なデリゲートメソッドを実装する。

リクエスト処理では、setHTTPShouldHandleCookies を使い、デフォルトの NSHTTPCookieStorage の使用を中止する。
AppController.m

// WebResourceLoadDelegate
- (NSURLRequest *)webView:(WebView *)sender
resource:(id)identifier
willSendRequest:(NSURLRequest *)request
redirectResponse:(NSURLResponse *)redirectResponse
fromDataSource:(WebDataSource *)dataSource
{
[(NSMutableURLRequest*)request setHTTPShouldHandleCookies:NO];
return request;
}


続いてレスポンス処理では、受け取ったヘッダ情報を XCHTTPCookieStorageへ渡す。
- (void)webView:(WebView *)sender
resource:(id)identifier
didReceiveResponse:(NSURLResponse *)response
fromDataSource:(WebDataSource *)dataSource
{
NSDictionary* headers = [(NSHTTPURLResponse*)response allHeaderFields];
NSURL* URL = [response URL];

NSArray* cookies =
[NSHTTPCookie cookiesWithResponseHeaderFields:headers forURL:URL];

[[XCHTTPCookieStorage sharedHTTPCookieStorage] setCookies:cookies
forURL:URL
mainDocumentURL:URL];
}



(2) XCHTTPCookieStorage の実装

XCHTTPCookieStorage.m

初期化。
- (id)init
{
if (self = [super init]) {
_cookie_accept_policy = NSHTTPCookieAcceptPolicyAlways;
_cookies = [[NSMutableDictionary alloc] init];
}
return self;
}


インスタンス取得(シングルトン)。
+ (XCHTTPCookieStorage *)sharedHTTPCookieStorage
{
static XCHTTPCookieStorage* _cookie_storage = nil;

if (!_cookie_storage) {
_cookie_storage = [[XCHTTPCookieStorage alloc] init];
}
return _cookie_storage;
}


渡されたクッキーを内部処理する(保存する)。
- (void)setCookies:(NSArray *)cookies forURL:(NSURL *)URL mainDocumentURL:(NSURL *)mainDocumentURL
{
for (NSHTTPCookie *cookie in cookies) {
[self setCookie:cookie];
}
}


_keyForCookie: で生成される文字列をキーとして、NSMutableDictionaryへ格納する。
- (void)setCookie:(NSHTTPCookie *)cookie
{
[_cookies setValue:cookie forKey:[self _keyForCookie:cookie]];
}



_keyForCookie: はドメイン名、パス、名前を '/'区切りで連結したものを返す。この辺りは以前参考にした mySTEP の方法を借用した。
- (NSString*)_keyForCookie:(NSHTTPCookie*)cookie
{
return [NSString stringWithFormat:@"%@/%@/%@",
[cookie domain], [cookie path], [cookie name]];
}



実行時に NSDictionary に格納しているクッキーが見られるように「print cookies」ボタンを追加し、-[AppController printCookies:] へ接続する。


- (IBAction)printCookies:(id)sender
{
NSLog(@"%@", [[XCHTTPCookieStorage sharedHTTPCookieStorage] cookies]);
}



実行してみよう。
google.comを開く。


この時のクッキーは次の通り。既に1つ受け取っている。


ページの右上にある「ログイン」リンクを押す。


クッキーを見ると、1つ増えている。



サンプル:
CookieStorage-1.zip

- - - -
粗い実装だがまずは受け取りができるようなった。次はクッキー送出に取りかかってみる。