OSDN Git Service

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