URIとCGIのescape

最近、さまざまなWebサービスがある。
amazonだったり、Yahoo!だったり。
そこで、Rubyを使い便利ツールを作って遊んでいるのだが、RESTでリクエストする場合はエスケープしてやらないといけない。
エスケープしてくれる人はいないかと探したところ、URI.escapeとCGI.escapeの二人がエスケープしてくれる模様だ。
まずURI.escape

URI.escape(str[, unsafe])
URI.encode(str[, unsafe])
URI 文字列をエンコードした文字列を返します。unsafe には、URI として指定できない文字を正規表現か文字列で指定します(デフォルトは、定数 URI::UNSAFE
/[^-_.!~*'()a-zA-Z\d;\/?:@&=+$,\[\]]/n
です)。

どうやら、デフォルトではURIとして使ってはいけない文字をエスケープしてくれるようだ。
しかし、"?"や"&"などWebサービスにとって意味のある文字はスルーされる。
続いて、CGI.escape

CGI.escape(string)
string を URL エンコードした文字列を新しく作成し返します。

具体的に何をエスケープしてくれるのか書いてないので、ソースを見てみる。

# cgi.rb - cgi support library
# 
# Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
# 
# Copyright (C) 2000  Information-technology Promotion Agency, Japan
#
# Author: Wakou Aoyama <wakou@ruby-lang.org>
中略
  # URL-encode a string.
  #   url_encoded_string = CGI::escape("'Stop!' said Fred")
  #      # => "%27Stop%21%27+said+Fred"
  def CGI::escape(string)
    string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
      '%' + $1.unpack('H2' * $1.size).join('%').upcase
    end.tr(' ', '+')
  end

こちらは"?"や"&"もエスケープしてくれる模様だ。

結論

各種Webサービスを使うときに、クエリーとなる文字列をエスケープする場合はCGI.escapeを使うべし。