Go1.5.x から URL.RawPath が追加

Goがv1.5(.1?) になりWebサーバーで undecodedなURLのpathを取得する定番の方法が決まったのでメモしておく。

URL.EscapedPath()を使うのが解決策。 また確認した所ではURL.RequestURI()の挙動にも変更が加えられており、これでも解決できる。

背景

少し前はWebサーバーを書く時Undecodedなリクエストパスを取得したくなると少し困っていた。 以下の様にリクエストパスを得るがv1.4.3 以前では後述する問題があった。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
func sampleHandler(w http.ResponseWriter, r * http.Request) {
	fmt.Fprintf(w, "r.RequestURI:%s\n", r.RequestURI)
	fmt.Fprintf(w, "r.URL.RequestURI():%s\n", r.URL.RequestURI())
	// fmt.Fprintf(w, "r.URL.RawPath:%s\n", r.URL.RawPath)
	// fmt.Fprintf(w, "r.URL.EscapedPath():%s\n", r.URL.EscapedPath())
}
func main() {
	http.HandleFunc("/", sampleHandler)
	http.ListenAndServe(":18080", nil)
}

v1.4.3の時の挙動

r.RequestURIはリクエスト内容が直接出力されるが、 absolute-formrequest-targetに使われていると スキーマなどが含まれて扱いにくい。 URL.RequestURI()はGoがエンコードした内容が含まれる。 そのため%24で転送された部分が$として残る事になる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ export GOROOT=${HOME}/go1.4/
$ ~/go1.4/bin/go run ./main.go &
$ telnet localhost 18080
Trying ::1...
Connected to localhost.
Escape character is '^]'.
GET /test_%24host%20$ HTTP/1.1
Host: localhost

HTTP/1.1 200 OK
Date: Thu, 29 Oct 2015 13:46:11 GMT
Content-Length: 66
Content-Type: text/plain; charset=utf-8

r.RequestURI:/test_%24host%20$
r.URL.RequestURI():/test_$host%20$
GET http://localhost/test_%24host%20$ HTTP/1.1
Host: localhost

HTTP/1.1 200 OK
Date: Thu, 29 Oct 2015 13:46:40 GMT
Content-Length: 82
Content-Type: text/plain; charset=utf-8

r.RequestURI:http://localhost/test_%24host%20$
r.URL.RequestURI():/test_$host%20$
^C
Connection closed by foreign host.

v1.5.1の時の挙動

r.RequestURIの挙動は変わらない。変わったのはURL.RequestURI()だ。

URL.RequestURI()はリクエストされたrequest-target が妥当な内容の場合、該当リクエストのパス部分を返す。 これはリクエストから取られGoが再エンコードする訳ではない。 さらにabsolute-formであってもパス部分が取得できる。 ただし、この変更が正しいのかわからない。

困っていた内容を解決する意図のURL.EscapedPath() が追加されていた。 これを使うのが良さそう。

とにかく、これで解決した。やったぜ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ telnet localhost 18080
Trying ::1...
Connected to localhost.
Escape character is '^]'.
GET /test_%24host%20$ HTTP/1.1
Host: localhost

HTTP/1.1 200 OK
Date: Thu, 29 Oct 2015 14:18:40 GMT
Content-Length: 68
Content-Type: text/plain; charset=utf-8

r.RequestURI:/test_%24host%20$
r.URL.RequestURI():/test_%24host%20$
GET http://localhost/test_%24host%20$ HTTP/1.1
Host: localhost

HTTP/1.1 200 OK
Date: Thu, 29 Oct 2015 14:19:03 GMT
Content-Length: 84
Content-Type: text/plain; charset=utf-8

r.RequestURI:http://localhost/test_%24host%20$
r.URL.RequestURI():/test_%24host%20$
^C
Connection closed by foreign host.
comments powered by Disqus