Skip to content

Commit c190797

Browse files
committed
Fix for release.r56
1 parent dc7f9ee commit c190797

File tree

4 files changed

+211
-16
lines changed

4 files changed

+211
-16
lines changed

Makefile

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ TARG=web
44
GOFMT=gofmt -s -spaces=true -tabindent=false -tabwidth=4
55

66
GOFILES=\
7+
cookie.go\
78
fcgi.go\
89
request.go\
910
scgi.go\
@@ -14,13 +15,7 @@ GOFILES=\
1415
include $(GOROOT)/src/Make.pkg
1516

1617
format:
17-
${GOFMT} -w fcgi.go
18-
${GOFMT} -w request.go
19-
${GOFMT} -w scgi.go
20-
${GOFMT} -w servefile.go
21-
${GOFMT} -w status.go
22-
${GOFMT} -w web.go
23-
${GOFMT} -w web_test.go
18+
${GOFMT} -w ${GOFILES}
2419
${GOFMT} -w examples/arcchallenge.go
2520
${GOFMT} -w examples/hello.go
2621
${GOFMT} -w examples/methodhandler.go

cookie.go

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// Copyright 2009 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package web
6+
7+
import (
8+
"bytes"
9+
"fmt"
10+
"http"
11+
"io"
12+
"os"
13+
"sort"
14+
"strconv"
15+
"strings"
16+
"time"
17+
)
18+
19+
// writeSetCookies writes the wire representation of the set-cookies
20+
// to w. Each cookie is written on a separate "Set-Cookie: " line.
21+
// This choice is made because HTTP parsers tend to have a limit on
22+
// line-length, so it seems safer to place cookies on separate lines.
23+
func writeSetCookies(w io.Writer, kk []*http.Cookie) os.Error {
24+
if kk == nil {
25+
return nil
26+
}
27+
lines := make([]string, 0, len(kk))
28+
var b bytes.Buffer
29+
for _, c := range kk {
30+
b.Reset()
31+
// TODO(petar): c.Value (below) should be unquoted if it is recognized as quoted
32+
fmt.Fprintf(&b, "%s=%s", http.CanonicalHeaderKey(c.Name), c.Value)
33+
if c.Version > 0 {
34+
fmt.Fprintf(&b, "Version=%d; ", c.Version)
35+
}
36+
if len(c.Path) > 0 {
37+
fmt.Fprintf(&b, "; Path=%s", http.URLEscape(c.Path))
38+
}
39+
if len(c.Domain) > 0 {
40+
fmt.Fprintf(&b, "; Domain=%s", http.URLEscape(c.Domain))
41+
}
42+
if len(c.Expires.Zone) > 0 {
43+
fmt.Fprintf(&b, "; Expires=%s", c.Expires.Format(time.RFC1123))
44+
}
45+
if c.MaxAge >= 0 {
46+
fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge)
47+
}
48+
if c.HttpOnly {
49+
fmt.Fprintf(&b, "; HttpOnly")
50+
}
51+
if c.Secure {
52+
fmt.Fprintf(&b, "; Secure")
53+
}
54+
if len(c.Comment) > 0 {
55+
fmt.Fprintf(&b, "; Comment=%s", http.URLEscape(c.Comment))
56+
}
57+
lines = append(lines, "Set-Cookie: "+b.String()+"\r\n")
58+
}
59+
sort.SortStrings(lines)
60+
for _, l := range lines {
61+
if _, err := io.WriteString(w, l); err != nil {
62+
return err
63+
}
64+
}
65+
return nil
66+
}
67+
68+
// writeCookies writes the wire representation of the cookies
69+
// to w. Each cookie is written on a separate "Cookie: " line.
70+
// This choice is made because HTTP parsers tend to have a limit on
71+
// line-length, so it seems safer to place cookies on separate lines.
72+
func writeCookies(w io.Writer, kk []*http.Cookie) os.Error {
73+
lines := make([]string, 0, len(kk))
74+
var b bytes.Buffer
75+
for _, c := range kk {
76+
b.Reset()
77+
n := c.Name
78+
if c.Version > 0 {
79+
fmt.Fprintf(&b, "$Version=%d; ", c.Version)
80+
}
81+
// TODO(petar): c.Value (below) should be unquoted if it is recognized as quoted
82+
fmt.Fprintf(&b, "%s=%s", http.CanonicalHeaderKey(n), c.Value)
83+
if len(c.Path) > 0 {
84+
fmt.Fprintf(&b, "; $Path=%s", http.URLEscape(c.Path))
85+
}
86+
if len(c.Domain) > 0 {
87+
fmt.Fprintf(&b, "; $Domain=%s", http.URLEscape(c.Domain))
88+
}
89+
if c.HttpOnly {
90+
fmt.Fprintf(&b, "; $HttpOnly")
91+
}
92+
if len(c.Comment) > 0 {
93+
fmt.Fprintf(&b, "; $Comment=%s", http.URLEscape(c.Comment))
94+
}
95+
lines = append(lines, "Cookie: "+b.String()+"\r\n")
96+
}
97+
sort.SortStrings(lines)
98+
for _, l := range lines {
99+
if _, err := io.WriteString(w, l); err != nil {
100+
return err
101+
}
102+
}
103+
return nil
104+
}
105+
106+
// readCookies parses all "Cookie" values from
107+
// the header h, removes the successfully parsed values from the
108+
// "Cookie" key in h and returns the parsed Cookies.
109+
func readCookies(h http.Header) []*http.Cookie {
110+
cookies := []*http.Cookie{}
111+
lines, ok := h["Cookie"]
112+
if !ok {
113+
return cookies
114+
}
115+
unparsedLines := []string{}
116+
for _, line := range lines {
117+
parts := strings.Split(strings.TrimSpace(line), ";", -1)
118+
if len(parts) == 1 && parts[0] == "" {
119+
continue
120+
}
121+
// Per-line attributes
122+
var lineCookies = make(map[string]string)
123+
var version int
124+
var path string
125+
var domain string
126+
var comment string
127+
var httponly bool
128+
for i := 0; i < len(parts); i++ {
129+
parts[i] = strings.TrimSpace(parts[i])
130+
if len(parts[i]) == 0 {
131+
continue
132+
}
133+
attr, val := parts[i], ""
134+
var err os.Error
135+
if j := strings.Index(attr, "="); j >= 0 {
136+
attr, val = attr[:j], attr[j+1:]
137+
val, err = http.URLUnescape(val)
138+
if err != nil {
139+
continue
140+
}
141+
}
142+
switch strings.ToLower(attr) {
143+
case "$httponly":
144+
httponly = true
145+
case "$version":
146+
version, err = strconv.Atoi(val)
147+
if err != nil {
148+
version = 0
149+
continue
150+
}
151+
case "$domain":
152+
domain = val
153+
// TODO: Add domain parsing
154+
case "$path":
155+
path = val
156+
// TODO: Add path parsing
157+
case "$comment":
158+
comment = val
159+
default:
160+
lineCookies[attr] = val
161+
}
162+
}
163+
if len(lineCookies) == 0 {
164+
unparsedLines = append(unparsedLines, line)
165+
}
166+
for n, v := range lineCookies {
167+
cookies = append(cookies, &http.Cookie{
168+
Name: n,
169+
Value: v,
170+
Path: path,
171+
Domain: domain,
172+
Comment: comment,
173+
Version: version,
174+
HttpOnly: httponly,
175+
MaxAge: -1,
176+
Raw: line,
177+
})
178+
}
179+
}
180+
h["Cookie"] = unparsedLines, len(unparsedLines) > 0
181+
return cookies
182+
}

request.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ func newRequestCgi(headers http.Header, body io.Reader) *Request {
118118
httpheader["Content-Length"] = clength
119119
}
120120
}
121+
122+
//read the cookies
123+
cookies := readCookies(httpheader)
121124

122125
req := Request{
123126
Method: method,
@@ -130,6 +133,7 @@ func newRequestCgi(headers http.Header, body io.Reader) *Request {
130133
Headers: httpheader,
131134
RemoteAddr: remoteAddr,
132135
RemotePort: remotePort,
136+
Cookie: cookies,
133137
}
134138

135139
return &req

web_test.go

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ func buildTestResponse(buf *bytes.Buffer) *testResponse {
8484
return &response
8585
}
8686

87-
func getTestResponse(method string, path string, body string, headers map[string][]string) *testResponse {
88-
req := buildTestRequest(method, path, body, headers)
87+
func getTestResponse(method string, path string, body string, headers map[string][]string, cookies []*http.Cookie) *testResponse {
88+
req := buildTestRequest(method, path, body, headers, cookies)
8989
var buf bytes.Buffer
9090

9191
tcpb := tcpBuffer{nil, &buf}
@@ -205,7 +205,7 @@ var tests = []Test{
205205
{"GET", "/methodhandler3/b", "", 200, `ab`},
206206
}
207207

208-
func buildTestRequest(method string, path string, body string, headers map[string][]string) *Request {
208+
func buildTestRequest(method string, path string, body string, headers map[string][]string, cookies []*http.Cookie) *Request {
209209
host := "127.0.0.1"
210210
port := "80"
211211
rawurl := "http://" + host + ":" + port + path
@@ -225,6 +225,7 @@ func buildTestRequest(method string, path string, body string, headers map[strin
225225

226226
req := Request{Method: method,
227227
RawURL: rawurl,
228+
Cookie: cookies,
228229
URL: url,
229230
Proto: proto,
230231
Host: host,
@@ -238,7 +239,7 @@ func buildTestRequest(method string, path string, body string, headers map[strin
238239

239240
func TestRouting(t *testing.T) {
240241
for _, test := range tests {
241-
resp := getTestResponse(test.method, test.path, test.body, make(map[string][]string))
242+
resp := getTestResponse(test.method, test.path, test.body, make(map[string][]string), nil)
242243

243244
if resp.statusCode != test.expectedStatus {
244245
t.Fatalf("expected status %d got %d", test.expectedStatus, resp.statusCode)
@@ -262,8 +263,8 @@ func TestHead(t *testing.T) {
262263
if test.method != "GET" {
263264
continue
264265
}
265-
getresp := getTestResponse("GET", test.path, test.body, make(map[string][]string))
266-
headresp := getTestResponse("HEAD", test.path, test.body, make(map[string][]string))
266+
getresp := getTestResponse("GET", test.path, test.body, make(map[string][]string), nil)
267+
headresp := getTestResponse("HEAD", test.path, test.body, make(map[string][]string), nil)
267268

268269
if getresp.statusCode != headresp.statusCode {
269270
t.Fatalf("head and get status differ. expected %d got %d", getresp.statusCode, headresp.statusCode)
@@ -603,15 +604,28 @@ func TestFcgiChunks(t *testing.T) {
603604
}
604605
}
605606

607+
func makeCookie(vals map[string]string) []*http.Cookie {
608+
var cookies []*http.Cookie
609+
for k,v := range vals {
610+
c := &http.Cookie{
611+
Name: k,
612+
Value: v,
613+
}
614+
cookies = append(cookies, c)
615+
}
616+
return cookies
617+
}
618+
606619
func TestSecureCookie(t *testing.T) {
607620
mainServer.Config.CookieSecret = "7C19QRmwf3mHZ9CPAaPQ0hsWeufKd"
608-
resp1 := getTestResponse("POST", "/securecookie/set/a/1", "", nil)
621+
resp1 := getTestResponse("POST", "/securecookie/set/a/1", "", nil, nil)
609622
sval, ok := resp1.cookies["a"]
610623
if !ok {
611624
t.Fatalf("Failed to get cookie ")
612625
}
613-
cookie := fmt.Sprintf("a=%s", sval)
614-
resp2 := getTestResponse("GET", "/securecookie/get/a", "", map[string][]string{"Cookie": {cookie}})
626+
cookies := makeCookie(map[string]string {"a": sval});
627+
628+
resp2 := getTestResponse("GET", "/securecookie/get/a", "", nil, cookies)
615629

616630
if resp2.body != "1" {
617631
t.Fatalf("SecureCookie test failed")

0 commit comments

Comments
 (0)