HTTPクライアント作成

簡単なcommon lispのHTTPクライアントをHTTPの勉強を兼ねて作成。

ソースコード(*.lisp)は、約170行程度。

まだまだ十分な完成度とは云えないが、せっかくなので公開してみる。
これ、tiny-http(0.1.3)※置き場は暫定


インストールが必要な依存packageは次の通り、cl-ppcre(正規表現)、cl+ssl(ssl)、guess(文字コード判定)、common-utils(自分用のutility関数群)。

以下、説明など。

機能・特徴

  • GET、POST、HEADメソッドに対応
  • HTTPS対応
  • HTTPヘッダの取得や追加が自由
  • 文字コードを、そこそこちゃんと適切に扱ってくれる
  • 小さい?

欠点・難点

  • URL指定に非対応
  • 30x系のレスポンスを自動的にリダイレクトしてくれない
  • 巨大データを扱うことを想定していない
  • POSTが使いづらい
  • 未対応・非対応が結構ある(OPTIONS、TRACE、KeepAlive、Trailer、...)
  • コメント・ドキュメントがほぼない
  • エラー処理が皆無
  • 現時点(20090702)では、テスト不十分(多分バグが結構ある)
  • SBCLでしか使えない
  • etc

まあ、バグや機能的なものに関しては、自分で使いながら修正と-必要なら-改良していこう。 ※ これを使ってみようという(奇特な?)人がいるなら、ですが、基本的にフィードバックは歓迎です。

common lispには、既にいくつかHTMLクライアントがあるようなので、そのうちそっちに移行するかもしれないけど、当面は自作のものを使おうかな。

API的なもの

externalな関数は三つ。

get host path &key ssl port header external-format decoder
  => (values HTML status-code header-fields)


post host path body &key ssl port header external-format decoder
  => (values HTML status-code header-fields)


head host path &key ssl port header
  => (values status-code header-fields)


hostとpath、portは、そのままホスト名とパス、ポート番号。
sslがtならhttpsで通信を行い、nilならhttpで通信を行う。デフォルトはnil
portのデフォルトはsslnilなら80で、tなら443。


bodyは、postの時にメッセージボディとして送られるデータで、stringか(vector (unsigned-byte 8))のいずれかの型である必要がある。


headerは、送信時に追加するヘッダーフィールドで、plist形式で指定する。何故か各関数の戻り値のheader-fieldsはalist形式。
Ex. (:accept "text/plain" :authorization "Basic jidS3isdfS6F=")


external-formatとdecoderは、文字列のエンコードに関係していて、
decoderは、(funcall decoder octet-vector header-fields)みたいな感じで、レスポンスボディ(HTML)のデコードに使われる二引数の関数。
external-formatは、(or :guess :octets :ascii :utf-8 :euc-jp ...その他文字コード指定...)のような値をとる。


:guess -> 文字コード自動推論
:octets -> 何も変換を行わずに、(vector (unsigned-byte 8))をHTMLとして返す
:ascii -> asciiコードの範囲内のものだけを適切に変換する。範囲外のものは、*default-unknown-character*の値で埋められる。
その他 -> 指定された(:utf-8などの)文字コードとしてデコードを行う
decoderとexternal-formatの両方が指定されている場合は、decoderが優先される。
それぞれのデフォルト値は、decoderがnilで、external-formatが:guess。


多分、これでほぼ全部の説明をカバーしてるはず。
それほど複雑でもないので、使用例などは割愛。

感想

HTTPS対応が、以下のコードだけで出来たのには少し驚いた。

(setf socket-stream (cl+ssl:make-ssl-client-stream socket-stream))