ページ

ラベル ASIHTTPRequest の投稿を表示しています。 すべての投稿を表示
ラベル ASIHTTPRequest の投稿を表示しています。 すべての投稿を表示

2010年4月12日月曜日

Twitpicアップローダ開発(4) 2回目以降の認証失敗解決〜Keep-Aliveをオフにする

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

(前回)Cocoaの日々: Twitpicアップローダ開発(3) 開発中

2回目以降のアップロードに失敗する件について調査した。

現象は1回目のアップロード成功後、2回目が失敗する。失敗時のエラーは "1001 - Invalid twitter username or password"
1回目と2回目で同じ username/password を使っていることは確認済。

ネット上で情報を探した限りでは同様の問題については1件だけみつかった。
Twitpic not working, Posterous is... why? - Stack Overflow

ただ解決していない様子。


さらに調査したところ、1回目の成功後,60秒すぎると2回目でも成功するようになることがわかった。また別プロセスでほぼ同時にアップロードを行った場合も両プロセスともに成功した。

このことからなんらかのセッション管理が影響を及ぼしているのだと考えてリクエストヘッダやレスポンスをダンプしてみた。

リクエストヘッダ

twitpic.up[25881:80f] requestHeaders : {
    "Accept-Encoding" = gzip;
    "Content-Length" = 39135;
    "Content-Type" = "multipart/form-data; charset=utf-8; boundary=0xKhTmLbOuNdArY";
    Cookie = "__qca=P0-1902714012-126624....(略)";
    "User-Agent" = "twitpic.up 1.0 rv:0.1 (Macintosh; Mac OS X 10.6.3; ja_JP)";
}

レスポンスヘッダ
twitpic.up[25881:80f] responseHeaders: {
    "Access-Control-Allow-Origin" = "*";
    Connection = "keep-alive";
    "Content-Encoding" = gzip;
    "Content-Type" = "application/xml";
    Date = "Mon, 12 Apr 2010 14:28:35 GMT";
    Server = "nginx/0.6.35";
    "Transfer-Encoding" = Identity;
    "X-Powered-By" = "PHP/5.2.10";
}

リクエスト時に Cookie が渡されているが、これはどうも WebKit の Cookie が使われているようだ。WebKit の Cookie は以前のブログで見たようにすべてのアプリで共通に使われる。実際、別のサイト(例えば google.comなど)に ASIHTTPRequest からリクエストを送ると、初めてにもかかわらず Googleサイト用の Cookie が飛んでいた。

Cookie が怪しそうだ。

前回のコメントで [ASIHTTPRequest setSessionCookies:nil]; を呼ぶと2回に1回は成功する様になるとのアドバイスをもらったので、試したところ確かにそのような結果となった。やはり Cookie なのか? ただ2回に1回というのがよくわからない。

その後、ASIHTTPRequest やレスポンスヘッダを眺める内に Connecion = "keep-alive" が気になった。そういえば 60秒後に成功するというのはなんとなくだが keep-alive のタイムアウトっぽい。そこで試しにこれを切ってみる。ASIHTTPReuqest には shouldAttemptPersistentConnection というプロパティがあるのでこれに NO を入れてやれば良い。

request.shouldAttemptPersistentConnection = NO;

すると...成功。連続で何度やっても成功した。おお、原因は Keep-Alive だったのか。

レスポンスを見ると Connection= close になっているので当たりのようだ。
twitpic.up[25839:80f] responseHeaders: {
    "Access-Control-Allow-Origin" = "*";
    Connection = close;
    "Content-Encoding" = gzip;
    "Content-Type" = "application/xml";
    Date = "Mon, 12 Apr 2010 13:34:22 GMT";
    Server = "nginx/0.6.35";
    "Transfer-Encoding" = Identity;
    "X-Powered-By" = "PHP/5.2.9";
}

Twitpicサーバ側ではなく、クライアント側(ASIHTTPRequestの設定)が原因だったか。ネットで探しても解決策がなかなか見つからないわけだ。


- - - -
Keep-Aliveだと失敗する理由はわかりません。誰か分かる人、コメント投稿をどうぞ。

2010年3月29日月曜日

Keychain Services 調査 (23) twitpic へ画像をアップロード(その3)画像をアップロード

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

(前回)Cocoaの日々: Keychain Services 調査 (22) twitpic へ画像をアップロード(その2)asi-http-request を使う

いよいよ twitpic へ画像をアップロードする。今回は sample.jpg を用意してこれをアップロードしてみよう。


asi-http-request ではフォームデータ送信用のクラス ASIFormDataRequest が用意されており、これを使うと multipart/form-data なリクエストも数行で送信することができる。使い方は How to use it の中の Sending data with POST or PUT requests に書かれている。

ASIHTTPRequest example code - All-Seeing Interactive

ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url]; 
[request setPostValue:@"Ben" forKey:@"first_name"]; 
[request setPostValue:@"Copsey" forKey:@"last_name"]; 
[request setFile:@"/Users/ben/Desktop/ben.jpg" forKey:@"photo"];

やってみよう。sample.jpg を xcodeのプロジェクトへ追加した後、下のコードを書く。

NSURL *url = [NSURL URLWithString:@"http://twitpic.com/api/uploadAndPost"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];

[request setPostValue:loginAccount.loginId forKey:@"username"];
[request setPostValue:loginAccount.password forKey:@"password"];

NSString* filepath = [[NSBundle mainBundle] pathForImageResource:@"sample"];
NSLog(@"filepath=%@", filepath);

[request setFile:filepath forKey:@"media"];
[request setPostValue:@"Hello twitpic!" forKey:@"message"];
[request startSynchronous];

NSError* error = [request error];
if (!error) {
NSString* response = [request responseString];
NSLog(@"%@", response);
} else {
NSLog(@"error: %@", error);
}


実行してみよう。ID, パスワードを入力する。
Login を押すとリクエストが飛ぶ。ログを見るとうまく行っているようだ。

KeychainSample2[3461:80f] updated keychain item
KeychainSample2[3461:80f] filepath=/Users/hashi/development/SampleCode/KeychainSample2/build/Debug/KeychainSample2.app/Contents/Resources/sample.jpg
KeychainSample2[3461:80f]
 111...
 1254....
 1bh2pu
 http://twitpic.com/1bh2pu



Twitpic のページを表示してみる。

出た。ちょっとうれしい。

2010年3月27日土曜日

Keychain Services 調査 (22) twitpic へ画像をアップロード(その2)asi-http-request を使う

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

(前回)Cocoaの日々: Keychain Services 調査 (21) twitpic へ画像をアップロード(その1)調査

asi-http-request ライブラリを使うことにする。まずはサンプルプログラムへライブラリを組み込んで動作確認をやってみる。

組み込み方法はサポートページに図入りで詳しく書いてある。
How to use ASIHTTPRequest in your projects - All-Seeing Interactive


まずライブラリのソースコードをダウンロードする。
Downloads for pokeb's asi-http-request - GitHub

今回は v1.6.1 の zip を落としてみた。解凍すると Xcodeのプロジェクト一式が入っている。

Classes 内のファイル(11個)をサンプルプログラムのプロジェクトへコピーする。
次にサンプルプログラムのプロジェクトへフレームワークと動的ライブラリを追加する。追加するのは次の2つ。



Mac OS X の場合はこれで終わり。iPhone の場合はもういくつかのファイルを追加擦る必要がある。


動作確認で google.com のページを GET してみよう。サポートページの "How to use it" を参考に同期リクエストを投げてみる。
ASIHTTPRequest example code - All-Seeing Interactive


NSURL *url = [NSURL URLWithString:@"http://www.google.com/"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSError* error = [request error];
if (!error) {
NSString* response = [request responseString];
NSLog(@"%@", response);
} else {
NSLog(@"error: %@", error);
}

実行結果



(続く)