rfc.http
- HTTPクライアント ¶このモジュールは、RFC2616 "Hypertext Transfer Protocol – HTTP/1.1" で定義されているHTTP/1.1に対する簡単なクライアントAPIを提供します。 (https://www.ietf.org/rfc/rfc2616.txt).
現在のAPIは、HTTP/1.1のプロトコルの一部のみ実装されています。 より先進的な機能、例えば永続的接続などは将来のバージョンで追加されるでしょう。
HTTPサーバを書くためのライブラリを探しているなら、 Gauche-makikiを見てください (https://github.com/shirok/Gauche-makiki)。
{rfc.http
}
サーバから接続が切られた場合や、サーバの返したHTTPレスポンスのフォーマットが
正しくない場合に投げられるコンディションです。<error>
を継承します。
• HTTPクライアント中間レベルAPI: | ||
• HTTPクライアントユーティリティ: | ||
• セキュアhttpコネクション: |
{rfc.http
}
serverに、それぞれHTTPのGET、HEAD、POST、PUT、DELETEリクエストを送り、
サーバの応答を返します。
デフォルトでは、 サーバがステータスコード 300, 301, 302, 303, 305 の応答を返し、 RFC2616による自動リダイレクトが許されている場合は、 これらの手続きは自動的に応答のメッセージヘッダの "location" で返されるURIに対して リクエストを再送します。 この動作はredirect-handlerキーワード引数でカスタマイズしたり 抑制したりできます。下の"キーワード引数"を参照してください。
必須の引数: server引数では、文字列でHTTPサーバ名を指定します。 サーバ名は、オプションでコロンに続いてポート番号を付加できます。 IPアドレスも使えます。IPv6アドレスは角括弧で囲んでください。
また、"unix:/path"
という形式でUnixドメインソケットに接続することもできます。
/path
部分にはソケットへの絶対パスを指定します。
Examples: "w3c.org"
, "mycompany.com:8080"
,
"192.168.0.1:8000"
, "[::1]:8000"
request-uri引数は文字列かリストです。 文字列の場合、RFC2616で規定されているリクエストURIと解釈されます。 通常これはHTTP URLのパス部分です。 文字列はそのままサーバに渡されるので、呼び出し側で必要な 文字コード変換やurlエンコーディングを行う必要があります。
request-uriがリストの場合は、次の形式でなければなりません。
(path (name value) ...)
ここでpathはリクエストURIのパスコンポーネントまでを指定する
文字列です。与えられたnameとvalueのalistから、
httpリクエスト手続きはHTML4で定められた
application/x-www-form-urlencoded
形式の
クエリ文字列を構成し、pathにアペンドします。
例えば次のふたつのリクエストは同じ効果を持ちます。
二番目の呼び出しではurlエスケープが自動的に行われることに注目してください。
(http-get "example.com" "/search?q=foo%20bar&n=20") (http-get "example.com" '("/search" (q "foo bar") (n 20)))
request-encodingキーワード引数が与えられた場合、 nameとvalueはまずその文字エンコーディングに変換されたのちに urlエスケープされます。そうでない場合はgaucheの内部 エンコーディングがそのまま使われます。
いくつかの手続きは、リクエストメッセージのボディを指定するbodyを第3引数として
取ります。bodyは文字列かリストで、文字列の場合はそのまま送られ、
リストの場合はmultipart/form-data
形式にエンコードされて送られます。
bodyがリストの場合、それはパラメータ指定のリストです。
各パラメータ指定は、("submit" "OK")
のような名前と値のリスト、
もしくは("upload" :file "logo.png" :content-type "image/png")
のように名前の後にキーワード-値リストを付加したものです。
最初の形式は使うのが簡単で、またrequest-uriのクエリパラメータリストと
同じ形式なのでGETとPOSTでルーチンを共有したい場合にも便利でしょう。
この形式では、各値はMIMEパートにtext/plain
として置かれます。
文字コードは下に述べるrequest-encoding
キーワード引数により変換されます。
二番目の形式では、MIMEパートの属性についてより細かな指定を行うことができます。 以下のキーワードが特別に扱われます。
:value
パラメータの値を指定します。簡潔な(name val)
形式は
(name :value val)
の省略形です。
:file
指定された名前のファイルの中身をパラメータの値として挿入します。
ファイルのアップロードに便利です。このオプションは:value
より
優先されます。MIMEタイプは、指定が無ければ
application/octet-stream
となります。
:content-type
MIMEタイプをオーバライドします。与えられた値にcharsetパラメータが ついていない場合は自動的に付加されます。
:content-transfer-encoding
content-transfer-encodingを
7bit
、binary
、quoted-printable
、base64
の
いずれかで指定します。指定が無ければbinary
が使われます。
残りのキーワードはMIMEパートのヘッダにそのまま使われます。
戻り値: 全ての手続きは3つの値を返します。
1つ目は、RFC2616で定義されているステータスコードの文字列値(例えば、成功時の 200、"Not found"の404など)です。
2つ目は、パーズされたヘッダのリストで、リストの要素は(header-name
value …)
です。header-nameはヘッダの文字列名(例えば、
"content-type"や"location"など)で、valueは対応する値の文字列値です。
ヘッダ名は小文字に変換されます。値は、RFC2822で定義されている無指定行区切
(ソフト・ライン・ブレイク)が除かれる以外はそのままです。
サーバが同じ名前のヘッダを1つ以上返した場合は、
1つのリストに統合されます。それ以外では、2つ目の戻り値に
おけるヘッダのリストの順番は、サーバの応答での順番と同じです。
3つ目の戻り値は、サーバの応答におけるメッセージボディです。
デフォルトでは、文字列で表現されたメッセージボディそのものです。
サーバの応答がボディを持たない場合、3つ目の戻り値は#f
です。
キーワード引数によって、メッセージボディがどのように扱われるかを制御できます。
例えば、中間的な文字列を作らずに、返されたメッセージボディを直接ファイルに
格納することが出来ます。詳細は以下で説明しています。
キーワード引数:
デフォルトで、これらの手続きはリクエストメッセージに"Host"
ヘッダ・フィールドを
追加するだけです。他のヘッダ・フィールドを追加するためにキーワード引数を
与えることができます。
(http-get "foo.bar.com" "/index.html" :accept-language "ja" :user-agent "My Scheme Program/1.0")
以下のキーワード引数は手続きによって解釈され、リクエストヘッダには現れません。
request-encoding
request-uriやbodyがリストで与えられた場合、パラメータの
名前や値はまずこの引数で指定される文字エンコーディングへと変換され、
その後、application/x-www-form-urlencoded
や
multipart/form-data
MIME形式にしたがったエンコーディングが行われます。
この引数が省略された場合はGaucheの内部文字エンコーディングが使われます。
multipart/form-data
については、パラメータにcontent-type
ヘッダを
与えることでパラメータごとに文字エンコーディングの設定をオーバライドできます。
詳しくは上のbody引数の説明を参照してください。
request-uriやbodyに文字列を与えた場合は、文字エンコーディング変換は 行われません。呼び出し側で望みの文字コードにあらかじめ変換しておいてください。
proxy
httpプロキシサーバを、hostname
またはhostname:port
形式の
文字列で指定します。省略された場合、パラメータhttp-proxy
の値が
使われます。
redirect-handler
サーバが3xxステータスコードを返した場合のリダイレクトの処理を指定します。
#f
, #t
もしくは手続きを渡すことができます。省略時は#t
となります。
#f
が渡された場合は、リダイレクトは処理されません。3xxステータスコードを
持つレスポンスもそのままhttp-*
から返されます。
手続きが渡された場合は、サーバが3xxステータスコードを返すとその手続きが4つの引数で
呼ばれます。最初の引数はリクエストメソッド(シンボル、例:GET
)、
次がレスポンスステータスコード(文字列、例:"302"
)、
次がパーズされたレスポンスヘッダ、そして最後がレスポンスボディです(レスポンスボディが
あれば文字列、なければ#f
)。
この手続きは、ペアか#f
を返さねばなりません。ペアの場合、それは
(method . url)
という形で、methodがシンボルによるリクエストメソッド、
urlが文字列で次にリクエストすべきURLを表します。
ペアが返されれば、http-*
手続きはそのURLへ、指定されたメソッドでリクエストを
再送します。(メソッドを返すことで、例えばPOSTリクエストのリダイレクトをGETリクエストに
置き換えることが可能です)。
手続きが#f
を返した場合、リダイレクトは行われません。
redirect-handlerが#t
(デフォルト値)の場合、
パラメータhttp-default-redirect-handler
の値が
redirect-handlerに渡されたかのように振る舞います。
このパラメータの初期値は、標準的なリダイレクトの振る舞いをする手続きになっています。
下のhttp-default-redirect-handler
の項目を参照してください。
リダイレクトのループは自動的に検出され、<http-error>
が投げられます。
no-redirect
これは互換性のためだけに残されている、古い引数です。真の値を与えると、
redirect-handlerに#f
を渡したのと同じ効果を持ちます。
secure
真の値が与えられた場合、セキュアな接続が使われます。
値によってhttps接続につかうトランスポートエージェントを指定できます。
有効な値は#t
もしくはシンボルのtls
かstunnel
です。
#f
が与えられた場合(デフォルト)はセキュアでない通常のhttpが使われます。
詳しくは下の「セキュアな接続」の項を参照してください。
auth-user, auth-password
これらのキーワード引数が与えられた場合、Basic認証用のAuthorizationヘッダが リクエストに付加されます。将来はBasic認証以外の認証方式もサポートするかもしれません。
sink, flusher
これらのキーワード引数によりリプライメッセージ・ボディがどのように扱われるかを カスタマイズできます。sinkには出力ポートを、flusherには2引数を 取る手続きを渡さなければなりません。
手続きがメッセージ・ボディを受信し始めると、sinkへ受け取った データ片をフィードします。手続きがメッセージ・ボディを受信し終わると、 flusherに与えられた手続きが、sinkと(手続きからの2つ目の 戻り値と同じフォーマットの)メッセージ・ヘッダ・フィールドのリストとともに 呼び出されます。flusherの戻り値が、手続きからの3つ目の戻り値と なります。
したがって、sinkのデフォルト値は、新しく開かれた文字列ポートで、
flusherのデフォルト値は(lambda (sink headers) (get-output-string sink))
とも言えます。
以下のサンプルは、(とても大きい可能性のある)文字列バッファを作らずに、 メッセージ・ボディを直接ファイルに保存します。
(call-with-output-file "page.html" (lambda (out) (http-get "www.schemers.org" "/" :sink out :flusher (lambda _ #t))))
The module also provides some utility procedures.
{rfc.http
}
user-agentヘッダに渡される値のデフォルト値を指定するパラメータです。
デフォルトの値はgauche.http/*
(*
部分はGaucheのバージョン)
になっています。
各アプリケーションは適切な値を設定するようにしてください。
{rfc.http
}
このパラメータの値がhttp-get
等のhttpプロキシのデフォルトの値として
使われます。デフォルトの値は#f
(プロキシを使用しない) です。
{rfc.http
}
http-*
手続きにredirect-handler
キーワード引数が与えられなかった
場合のデフォルトの動作を指定します。この値を変える場合、それは
redirect-handler
引数のプロトコルに従う手続きでなければなりません。
上のhttp-*
手続きの項目を参照してください。
デフォルトの動作は以下の通りです。
300
, 301
, 305
, 307
元のリクエストがGET
かHEAD
の場合に限り、同じリクエストを使って
location
ヘッダに与えられたURLにリダイレクトします。
302
location
ヘッダに与えられたURLにリダイレクトします。
元がHEAD
リクエストならHEAD
を、それ以外ならGET
リクエストを
使います。
厳密に言えばこれはRFC2616違反ですが、RFC2616の注記にもあるように、 多くのユーザエージェントがこの振る舞いをするので、それに合わせてあります。 (将来は変えるかもしれません。)
303
location
ヘッダに与えられたURLにリダイレクトします。
元がHEAD
リクエストならHEAD
を、それ以外ならGET
リクエストを
使います。
リダイレクトしません。
次のコードは、デフォルトの振る舞いを特定のリクエストでインターセプトする例です。
(http-get server uri :redirect-handler (^[method status headers body] (if (and (equal? status "302") (not (member method '(GET HEAD)))) #f ((http-default-request-handler) method status headers body))))
{rfc.http
}
クエリパラメータのリストからリクエストURIを生成する補助関数です。
encoding引数はクエリパラメータの文字エンコーディングを指定します。
(http-compose-query "/search" '((q "$foo") (n 20))) ⇒ "/search?q=%24foo&n=20" (http-compose-query "" '((x "a b") (x 2))) ⇒ "?x=a%20b&x=2"
pathが#f
の場合は、クエリパラメータの部分だけが返されます
(次の例と直前の例を比べてみてください)。
(http-compose-query #f '((x "a b") (x 2))) ⇒ "x=a%20b&x=2"
これはrfc.uri
モジュールのuri-compose-query
手続きの上に
作られています (rfc.uri
- URIの解析と作成参照)。
{rfc.http
}
multibyte/form-data
形式にエンコードされたデータを
パラメータのリストから組み立てるための補助手続きです。
paramsの形式はhttpリクエスト手続きのbody部にリストを渡す場合の形式と同様です。
結果は出力ポートportに書き出され、
MIMEメッセージを構築するのに必要なboundary stringが返されます。
portに#f
を渡した場合は、
boundary stringとデータをエンコードした文字列の二つの値が返されます。
encodingは文字エンコーディングを指定します。 省略時はGaucheのネイティブエンコーディングが使われます。
(define p (open-output-string)) (http-compose-form-data '((name "Preludes and Fugues") (composer "Shostakovich, Dmitri") (opus "87")) p) ⇒ "boundary-fh87o52rp6zkubp2uhdmo" (get-output-string p) ⇒ "\r\n--boundary-fh87o52rp6zkubp2uhdmo\r\nContent-type: te xt/plain; charset=utf-8\r\nContent-transfer-encoding: bi nary\r\ncontent-disposition: form-data; name=title\r\n\r\n Preludes and Fugues\r\n--boundary-fh87o52rp6zkubp2uhdmo... ;; (以下省略)
{rfc.http
}
HTTPステータスコードcode
の簡単な説明を返します。
code
は整数か、整数を表す文字列です(例: "404"
)。
code
が知られているものでなかった場合は#f
が返されます。
(http-status-code->description 404) ⇒ "Not Found"
http-get
等httpリクエスト発行APIのsecure
キーワード引数に、
真の値を渡した場合、セキュアなコネクションが使われます。
すなわち、http
ではなくhttps
で接続されるということです。
実際にsecure
キーワード引数に渡せる値は以下の通りです。
#t
tls
rfc.tls
モジュールを使ってセキュアな接続を行います。
詳しくはrfc.tls
- トランスポート・レイヤ・セキュリティを参照してください。
CA証明書のパスを設定する必要があるかもしれません。
stunnel
stunnel
プロセスをサブプロセスとして起動してそれを通じてセキュアな接続を作ります。
#f
セキュアな接続を行いません。
指定されたセキュア接続を行うサブシステムが実行中のGaucheでは使えない場合は、 エラーが報告されます。 サブシステムが使えるかどうかをチェックしたい場合は次の手続きを使ってください。
{rfc.http
}
type引数はtls
かstunnel
でなければなりません。
省略時はtls
とみなされます。
指定のセキュア接続を行うサブシステムが実行中のGaucheで使える場合は#t
が、
使えない場合は#f
が返されます。