OSDN Git Service

Update to current version of Go library.
[pf3gnuchains/gcc-fork.git] / libgo / go / http / request_test.go
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 http_test
6
7 import (
8         "bytes"
9         "fmt"
10         . "http"
11         "http/httptest"
12         "io"
13         "io/ioutil"
14         "mime/multipart"
15         "os"
16         "reflect"
17         "regexp"
18         "strings"
19         "testing"
20 )
21
22 type stringMultimap map[string][]string
23
24 type parseTest struct {
25         query string
26         out   stringMultimap
27 }
28
29 var parseTests = []parseTest{
30         {
31                 query: "a=1&b=2",
32                 out:   stringMultimap{"a": []string{"1"}, "b": []string{"2"}},
33         },
34         {
35                 query: "a=1&a=2&a=banana",
36                 out:   stringMultimap{"a": []string{"1", "2", "banana"}},
37         },
38         {
39                 query: "ascii=%3Ckey%3A+0x90%3E",
40                 out:   stringMultimap{"ascii": []string{"<key: 0x90>"}},
41         },
42 }
43
44 func TestParseForm(t *testing.T) {
45         for i, test := range parseTests {
46                 form, err := ParseQuery(test.query)
47                 if err != nil {
48                         t.Errorf("test %d: Unexpected error: %v", i, err)
49                         continue
50                 }
51                 if len(form) != len(test.out) {
52                         t.Errorf("test %d: len(form) = %d, want %d", i, len(form), len(test.out))
53                 }
54                 for k, evs := range test.out {
55                         vs, ok := form[k]
56                         if !ok {
57                                 t.Errorf("test %d: Missing key %q", i, k)
58                                 continue
59                         }
60                         if len(vs) != len(evs) {
61                                 t.Errorf("test %d: len(form[%q]) = %d, want %d", i, k, len(vs), len(evs))
62                                 continue
63                         }
64                         for j, ev := range evs {
65                                 if v := vs[j]; v != ev {
66                                         t.Errorf("test %d: form[%q][%d] = %q, want %q", i, k, j, v, ev)
67                                 }
68                         }
69                 }
70         }
71 }
72
73 func TestQuery(t *testing.T) {
74         req := &Request{Method: "GET"}
75         req.URL, _ = ParseURL("http://www.google.com/search?q=foo&q=bar")
76         if q := req.FormValue("q"); q != "foo" {
77                 t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
78         }
79 }
80
81 func TestPostQuery(t *testing.T) {
82         req := &Request{Method: "POST"}
83         req.URL, _ = ParseURL("http://www.google.com/search?q=foo&q=bar&both=x")
84         req.Header = Header{
85                 "Content-Type": {"application/x-www-form-urlencoded; boo!"},
86         }
87         req.Body = ioutil.NopCloser(strings.NewReader("z=post&both=y"))
88         if q := req.FormValue("q"); q != "foo" {
89                 t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
90         }
91         if z := req.FormValue("z"); z != "post" {
92                 t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
93         }
94         if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"x", "y"}) {
95                 t.Errorf(`req.FormValue("both") = %q, want ["x", "y"]`, both)
96         }
97 }
98
99 type stringMap map[string][]string
100 type parseContentTypeTest struct {
101         contentType stringMap
102         error       bool
103 }
104
105 var parseContentTypeTests = []parseContentTypeTest{
106         {contentType: stringMap{"Content-Type": {"text/plain"}}},
107         {contentType: stringMap{}}, // Non-existent keys are not placed. The value nil is illegal.
108         {contentType: stringMap{"Content-Type": {"text/plain; boundary="}}},
109         {
110                 contentType: stringMap{"Content-Type": {"application/unknown"}},
111                 error:       true,
112         },
113 }
114
115 func TestPostContentTypeParsing(t *testing.T) {
116         for i, test := range parseContentTypeTests {
117                 req := &Request{
118                         Method: "POST",
119                         Header: Header(test.contentType),
120                         Body:   ioutil.NopCloser(bytes.NewBufferString("body")),
121                 }
122                 err := req.ParseForm()
123                 if !test.error && err != nil {
124                         t.Errorf("test %d: Unexpected error: %v", i, err)
125                 }
126                 if test.error && err == nil {
127                         t.Errorf("test %d should have returned error", i)
128                 }
129         }
130 }
131
132 func TestMultipartReader(t *testing.T) {
133         req := &Request{
134                 Method: "POST",
135                 Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}},
136                 Body:   ioutil.NopCloser(new(bytes.Buffer)),
137         }
138         multipart, err := req.MultipartReader()
139         if multipart == nil {
140                 t.Errorf("expected multipart; error: %v", err)
141         }
142
143         req.Header = Header{"Content-Type": {"text/plain"}}
144         multipart, err = req.MultipartReader()
145         if multipart != nil {
146                 t.Errorf("unexpected multipart for text/plain")
147         }
148 }
149
150 func TestRedirect(t *testing.T) {
151         ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
152                 switch r.URL.Path {
153                 case "/":
154                         w.Header().Set("Location", "/foo/")
155                         w.WriteHeader(StatusSeeOther)
156                 case "/foo/":
157                         fmt.Fprintf(w, "foo")
158                 default:
159                         w.WriteHeader(StatusBadRequest)
160                 }
161         }))
162         defer ts.Close()
163
164         var end = regexp.MustCompile("/foo/$")
165         r, url, err := Get(ts.URL)
166         if err != nil {
167                 t.Fatal(err)
168         }
169         r.Body.Close()
170         if r.StatusCode != 200 || !end.MatchString(url) {
171                 t.Fatalf("Get got status %d at %q, want 200 matching /foo/$", r.StatusCode, url)
172         }
173 }
174
175 func TestMultipartRequest(t *testing.T) {
176         // Test that we can read the values and files of a 
177         // multipart request with FormValue and FormFile,
178         // and that ParseMultipartForm can be called multiple times.
179         req := newTestMultipartRequest(t)
180         if err := req.ParseMultipartForm(25); err != nil {
181                 t.Fatal("ParseMultipartForm first call:", err)
182         }
183         defer req.MultipartForm.RemoveAll()
184         validateTestMultipartContents(t, req, false)
185         if err := req.ParseMultipartForm(25); err != nil {
186                 t.Fatal("ParseMultipartForm second call:", err)
187         }
188         validateTestMultipartContents(t, req, false)
189 }
190
191 func TestMultipartRequestAuto(t *testing.T) {
192         // Test that FormValue and FormFile automatically invoke
193         // ParseMultipartForm and return the right values.
194         req := newTestMultipartRequest(t)
195         defer func() {
196                 if req.MultipartForm != nil {
197                         req.MultipartForm.RemoveAll()
198                 }
199         }()
200         validateTestMultipartContents(t, req, true)
201 }
202
203 func TestEmptyMultipartRequest(t *testing.T) {
204         // Test that FormValue and FormFile automatically invoke
205         // ParseMultipartForm and return the right values.
206         req, err := NewRequest("GET", "/", nil)
207         if err != nil {
208                 t.Errorf("NewRequest err = %q", err)
209         }
210         testMissingFile(t, req)
211 }
212
213 func testMissingFile(t *testing.T, req *Request) {
214         f, fh, err := req.FormFile("missing")
215         if f != nil {
216                 t.Errorf("FormFile file = %q, want nil", f, nil)
217         }
218         if fh != nil {
219                 t.Errorf("FormFile file header = %q, want nil", fh, nil)
220         }
221         if err != ErrMissingFile {
222                 t.Errorf("FormFile err = %q, want nil", err, ErrMissingFile)
223         }
224 }
225
226 func newTestMultipartRequest(t *testing.T) *Request {
227         b := bytes.NewBufferString(strings.Replace(message, "\n", "\r\n", -1))
228         req, err := NewRequest("POST", "/", b)
229         if err != nil {
230                 t.Fatalf("NewRequest:", err)
231         }
232         ctype := fmt.Sprintf(`multipart/form-data; boundary="%s"`, boundary)
233         req.Header.Set("Content-type", ctype)
234         return req
235 }
236
237 func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) {
238         if g, e := req.FormValue("texta"), textaValue; g != e {
239                 t.Errorf("texta value = %q, want %q", g, e)
240         }
241         if g, e := req.FormValue("texta"), textaValue; g != e {
242                 t.Errorf("texta value = %q, want %q", g, e)
243         }
244         if g := req.FormValue("missing"); g != "" {
245                 t.Errorf("missing value = %q, want empty string", g)
246         }
247
248         assertMem := func(n string, fd multipart.File) {
249                 if _, ok := fd.(*os.File); ok {
250                         t.Error(n, " is *os.File, should not be")
251                 }
252         }
253         fd := testMultipartFile(t, req, "filea", "filea.txt", fileaContents)
254         assertMem("filea", fd)
255         fd = testMultipartFile(t, req, "fileb", "fileb.txt", filebContents)
256         if allMem {
257                 assertMem("fileb", fd)
258         } else {
259                 if _, ok := fd.(*os.File); !ok {
260                         t.Errorf("fileb has unexpected underlying type %T", fd)
261                 }
262         }
263
264         testMissingFile(t, req)
265 }
266
267 func testMultipartFile(t *testing.T, req *Request, key, expectFilename, expectContent string) multipart.File {
268         f, fh, err := req.FormFile(key)
269         if err != nil {
270                 t.Fatalf("FormFile(%q):", key, err)
271         }
272         if fh.Filename != expectFilename {
273                 t.Errorf("filename = %q, want %q", fh.Filename, expectFilename)
274         }
275         var b bytes.Buffer
276         _, err = io.Copy(&b, f)
277         if err != nil {
278                 t.Fatal("copying contents:", err)
279         }
280         if g := b.String(); g != expectContent {
281                 t.Errorf("contents = %q, want %q", g, expectContent)
282         }
283         return f
284 }
285
286 const (
287         fileaContents = "This is a test file."
288         filebContents = "Another test file."
289         textaValue    = "foo"
290         textbValue    = "bar"
291         boundary      = `MyBoundary`
292 )
293
294 const message = `
295 --MyBoundary
296 Content-Disposition: form-data; name="filea"; filename="filea.txt"
297 Content-Type: text/plain
298
299 ` + fileaContents + `
300 --MyBoundary
301 Content-Disposition: form-data; name="fileb"; filename="fileb.txt"
302 Content-Type: text/plain
303
304 ` + filebContents + `
305 --MyBoundary
306 Content-Disposition: form-data; name="texta"
307
308 ` + textaValue + `
309 --MyBoundary
310 Content-Disposition: form-data; name="textb"
311
312 ` + textbValue + `
313 --MyBoundary--
314 `