mirror of
https://github.com/golang/go
synced 2024-11-20 03:24:41 -07:00
http: add Header.Write method
R=golang-dev, bradfitz, dsymonds CC=golang-dev https://golang.org/cl/4426069
This commit is contained in:
parent
d2d50f85ba
commit
f319e1df37
@ -168,17 +168,8 @@ func (r *response) WriteHeader(code int) {
|
||||
r.header.Add("Content-Type", "text/html; charset=utf-8")
|
||||
}
|
||||
|
||||
// TODO: add a method on http.Header to write itself to an io.Writer?
|
||||
// This is duplicated code.
|
||||
for k, vv := range r.header {
|
||||
for _, v := range vv {
|
||||
v = strings.Replace(v, "\n", "", -1)
|
||||
v = strings.Replace(v, "\r", "", -1)
|
||||
v = strings.TrimSpace(v)
|
||||
fmt.Fprintf(r.bufw, "%s: %s\r\n", k, v)
|
||||
}
|
||||
}
|
||||
r.bufw.Write([]byte("\r\n"))
|
||||
r.header.Write(r.bufw)
|
||||
r.bufw.WriteString("\r\n")
|
||||
r.bufw.Flush()
|
||||
}
|
||||
|
||||
|
@ -169,15 +169,7 @@ func (r *response) WriteHeader(code int) {
|
||||
}
|
||||
|
||||
fmt.Fprintf(r.w, "Status: %d %s\r\n", code, http.StatusText(code))
|
||||
// TODO(eds): this is duplicated in http and http/cgi
|
||||
for k, vv := range r.header {
|
||||
for _, v := range vv {
|
||||
v = strings.Replace(v, "\n", "", -1)
|
||||
v = strings.Replace(v, "\r", "", -1)
|
||||
v = strings.TrimSpace(v)
|
||||
fmt.Fprintf(r.w, "%s: %s\r\n", k, v)
|
||||
}
|
||||
}
|
||||
r.header.Write(r.w)
|
||||
r.w.WriteString("\r\n")
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,14 @@
|
||||
|
||||
package http
|
||||
|
||||
import "net/textproto"
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A Header represents the key-value pairs in an HTTP header.
|
||||
type Header map[string][]string
|
||||
@ -35,6 +42,37 @@ func (h Header) Del(key string) {
|
||||
textproto.MIMEHeader(h).Del(key)
|
||||
}
|
||||
|
||||
// Write writes a header in wire format.
|
||||
func (h Header) Write(w io.Writer) os.Error {
|
||||
return h.WriteSubset(w, nil)
|
||||
}
|
||||
|
||||
// WriteSubset writes a header in wire format.
|
||||
// If exclude is not nil, keys where exclude[key] == true are not written.
|
||||
func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) os.Error {
|
||||
keys := make([]string, 0, len(h))
|
||||
for k := range h {
|
||||
if exclude == nil || !exclude[k] {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
sort.SortStrings(keys)
|
||||
for _, k := range keys {
|
||||
for _, v := range h[k] {
|
||||
v = strings.Replace(v, "\n", " ", -1)
|
||||
v = strings.Replace(v, "\r", " ", -1)
|
||||
v = strings.TrimSpace(v)
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
if _, err := fmt.Fprintf(w, "%s: %s\r\n", k, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CanonicalHeaderKey returns the canonical format of the
|
||||
// header key s. The canonicalization converts the first
|
||||
// letter and any letter following a hyphen to upper case;
|
||||
|
71
src/pkg/http/header_test.go
Normal file
71
src/pkg/http/header_test.go
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var headerWriteTests = []struct {
|
||||
h Header
|
||||
exclude map[string]bool
|
||||
expected string
|
||||
}{
|
||||
{Header{}, nil, ""},
|
||||
{
|
||||
Header{
|
||||
"Content-Type": {"text/html; charset=UTF-8"},
|
||||
"Content-Length": {"0"},
|
||||
},
|
||||
nil,
|
||||
"Content-Length: 0\r\nContent-Type: text/html; charset=UTF-8\r\n",
|
||||
},
|
||||
{
|
||||
Header{
|
||||
"Content-Length": {"0", "1", "2"},
|
||||
},
|
||||
nil,
|
||||
"Content-Length: 0\r\nContent-Length: 1\r\nContent-Length: 2\r\n",
|
||||
},
|
||||
{
|
||||
Header{
|
||||
"Expires": {"-1"},
|
||||
"Content-Length": {"0"},
|
||||
"Content-Encoding": {"gzip"},
|
||||
},
|
||||
map[string]bool{"Content-Length": true},
|
||||
"Content-Encoding: gzip\r\nExpires: -1\r\n",
|
||||
},
|
||||
{
|
||||
Header{
|
||||
"Expires": {"-1"},
|
||||
"Content-Length": {"0", "1", "2"},
|
||||
"Content-Encoding": {"gzip"},
|
||||
},
|
||||
map[string]bool{"Content-Length": true},
|
||||
"Content-Encoding: gzip\r\nExpires: -1\r\n",
|
||||
},
|
||||
{
|
||||
Header{
|
||||
"Expires": {"-1"},
|
||||
"Content-Length": {"0"},
|
||||
"Content-Encoding": {"gzip"},
|
||||
},
|
||||
map[string]bool{"Content-Length": true, "Expires": true, "Content-Encoding": true},
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
func TestHeaderWrite(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
for i, test := range headerWriteTests {
|
||||
test.h.WriteSubset(&buf, test.exclude)
|
||||
if buf.String() != test.expected {
|
||||
t.Errorf("#%d:\n got: %q\nwant: %q", i, buf.String(), test.expected)
|
||||
}
|
||||
buf.Reset()
|
||||
}
|
||||
}
|
@ -300,7 +300,7 @@ func (req *Request) write(w io.Writer, usingProxy bool) os.Error {
|
||||
// from Request, and introduce Request methods along the lines of
|
||||
// Response.{GetHeader,AddHeader} and string constants for "Host",
|
||||
// "User-Agent" and "Referer".
|
||||
err = writeSortedHeader(w, req.Header, reqExcludeHeader)
|
||||
err = req.Header.WriteSubset(w, reqExcludeHeader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -8,11 +8,9 @@ package http
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@ -192,7 +190,7 @@ func (resp *Response) Write(w io.Writer) os.Error {
|
||||
}
|
||||
|
||||
// Rest of header
|
||||
err = writeSortedHeader(w, resp.Header, respExcludeHeader)
|
||||
err = resp.Header.WriteSubset(w, respExcludeHeader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -213,27 +211,3 @@ func (resp *Response) Write(w io.Writer) os.Error {
|
||||
// Success
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeSortedHeader(w io.Writer, h Header, exclude map[string]bool) os.Error {
|
||||
keys := make([]string, 0, len(h))
|
||||
for k := range h {
|
||||
if exclude == nil || !exclude[k] {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
sort.SortStrings(keys)
|
||||
for _, k := range keys {
|
||||
for _, v := range h[k] {
|
||||
v = strings.Replace(v, "\n", " ", -1)
|
||||
v = strings.Replace(v, "\r", " ", -1)
|
||||
v = strings.TrimSpace(v)
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
if _, err := fmt.Fprintf(w, "%s: %s\r\n", k, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -309,7 +309,7 @@ func (w *response) WriteHeader(code int) {
|
||||
text = "status code " + codestring
|
||||
}
|
||||
io.WriteString(w.conn.buf, proto+" "+codestring+" "+text+"\r\n")
|
||||
writeSortedHeader(w.conn.buf, w.header, nil)
|
||||
w.header.Write(w.conn.buf)
|
||||
io.WriteString(w.conn.buf, "\r\n")
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user