HaskellでTwitterクライアント開発blog(仮)

今すぐに挫折するかもしれない程度のモチベーションによるTwitterクライアント開発記

Network.CurlでHTTPS通信に対応しようとしてみたけど……

今までHTTP通信でOAuthのトークンリクエスト・API呼び出しをやっていたのをHTTPS通信に変更することを試みてみました。

今回、HTTPS通信に切り替えるにあたって、少々関数のインタフェースを変更……
変更したのはOAuthモジュールのoauthRequest,apiRequest関数(つまり、HTTPリクエストを生成する関数)で、返り値を、IO Response_String型ではなくIO Stringにし、レスポンスボディだけ受け取るようにしました。
結局レスポンスボディだけしか使ってなかったので。

これにより、Mainモジュールではレスポンスボディの処理だけ考えれば良くなったので、HTTP通信周りは完全にOAuthモジュール内に隠蔽されることになり、HTTPS通信を行うにあたって変更するのはOAuthモジュールの以下の関数(と、URL)だけになります。

で、HaskellHTTPS通信を行う方法ですが、Network.Curlモジュールを使うことにしました。
http-enumeratorとか使う方法もあるようですが、よくわからなかったので……

で、cURLの使い方は、まず

Network.Curl.Easy.initialize :: IO Curl 

を呼んでから、

Network.Curl.setopts :: Curl -> [CurlOption] -> IO ()

でオプションを設定し、

Network.Curl.do_curl_ ::
(CurlHeader headerTy, CurlBuffer bodyTy) =>
Curl
-> URLString
-> [CurlOption]
-> IO (CurlResponse_ headerTy bodyTy)

を呼んでレスポンスを処理すればいいと。

 そこでまず、HTTPで通信する例をNetwork.Curlモジュールを利用したものに書き換えてみました。

 

いろいろ雑ですが、まぁこれで通りました。トークンリクエストもAPI呼び出しも問題無さそうです。
実際は、Curlオプションをどう設定すればいいのか分からずかなり躓いたのですが……
ちなみにOAuth側でPOSTリクエストボディ周りをサボっても通りましたが、その場合もしっかりCurlPostFieldSize=0を指定しないとエラーになってしまいました。

 

で、HTTPS
HTTPSプロトコル自体、「サーバ・クライアント間の通信を暗号化してセキュリティを向上させる」以上の知識がなく、具体的にどんな手続きをすればいいのかよくわかんなかったので、HTTPS通信でTwitter APIを利用している例を調べました。

http://d.hatena.ne.jp/aquarla/20101005/1286274634

http://d.hatena.ne.jp/unageanu/20070504

それにしても、Twitter APIについて調べるとRubyでやってる人が多いですね……
つまり、PEMファイルを落としてそれをCA_Fileに設定して通信、という手順っぽい。
そこでPEMファイルを落としてきていろいろ設定を頑張ってみたのですが。

上で提示したHTTP用のコードで、アドレスだけhttpsに変えると通ってしまう……

というよくわからない事態になりました。PEMファイル関係ありません。
CA_Fileに対応していそうなCurlCAInfo,CurlCAPath, CurlCRLFileなんてオプションも見つけたのですが、
設定しても動くし、そもそも全然違うファイル(PEM形式ですら無い、空のファイル)を指定しても動く。
さっきから「動く」といってるのは200 OKステータスが返って問題なく通信できているという意味です。

よくわからなくなってきました。わかっていることは

(1)simpleHTTPだとhttps://~アドレスへのアクセスは403 Unauthorizedで弾かれる。
→初期にハマったミス

(2)du_curl_にはURLStringというフィールドがあり、ここにhttp://api~を入れても、https://api~を入れても通る。
→つまり、simpleHTTPとは明らかに挙動が違う。https通信がちゃんとできているのか、実は内部で「証明書がちゃんとできてないからHTTPプロトコルで送るか」みたいな挙動になっているのか?

(3)du_curl_にはCurlSSLCertというオプションもあり、ここにPEMファイルや他の適当なファイルを指定すると通らない。
→このオプションは怪しいけど、今回の認証にはあんまり関係ないっぽい?

ということ。怖いのはhttpsを指定しても暗号化なんて全然されてませんでした!ってオチなのですが。
一応、httpsアドレスを指定してちゃんとリクエストが通ってるので、当面コレで行きます。
明らかに上のRubyでやってる人たちとは違うことしてますが、いいんでしょうか……