proxy認証する場合にhttp_proxy変数に
$ export http_proxy=http://user:pass@host:port
とやるのだが、userやpassに':'や'@'を入れたい場合はどうするのかなと思ってちょっと調べてみた。ユーザ名には使わないだろうけどパスワードだとありうるので。
おそらく、アプリケーション依存だと思うのだけども、GNU WgetとcURLの場合はパーセントエンコードをすれば良いようである。
Wgetの方はsrc/url.cのparse_credentials関数で、urlからuserとpasswdを抽出する時にunescapeしている。
static bool parse_credentials (const char *beg, const char *end, char **user, char **passwd) { char *colon; const char *userend; if (beg == end) return false; /* empty user name */ colon = memchr (beg, ':', end - beg); if (colon == beg) return false; /* again empty user name */ if (colon) { *passwd = strdupdelim (colon + 1, end); userend = colon; url_unescape (*passwd); } else { *passwd = NULL; userend = end; } *user = strdupdelim (beg, userend); url_unescape (*user); return true; }
cURLの方はlib/url.cでproxyのURLをparseするparse_proxy関数の中でunescapeを行っている
static CURLcode parse_proxy(struct SessionHandle *data, struct connectdata *conn, char *proxy) { ... if(1 <= sscanf(proxyptr, "%" MAX_CURL_USER_LENGTH_TXT"[^:@]:" "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", proxyuser, proxypasswd)) { CURLcode res = CURLE_OK; /* found user and password, rip them out. note that we are unescaping them, as there is otherwise no way to have a username or password with reserved characters like ':' in them. */ Curl_safefree(conn->proxyuser); conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); if(!conn->proxyuser) res = CURLE_OUT_OF_MEMORY; else { Curl_safefree(conn->proxypasswd); conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); if(!conn->proxypasswd) res = CURLE_OUT_OF_MEMORY; } ... }
仕様としてはURIのRFCとしてRFC 3986があるのだけども、特にどうするとは明記していないように思える。URIにユーザ情報を入れることができるとは書いてあるが、
3.2. Authority Many URI schemes include a hierarchical element for a naming authority so that governance of the name space defined by the remainder of the URI is delegated to that authority (which may, in turn, delegate it further). The generic syntax provides a common means for distinguishing an authority based on a registered name or server address, along with optional port and user information. ... authority = [ userinfo "@" ] host [ ":" port ]
パスワードをそのまま入れることに関してはセキュリティの面からdeprecatedになっている。ただ、proxy認証をするときの設定に利用することを意識しているのか不明であるし、パーセントエンコードの文字列(pct-encoded)をuserinfoの部分に書くのは認められているので、上記のような実装が妥当なのだろう。
3.2.1. User Information The userinfo subcomponent may consist of a user name and, optionally, scheme-specific information about how to gain authorization to access the resource. The user information, if present, is followed by a commercial at-sign ("@") that delimits it from the host. userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) Use of the format "user:password" in the userinfo field is deprecated. Applications should not render as clear text any data after the first colon (":") character found within a userinfo subcomponent unless the data after the colon is the empty string (indicating no password). Applications may choose to ignore or reject such data when it is received as part of a reference and should reject the storage of such data in unencrypted form. The passing of authentication information in clear text has proven to be a security risk in almost every case where it has been used.