]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: speed up parsing of Cookie headers
authorsergey <sngasuan@gmail.com>
Sun, 24 Feb 2019 11:26:55 +0000 (14:26 +0300)
committerBrad Fitzpatrick <bradfitz@golang.org>
Mon, 15 Apr 2019 19:30:44 +0000 (19:30 +0000)
Parse the headers without splitting them upfront to reduce
memory allocations.

For non-pathological Cookie headers we can make
a good estimate of the number of cookies in there and preallocate
the slice of cookies

name              old time/op    new time/op    delta
CookieString-4      1.73µs ± 2%    1.70µs ± 5%     ~     (p=0.841 n=5+5)
ReadSetCookies-4    6.09µs ± 3%    5.93µs ± 3%     ~     (p=0.095 n=5+5)
ReadCookies-4       7.63µs ± 1%    6.41µs ± 4%  -15.99%  (p=0.008 n=5+5)

name              old alloc/op   new alloc/op   delta
CookieString-4        360B ± 0%      360B ± 0%     ~     (all equal)
ReadSetCookies-4      976B ± 0%      976B ± 0%     ~     (all equal)
ReadCookies-4       2.17kB ± 0%    1.84kB ± 0%  -15.13%  (p=0.008 n=5+5)

name              old allocs/op  new allocs/op  delta
CookieString-4        5.00 ± 0%      5.00 ± 0%     ~     (all equal)
ReadSetCookies-4      15.0 ± 0%      15.0 ± 0%     ~     (all equal)
ReadCookies-4         16.0 ± 0%      11.0 ± 0%  -31.25%  (p=0.008 n=5+5)

Change-Id: Ica1ca0d40c0d8d275134d1dfafb73f1082115826
Reviewed-on: https://go-review.googlesource.com/c/go/+/163617
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/net/http/cookie.go

index b8bc72b622518cba15985f69d85c1b82cd36daf5..7d02796f3062a6bae15e9d29efeddedb19d4c00b 100644 (file)
@@ -230,25 +230,28 @@ func (c *Cookie) String() string {
 //
 // if filter isn't empty, only cookies of that name are returned
 func readCookies(h Header, filter string) []*Cookie {
-       lines, ok := h["Cookie"]
-       if !ok {
+       lines := h["Cookie"]
+       if len(lines) == 0 {
                return []*Cookie{}
        }
 
-       cookies := []*Cookie{}
+       cookies := make([]*Cookie, 0, len(lines)+strings.Count(lines[0], ";"))
        for _, line := range lines {
-               parts := strings.Split(strings.TrimSpace(line), ";")
-               if len(parts) == 1 && parts[0] == "" {
-                       continue
-               }
-               // Per-line attributes
-               for i := 0; i < len(parts); i++ {
-                       parts[i] = strings.TrimSpace(parts[i])
-                       if len(parts[i]) == 0 {
+               line = strings.TrimSpace(line)
+
+               var part string
+               for len(line) > 0 { // continue since we have rest
+                       if splitIndex := strings.Index(line, ";"); splitIndex > 0 {
+                               part, line = line[:splitIndex], line[splitIndex+1:]
+                       } else {
+                               part, line = line, ""
+                       }
+                       part = strings.TrimSpace(part)
+                       if len(part) == 0 {
                                continue
                        }
-                       name, val := parts[i], ""
-                       if j := strings.Index(name, "="); j >= 0 {
+                       name, val := part, ""
+                       if j := strings.Index(part, "="); j >= 0 {
                                name, val = name[:j], name[j+1:]
                        }
                        if !isCookieNameValid(name) {