Commit 37666561 authored by Russ Cox's avatar Russ Cox

http: fix handling of Close, use Close in http.Post

default to HTTP/1.1

R=petar-m
CC=golang-dev
https://golang.org/cl/224041
parent 1be05bbe
...@@ -139,6 +139,7 @@ func Post(url string, bodyType string, body io.Reader) (r *Response, err os.Erro ...@@ -139,6 +139,7 @@ func Post(url string, bodyType string, body io.Reader) (r *Response, err os.Erro
req.Method = "POST" req.Method = "POST"
req.ProtoMajor = 1 req.ProtoMajor = 1
req.ProtoMinor = 1 req.ProtoMinor = 1
req.Close = true
req.Body = nopCloser{body} req.Body = nopCloser{body}
req.Header = map[string]string{ req.Header = map[string]string{
"Content-Type": bodyType, "Content-Type": bodyType,
......
...@@ -82,6 +82,43 @@ var reqWriteTests = []reqWriteTest{ ...@@ -82,6 +82,43 @@ var reqWriteTests = []reqWriteTest{
"Transfer-Encoding: chunked\r\n\r\n" + "Transfer-Encoding: chunked\r\n\r\n" +
"6\r\nabcdef\r\n0\r\n\r\n", "6\r\nabcdef\r\n0\r\n\r\n",
}, },
// HTTP/1.1 POST => chunked coding; body; empty trailer
reqWriteTest{
Request{
Method: "POST",
URL: &URL{
Scheme: "http",
Host: "www.google.com",
Path: "/search",
},
ProtoMajor: 1,
ProtoMinor: 1,
Header: map[string]string{},
Close: true,
Body: nopCloser{bytes.NewBufferString("abcdef")},
TransferEncoding: []string{"chunked"},
},
"POST /search HTTP/1.1\r\n" +
"Host: www.google.com\r\n" +
"User-Agent: Go http package\r\n" +
"Connection: close\r\n" +
"Transfer-Encoding: chunked\r\n\r\n" +
"6\r\nabcdef\r\n0\r\n\r\n",
},
// default to HTTP/1.1
reqWriteTest{
Request{
Method: "GET",
RawURL: "/search",
Host: "www.google.com",
},
"GET /search HTTP/1.1\r\n" +
"Host: www.google.com\r\n" +
"User-Agent: Go http package\r\n" +
"\r\n",
},
} }
func TestRequestWrite(t *testing.T) { func TestRequestWrite(t *testing.T) {
......
...@@ -188,9 +188,13 @@ func (resp *Response) Write(w io.Writer) os.Error { ...@@ -188,9 +188,13 @@ func (resp *Response) Write(w io.Writer) os.Error {
resp.RequestMethod = strings.ToUpper(resp.RequestMethod) resp.RequestMethod = strings.ToUpper(resp.RequestMethod)
// Status line // Status line
text, ok := statusText[resp.StatusCode] text := resp.Status
if !ok { if text == "" {
text = "status code " + strconv.Itoa(resp.StatusCode) var ok bool
text, ok = statusText[resp.StatusCode]
if !ok {
text = "status code " + strconv.Itoa(resp.StatusCode)
}
} }
io.WriteString(w, "HTTP/"+strconv.Itoa(resp.ProtoMajor)+".") io.WriteString(w, "HTTP/"+strconv.Itoa(resp.ProtoMajor)+".")
io.WriteString(w, strconv.Itoa(resp.ProtoMinor)+" ") io.WriteString(w, strconv.Itoa(resp.ProtoMinor)+" ")
......
...@@ -42,10 +42,11 @@ var respWriteTests = []respWriteTest{ ...@@ -42,10 +42,11 @@ var respWriteTests = []respWriteTest{
Body: nopCloser{bytes.NewBufferString("abcdef")}, Body: nopCloser{bytes.NewBufferString("abcdef")},
ContentLength: 6, ContentLength: 6,
TransferEncoding: []string{"chunked"}, TransferEncoding: []string{"chunked"},
Close: true, // TODO(petar): "Connection: close" is not written Close: true,
}, },
"HTTP/1.1 200 OK\r\n" + "HTTP/1.1 200 OK\r\n" +
"Connection: close\r\n" +
"Transfer-Encoding: chunked\r\n\r\n" + "Transfer-Encoding: chunked\r\n\r\n" +
"6\r\nabcdef\r\n0\r\n\r\n", "6\r\nabcdef\r\n0\r\n\r\n",
}, },
......
...@@ -79,19 +79,27 @@ func noBodyExpected(requestMethod string) bool { ...@@ -79,19 +79,27 @@ func noBodyExpected(requestMethod string) bool {
} }
func (t *transferWriter) WriteHeader(w io.Writer) (err os.Error) { func (t *transferWriter) WriteHeader(w io.Writer) (err os.Error) {
if t.Close {
_, err = io.WriteString(w, "Connection: close\r\n")
if err != nil {
return
}
}
// Write Content-Length and/or Transfer-Encoding whose values are a // Write Content-Length and/or Transfer-Encoding whose values are a
// function of the sanitized field triple (Body, ContentLength, // function of the sanitized field triple (Body, ContentLength,
// TransferEncoding) // TransferEncoding)
if chunked(t.TransferEncoding) { if chunked(t.TransferEncoding) {
_, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n") _, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n")
} else { if err != nil {
if t.ContentLength > 0 || t.ResponseToHEAD { return
io.WriteString(w, "Content-Length: ") }
_, err = io.WriteString(w, strconv.Itoa64(t.ContentLength)+"\r\n") } else if t.ContentLength > 0 || t.ResponseToHEAD {
io.WriteString(w, "Content-Length: ")
_, err = io.WriteString(w, strconv.Itoa64(t.ContentLength)+"\r\n")
if err != nil {
return
} }
}
if err != nil {
return
} }
// Write Trailer header // Write Trailer header
...@@ -184,6 +192,11 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) { ...@@ -184,6 +192,11 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
t.RequestMethod = "GET" t.RequestMethod = "GET"
} }
// Default to HTTP/1.1
if t.ProtoMajor == 0 && t.ProtoMinor == 0 {
t.ProtoMajor, t.ProtoMinor = 1, 1
}
// Transfer encoding, content length // Transfer encoding, content length
t.TransferEncoding, err = fixTransferEncoding(t.Header) t.TransferEncoding, err = fixTransferEncoding(t.Header)
if err != nil { if err != nil {
...@@ -347,6 +360,7 @@ func shouldClose(major, minor int, header map[string]string) bool { ...@@ -347,6 +360,7 @@ func shouldClose(major, minor int, header map[string]string) bool {
// TODO: Should split on commas, toss surrounding white space, // TODO: Should split on commas, toss surrounding white space,
// and check each field. // and check each field.
if v == "close" { if v == "close" {
header["Connection"] = "", false
return true return true
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment