diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-01-25 21:54:22 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-01-25 21:54:22 +0000 |
commit | af92e385667da3fc91ac7f9f0867a56c111110b8 (patch) | |
tree | c8e8990a2197e33f6fe50a28a16714aafe982102 /libgo/go/net/http | |
parent | df1304ee03f41aed179545d1e8b4684cfd22bbdf (diff) | |
download | gcc-af92e385667da3fc91ac7f9f0867a56c111110b8.tar.gz |
libgo: Update to weekly.2012-01-20.
From-SVN: r183540
Diffstat (limited to 'libgo/go/net/http')
-rw-r--r-- | libgo/go/net/http/cgi/host.go | 2 | ||||
-rw-r--r-- | libgo/go/net/http/cgi/host_test.go | 2 | ||||
-rw-r--r-- | libgo/go/net/http/client.go | 19 | ||||
-rw-r--r-- | libgo/go/net/http/client_test.go | 87 | ||||
-rw-r--r-- | libgo/go/net/http/doc.go | 3 | ||||
-rw-r--r-- | libgo/go/net/http/fs_test.go | 12 | ||||
-rw-r--r-- | libgo/go/net/http/httputil/dump.go | 25 | ||||
-rw-r--r-- | libgo/go/net/http/httputil/reverseproxy.go | 5 | ||||
-rw-r--r-- | libgo/go/net/http/readrequest_test.go | 30 | ||||
-rw-r--r-- | libgo/go/net/http/request.go | 22 | ||||
-rw-r--r-- | libgo/go/net/http/requestwrite_test.go | 16 | ||||
-rw-r--r-- | libgo/go/net/http/serve_test.go | 22 | ||||
-rw-r--r-- | libgo/go/net/http/server.go | 15 | ||||
-rw-r--r-- | libgo/go/net/http/transport.go | 7 |
14 files changed, 154 insertions, 113 deletions
diff --git a/libgo/go/net/http/cgi/host.go b/libgo/go/net/http/cgi/host.go index 615d366aedc..73a9b6ea681 100644 --- a/libgo/go/net/http/cgi/host.go +++ b/libgo/go/net/http/cgi/host.go @@ -124,7 +124,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { "GATEWAY_INTERFACE=CGI/1.1", "REQUEST_METHOD=" + req.Method, "QUERY_STRING=" + req.URL.RawQuery, - "REQUEST_URI=" + req.URL.RawPath, + "REQUEST_URI=" + req.URL.RequestURI(), "PATH_INFO=" + pathInfo, "SCRIPT_NAME=" + root, "SCRIPT_FILENAME=" + h.Path, diff --git a/libgo/go/net/http/cgi/host_test.go b/libgo/go/net/http/cgi/host_test.go index 849cb008b76..b8dbdb4edd2 100644 --- a/libgo/go/net/http/cgi/host_test.go +++ b/libgo/go/net/http/cgi/host_test.go @@ -364,7 +364,7 @@ func TestCopyError(t *testing.T) { conn.Close() tries := 0 - for tries < 15 && childRunning() { + for tries < 25 && childRunning() { time.Sleep(50 * time.Millisecond * time.Duration(tries)) tries++ } diff --git a/libgo/go/net/http/client.go b/libgo/go/net/http/client.go index a4f8f19aac8..1d70672695c 100644 --- a/libgo/go/net/http/client.go +++ b/libgo/go/net/http/client.go @@ -24,11 +24,13 @@ import ( // The Client's Transport typically has internal state (cached // TCP connections), so Clients should be reused instead of created as // needed. Clients are safe for concurrent use by multiple goroutines. -// -// Client is not yet very configurable. type Client struct { - Transport RoundTripper // if nil, DefaultTransport is used + // Transport specifies the mechanism by which individual + // HTTP requests are made. + // If nil, DefaultTransport is used. + Transport RoundTripper + // CheckRedirect specifies the policy for handling redirects. // If CheckRedirect is not nil, the client calls it before // following an HTTP redirect. The arguments req and via // are the upcoming request and the requests made already, @@ -121,9 +123,8 @@ func send(req *Request, t RoundTripper) (resp *Response, err error) { req.Header = make(Header) } - info := req.URL.RawUserinfo - if len(info) > 0 { - req.Header.Set("Authorization", "Basic "+base64.URLEncoding.EncodeToString([]byte(info))) + if u := req.URL.User; u != nil { + req.Header.Set("Authorization", "Basic "+base64.URLEncoding.EncodeToString([]byte(u.String()))) } return t.RoundTrip(req) } @@ -213,11 +214,11 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err error) { break } } - for _, cookie := range jar.Cookies(req.URL) { - req.AddCookie(cookie) - } } + for _, cookie := range jar.Cookies(req.URL) { + req.AddCookie(cookie) + } urlStr = req.URL.String() if r, err = send(req, c.Transport); err != nil { break diff --git a/libgo/go/net/http/client_test.go b/libgo/go/net/http/client_test.go index 57a9dd9574d..c74611011a8 100644 --- a/libgo/go/net/http/client_test.go +++ b/libgo/go/net/http/client_test.go @@ -18,6 +18,7 @@ import ( "net/url" "strconv" "strings" + "sync" "testing" ) @@ -236,6 +237,92 @@ func TestRedirects(t *testing.T) { } } +var expectedCookies = []*Cookie{ + &Cookie{Name: "ChocolateChip", Value: "tasty"}, + &Cookie{Name: "First", Value: "Hit"}, + &Cookie{Name: "Second", Value: "Hit"}, +} + +var echoCookiesRedirectHandler = HandlerFunc(func(w ResponseWriter, r *Request) { + for _, cookie := range r.Cookies() { + SetCookie(w, cookie) + } + if r.URL.Path == "/" { + SetCookie(w, expectedCookies[1]) + Redirect(w, r, "/second", StatusMovedPermanently) + } else { + SetCookie(w, expectedCookies[2]) + w.Write([]byte("hello")) + } +}) + +// Just enough correctness for our redirect tests. Uses the URL.Host as the +// scope of all cookies. +type TestJar struct { + m sync.Mutex + perURL map[string][]*Cookie +} + +func (j *TestJar) SetCookies(u *url.URL, cookies []*Cookie) { + j.m.Lock() + defer j.m.Unlock() + j.perURL[u.Host] = cookies +} + +func (j *TestJar) Cookies(u *url.URL) []*Cookie { + j.m.Lock() + defer j.m.Unlock() + return j.perURL[u.Host] +} + +func TestRedirectCookiesOnRequest(t *testing.T) { + var ts *httptest.Server + ts = httptest.NewServer(echoCookiesRedirectHandler) + defer ts.Close() + c := &Client{} + req, _ := NewRequest("GET", ts.URL, nil) + req.AddCookie(expectedCookies[0]) + // TODO: Uncomment when an implementation of a RFC6265 cookie jar lands. + _ = c + // resp, _ := c.Do(req) + // matchReturnedCookies(t, expectedCookies, resp.Cookies()) + + req, _ = NewRequest("GET", ts.URL, nil) + // resp, _ = c.Do(req) + // matchReturnedCookies(t, expectedCookies[1:], resp.Cookies()) +} + +func TestRedirectCookiesJar(t *testing.T) { + var ts *httptest.Server + ts = httptest.NewServer(echoCookiesRedirectHandler) + defer ts.Close() + c := &Client{} + c.Jar = &TestJar{perURL: make(map[string][]*Cookie)} + u, _ := url.Parse(ts.URL) + c.Jar.SetCookies(u, []*Cookie{expectedCookies[0]}) + resp, _ := c.Get(ts.URL) + matchReturnedCookies(t, expectedCookies, resp.Cookies()) +} + +func matchReturnedCookies(t *testing.T, expected, given []*Cookie) { + t.Logf("Received cookies: %v", given) + if len(given) != len(expected) { + t.Errorf("Expected %d cookies, got %d", len(expected), len(given)) + } + for _, ec := range expected { + foundC := false + for _, c := range given { + if ec.Name == c.Name && ec.Value == c.Value { + foundC = true + break + } + } + if !foundC { + t.Errorf("Missing cookie %v", ec) + } + } +} + func TestStreamingGet(t *testing.T) { say := make(chan string) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { diff --git a/libgo/go/net/http/doc.go b/libgo/go/net/http/doc.go index 2dbcf8dc97c..8962ed31e6a 100644 --- a/libgo/go/net/http/doc.go +++ b/libgo/go/net/http/doc.go @@ -34,7 +34,8 @@ settings, create a Client: resp, err := client.Get("http://example.com") // ... - req := http.NewRequest("GET", "http://example.com", nil) + req, err := http.NewRequest("GET", "http://example.com", nil) + // ... req.Header.Add("If-None-Match", `W/"wyzzy"`) resp, err := client.Do(req) // ... diff --git a/libgo/go/net/http/fs_test.go b/libgo/go/net/http/fs_test.go index 976ee75c7dd..85cad3ec71b 100644 --- a/libgo/go/net/http/fs_test.go +++ b/libgo/go/net/http/fs_test.go @@ -224,16 +224,15 @@ func TestEmptyDirOpenCWD(t *testing.T) { func TestServeFileContentType(t *testing.T) { const ctype = "icecream/chocolate" - override := false ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { - if override { + if r.FormValue("override") == "1" { w.Header().Set("Content-Type", ctype) } ServeFile(w, r, "testdata/file") })) defer ts.Close() - get := func(want string) { - resp, err := Get(ts.URL) + get := func(override, want string) { + resp, err := Get(ts.URL + "?override=" + override) if err != nil { t.Fatal(err) } @@ -241,9 +240,8 @@ func TestServeFileContentType(t *testing.T) { t.Errorf("Content-Type mismatch: got %q, want %q", h, want) } } - get("text/plain; charset=utf-8") - override = true - get(ctype) + get("0", "text/plain; charset=utf-8") + get("1", ctype) } func TestServeFileMimeType(t *testing.T) { diff --git a/libgo/go/net/http/httputil/dump.go b/libgo/go/net/http/httputil/dump.go index 31696aec86e..b8a98ee4292 100644 --- a/libgo/go/net/http/httputil/dump.go +++ b/libgo/go/net/http/httputil/dump.go @@ -13,6 +13,7 @@ import ( "net" "net/http" "strings" + "time" ) // One of the copies, say from b to r2, could be avoided by using a more @@ -36,12 +37,12 @@ type dumpConn struct { io.Reader } -func (c *dumpConn) Close() error { return nil } -func (c *dumpConn) LocalAddr() net.Addr { return nil } -func (c *dumpConn) RemoteAddr() net.Addr { return nil } -func (c *dumpConn) SetTimeout(nsec int64) error { return nil } -func (c *dumpConn) SetReadTimeout(nsec int64) error { return nil } -func (c *dumpConn) SetWriteTimeout(nsec int64) error { return nil } +func (c *dumpConn) Close() error { return nil } +func (c *dumpConn) LocalAddr() net.Addr { return nil } +func (c *dumpConn) RemoteAddr() net.Addr { return nil } +func (c *dumpConn) SetDeadline(t time.Time) error { return nil } +func (c *dumpConn) SetReadDeadline(t time.Time) error { return nil } +func (c *dumpConn) SetWriteDeadline(t time.Time) error { return nil } // DumpRequestOut is like DumpRequest but includes // headers that the standard http.Transport adds, @@ -124,16 +125,8 @@ func DumpRequest(req *http.Request, body bool) (dump []byte, err error) { var b bytes.Buffer - urlStr := req.URL.Raw - if urlStr == "" { - urlStr = valueOrDefault(req.URL.EncodedPath(), "/") - if req.URL.RawQuery != "" { - urlStr += "?" + req.URL.RawQuery - } - } - - fmt.Fprintf(&b, "%s %s HTTP/%d.%d\r\n", valueOrDefault(req.Method, "GET"), urlStr, - req.ProtoMajor, req.ProtoMinor) + fmt.Fprintf(&b, "%s %s HTTP/%d.%d\r\n", valueOrDefault(req.Method, "GET"), + req.URL.RequestURI(), req.ProtoMajor, req.ProtoMinor) host := req.Host if host == "" && req.URL != nil { diff --git a/libgo/go/net/http/httputil/reverseproxy.go b/libgo/go/net/http/httputil/reverseproxy.go index 1dc83e7d032..1072e2e3426 100644 --- a/libgo/go/net/http/httputil/reverseproxy.go +++ b/libgo/go/net/http/httputil/reverseproxy.go @@ -59,11 +59,6 @@ func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy { req.URL.Scheme = target.Scheme req.URL.Host = target.Host req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path) - if q := req.URL.RawQuery; q != "" { - req.URL.RawPath = req.URL.Path + "?" + q - } else { - req.URL.RawPath = req.URL.Path - } req.URL.RawQuery = target.RawQuery } return &ReverseProxy{Director: director} diff --git a/libgo/go/net/http/readrequest_test.go b/libgo/go/net/http/readrequest_test.go index ad7e3c02b0c..da3e4050fe1 100644 --- a/libgo/go/net/http/readrequest_test.go +++ b/libgo/go/net/http/readrequest_test.go @@ -44,15 +44,9 @@ var reqTests = []reqTest{ &Request{ Method: "GET", URL: &url.URL{ - Raw: "http://www.techcrunch.com/", - Scheme: "http", - RawPath: "/", - RawAuthority: "www.techcrunch.com", - RawUserinfo: "", - Host: "www.techcrunch.com", - Path: "/", - RawQuery: "", - Fragment: "", + Scheme: "http", + Host: "www.techcrunch.com", + Path: "/", }, Proto: "HTTP/1.1", ProtoMajor: 1, @@ -86,9 +80,7 @@ var reqTests = []reqTest{ &Request{ Method: "GET", URL: &url.URL{ - Raw: "/", - Path: "/", - RawPath: "/", + Path: "/", }, Proto: "HTTP/1.1", ProtoMajor: 1, @@ -113,15 +105,7 @@ var reqTests = []reqTest{ &Request{ Method: "GET", URL: &url.URL{ - Raw: "//user@host/is/actually/a/path/", - Scheme: "", - RawPath: "//user@host/is/actually/a/path/", - RawAuthority: "", - RawUserinfo: "", - Host: "", - Path: "//user@host/is/actually/a/path/", - RawQuery: "", - Fragment: "", + Path: "//user@host/is/actually/a/path/", }, Proto: "HTTP/1.1", ProtoMajor: 1, @@ -170,9 +154,7 @@ var reqTests = []reqTest{ &Request{ Method: "POST", URL: &url.URL{ - Raw: "/", - Path: "/", - RawPath: "/", + Path: "/", }, TransferEncoding: []string{"chunked"}, Proto: "HTTP/1.1", diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go index 260301005eb..5a4e739073a 100644 --- a/libgo/go/net/http/request.go +++ b/libgo/go/net/http/request.go @@ -302,26 +302,14 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err host = req.URL.Host } - urlStr := req.URL.RawPath - if strings.HasPrefix(urlStr, "?") { - urlStr = "/" + urlStr // Issue 2344 - } - if urlStr == "" { - urlStr = valueOrDefault(req.URL.RawPath, valueOrDefault(req.URL.EncodedPath(), "/")) - if req.URL.RawQuery != "" { - urlStr += "?" + req.URL.RawQuery - } - if usingProxy { - if urlStr == "" || urlStr[0] != '/' { - urlStr = "/" + urlStr - } - urlStr = req.URL.Scheme + "://" + host + urlStr - } + ruri := req.URL.RequestURI() + if usingProxy && req.URL.Scheme != "" && req.URL.Opaque == "" { + ruri = req.URL.Scheme + "://" + host + ruri } - // TODO(bradfitz): escape at least newlines in urlStr? + // TODO(bradfitz): escape at least newlines in ruri? bw := bufio.NewWriter(w) - fmt.Fprintf(bw, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), urlStr) + fmt.Fprintf(bw, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri) // Header lines fmt.Fprintf(bw, "Host: %s\r\n", host) diff --git a/libgo/go/net/http/requestwrite_test.go b/libgo/go/net/http/requestwrite_test.go index 8081589f5f2..fc3186f0c0c 100644 --- a/libgo/go/net/http/requestwrite_test.go +++ b/libgo/go/net/http/requestwrite_test.go @@ -32,15 +32,9 @@ var reqWriteTests = []reqWriteTest{ Req: Request{ Method: "GET", URL: &url.URL{ - Raw: "http://www.techcrunch.com/", - Scheme: "http", - RawPath: "http://www.techcrunch.com/", - RawAuthority: "www.techcrunch.com", - RawUserinfo: "", - Host: "www.techcrunch.com", - Path: "/", - RawQuery: "", - Fragment: "", + Scheme: "http", + Host: "www.techcrunch.com", + Path: "/", }, Proto: "HTTP/1.1", ProtoMajor: 1, @@ -60,7 +54,7 @@ var reqWriteTests = []reqWriteTest{ Form: map[string][]string{}, }, - WantWrite: "GET http://www.techcrunch.com/ HTTP/1.1\r\n" + + WantWrite: "GET / HTTP/1.1\r\n" + "Host: www.techcrunch.com\r\n" + "User-Agent: Fake\r\n" + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" + @@ -198,7 +192,7 @@ var reqWriteTests = []reqWriteTest{ "\r\n" + "abcdef", - WantProxy: "POST / HTTP/1.1\r\n" + + WantProxy: "POST http://example.com/ HTTP/1.1\r\n" + "Host: example.com\r\n" + "User-Agent: Go http package\r\n" + "Content-Length: 6\r\n" + diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go index 24e6b50dab8..147c216ec78 100644 --- a/libgo/go/net/http/serve_test.go +++ b/libgo/go/net/http/serve_test.go @@ -84,15 +84,15 @@ func (c *testConn) RemoteAddr() net.Addr { return dummyAddr("remote-addr") } -func (c *testConn) SetTimeout(nsec int64) error { +func (c *testConn) SetDeadline(t time.Time) error { return nil } -func (c *testConn) SetReadTimeout(nsec int64) error { +func (c *testConn) SetReadDeadline(t time.Time) error { return nil } -func (c *testConn) SetWriteTimeout(nsec int64) error { +func (c *testConn) SetWriteDeadline(t time.Time) error { return nil } @@ -642,7 +642,7 @@ func TestServerExpect(t *testing.T) { // Note using r.FormValue("readbody") because for POST // requests that would read from r.Body, which we only // conditionally want to do. - if strings.Contains(r.URL.RawPath, "readbody=true") { + if strings.Contains(r.URL.RawQuery, "readbody=true") { ioutil.ReadAll(r.Body) w.Write([]byte("Hi")) } else { @@ -904,17 +904,13 @@ func testHandlerPanic(t *testing.T, withHijack bool) { panic("intentional death for testing") })) defer ts.Close() - _, err := Get(ts.URL) - if err == nil { - t.Logf("expected an error") - } // Do a blocking read on the log output pipe so its logging // doesn't bleed into the next test. But wait only 5 seconds // for it. - done := make(chan bool) + done := make(chan bool, 1) go func() { - buf := make([]byte, 1024) + buf := make([]byte, 4<<10) _, err := pr.Read(buf) pr.Close() if err != nil { @@ -922,6 +918,12 @@ func testHandlerPanic(t *testing.T, withHijack bool) { } done <- true }() + + _, err := Get(ts.URL) + if err == nil { + t.Logf("expected an error") + } + select { case <-done: return diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go index fa9009517db..bad3bcb2896 100644 --- a/libgo/go/net/http/server.go +++ b/libgo/go/net/http/server.go @@ -569,14 +569,15 @@ func (c *conn) serve() { if err == nil { return } - if c.rwc != nil { // may be nil if connection hijacked - c.rwc.Close() - } var buf bytes.Buffer fmt.Fprintf(&buf, "http: panic serving %v: %v\n", c.remoteAddr, err) buf.Write(debug.Stack()) log.Print(buf.String()) + + if c.rwc != nil { // may be nil if connection hijacked + c.rwc.Close() + } }() if tlsConn, ok := c.rwc.(*tls.Conn); ok { @@ -954,8 +955,8 @@ func Serve(l net.Listener, handler Handler) error { type Server struct { Addr string // TCP address to listen on, ":http" if empty Handler Handler // handler to invoke, http.DefaultServeMux if nil - ReadTimeout time.Duration // the net.Conn.SetReadTimeout value for new connections - WriteTimeout time.Duration // the net.Conn.SetWriteTimeout value for new connections + ReadTimeout time.Duration // maximum duration before timing out read of the request + WriteTimeout time.Duration // maximum duration before timing out write of the response MaxHeaderBytes int // maximum size of request headers, DefaultMaxHeaderBytes if 0 } @@ -989,10 +990,10 @@ func (srv *Server) Serve(l net.Listener) error { return e } if srv.ReadTimeout != 0 { - rw.SetReadTimeout(srv.ReadTimeout.Nanoseconds()) + rw.SetReadDeadline(time.Now().Add(srv.ReadTimeout)) } if srv.WriteTimeout != 0 { - rw.SetWriteTimeout(srv.WriteTimeout.Nanoseconds()) + rw.SetWriteDeadline(time.Now().Add(srv.WriteTimeout)) } c, err := srv.newConn(rw) if err != nil { diff --git a/libgo/go/net/http/transport.go b/libgo/go/net/http/transport.go index 33ad32861b5..1b9ad1b85c5 100644 --- a/libgo/go/net/http/transport.go +++ b/libgo/go/net/http/transport.go @@ -229,9 +229,8 @@ func (cm *connectMethod) proxyAuth() string { if cm.proxyURL == nil { return "" } - proxyInfo := cm.proxyURL.RawUserinfo - if proxyInfo != "" { - return "Basic " + base64.URLEncoding.EncodeToString([]byte(proxyInfo)) + if u := cm.proxyURL.User; u != nil { + return "Basic " + base64.URLEncoding.EncodeToString([]byte(u.String())) } return "" } @@ -332,7 +331,7 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) { case cm.targetScheme == "https": connectReq := &Request{ Method: "CONNECT", - URL: &url.URL{RawPath: cm.targetAddr}, + URL: &url.URL{Opaque: cm.targetAddr}, Host: cm.targetAddr, Header: make(Header), } |