diff options
Diffstat (limited to 'src/pkg/http/serve_test.go')
| -rw-r--r-- | src/pkg/http/serve_test.go | 147 | 
1 files changed, 94 insertions, 53 deletions
| diff --git a/src/pkg/http/serve_test.go b/src/pkg/http/serve_test.go index c3c7b8d33..120a02605 100644 --- a/src/pkg/http/serve_test.go +++ b/src/pkg/http/serve_test.go @@ -252,7 +252,7 @@ func TestServerTimeouts(t *testing.T) {  	// Hit the HTTP server successfully.  	tr := &Transport{DisableKeepAlives: true} // they interfere with this test  	c := &Client{Transport: tr} -	r, _, err := c.Get(url) +	r, err := c.Get(url)  	if err != nil {  		t.Fatalf("http Get #1: %v", err)  	} @@ -282,7 +282,7 @@ func TestServerTimeouts(t *testing.T) {  	// Hit the HTTP server successfully again, verifying that the  	// previous slow connection didn't run our handler.  (that we  	// get "req=2", not "req=3") -	r, _, err = Get(url) +	r, err = Get(url)  	if err != nil {  		t.Fatalf("http Get #2: %v", err)  	} @@ -323,7 +323,7 @@ func TestIdentityResponse(t *testing.T) {  	// responses.  	for _, te := range []string{"", "identity"} {  		url := ts.URL + "/?te=" + te -		res, _, err := Get(url) +		res, err := Get(url)  		if err != nil {  			t.Fatalf("error with Get of %s: %v", url, err)  		} @@ -342,7 +342,7 @@ func TestIdentityResponse(t *testing.T) {  	// Verify that ErrContentLength is returned  	url := ts.URL + "/?overwrite=1" -	_, _, err := Get(url) +	_, err := Get(url)  	if err != nil {  		t.Fatalf("error with Get of %s: %v", url, err)  	} @@ -389,7 +389,7 @@ func TestServeHTTP10Close(t *testing.T) {  	}  	r := bufio.NewReader(conn) -	_, err = ReadResponse(r, "GET") +	_, err = ReadResponse(r, &Request{Method: "GET"})  	if err != nil {  		t.Fatal("ReadResponse error:", err)  	} @@ -417,7 +417,7 @@ func TestSetsRemoteAddr(t *testing.T) {  	}))  	defer ts.Close() -	res, _, err := Get(ts.URL) +	res, err := Get(ts.URL)  	if err != nil {  		t.Fatalf("Get error: %v", err)  	} @@ -438,7 +438,7 @@ func TestChunkedResponseHeaders(t *testing.T) {  	}))  	defer ts.Close() -	res, _, err := Get(ts.URL) +	res, err := Get(ts.URL)  	if err != nil {  		t.Fatalf("Get error: %v", err)  	} @@ -465,7 +465,7 @@ func Test304Responses(t *testing.T) {  		}  	}))  	defer ts.Close() -	res, _, err := Get(ts.URL) +	res, err := Get(ts.URL)  	if err != nil {  		t.Error(err)  	} @@ -516,7 +516,7 @@ func TestTLSServer(t *testing.T) {  	if !strings.HasPrefix(ts.URL, "https://") {  		t.Fatalf("expected test TLS server to start with https://, got %q", ts.URL)  	} -	res, _, err := Get(ts.URL) +	res, err := Get(ts.URL)  	if err != nil {  		t.Error(err)  	} @@ -551,7 +551,7 @@ var serverExpectTests = []serverExpectTest{  	{100, "", true, "200 OK"},  	// 100-continue but requesting client to deny us, -	// so it never eads the body. +	// so it never reads the body.  	{100, "100-continue", false, "401 Unauthorized"},  	// Likewise without 100-continue:  	{100, "", false, "401 Unauthorized"}, @@ -618,49 +618,29 @@ func TestServerExpect(t *testing.T) {  }  func TestServerConsumesRequestBody(t *testing.T) { -	log := make(chan string, 100) - -	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { -		log <- "got_request" -		w.WriteHeader(StatusOK) -		log <- "wrote_header" -	})) -	defer ts.Close() - -	conn, err := net.Dial("tcp", ts.Listener.Addr().String()) -	if err != nil { -		t.Fatalf("Dial: %v", err) -	} -	defer conn.Close() - -	bufr := bufio.NewReader(conn) -	gotres := make(chan bool) -	go func() { -		line, err := bufr.ReadString('\n') -		if err != nil { -			t.Fatal(err) +	conn := new(testConn) +	body := strings.Repeat("x", 1<<20) +	conn.readBuf.Write([]byte(fmt.Sprintf( +		"POST / HTTP/1.1\r\n"+ +			"Host: test\r\n"+ +			"Content-Length: %d\r\n"+ +			"\r\n", len(body)))) +	conn.readBuf.Write([]byte(body)) + +	done := make(chan bool) + +	ls := &oneConnListener{conn} +	go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) { +		if conn.readBuf.Len() < len(body)/2 { +			t.Errorf("on request, read buffer length is %d; expected about 1MB", conn.readBuf.Len())  		} -		log <- line -		gotres <- true -	}() - -	size := 1 << 20 -	log <- "writing_request" -	fmt.Fprintf(conn, "POST / HTTP/1.0\r\nContent-Length: %d\r\n\r\n", size) -	time.Sleep(25e6) // give server chance to misbehave & speak out of turn -	log <- "slept_after_req_headers" -	conn.Write([]byte(strings.Repeat("a", size))) - -	<-gotres -	expected := []string{ -		"writing_request", "got_request", -		"slept_after_req_headers", "wrote_header", -		"HTTP/1.0 200 OK\r\n"} -	for step, e := range expected { -		if g := <-log; e != g { -			t.Errorf("on step %d expected %q, got %q", step, e, g) +		rw.WriteHeader(200) +		if g, e := conn.readBuf.Len(), 0; g != e { +			t.Errorf("after WriteHeader, read buffer length is %d; want %d", g, e)  		} -	} +		done <- true +	})) +	<-done  }  func TestTimeoutHandler(t *testing.T) { @@ -677,7 +657,7 @@ func TestTimeoutHandler(t *testing.T) {  	// Succeed without timing out:  	sendHi <- true -	res, _, err := Get(ts.URL) +	res, err := Get(ts.URL)  	if err != nil {  		t.Error(err)  	} @@ -694,7 +674,7 @@ func TestTimeoutHandler(t *testing.T) {  	// Times out:  	timeout <- 1 -	res, _, err = Get(ts.URL) +	res, err = Get(ts.URL)  	if err != nil {  		t.Error(err)  	} @@ -713,3 +693,64 @@ func TestTimeoutHandler(t *testing.T) {  		t.Errorf("expected Write error of %v; got %v", e, g)  	}  } + +// Verifies we don't path.Clean() on the wrong parts in redirects. +func TestRedirectMunging(t *testing.T) { +	req, _ := NewRequest("GET", "http://example.com/", nil) + +	resp := httptest.NewRecorder() +	Redirect(resp, req, "/foo?next=http://bar.com/", 302) +	if g, e := resp.Header().Get("Location"), "/foo?next=http://bar.com/"; g != e { +		t.Errorf("Location header was %q; want %q", g, e) +	} + +	resp = httptest.NewRecorder() +	Redirect(resp, req, "http://localhost:8080/_ah/login?continue=http://localhost:8080/", 302) +	if g, e := resp.Header().Get("Location"), "http://localhost:8080/_ah/login?continue=http://localhost:8080/"; g != e { +		t.Errorf("Location header was %q; want %q", g, e) +	} +} + +// TestZeroLengthPostAndResponse exercises an optimization done by the Transport: +// when there is no body (either because the method doesn't permit a body, or an +// explicit Content-Length of zero is present), then the transport can re-use the +// connection immediately. But when it re-uses the connection, it typically closes +// the previous request's body, which is not optimal for zero-lengthed bodies, +// as the client would then see http.ErrBodyReadAfterClose and not 0, os.EOF. +func TestZeroLengthPostAndResponse(t *testing.T) { +	ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) { +		all, err := ioutil.ReadAll(r.Body) +		if err != nil { +			t.Fatalf("handler ReadAll: %v", err) +		} +		if len(all) != 0 { +			t.Errorf("handler got %d bytes; expected 0", len(all)) +		} +		rw.Header().Set("Content-Length", "0") +	})) +	defer ts.Close() + +	req, err := NewRequest("POST", ts.URL, strings.NewReader("")) +	if err != nil { +		t.Fatal(err) +	} +	req.ContentLength = 0 + +	var resp [5]*Response +	for i := range resp { +		resp[i], err = DefaultClient.Do(req) +		if err != nil { +			t.Fatalf("client post #%d: %v", i, err) +		} +	} + +	for i := range resp { +		all, err := ioutil.ReadAll(resp[i].Body) +		if err != nil { +			t.Fatalf("req #%d: client ReadAll: %v", i, err) +		} +		if len(all) != 0 { +			t.Errorf("req #%d: client got %d bytes; expected 0", i, len(all)) +		} +	} +} | 
