summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/pkg/http/request.go2
-rw-r--r--src/pkg/http/url.go38
-rw-r--r--src/pkg/http/url_test.go19
3 files changed, 41 insertions, 18 deletions
diff --git a/src/pkg/http/request.go b/src/pkg/http/request.go
index 10dc08c2b..884fe48fa 100644
--- a/src/pkg/http/request.go
+++ b/src/pkg/http/request.go
@@ -134,7 +134,7 @@ const defaultUserAgent = "Go http package"
//
// If Body is present, "Transfer-Encoding: chunked" is forced as a header.
func (req *Request) Write(w io.Writer) os.Error {
- uri := URLEscape(req.URL.Path)
+ uri := urlEscape(req.URL.Path, false)
if req.URL.RawQuery != "" {
uri += "?" + req.URL.RawQuery
}
diff --git a/src/pkg/http/url.go b/src/pkg/http/url.go
index f879f8d8f..40ea86549 100644
--- a/src/pkg/http/url.go
+++ b/src/pkg/http/url.go
@@ -128,7 +128,13 @@ func CanonicalPath(path string) string {
// converting %AB into the byte 0xAB and '+' into ' ' (space).
// It returns an error if any % is not followed
// 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.
n := 0
hasPlus := false
@@ -145,7 +151,7 @@ func URLUnescape(s string) (string, os.Error) {
}
i += 3
case '+':
- hasPlus = true
+ hasPlus = doPlus
i++
default:
i++
@@ -165,7 +171,11 @@ func URLUnescape(s string) (string, os.Error) {
j++
i += 3
case '+':
- t[j] = ' '
+ if doPlus {
+ t[j] = ' '
+ } else {
+ t[j] = '+'
+ }
j++
i++
default:
@@ -178,12 +188,14 @@ func URLUnescape(s string) (string, os.Error) {
}
// 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
for i := 0; i < len(s); i++ {
c := s[i]
if shouldEscape(c) {
- if c == ' ' {
+ if c == ' ' && doPlus {
spaceCount++
} else {
hexCount++
@@ -199,7 +211,7 @@ func URLEscape(s string) string {
j := 0
for i := 0; i < len(s); i++ {
switch c := s[i]; {
- case c == ' ':
+ case c == ' ' && doPlus:
t[j] = '+'
j++
case shouldEscape(c):
@@ -314,16 +326,16 @@ func ParseURL(rawurl string) (url *URL, err os.Error) {
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
}
// Remove escapes from the Authority and Userinfo fields, and verify
// 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
}
- if url.Userinfo, err = URLUnescape(url.Userinfo); err != nil {
+ if url.Userinfo, err = urlUnescape(url.Userinfo, false); err != nil {
goto Error
}
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 {
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 url, nil
@@ -368,16 +380,16 @@ func (url *URL) String() string {
if url.Host != "" || url.Userinfo != "" {
result += "//"
if url.Userinfo != "" {
- result += URLEscape(url.Userinfo) + "@"
+ result += urlEscape(url.Userinfo, false) + "@"
}
result += url.Host
}
- result += URLEscape(url.Path)
+ result += urlEscape(url.Path, false)
if url.RawQuery != "" {
result += "?" + url.RawQuery
}
if url.Fragment != "" {
- result += "#" + URLEscape(url.Fragment)
+ result += "#" + urlEscape(url.Fragment, false)
}
return result
}
diff --git a/src/pkg/http/url_test.go b/src/pkg/http/url_test.go
index 542ad0a38..a16bbbddf 100644
--- a/src/pkg/http/url_test.go
+++ b/src/pkg/http/url_test.go
@@ -54,7 +54,7 @@ var urltests = []URLTest{
"www.google.com", "", "www.google.com",
"/file one&two", "", "",
},
- "http://www.google.com/file+one%26two",
+ "http://www.google.com/file%20one%26two",
},
// user
URLTest{
@@ -76,7 +76,7 @@ var urltests = []URLTest{
"john doe@www.google.com", "john doe", "www.google.com",
"/", "", "",
},
- "ftp://john+doe@www.google.com/",
+ "ftp://john%20doe@www.google.com/",
},
// query
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
URLTest{
"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",
"", "", "",
- "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
URLTest{