Commit 469e3a91 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: correct and faster hasToken

Fixes #3535

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/6245060
parent cb62365f
......@@ -76,3 +76,38 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
// the rest are converted to lowercase. For example, the
// canonical key for "accept-encoding" is "Accept-Encoding".
func CanonicalHeaderKey(s string) string { return textproto.CanonicalMIMEHeaderKey(s) }
// hasToken returns whether token appears with v, ASCII
// case-insensitive, with space or comma boundaries.
// token must be all lowercase.
// v may contain mixed cased.
func hasToken(v, token string) bool {
if len(token) > len(v) || token == "" {
return false
}
if v == token {
return true
}
for sp := 0; sp <= len(v)-len(token); sp++ {
// Check that first character is good.
if b := v[sp]; b != token[0] && b|0x20 != token[0] {
continue
}
// Check that start pos is on a valid token boundary.
if sp > 0 && !isTokenBoundary(v[sp-1]) {
continue
}
// Check that end pos is on a valid token boundary.
if endPos := sp + len(token); endPos != len(v) && !isTokenBoundary(v[endPos]) {
continue
}
if strings.EqualFold(v[sp:sp+len(token)], token) {
return true
}
}
return false
}
func isTokenBoundary(b byte) bool {
return b == ' ' || b == ',' || b == '\t'
}
......@@ -79,3 +79,46 @@ func TestHeaderWrite(t *testing.T) {
buf.Reset()
}
}
type hasTokenTest struct {
header string
token string
want bool
}
var hasTokenTests = []hasTokenTest{
{"", "", false},
{"", "foo", false},
{"foo", "foo", true},
{"foo ", "foo", true},
{" foo", "foo", true},
{" foo ", "foo", true},
{"foo,bar", "foo", true},
{"bar,foo", "foo", true},
{"bar, foo", "foo", true},
{"bar,foo, baz", "foo", true},
{"bar, foo,baz", "foo", true},
{"bar,foo, baz", "foo", true},
{"bar, foo, baz", "foo", true},
{"FOO", "foo", true},
{"FOO ", "foo", true},
{" FOO", "foo", true},
{" FOO ", "foo", true},
{"FOO,BAR", "foo", true},
{"BAR,FOO", "foo", true},
{"BAR, FOO", "foo", true},
{"BAR,FOO, baz", "foo", true},
{"BAR, FOO,BAZ", "foo", true},
{"BAR,FOO, BAZ", "foo", true},
{"BAR, FOO, BAZ", "foo", true},
{"foobar", "foo", false},
{"barfoo ", "foo", false},
}
func TestHasToken(t *testing.T) {
for _, tt := range hasTokenTests {
if hasToken(tt.header, tt.token) != tt.want {
t.Errorf("hasToken(%q, %q) = %v; want %v", tt.header, tt.token, !tt.want, tt.want)
}
}
}
......@@ -745,11 +745,3 @@ func (r *Request) wantsHttp10KeepAlive() bool {
func (r *Request) wantsClose() bool {
return hasToken(r.Header.Get("Connection"), "close")
}
func hasToken(s, token string) bool {
if s == "" {
return false
}
// TODO This is a poor implementation of the RFC. See http://golang.org/issue/3535
return strings.Contains(strings.ToLower(s), token)
}
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