summaryrefslogtreecommitdiff
path: root/src/pkg/net/http
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/net/http')
-rw-r--r--src/pkg/net/http/client_test.go6
-rw-r--r--src/pkg/net/http/request.go6
-rw-r--r--src/pkg/net/http/request_test.go19
-rw-r--r--src/pkg/net/http/server.go2
-rw-r--r--src/pkg/net/http/transport.go2
-rw-r--r--src/pkg/net/http/transport_test.go26
-rw-r--r--src/pkg/net/http/triv.go53
7 files changed, 76 insertions, 38 deletions
diff --git a/src/pkg/net/http/client_test.go b/src/pkg/net/http/client_test.go
index aa0bf4be6..e00b62e59 100644
--- a/src/pkg/net/http/client_test.go
+++ b/src/pkg/net/http/client_test.go
@@ -238,9 +238,9 @@ func TestRedirects(t *testing.T) {
}
var expectedCookies = []*Cookie{
- &Cookie{Name: "ChocolateChip", Value: "tasty"},
- &Cookie{Name: "First", Value: "Hit"},
- &Cookie{Name: "Second", Value: "Hit"},
+ {Name: "ChocolateChip", Value: "tasty"},
+ {Name: "First", Value: "Hit"},
+ {Name: "Second", Value: "Hit"},
}
var echoCookiesRedirectHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
diff --git a/src/pkg/net/http/request.go b/src/pkg/net/http/request.go
index 527765780..f5bc6eb91 100644
--- a/src/pkg/net/http/request.go
+++ b/src/pkg/net/http/request.go
@@ -455,11 +455,13 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) {
// First line: GET /index.html HTTP/1.0
var s string
if s, err = tp.ReadLine(); err != nil {
+ return nil, err
+ }
+ defer func() {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
- return nil, err
- }
+ }()
var f []string
if f = strings.SplitN(s, " ", 3); len(f) < 3 {
diff --git a/src/pkg/net/http/request_test.go b/src/pkg/net/http/request_test.go
index 7a3556d03..6e00b9bfd 100644
--- a/src/pkg/net/http/request_test.go
+++ b/src/pkg/net/http/request_test.go
@@ -5,6 +5,7 @@
package http_test
import (
+ "bufio"
"bytes"
"fmt"
"io"
@@ -177,6 +178,24 @@ func TestRequestMultipartCallOrder(t *testing.T) {
}
}
+var readRequestErrorTests = []struct {
+ in string
+ err error
+}{
+ {"GET / HTTP/1.1\r\nheader:foo\r\n\r\n", nil},
+ {"GET / HTTP/1.1\r\nheader:foo\r\n", io.ErrUnexpectedEOF},
+ {"", io.EOF},
+}
+
+func TestReadRequestErrors(t *testing.T) {
+ for i, tt := range readRequestErrorTests {
+ _, err := ReadRequest(bufio.NewReader(strings.NewReader(tt.in)))
+ if err != tt.err {
+ t.Errorf("%d. got error = %v; want %v", i, err, tt.err)
+ }
+ }
+}
+
func testMissingFile(t *testing.T, req *Request) {
f, fh, err := req.FormFile("missing")
if f != nil {
diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go
index fa0df54a2..228ac4019 100644
--- a/src/pkg/net/http/server.go
+++ b/src/pkg/net/http/server.go
@@ -601,7 +601,7 @@ func (c *conn) serve() {
// while they're still writing their
// request. Undefined behavior.
msg = "413 Request Entity Too Large"
- } else if err == io.ErrUnexpectedEOF {
+ } else if err == io.EOF {
break // Don't reply
} else if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
break // Don't reply
diff --git a/src/pkg/net/http/transport.go b/src/pkg/net/http/transport.go
index 09579f8a0..024975946 100644
--- a/src/pkg/net/http/transport.go
+++ b/src/pkg/net/http/transport.go
@@ -196,7 +196,7 @@ func (t *Transport) CloseIdleConnections() {
pconn.close()
}
}
- t.idleConn = nil
+ t.idleConn = make(map[string][]*persistConn)
}
//
diff --git a/src/pkg/net/http/transport_test.go b/src/pkg/net/http/transport_test.go
index cbb3884f9..a9e401de5 100644
--- a/src/pkg/net/http/transport_test.go
+++ b/src/pkg/net/http/transport_test.go
@@ -698,6 +698,32 @@ func TestTransportPersistConnLeak(t *testing.T) {
}
}
+// This used to crash; http://golang.org/issue/3266
+func TestTransportIdleConnCrash(t *testing.T) {
+ tr := &Transport{}
+ c := &Client{Transport: tr}
+
+ unblockCh := make(chan bool, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ <-unblockCh
+ tr.CloseIdleConnections()
+ }))
+ defer ts.Close()
+
+ didreq := make(chan bool)
+ go func() {
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Error(err)
+ } else {
+ res.Body.Close() // returns idle conn
+ }
+ didreq <- true
+ }()
+ unblockCh <- true
+ <-didreq
+}
+
type fooProto struct{}
func (fooProto) RoundTrip(req *Request) (*Response, error) {
diff --git a/src/pkg/net/http/triv.go b/src/pkg/net/http/triv.go
index 269af0ca3..232d65089 100644
--- a/src/pkg/net/http/triv.go
+++ b/src/pkg/net/http/triv.go
@@ -15,7 +15,9 @@ import (
"log"
"net/http"
"os"
+ "os/exec"
"strconv"
+ "sync"
)
// hello world, the web server
@@ -28,14 +30,21 @@ func HelloServer(w http.ResponseWriter, req *http.Request) {
// Simple counter server. POSTing to it will set the value.
type Counter struct {
- n int
+ mu sync.Mutex // protects n
+ n int
}
// This makes Counter satisfy the expvar.Var interface, so we can export
// it directly.
-func (ctr *Counter) String() string { return fmt.Sprintf("%d", ctr.n) }
+func (ctr *Counter) String() string {
+ ctr.mu.Lock()
+ defer ctr.mu.Unlock()
+ return fmt.Sprintf("%d", ctr.n)
+}
func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ ctr.mu.Lock()
+ defer ctr.mu.Unlock()
switch req.Method {
case "GET":
ctr.n++
@@ -95,54 +104,36 @@ func (ch Chan) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// exec a program, redirecting output
func DateServer(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
- r, w, err := os.Pipe()
- if err != nil {
- fmt.Fprintf(rw, "pipe: %s\n", err)
- return
- }
- p, err := os.StartProcess("/bin/date", []string{"date"}, &os.ProcAttr{Files: []*os.File{nil, w, w}})
- defer r.Close()
- w.Close()
- if err != nil {
- fmt.Fprintf(rw, "fork/exec: %s\n", err)
- return
- }
- io.Copy(rw, r)
- wait, err := p.Wait(0)
+ date, err := exec.Command("/bin/date").Output()
if err != nil {
- fmt.Fprintf(rw, "wait: %s\n", err)
- return
- }
- if !wait.Exited() || wait.ExitStatus() != 0 {
- fmt.Fprintf(rw, "date: %v\n", wait)
+ http.Error(rw, err.Error(), 500)
return
}
+ rw.Write(date)
}
func Logger(w http.ResponseWriter, req *http.Request) {
- log.Print(req.URL.Raw)
- w.WriteHeader(404)
- w.Write([]byte("oops"))
+ log.Print(req.URL)
+ http.Error(w, "oops", 404)
}
-var webroot = flag.String("root", "/home/rsc", "web root directory")
+var webroot = flag.String("root", os.Getenv("HOME"), "web root directory")
func main() {
flag.Parse()
// The counter is published as a variable directly.
ctr := new(Counter)
- http.Handle("/counter", ctr)
expvar.Publish("counter", ctr)
-
+ http.Handle("/counter", ctr)
http.Handle("/", http.HandlerFunc(Logger))
http.Handle("/go/", http.StripPrefix("/go/", http.FileServer(http.Dir(*webroot))))
- http.Handle("/flags", http.HandlerFunc(FlagServer))
- http.Handle("/args", http.HandlerFunc(ArgServer))
- http.Handle("/go/hello", http.HandlerFunc(HelloServer))
http.Handle("/chan", ChanCreate())
- http.Handle("/date", http.HandlerFunc(DateServer))
+ http.HandleFunc("/flags", FlagServer)
+ http.HandleFunc("/args", ArgServer)
+ http.HandleFunc("/go/hello", HelloServer)
+ http.HandleFunc("/date", DateServer)
err := http.ListenAndServe(":12345", nil)
if err != nil {
log.Panicln("ListenAndServe:", err)