週刊(月刊?)プレカリアート
Good luck new year!
- 2009-12-30 (水)
- コンピュータ
かなり久しぶりに更新します。外国の友人から貰ったメールが変なので報告したいけど、別ブログにはあんまりそぐわないからこっちに。
Good luck new year!
Dear friends,how are you ?
I found a website ( www.motonn.com),
There are many products, laptop computers,mobile phones, digital
cameras, DJ Equipment, etc.
The most important is that the price is very cheap, and they delivery fast .
I have received my product, quality is very good,
I know you are interested in electronic products,
Therefore write and tell you,
You don’t miss this chance,
Hope this product will bring good luck in 2010 for you,
Wish you good luck in the New Year, happy every day!
I’ve just received a greeting mail from my friend; however, it is a suspicious mail. The content of this mail is to advertise a website. Therefore, I come to the conclusion that it’s spam and my friend was infected with a computer virus.
I googled a sentence of this mail but I didn’t find.
友達から年賀メール(まだ12月30日だけど)を貰うのは有り難いのだけど、これはスパムですよね、どうみても。ということは、ウィルスにでも感染してスパムを送っているのかなんなのか知らないけど、たぶん本人が送ったものではないと思います。
文面で検索をしてもひっかからないから、まだ未知のもののようです。2010年の年賀メールだから、最近出たのでしょうね。
ヘッダを読む
長いので全部は載せないけど
Return-Path: < ○○@gmail.com>
X-Original-To: ○○@○○.u-tokyo.ac.jp
Delivered-To: ○○@○○.u-tokyo.ac.jp
Received: (略)
Received: by 10.91.138.5 with SMTP id q5mr8273279agn.103.1262103696252; Tue, 29 Dec 2009 08:21:36 -0800 (PST)
を見る限りだと、これはgmailからの送信ではないのかな。gmailのIPアドレス割当を知らないけど、hostしてもtracerouteしても怪しさ満点です。そもそも文面が友人が宣伝しているのとはずいぶん違う。
皆様もウィルスにはお気をつけ下さい。
さっそくGoogleにクロールされた
仕事が早い。これでこの文面で検索した人は他にも事例があることに気づくはず。英語で書いておいた方がいいのかな。
ブログリンクです。よろしければクリックお願いします。
CFNetworkでHTTP POST
- 2009-05-11 (月)
- プログラミング
前回の続き。
CFURLRef theURL = CFURLCreateWithString(kCFAllocatorDefault, CFSTR("http://mixi.jp/login.pl"), NULL);
mixiのログインをやってみる。
CFHTTPMessageRef theRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("POST"), theURL, kCFHTTPVersion1_1);
POSTを指定してやる。
CFDataRef thePostData = CFStringCreateExternalRepresentation( NULL, CFSTR("next_url=%2Fhome.pl&email=メアド%40ドメイン.org&password=パスワード&x=71&y=14"), CFStringGetSystemEncoding(), '?');
CFStringCreateExternalRepresentation()を使ってCFDataRefをCFStringRefから作る。使い回すわけでもないのでCFSTR()で作っちゃう。後ろのx=71とかy=14って何だろう?エンコーディングはCFStringGetSystemEncoding()でよい。最後の’?'は解釈できない文字を?で置き換えるという意味らしい。
CFHTTPMessageSetBody(theRequest, thePostData);
POSTデータをくっつける。あとは前回と同じでPOSTできる。とりあえずmixiがcookieを返すので、あとは色々できそうだ。check.plがいきなりリダイレクトするので、その処理もやらないと。あと、ステータスコードも取得しないと。
Rubyのリファレンスページにあるリダイレクトのやり方。
def fetch( uri_str, limit = 10 )
# 適切な例外クラスに変えるべき
raise ArgumentError, 'http redirect too deep' if limit == 0
response = Net::HTTP.get_response(URI.parse(uri_str))
case response
when Net::HTTPSuccess then response
when Net::HTTPRedirection then fetch(response['location'], limit - 1)
else
response.error!
end
end
print fetch('http://www.ruby-lang.org')
なるほど、上限を決めて再帰すればいいのね。
ブログリンクです。よろしければクリックお願いします。
CFNetworkでHTTP GET
- 2009-05-09 (土)
- プログラミング
似たような記事はあちこちにあるけど、とりあえずまとめてみる。
とりあえずコード。単なるテストなのでごちゃごちゃ。
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// insert code here...
CFURLRef theURL = CFURLCreateWithString(kCFAllocatorDefault, CFSTR("http://mixi.jp"), NULL);
CFHTTPMessageRef theRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), theURL, kCFHTTPVersion1_1);
CFReadStreamRef theStream = CFReadStreamCreateForHTTPRequest(NULL, theRequest);
CFReadStreamOpen(theStream);
CFIndex n;
UInt8 theBuffer[8192];
CFMutableDataRef theCFData = CFDataCreateMutable( NULL, 0 );
while(true)
{
n = CFReadStreamRead(theStream, theBuffer, sizeof(theBuffer));
if( n == 0 )
break;
CFDataAppendBytes( theCFData, theBuffer, n );
}
CFStringRef theContents = CFStringCreateFromExternalRepresentation( NULL, theCFData, kCFStringEncodingEUC_JP );
CFRelease(theCFData);
// CFShowStr(theContents);
// CFIndex stringLength1 = CFStringGetMaximumSizeOfFileSystemRepresentation( theContents );
CFIndex stringLength = CFStringGetMaximumSizeForEncoding( CFStringGetLength(theContents), kCFStringEncodingUTF8 );
char *c = new char[stringLength];
CFStringGetCString( theContents, c, stringLength, kCFStringEncodingUTF8 );
puts(c);
delete [] c;
puts("----------------------");
CFHTTPMessageRef responseHeader = (CFHTTPMessageRef)CFReadStreamCopyProperty(theStream, kCFStreamPropertyHTTPResponseHeader);
CFDictionaryRef headers = CFHTTPMessageCopyAllHeaderFields(responseHeader);
CFIndex count = CFDictionaryGetCount(headers);
if( count > 0 )
{
CFStringRef *keys = new CFStringRef[count];
CFStringRef *values = new CFStringRef[count];
CFDictionaryGetKeysAndValues(headers, (const void **)keys, (const void **)values);
for( int i = 0; i < count; i++ )
{
CFShow( keys[i] );
CFShow( values[i] );
puts("");
}
delete [] keys;
delete [] values;
}
CFRelease(headers);
puts("----------------------");
CFRelease(theRequest);
CFRelease(theURL);
[pool drain];
return 0;
}
解説
CFURLRef theURL = CFURLCreateWithString(kCFAllocatorDefault, CFSTR("http://mixi.jp"), NULL);
まずCFURLRefを作る。CFなんとかRefというのは実はポインタ型なので、*はつけなくていい。
CFSTR()は普通のC文字列(charの配列)から簡易CFStringRef型の文字列を作る。確か、内部で使い回しの領域に文字列オブジェクトを置くので、CFRelease()しなくてよいので使いやすい。その代わり、いつまでも内容が保証されるわけじゃないので、今回のようにすぐに渡してそれっきりにするのがよい。
CFURLCreateWithString()でCFURLRefインスタンスを作る。
一般にCFなんとかを生成する関数(コンストラクタ?)はアロケータを指定するけど、大抵はkCFAllocatorDefaultとかNULLを渡しておけばよいようだ。
CFHTTPMessageRef theRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), theURL, kCFHTTPVersion1_1);
CFHTTPMessageRefのインスタンスを作る。GETリクエストをするわけだけど、使い回すわけでもないのでCFSTR()を使う。あとはさっき作ったURLインスタンスを渡す。HTTPのバージョンは1.1でいいのでこれも決めうちで。アロケータもデフォルト。
CFReadStreamRef theStream = CFReadStreamCreateForHTTPRequest(NULL, theRequest); CFReadStreamOpen(theStream);
リクエストからストリームを作る。特に指定する物はないので簡単。ついでにストリームを開いちゃう。一緒にやってくれたらいいのに・・・ストリームを作って開かないってあるのかな。
ストリームから読み込む
CFIndex n;
UInt8 theBuffer[8192];
CFMutableDataRef theCFData = CFDataCreateMutable( NULL, 0 );
while(true)
{
n = CFReadStreamRead(theStream, theBuffer, sizeof(theBuffer));
if( n == 0 )
break;
CFDataAppendBytes( theCFData, theBuffer, n );
}
CFIndexはintらしい(調べてない)。UInt8はunsigned charで、バッファ用に適当な長さの配列を作っておく。最終的にCFStringにしたいので、CFDataに放り込む。可変長のものはCFMutableDataRef。一般にMutableが付いているのは中身を変更できる。
CFReadStreamRead()でストリームから読み込む。ネットワークはしばしばサイズ上限まで読まないことがあるのでnに読んだバイト数を記録する。Cの文字列のように’\0′終端じゃないから、長さを覚えておいてやる必要がある。読み込みサイズが0バイトなら終わり。そうでなければ、CFDataAppendBytes()で後ろにくっつける。
CFStringを作る
CFStringRef theContents = CFStringCreateFromExternalRepresentation( NULL, theCFData, kCFStringEncodingEUC_JP ); CFRelease(theCFData);
CFStringをCFDataから作る。その際にkCFStringEncodingEUC_JPを指定している。CFDataは単なるバイト列なのでエンコーディング情報がない(往々にしてアルファベット文化圏はその辺に疎いけど、CFStringの設計者は理解しているようだ)ので指定する。
CFDataはもう要らないので解放する。解放のタイミングは不要になったらすぐに解放するのか、しっぽでまとめて解放する方が見やすいのか。
// CFShowStr(theContents);
CFShowStr()は文字列情報を出力するようなので不適。
// CFIndex stringLength1 = CFStringGetMaximumSizeOfFileSystemRepresentation( theContents ); CFIndex stringLength = CFStringGetMaximumSizeForEncoding( CFStringGetLength(theContents), kCFStringEncodingUTF8 ); char *c = new char[stringLength]; CFStringGetCString( theContents, c, stringLength, kCFStringEncodingUTF8 ); puts(c); delete [] c;
仕方がないのでC文字列を作る。
CFStringは「文字数」で表すようだが、char配列はバイト数である。よく「2バイト文字」と言うが、1文字=1バイトあるいは2バイトと決め打ちするのはよくない。Unicodeはたしか1文字を21ビットで表すが、これはあまり使いやすくないので適当にエンコードして使う。UTF-8は基本8ビット(=1バイト)だが、収まらないときは2バイトとか3バイトになるようだ。日本語は一般に3バイトになるが、重箱の隅をつつくと1文字が15バイトになる(株式会社って文字とか)ものもあるそうだ。
そういうわけで、文字数とエンコーディングを指定してCFStringGetMaximumSizeForEncoding()すると必要なバイト数を返す。CFStringGetMaximumSizeOfFileSystemRepresentation()は大きすぎるようだ。
必要なバイト数を得てから、char配列を作りCFStringGetCString()で流し込む。puts()して終わったら忘れないうちに解放。
HTTPレスポンスヘッダを得る
CFHTTPMessageRef responseHeader = (CFHTTPMessageRef)CFReadStreamCopyProperty(theStream, kCFStreamPropertyHTTPResponseHeader);
どういうわけか、HTTPの本文を読んでからじゃないとNULLが返るようなので、終わってから呼ぶ。CFReadStreamCopyProperty()は色々できるようだが、今回はkCFStreamPropertyHTTPResponseHeaderを指定する。
CFDictionaryRef headers = CFHTTPMessageCopyAllHeaderFields(responseHeader);
CFDictionaryを得る。CFDictionaryは連想配列で、キーに対して値を問い合わせるコンテナ。C++のSTLだとstd::mapのようなもの。
CFIndex count = CFDictionaryGetCount(headers);
if( count > 0 )
{
(略)
}
CFRelease(headers);
連想配列にいくつキーと値のペアがあるか調べる。0より大きければ次のコードを実行する。終わったらheaderを解放する。
CFStringRef *keys = new CFStringRef[count]; CFStringRef *values = new CFStringRef[count]; CFDictionaryGetKeysAndValues(headers, (const void **)keys, (const void **)values);
CFDictionaryGetKeysAndValues()でキーと値のペアを取得。CFStringRefの配列へのポインタを渡してやると、CFStringRefの配列が返される。
for( int i = 0; i < count; i++ )
{
CFShow( keys[i] );
CFShow( values[i] );
puts("");
}
delete [] keys;
delete [] values;
全てのペアを表示すればヘッダの内容がわかる。
BSD Socketがいいか、CFNetworkがいいか
正直なところ、こんなに面倒くさいことをするならBSD Socketを直接叩いた方がいいような気がする。URLのパース、DNSの問い合わせ、何かと古くさいSocketを直接叩くのは結構ダサいけど、面倒は少ない。必要ならBSD Socketをラップしちゃえばいいのだからね。
あとは、ヘッダもSocketから読むとゴチャゴチャ読むので、パースしてやる必要がある。これもそうたいした手間ではないし、CFなんとかを使っても面倒くさいから、どっちがいいかはよくわからない。
さらにPUTしてやろうとすると、SetBodyなんとかを使ったりするんだろう。Socketならwriteでがりがり書いてやるだけである。
ブログリンクです。よろしければクリックお願いします。
- Search
- Feeds
- Meta