For Gauche 0.9.5


Next: , Previous: , Up: ライブラリモジュール - ユーティリティ   [Contents][Index]

12.41 rfc.uri - URIの解析と作成

Module: rfc.uri

RFC 2396 (RFC2396)で定義されている Uniform Resource Identifiers、 またRFC 2397で定義されているData URI Schemeをパーズおよび構築する 手続き群を提供します。

First, lets review the structur of URI briefly. The following graph shows how the URI is constructed:

URI-+-scheme
    |
    +-specific--+--authority-+--userinfo
                |            +--host
                |            +--port
                +--path
                +--query
                +--fragment

Not all URIs have this full hierachy. For exmaple, mailto:admin@example.com has only scheme (mailto) and specific (admin@example.com) parts.

Most popular URI schemes, however, organize resources in a tree, so they adopt authority (which usually identifies the server) and the hierarchical path. In the URI http://example.com:8080/search?q=key#results, the authority part is exmaple.com:8080, the path is /search, the query is key and the fragment is results. The userinfo can be provided before hostname, such as anonymous in ftp://anonymous@example.com/pub/.

We have procedures that decompose a URI into those parts, and that compose a URI from those parts.

URIのパーズ

Function: uri-ref uri parts

Extract specific part(s) from the given URI. You can fully decompose URI by the procedures described below, but in actual applications, you often need only some of the parts. This procedure comes handy for it.

The parts argument may be a symbol, or a list of symbols, to name the desired parts. The recognized symbos are as follows.

scheme

The scheme part, as string..

authority

The authority part, as string. If URI doesn’t have the part, #f.

userinfo

The userinfo part, as string. If URI doesn’t have the part, #f.

host

The host part, as string. If URI doesn’t have the part, #f.

port

The port part, as integer. If URI doesn’t have the part, #f.

path

The path part, as string. If URI isn’t hierarchical, this returns the specific part.

query

The query part, as string. If URI doesn’t have the part, #f.

fragment

The fragment part, as string. If URI doesn’t have the part, #f.

scheme+authority

The scheme and authority part.

host+port

The host and port part.

userinfo+host+port

The userinfo, host and port part.

path+query

The path and query part.

path+query+fragment

The path, query and fragment part.

(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"

You can extract multiple parts at once by specifying a list of parts. A list of parts is returned.

(uri-ref uri '(host+port path+query))
  ⇒ ("example.com:8080" "/search?q=word")
Function: uri-parse uri
Function: uri-scheme&specific uri
Function: uri-decompose-hierarchical specific
Function: uri-decompose-authority authority

URIの一般的なパーザです。これらの関数はURIエンコーディングを デコードしません。URIスキームによってどの部分をデコードすべきかが 異なるからです。パージングを行った後に、後述のuri-decode等を 使ってデコードを行ってください。

uri-parseは最も手軽な手続きで、uriを以下に示す部分に 分割し、多値で返します。 もし該当する部分がuriに無かった場合は、その部分には#fが返ります。

以下の手続きはより詳細に、段階をふんで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 に渡すと、authoritypathqueryfragment の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 に渡すと、userinfohostport が返ります。

(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
Function: uri-decompose-data uri

Data URI文字列uriをパーズします。data:スキームは有っても無くても 構いません。渡されたuriがdata uriとして無効な文字列であればエラーが投げられます。

二つの値、パーズされたContent-Typeおよびデコードされたデータを返します。 Content-Typeがtext/*であればデコードされたデータは文字列で、 そうでなければu8vectorで返されます。

Content-Typeはmime-parse-content-typeでパーズされます (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
 "data:application/octet-stream;base64,AAECAw==")
  ⇒ ("application" "octet-stream") and #u8(0 1 2 3)

URIの構築

Function: uri-compose :key scheme userinfo host port authority path path* query fragment specific

与えられたコンポーネントから 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"
Function: uri-merge base-uri relative-uri relative-uri2 …

引数は、完全な、あるいは部分的なURIを表す文字列です。 この手続きは、RFC3986 Section 5.2. “Relative Resolution” に 示されるアルゴリズムに従い、relative-uribase-uriからの相対 として解決します。

relative-uri2 … が与えられた場合は、まずrelative-uribase-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"
Function: uri-compose-data data :key content-type encoding

与えられた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=="

URIのエンコードとデコード

Function: uri-decode :key :cgi-decode
Function: uri-decode-string string :key :cgi-decode :encoding

URI エンコーディング、すなわち、%でエスケープされた URI 文字列を デコードします。uri-decode は現在の入力ポートから入力を受け取り、 デコードした結果を現在の出力ポートに書き出します。 uri-decode-stringstring を入力とし、デコードした 文字列を返します。

cgi-decode が真の場合は、+ がスペース文字に置換されます。

uri-decode-stringには、外部の文字エンコーディングを指定する encodingキーワード引数を与えることができます。この引数が与えれた 場合、デコードされたオクテットの列を指定された文字エンコーディングであると してGaucheの内部文字エンコーディングへと変換したものが返されます。

Function: uri-encode :key :noescape
Function: uri-encode-string string :key :noescape :encoding

安全でない文字を、%によるエスケープでエンコードします。 uri-encode は現在の入力ポートから入力を受け取り、 結果を現在の出力ポートに書き出します。 uri-encode-stringstring を入力とし、エンコードした 文字列を返します。

デフォルトでは、RFC3986 で"非予約文字"として規定されていない文字は エスケープされます。noescape 引数に異なる文字セットを渡すことで、 それらがエンコードされるのを抑止することができます。 例えば古いRFC2396では"非予約文字"がいくつか多かったのですが、 *rfc2396-unreserved-char-set* (下記参照) を渡すことで それらの文字がエスケープされるのを防ぐことができます。

マルチバイト文字は、デフォルトではGauche のネイティブなマルチバイト表現の オクテット・ストリームとしてエンコードされます。ただし uri-encode-stringにはencodingキーワード引数を渡すことができて、 その場合はまずstringが指定された文字エンコーディングへと変換されます。

Constant: *rfc2396-unreserved-char-set*
Constant: *rfc3986-unreserved-char-set*

これらの定数はそれぞれ、RFC2396とRFC3986で定義されている 「非予約文字」の文字集合に束縛されています。 (文字集合の操作については、文字集合および文字集合ライブラリ を参照して下さい。)


Next: , Previous: , Up: ライブラリモジュール - ユーティリティ   [Contents][Index]