mirror of
https://github.com/golang/go
synced 2024-11-14 07:40:21 -07:00
http: most of a URL shouldn't use URL-escaping
Fixes #502. R=r, hoisie CC=golang-dev https://golang.org/cl/181179
This commit is contained in:
parent
448aa49cfe
commit
fe56e2cc35
@ -134,7 +134,7 @@ const defaultUserAgent = "Go http package"
|
|||||||
//
|
//
|
||||||
// If Body is present, "Transfer-Encoding: chunked" is forced as a header.
|
// If Body is present, "Transfer-Encoding: chunked" is forced as a header.
|
||||||
func (req *Request) Write(w io.Writer) os.Error {
|
func (req *Request) Write(w io.Writer) os.Error {
|
||||||
uri := URLEscape(req.URL.Path)
|
uri := urlEscape(req.URL.Path, false)
|
||||||
if req.URL.RawQuery != "" {
|
if req.URL.RawQuery != "" {
|
||||||
uri += "?" + req.URL.RawQuery
|
uri += "?" + req.URL.RawQuery
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,13 @@ func CanonicalPath(path string) string {
|
|||||||
// converting %AB into the byte 0xAB and '+' into ' ' (space).
|
// converting %AB into the byte 0xAB and '+' into ' ' (space).
|
||||||
// It returns an error if any % is not followed
|
// It returns an error if any % is not followed
|
||||||
// by two hexadecimal digits.
|
// by two hexadecimal digits.
|
||||||
func URLUnescape(s string) (string, os.Error) {
|
func URLUnescape(s string) (string, os.Error) { return urlUnescape(s, true) }
|
||||||
|
|
||||||
|
// urlUnescape is like URLUnescape but can be told not to
|
||||||
|
// convert + into space. URLUnescape implements what is
|
||||||
|
// called "URL encoding" but that only applies to query strings.
|
||||||
|
// Elsewhere in the URL, + does not mean space.
|
||||||
|
func urlUnescape(s string, doPlus bool) (string, os.Error) {
|
||||||
// Count %, check that they're well-formed.
|
// Count %, check that they're well-formed.
|
||||||
n := 0
|
n := 0
|
||||||
hasPlus := false
|
hasPlus := false
|
||||||
@ -145,7 +151,7 @@ func URLUnescape(s string) (string, os.Error) {
|
|||||||
}
|
}
|
||||||
i += 3
|
i += 3
|
||||||
case '+':
|
case '+':
|
||||||
hasPlus = true
|
hasPlus = doPlus
|
||||||
i++
|
i++
|
||||||
default:
|
default:
|
||||||
i++
|
i++
|
||||||
@ -165,7 +171,11 @@ func URLUnescape(s string) (string, os.Error) {
|
|||||||
j++
|
j++
|
||||||
i += 3
|
i += 3
|
||||||
case '+':
|
case '+':
|
||||||
|
if doPlus {
|
||||||
t[j] = ' '
|
t[j] = ' '
|
||||||
|
} else {
|
||||||
|
t[j] = '+'
|
||||||
|
}
|
||||||
j++
|
j++
|
||||||
i++
|
i++
|
||||||
default:
|
default:
|
||||||
@ -178,12 +188,14 @@ func URLUnescape(s string) (string, os.Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// URLEscape converts a string into URL-encoded form.
|
// URLEscape converts a string into URL-encoded form.
|
||||||
func URLEscape(s string) string {
|
func URLEscape(s string) string { return urlEscape(s, true) }
|
||||||
|
|
||||||
|
func urlEscape(s string, doPlus bool) string {
|
||||||
spaceCount, hexCount := 0, 0
|
spaceCount, hexCount := 0, 0
|
||||||
for i := 0; i < len(s); i++ {
|
for i := 0; i < len(s); i++ {
|
||||||
c := s[i]
|
c := s[i]
|
||||||
if shouldEscape(c) {
|
if shouldEscape(c) {
|
||||||
if c == ' ' {
|
if c == ' ' && doPlus {
|
||||||
spaceCount++
|
spaceCount++
|
||||||
} else {
|
} else {
|
||||||
hexCount++
|
hexCount++
|
||||||
@ -199,7 +211,7 @@ func URLEscape(s string) string {
|
|||||||
j := 0
|
j := 0
|
||||||
for i := 0; i < len(s); i++ {
|
for i := 0; i < len(s); i++ {
|
||||||
switch c := s[i]; {
|
switch c := s[i]; {
|
||||||
case c == ' ':
|
case c == ' ' && doPlus:
|
||||||
t[j] = '+'
|
t[j] = '+'
|
||||||
j++
|
j++
|
||||||
case shouldEscape(c):
|
case shouldEscape(c):
|
||||||
@ -314,16 +326,16 @@ func ParseURL(rawurl string) (url *URL, err os.Error) {
|
|||||||
url.Userinfo, url.Host = split(url.Authority, '@', true)
|
url.Userinfo, url.Host = split(url.Authority, '@', true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if url.Path, err = URLUnescape(path); err != nil {
|
if url.Path, err = urlUnescape(path, false); err != nil {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove escapes from the Authority and Userinfo fields, and verify
|
// Remove escapes from the Authority and Userinfo fields, and verify
|
||||||
// that Scheme and Host contain no escapes (that would be illegal).
|
// that Scheme and Host contain no escapes (that would be illegal).
|
||||||
if url.Authority, err = URLUnescape(url.Authority); err != nil {
|
if url.Authority, err = urlUnescape(url.Authority, false); err != nil {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
if url.Userinfo, err = URLUnescape(url.Userinfo); err != nil {
|
if url.Userinfo, err = urlUnescape(url.Userinfo, false); err != nil {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
if strings.Index(url.Scheme, "%") >= 0 {
|
if strings.Index(url.Scheme, "%") >= 0 {
|
||||||
@ -349,7 +361,7 @@ func ParseURLReference(rawurlref string) (url *URL, err os.Error) {
|
|||||||
if url, err = ParseURL(rawurl); err != nil {
|
if url, err = ParseURL(rawurl); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if url.Fragment, err = URLUnescape(frag); err != nil {
|
if url.Fragment, err = urlUnescape(frag, false); err != nil {
|
||||||
return nil, &URLError{"parse", rawurl, err}
|
return nil, &URLError{"parse", rawurl, err}
|
||||||
}
|
}
|
||||||
return url, nil
|
return url, nil
|
||||||
@ -368,16 +380,16 @@ func (url *URL) String() string {
|
|||||||
if url.Host != "" || url.Userinfo != "" {
|
if url.Host != "" || url.Userinfo != "" {
|
||||||
result += "//"
|
result += "//"
|
||||||
if url.Userinfo != "" {
|
if url.Userinfo != "" {
|
||||||
result += URLEscape(url.Userinfo) + "@"
|
result += urlEscape(url.Userinfo, false) + "@"
|
||||||
}
|
}
|
||||||
result += url.Host
|
result += url.Host
|
||||||
}
|
}
|
||||||
result += URLEscape(url.Path)
|
result += urlEscape(url.Path, false)
|
||||||
if url.RawQuery != "" {
|
if url.RawQuery != "" {
|
||||||
result += "?" + url.RawQuery
|
result += "?" + url.RawQuery
|
||||||
}
|
}
|
||||||
if url.Fragment != "" {
|
if url.Fragment != "" {
|
||||||
result += "#" + URLEscape(url.Fragment)
|
result += "#" + urlEscape(url.Fragment, false)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ var urltests = []URLTest{
|
|||||||
"www.google.com", "", "www.google.com",
|
"www.google.com", "", "www.google.com",
|
||||||
"/file one&two", "", "",
|
"/file one&two", "", "",
|
||||||
},
|
},
|
||||||
"http://www.google.com/file+one%26two",
|
"http://www.google.com/file%20one%26two",
|
||||||
},
|
},
|
||||||
// user
|
// user
|
||||||
URLTest{
|
URLTest{
|
||||||
@ -76,7 +76,7 @@ var urltests = []URLTest{
|
|||||||
"john doe@www.google.com", "john doe", "www.google.com",
|
"john doe@www.google.com", "john doe", "www.google.com",
|
||||||
"/", "", "",
|
"/", "", "",
|
||||||
},
|
},
|
||||||
"ftp://john+doe@www.google.com/",
|
"ftp://john%20doe@www.google.com/",
|
||||||
},
|
},
|
||||||
// query
|
// query
|
||||||
URLTest{
|
URLTest{
|
||||||
@ -100,6 +100,17 @@ var urltests = []URLTest{
|
|||||||
},
|
},
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
|
// %20 outside query
|
||||||
|
URLTest{
|
||||||
|
"http://www.google.com/a%20b?q=c+d",
|
||||||
|
&URL{
|
||||||
|
"http://www.google.com/a%20b?q=c+d",
|
||||||
|
"http", "//www.google.com/a%20b?q=c+d",
|
||||||
|
"www.google.com", "", "www.google.com",
|
||||||
|
"/a b", "q=c+d", "",
|
||||||
|
},
|
||||||
|
"",
|
||||||
|
},
|
||||||
// path without /, so no query parsing
|
// path without /, so no query parsing
|
||||||
URLTest{
|
URLTest{
|
||||||
"http:www.google.com/?q=go+language",
|
"http:www.google.com/?q=go+language",
|
||||||
@ -107,9 +118,9 @@ var urltests = []URLTest{
|
|||||||
"http:www.google.com/?q=go+language",
|
"http:www.google.com/?q=go+language",
|
||||||
"http", "www.google.com/?q=go+language",
|
"http", "www.google.com/?q=go+language",
|
||||||
"", "", "",
|
"", "", "",
|
||||||
"www.google.com/?q=go language", "", "",
|
"www.google.com/?q=go+language", "", "",
|
||||||
},
|
},
|
||||||
"http:www.google.com/%3fq%3dgo+language",
|
"http:www.google.com/%3fq%3dgo%2blanguage",
|
||||||
},
|
},
|
||||||
// non-authority
|
// non-authority
|
||||||
URLTest{
|
URLTest{
|
||||||
|
Loading…
Reference in New Issue
Block a user