Skip to content

Commit

Permalink
Issue #69: Added RequestHeader.Add and ResponseHeader.Add for adding …
Browse files Browse the repository at this point in the history
…multiple headers with the same key
  • Loading branch information
valyala committed Mar 29, 2016
1 parent e9207da commit 12ba989
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 0 deletions.
2 changes: 2 additions & 0 deletions args_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ func TestArgsAdd(t *testing.T) {
t.Fatalf("unexpected value: %q. Expecting %q", v, "23")
}
baFound = true
default:
t.Fatalf("unexpected key found %q", k)
}
})
if !barFound || !bazFound || !oneFound || !baFound {
Expand Down
58 changes: 58 additions & 0 deletions header.go
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,35 @@ func (h *RequestHeader) del(key []byte) {
h.h = delAllArgsBytes(h.h, key)
}

// Add adds the given 'key: value' header.
//
// Multiple headers with the same key may be added.
func (h *ResponseHeader) Add(key, value string) {
k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing)
h.h = appendArg(h.h, b2s(k), value)
}

// AddBytesK adds the given 'key: value' header.
//
// Multiple headers with the same key may be added.
func (h *ResponseHeader) AddBytesK(key []byte, value string) {
h.Add(b2s(key), value)
}

// AddBytesV adds the given 'key: value' header.
//
// Multiple headers with the same key may be added.
func (h *ResponseHeader) AddBytesV(key string, value []byte) {
h.Add(key, b2s(value))
}

// AddBytesKV adds the given 'key: value' header.
//
// Multiple headers with the same key may be added.
func (h *ResponseHeader) AddBytesKV(key, value []byte) {
h.Add(b2s(key), b2s(value))
}

// Set sets the given 'key: value' header.
func (h *ResponseHeader) Set(key, value string) {
initHeaderKV(&h.bufKV, key, value, h.disableNormalizing)
Expand Down Expand Up @@ -917,6 +946,35 @@ func (h *RequestHeader) SetCookieBytesKV(key, value []byte) {
h.cookies = setArgBytes(h.cookies, key, value)
}

// Add adds the given 'key: value' header.
//
// Multiple headers with the same key may be added.
func (h *RequestHeader) Add(key, value string) {
k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing)
h.h = appendArg(h.h, b2s(k), value)
}

// AddBytesK adds the given 'key: value' header.
//
// Multiple headers with the same key may be added.
func (h *RequestHeader) AddBytesK(key []byte, value string) {
h.Add(b2s(key), value)
}

// AddBytesV adds the given 'key: value' header.
//
// Multiple headers with the same key may be added.
func (h *RequestHeader) AddBytesV(key string, value []byte) {
h.Add(key, b2s(value))
}

// AddBytesKV adds the given 'key: value' header.
//
// Multiple headers with the same key may be added.
func (h *RequestHeader) AddBytesKV(key, value []byte) {
h.Add(b2s(key), b2s(value))
}

// Set sets the given 'key: value' header.
func (h *RequestHeader) Set(key, value string) {
initHeaderKV(&h.bufKV, key, value, h.disableNormalizing)
Expand Down
105 changes: 105 additions & 0 deletions header_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,111 @@ import (
"testing"
)

func TestResponseHeaderAdd(t *testing.T) {
m := make(map[string]struct{})
var h ResponseHeader
h.Add("aaa", "bbb")
m["bbb"] = struct{}{}
for i := 0; i < 10; i++ {
v := fmt.Sprintf("%d", i)
h.Add("Foo-Bar", v)
m[v] = struct{}{}
}
if h.Len() != 12 {
t.Fatalf("unexpected header len %d. Expecting 12", h.Len())
}

h.VisitAll(func(k, v []byte) {
switch string(k) {
case "Aaa", "Foo-Bar":
if _, ok := m[string(v)]; !ok {
t.Fatalf("unexpected value found %q. key %q", v, k)
}
delete(m, string(v))
case "Content-Type":
default:
t.Fatalf("unexpected key found: %q", k)
}
})
if len(m) > 0 {
t.Fatalf("%d headers are missed", len(m))
}

s := h.String()
br := bufio.NewReader(bytes.NewBufferString(s))
var h1 ResponseHeader
if err := h1.Read(br); err != nil {
t.Fatalf("unexpected error: %s", err)
}

h.VisitAll(func(k, v []byte) {
switch string(k) {
case "Aaa", "Foo-Bar":
m[string(v)] = struct{}{}
case "Content-Type":
default:
t.Fatalf("unexpected key found: %q", k)
}
})
if len(m) != 11 {
t.Fatalf("unexpected number of headers: %d. Expecting 11", len(m))
}
}

func TestRequestHeaderAdd(t *testing.T) {
m := make(map[string]struct{})
var h RequestHeader
h.Add("aaa", "bbb")
m["bbb"] = struct{}{}
for i := 0; i < 10; i++ {
v := fmt.Sprintf("%d", i)
h.Add("Foo-Bar", v)
m[v] = struct{}{}
}
if h.Len() != 11 {
t.Fatalf("unexpected header len %d. Expecting 11", h.Len())
}

h.VisitAll(func(k, v []byte) {
switch string(k) {
case "Aaa", "Foo-Bar":
if _, ok := m[string(v)]; !ok {
t.Fatalf("unexpected value found %q. key %q", v, k)
}
delete(m, string(v))
default:
t.Fatalf("unexpected key found: %q", k)
}
})
if len(m) > 0 {
t.Fatalf("%d headers are missed", len(m))
}

s := h.String()
br := bufio.NewReader(bytes.NewBufferString(s))
var h1 RequestHeader
if err := h1.Read(br); err != nil {
t.Fatalf("unexpected error: %s", err)
}

h.VisitAll(func(k, v []byte) {
switch string(k) {
case "Aaa", "Foo-Bar":
m[string(v)] = struct{}{}
case "User-Agent":
default:
t.Fatalf("unexpected key found: %q", k)
}
})
if len(m) != 11 {
t.Fatalf("unexpected number of headers: %d. Expecting 11", len(m))
}
s1 := h1.String()
if s != s1 {
t.Fatalf("unexpected headers %q. Expecting %q", s1, s)
}
}

func TestHasHeaderValue(t *testing.T) {
testHasHeaderValue(t, "foobar", "foobar", true)
testHasHeaderValue(t, "foobar", "foo", false)
Expand Down

0 comments on commit 12ba989

Please sign in to comment.