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引数はシンボルもしくはシンボルのリストで、 抜き出したい部分を指定します。指定可能なシンボルは以下の通りです。
scheme
schemeパートを文字列で抜き出します。
authority
authorityパートを文字列で抜き出します。
URIにauthorityパートが無ければ#f
が返されます。
userinfo
userinfoパートを文字列で抜き出します。
URIにuserinfoパートが無ければ#f
が返されます。
host
hostパートを文字列で抜き出します。
URIにhostパートが無ければ#f
が返されます。
port
portパートを文字列で抜き出します。
URIにportパートが無ければ#f
が返されます。
path
pathパートを文字列で抜き出します。 URIが階層的でない場合は、specificパートが返されます。
query
queryパートを文字列で抜き出します。
URIにqueryパートが無ければ#f
が返されます。
fragment
fragmentパートを文字列で抜き出します。
URIにfragmentパートが無ければ#f
が返されます。
scheme+authority
schemeパートとauthorityパートの部分を文字列で。
host+port
hostパートとportパートの部分を文字列で。
userinfo+host+port
usertinfoパート、hostパート、portパートの部分を文字列で。
path+query
pathパートとqueryパートの部分を文字列で。
path+query+fragment
pathパートと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文字集合
を参照して下さい。)