]> Cypherpunks repositories - gostls13.git/commitdiff
http: add Header.Write method
authorEvan Shaw <chickencha@gmail.com>
Thu, 28 Apr 2011 07:16:15 +0000 (00:16 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Thu, 28 Apr 2011 07:16:15 +0000 (00:16 -0700)
R=golang-dev, bradfitz, dsymonds
CC=golang-dev
https://golang.org/cl/4426069

src/pkg/http/cgi/child.go
src/pkg/http/fcgi/child.go
src/pkg/http/header.go
src/pkg/http/header_test.go [new file with mode: 0644]
src/pkg/http/request.go
src/pkg/http/response.go
src/pkg/http/server.go

index c7d48b9eb3fbd96bb9d3638e5d29de81f3f8de58..e8d847d8c21edcd7f53ea39e1263587b4225693f 100644 (file)
@@ -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()
 }
 
index 114052bee9e3527e21f8c73b73197b5071a054d3..5e5f2e2c784527abfe4806b0cfeb63a720c75ebc 100644 (file)
@@ -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")
 }
 
index 95b0f3db6bb156a4ceb48580c8df2af8a76598e6..95140b01f2a84ddfba3a1c3546b7a5ec848bd9de 100644 (file)
@@ -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;
diff --git a/src/pkg/http/header_test.go b/src/pkg/http/header_test.go
new file mode 100644 (file)
index 0000000..7e24cb0
--- /dev/null
@@ -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()
+       }
+}
index b8e9a21423f6a53a1b4823258caa4f7b8c3b2b8a..70440d9ee1e0c81bc5ee0279ef6aa3898b6d3ea0 100644 (file)
@@ -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
        }
index 1f725ecdddd0b786ebe65413f386e2137c77d377..a65c2b14df6fa171563ab832b8670169e9a5daf7 100644 (file)
@@ -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
-}
index 96d2cb6387dc260ea0841e13fd0832f388d2e87f..d155f06a2d2d0a3c37671431fb507900bc169ac0 100644 (file)
@@ -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")
 }