Next: rfc.uuid - UUID, Previous: rfc.tls - トランスポート・レイヤ・セキュリティ, Up: ライブラリモジュール - ユーティリティ [Contents][Index]
rfc.uri - URIの解析と作成RFC 2396 (https://www.ietf.org/rfc/rfc2396.txt)で定義されている Uniform Resource Identifiers、 またRFC 2397で定義されているData URI Schemeをパーズおよび構築する 手続き群を提供します。
はじめに、URIの構造をざっとみておきましょう。次のグラフはURIがどのように構築されるかを 示しています。
URI-+-scheme
|
+-specific--+--authority-+--userinfo
| +--host
| +--port
+--path
+--query
+--fragment
全てのURIがここに示される完全な木構造を備えているわけではありません。
例えばmailto:admin@example.comはscheme (mailto)
と specific (admin@example.com) だけから構成されます。
しかし、良く使われるURIのほとんどはリソースを木構造で管理するので、
authority (通常はサーバ)と階層的なpathを持ちます。
http://example.com:8080/search?q=key#resultsでは、
authorityはexample.com:8080、pathは/search、
queryはkeyで、fragmentがresultsです。
userinfoはあればホスト名の前に付加されます。例えば
ftp://anonymous@example.com/pub/におけるanonymousです。
URIをこれらの部分に分解する手続きと、 部分からURIを組み立てる手続きが提供されます。
{rfc.uri} 与えられたURIから、指定部分を抜き出します。 このモジュールはURIを完全に分解する手続きも提供していますが、 現実のアプリケーションでは特定部分のみを取り出したい場合も多く、 この手続きはそういう場合に便利に使えます。
parts引数はシンボルもしくはシンボルのリストで、 抜き出したい部分を指定します。指定可能なシンボルは以下の通りです。
schemeschemeパートを文字列で抜き出します。
authorityauthorityパートを文字列で抜き出します。
URIにauthorityパートが無ければ#fが返されます。
userinfouserinfoパートを文字列で抜き出します。
URIにuserinfoパートが無ければ#fが返されます。
hosthostパートを文字列で抜き出します。
URIにhostパートが無ければ#fが返されます。
portportパートを文字列で抜き出します。
URIにportパートが無ければ#fが返されます。
pathpathパートを文字列で抜き出します。 URIが階層的でない場合は、specificパートが返されます。
queryqueryパートを文字列で抜き出します。
URIにqueryパートが無ければ#fが返されます。
fragmentfragmentパートを文字列で抜き出します。
URIにfragmentパートが無ければ#fが返されます。
scheme+authorityschemeパートとauthorityパートの部分を文字列で。
host+porthostパートとportパートの部分を文字列で。
userinfo+host+portusertinfoパート、hostパート、portパートの部分を文字列で。
path+querypathパートとqueryパートの部分を文字列で。
path+query+fragmentpathパートとqueryパートとfragmentパートの部分を文字列で。
(define uri "http://foo:bar@example.com:8080/search?q=word#results") (uri-ref uri 'scheme) ⇒ "http" (uri-ref uri 'authority) ⇒ "//foo:bar@example.com:8080/" (uri-ref uri 'userinfo) ⇒ "foo:bar" (uri-ref uri 'host) ⇒ "example.com" (uri-ref uri 'port) ⇒ 8080 (uri-ref uri 'path) ⇒ "/search" (uri-ref uri 'query) ⇒ "q=word" (uri-ref uri 'fragment) ⇒ "results" (uri-ref uri 'scheme+authority) ⇒ "http://foo:bar@example.com:8080/" (uri-ref uri 'host+port) ⇒ "example.com:8080" (uri-ref uri 'userinfo+host+port) ⇒ "foo:bar@example.com:8080" (uri-ref uri 'path+query) ⇒ "/search?q=word" (uri-ref uri 'path+query+fragment)⇒ "/search?q=word#results"
partsに抜き出したい部分を指定するリストを渡すと、 それぞの部分のリストが返されます。
(uri-ref uri '(host+port path+query))
⇒ ("example.com:8080" "/search?q=word")
{rfc.uri}
URIの一般的なパーザです。これらの関数はURIエンコーディングを
デコードしません。URIスキームによってどの部分をデコードすべきかが
異なるからです。パージングを行った後に、後述のuri-decode等を
使ってデコードを行ってください。
uri-parseは最も手軽な手続きで、uriを以下に示す部分に
分割し、多値で返します。
もし該当する部分がuriに無かった場合は、その部分には#fが返ります。
"mailto:foo@example.com"の"mailto")。
ftp://anonymous@ftp.example.com/pub/fooの"anonymous")。
ftp://anonymous@ftp.example.com/pub/fooの
"ftp.example.com")。
http://www.example.com:8080/の8080)。
http://www.example.com/index.htmlの"/index.html")。
http://www.example.com/search?key=xyz&lang=enの
"key=xyz&lang=en")。
http://www.example.com/document.html#section4の
"section4")。
以下の手続きはより詳細に、段階をふんでuriを分割してゆくものです。
uri-scheme&specific は URI uri を引数に取り、
スキーム部分と、そのスキーム特有の部分を表す2つの値を返します。
uri がスキーム部分を持たない場合、#f を返します。
(uri-scheme&specific "mailto:sclaus@north.pole") ⇒ "mailto" and "sclaus@north.pole" (uri-scheme&specific "/icons/new.gif") ⇒ #f and "/icons/new.gif"
URI が階層的な記法を用いている場合、すなわち、
“//authority/path?query#fragment”
のような場合、スキーム特有の部分を uri-decompose-hierarchical
に渡すと、authority、path、query、fragment
の4つの値が返ります。
(uri-decompose-hierarchical "//www.foo.com/about/company.html") ⇒ "www.foo.com", "/about/company.html", #f and #f (uri-decompose-hierarchical "//zzz.org/search?key=%3fhelp") ⇒ "zzz.org", "/search", "key=%3fhelp" and #f (uri-decompose-hierarchical "//jjj.jp/index.html#whatsnew") ⇒ "jjj.jp", "/index.html", #f and "whatsnew" (uri-decompose-hierarchical "my@address") ⇒ #f, #f, #f and #f
さらに、階層的 URI の authority の部分を
uri-decompose-authority に渡すと、userinfo、
host、port が返ります。
(uri-decompose-authority "yyy.jp:8080") ⇒ #f, "yyy.jp" and "8080" (uri-decompose-authority "[::1]:8080") ;(IPv6 host address) ⇒ #f, "::1" and "8080" (uri-decompose-authority "mylogin@yyy.jp") ⇒ "mylogin", "yyy.jp" and #f
{rfc.uri}
クエリ文字列(例: "foo=abc&bar") を、
パラメータのリスト(例: (("foo" ""abc") ("bar" #t))へと分解します。
各パラメータは名前(文字列)と値(文字列または#t)のリストで表されます。
CGIスクリプトを書いているなら、www.cgiモジュールの
cgi-parse-parametersの方が便利でしょう。この手続きの上に、
フォームパラメータやクッキーの取扱いなどを統合的に扱えるからです
(www.cgi - CGIユーティリティ参照)。
(uri-decompose-query "a=b&a=c") ⇒ (("a" "b") ("a" "c"))
#t.
(uri-decompose-query "a&b") ⇒ (("a" #t) ("b" #t))
(uri-decompose-query "a=b&a=c") ⇒ (("a" "b") ("a" "c"))
#tとなります。
(uri-decompose-query "a&b") ⇒ (("a" #t) ("b" #t))
省略可能引数separatorsには、パラメータの区切りに使われる文字集合を指定します。
デフォルトは#[&;]です。歴史的に&と;の両方が区切りに使われてきたので。
ただ、アプリケーションによっては&しか受け付けない場合があります。
この手続きの逆関数については下のurl-compose-queryを見てください。
{rfc.uri}
Data scheme形式のuriをパーズします。data:スキーム部分は有っても無くても
構いません。渡されたuriがdata uriとして無効な文字列であればエラーが投げられます。
二つの値、パーズされたContent-Typeおよびデコードされたデータを返します。
Content-Typeがtext/*であればデコードされたデータは文字列で、
そうでなければu8vectorで返されます。
Content-Typeはmime-parse-content-typeでパーズされます
(rfc.mime - MIMEメッセージ処理参照)。結果のデータ形式は次のようなリストです。
(type subtype (attribute . value) …).
いくつか例を示します。
(uri-decompose-data
"data:text/plain;charset=utf-8;base64,KGhlbGxvIHdvcmxkKQ==")
⇒ ("text" "plain" ("charset" . "utf-8")) and "(hello world)"
(uri-decompose-data
"application/octet-stream;base64,AAECAw==")
⇒ ("application" "octet-stream") and #u8(0 1 2 3)
{rfc.uri} 与えられたコンポーネントから URI を構成します。 妥当な URI を作成するためのコンポーネントの組み合わせはたくさんあります。 以下のダイアグラムは、考え得る組み合わせの方法を示しています。
/-----------------specific-------------------\
| |
scheme-+------authority-----+-+-------path*---------+-
| | | |
\-userinfo-host-port-/ \-path-query-fragment-/
キーワード引数に #f が与えられた場合、それはキーワード引数が
指定されないことと等価です。これは URI をパーズした結果を渡す場合に
特に有用です。
コンポーネントに適切でない文字が含まれている場合は、
url-compose に渡す前に正しくエスケープされなければなりません。
いくつかの例を示します。
(uri-compose :scheme "http" :host "foo.com" :port 80
:path "/index.html" :fragment "top")
⇒ "http://foo.com:80/index.html#top"
(uri-compose :scheme "http" :host "foo.net"
:path* "/cgi-bin/query.cgi?keyword=foo")
⇒ "http://foo.net/cgi-bin/query.cgi?keyword=foo"
(uri-compose :scheme "mailto" :specific "a@foo.org")
⇒ "mailto:a@foo.org"
(receive (authority path query fragment)
(uri-decompose-hierarchical "//foo.jp/index.html#whatsnew")
(uri-compose :authority authority :path path
:query query :fragment fragment))
⇒ "//foo.jp/index.html#whatsnew"
{rfc.uri} 引数は、完全な、あるいは部分的なURIを表す文字列です。 この手続きは、RFC3986 Section 5.2. “Relative Resolution” に 示されるアルゴリズムに従い、relative-uriをbase-uriからの相対 として解決します。
relative-uri2 … が与えられた場合は、まずrelative-uri がbase-uriを基準に解決され、その結果を新たな基準として次の relative-uri2を解決し、以下同様に続けます。
(uri-merge "http://example.com/foo/index.html" "a/b/c") ⇒ "http://example.com/foo/a/b/c" (uri-merge "http://example.com/foo/search?q=abc" "../about#me") ⇒ "http://example.com/about#me" (uri-merge "http://example.com/foo" "http://example.net/bar") ⇒ "http://example.net/bar" (uri-merge "http://example.com/foo/" "q" "?xyz") ⇒ "http://example.com/foo/q?xyz"
{rfc.uri}
paramsはパラーメータ指定のリストです。各パラメータ指定は
(name value)の形式で、nameは文字列、
valueは文字列もしくは#tです
(上のurl-decompose-queryも参照)。
各パラメータの名前と値はurlencodeされてから、URLのクエリパラメータとして結合されます。
パラメータの値が#tの場合は、名前だけのパラメータとなります。
(uri-compose-query '(("foo" "abc") ("bar" #t)))
⇒ "foo=abc&bar"
省略可能なencoding引数はパラメータの文字エンコーディングを指定します。
デフォルトはutf-8です。それ以外の場合は、各文字列はその文字エンコーディングに
変換された後でurlencodeされます。
rfc.httpのhttp-compose-queryはこの手続きの上に作られた
ユーティリティです(HTTPクライアントユーティリティ参照)。
{rfc.uri} 与えられたdataからData URIを構築して文字列で返します。
data引数は文字列かu8vectorでなければなりません。
content-typeキーワード引数は、#f (デフォルト)、
content typeを表現する文字列 (例: "text/plain;charset=utf-8")、
もしくはパーズされたcontent type (例: ("application" "octet-stream"))です。
#fである場合は、dataが完全な文字列であれば
text/plainにGaucheのネイティブ文字エンコーディングに基づくcharsetを
つけたもの、dataがそれ以外であればapplication/octet-streamが
使われます。
encodingキーワード引数は#f (デフォルト)、
もしくはシンボルuriまたはbase64です。これは文字エンコーディングではなく
トランスファーエンコーディングであることに注意。
#fの場合は、テキストデータならuriが、バイナリデータならbase64が
使われます。
(uri-compose-data "(hello world)") ⇒ "data:text/plain;charset=utf-8,%28hello%20world%29" (uri-compose-data "(hello world)" :encoding 'base64) ⇒ "data:text/plain;charset=utf-8;base64,KGhlbGxvIHdvcmxkKQ==" (uri-compose-data '#u8(0 1 2 3)) ⇒ "data:application/octet-stream;base64,AAECAw=="
{rfc.uri}
URI エンコーディング、すなわち、%でエスケープされた URI 文字列を
デコードします。uri-decode は現在の入力ポートから入力を受け取り、
デコードした結果を現在の出力ポートに書き出します。
uri-decode-string は string を入力とし、デコードした
文字列を返します。
cgi-decode が真の場合は、+ がスペース文字に置換されます。
uri-decode-stringには、外部の文字エンコーディングを指定する
encodingキーワード引数を与えることができます。この引数が与えれた
場合、デコードされたオクテットの列を指定された文字エンコーディングであると
してGaucheの内部文字エンコーディングへと変換したものが返されます。
{rfc.uri}
安全でない文字を、%によるエスケープでエンコードします。
uri-encode は現在の入力ポートから入力を受け取り、
結果を現在の出力ポートに書き出します。
uri-encode-string は string を入力とし、エンコードした
文字列を返します。
デフォルトでは、RFC3986 で"非予約文字"として規定されていない文字は
エスケープされます。noescape 引数に異なる文字集合を渡すことで、
それらがエンコードされるのを抑止することができます。
例えば古いRFC2396では"非予約文字"がいくつか多かったのですが、
*rfc2396-unreserved-char-set* (下記参照) を渡すことで
それらの文字がエスケープされるのを防ぐことができます。
マルチバイト文字は、デフォルトではGauche のネイティブなマルチバイト表現の
オクテット・ストリームとしてエンコードされます。ただし
uri-encode-stringにはencodingキーワード引数を渡すことができて、
その場合はまずstringが指定された文字エンコーディングへと変換されます。
{rfc.uri}
これらの定数はそれぞれ、RFC2396とRFC3986で定義されている
「非予約文字」の文字集合に束縛されています。
(文字集合の操作については、文字集合およびscheme.charset - R7RS文字集合
を参照して下さい。)
Next: rfc.uuid - UUID, Previous: rfc.tls - トランスポート・レイヤ・セキュリティ, Up: ライブラリモジュール - ユーティリティ [Contents][Index]