OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [net/] [http/] [response_test.go] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2010 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
6
 
7
import (
8
        "bufio"
9
        "bytes"
10
        "compress/gzip"
11
        "crypto/rand"
12
        "fmt"
13
        "io"
14
        "io/ioutil"
15
        "net/url"
16
        "reflect"
17
        "testing"
18
)
19
 
20
type respTest struct {
21
        Raw  string
22
        Resp Response
23
        Body string
24
}
25
 
26
func dummyReq(method string) *Request {
27
        return &Request{Method: method}
28
}
29
 
30
var respTests = []respTest{
31
        // Unchunked response without Content-Length.
32
        {
33
                "HTTP/1.0 200 OK\r\n" +
34
                        "Connection: close\r\n" +
35
                        "\r\n" +
36
                        "Body here\n",
37
 
38
                Response{
39
                        Status:     "200 OK",
40
                        StatusCode: 200,
41
                        Proto:      "HTTP/1.0",
42
                        ProtoMajor: 1,
43
                        ProtoMinor: 0,
44
                        Request:    dummyReq("GET"),
45
                        Header: Header{
46
                                "Connection": {"close"}, // TODO(rsc): Delete?
47
                        },
48
                        Close:         true,
49
                        ContentLength: -1,
50
                },
51
 
52
                "Body here\n",
53
        },
54
 
55
        // Unchunked HTTP/1.1 response without Content-Length or
56
        // Connection headers.
57
        {
58
                "HTTP/1.1 200 OK\r\n" +
59
                        "\r\n" +
60
                        "Body here\n",
61
 
62
                Response{
63
                        Status:        "200 OK",
64
                        StatusCode:    200,
65
                        Proto:         "HTTP/1.1",
66
                        ProtoMajor:    1,
67
                        ProtoMinor:    1,
68
                        Header:        Header{},
69
                        Request:       dummyReq("GET"),
70
                        Close:         true,
71
                        ContentLength: -1,
72
                },
73
 
74
                "Body here\n",
75
        },
76
 
77
        // Unchunked HTTP/1.1 204 response without Content-Length.
78
        {
79
                "HTTP/1.1 204 No Content\r\n" +
80
                        "\r\n" +
81
                        "Body should not be read!\n",
82
 
83
                Response{
84
                        Status:        "204 No Content",
85
                        StatusCode:    204,
86
                        Proto:         "HTTP/1.1",
87
                        ProtoMajor:    1,
88
                        ProtoMinor:    1,
89
                        Header:        Header{},
90
                        Request:       dummyReq("GET"),
91
                        Close:         false,
92
                        ContentLength: 0,
93
                },
94
 
95
                "",
96
        },
97
 
98
        // Unchunked response with Content-Length.
99
        {
100
                "HTTP/1.0 200 OK\r\n" +
101
                        "Content-Length: 10\r\n" +
102
                        "Connection: close\r\n" +
103
                        "\r\n" +
104
                        "Body here\n",
105
 
106
                Response{
107
                        Status:     "200 OK",
108
                        StatusCode: 200,
109
                        Proto:      "HTTP/1.0",
110
                        ProtoMajor: 1,
111
                        ProtoMinor: 0,
112
                        Request:    dummyReq("GET"),
113
                        Header: Header{
114
                                "Connection":     {"close"}, // TODO(rsc): Delete?
115
                                "Content-Length": {"10"},    // TODO(rsc): Delete?
116
                        },
117
                        Close:         true,
118
                        ContentLength: 10,
119
                },
120
 
121
                "Body here\n",
122
        },
123
 
124
        // Chunked response without Content-Length.
125
        {
126
                "HTTP/1.0 200 OK\r\n" +
127
                        "Transfer-Encoding: chunked\r\n" +
128
                        "\r\n" +
129
                        "0a\r\n" +
130
                        "Body here\n\r\n" +
131
                        "09\r\n" +
132
                        "continued\r\n" +
133
                        "0\r\n" +
134
                        "\r\n",
135
 
136
                Response{
137
                        Status:           "200 OK",
138
                        StatusCode:       200,
139
                        Proto:            "HTTP/1.0",
140
                        ProtoMajor:       1,
141
                        ProtoMinor:       0,
142
                        Request:          dummyReq("GET"),
143
                        Header:           Header{},
144
                        Close:            true,
145
                        ContentLength:    -1,
146
                        TransferEncoding: []string{"chunked"},
147
                },
148
 
149
                "Body here\ncontinued",
150
        },
151
 
152
        // Chunked response with Content-Length.
153
        {
154
                "HTTP/1.0 200 OK\r\n" +
155
                        "Transfer-Encoding: chunked\r\n" +
156
                        "Content-Length: 10\r\n" +
157
                        "\r\n" +
158
                        "0a\r\n" +
159
                        "Body here\n" +
160
                        "0\r\n" +
161
                        "\r\n",
162
 
163
                Response{
164
                        Status:           "200 OK",
165
                        StatusCode:       200,
166
                        Proto:            "HTTP/1.0",
167
                        ProtoMajor:       1,
168
                        ProtoMinor:       0,
169
                        Request:          dummyReq("GET"),
170
                        Header:           Header{},
171
                        Close:            true,
172
                        ContentLength:    -1, // TODO(rsc): Fix?
173
                        TransferEncoding: []string{"chunked"},
174
                },
175
 
176
                "Body here\n",
177
        },
178
 
179
        // Chunked response in response to a HEAD request (the "chunked" should
180
        // be ignored, as HEAD responses never have bodies)
181
        {
182
                "HTTP/1.0 200 OK\r\n" +
183
                        "Transfer-Encoding: chunked\r\n" +
184
                        "\r\n",
185
 
186
                Response{
187
                        Status:        "200 OK",
188
                        StatusCode:    200,
189
                        Proto:         "HTTP/1.0",
190
                        ProtoMajor:    1,
191
                        ProtoMinor:    0,
192
                        Request:       dummyReq("HEAD"),
193
                        Header:        Header{},
194
                        Close:         true,
195
                        ContentLength: 0,
196
                },
197
 
198
                "",
199
        },
200
 
201
        // explicit Content-Length of 0.
202
        {
203
                "HTTP/1.1 200 OK\r\n" +
204
                        "Content-Length: 0\r\n" +
205
                        "\r\n",
206
 
207
                Response{
208
                        Status:     "200 OK",
209
                        StatusCode: 200,
210
                        Proto:      "HTTP/1.1",
211
                        ProtoMajor: 1,
212
                        ProtoMinor: 1,
213
                        Request:    dummyReq("GET"),
214
                        Header: Header{
215
                                "Content-Length": {"0"},
216
                        },
217
                        Close:         false,
218
                        ContentLength: 0,
219
                },
220
 
221
                "",
222
        },
223
 
224
        // Status line without a Reason-Phrase, but trailing space.
225
        // (permitted by RFC 2616)
226
        {
227
                "HTTP/1.0 303 \r\n\r\n",
228
                Response{
229
                        Status:        "303 ",
230
                        StatusCode:    303,
231
                        Proto:         "HTTP/1.0",
232
                        ProtoMajor:    1,
233
                        ProtoMinor:    0,
234
                        Request:       dummyReq("GET"),
235
                        Header:        Header{},
236
                        Close:         true,
237
                        ContentLength: -1,
238
                },
239
 
240
                "",
241
        },
242
 
243
        // Status line without a Reason-Phrase, and no trailing space.
244
        // (not permitted by RFC 2616, but we'll accept it anyway)
245
        {
246
                "HTTP/1.0 303\r\n\r\n",
247
                Response{
248
                        Status:        "303 ",
249
                        StatusCode:    303,
250
                        Proto:         "HTTP/1.0",
251
                        ProtoMajor:    1,
252
                        ProtoMinor:    0,
253
                        Request:       dummyReq("GET"),
254
                        Header:        Header{},
255
                        Close:         true,
256
                        ContentLength: -1,
257
                },
258
 
259
                "",
260
        },
261
}
262
 
263
func TestReadResponse(t *testing.T) {
264
        for i := range respTests {
265
                tt := &respTests[i]
266
                var braw bytes.Buffer
267
                braw.WriteString(tt.Raw)
268
                resp, err := ReadResponse(bufio.NewReader(&braw), tt.Resp.Request)
269
                if err != nil {
270
                        t.Errorf("#%d: %s", i, err)
271
                        continue
272
                }
273
                rbody := resp.Body
274
                resp.Body = nil
275
                diff(t, fmt.Sprintf("#%d Response", i), resp, &tt.Resp)
276
                var bout bytes.Buffer
277
                if rbody != nil {
278
                        io.Copy(&bout, rbody)
279
                        rbody.Close()
280
                }
281
                body := bout.String()
282
                if body != tt.Body {
283
                        t.Errorf("#%d: Body = %q want %q", i, body, tt.Body)
284
                }
285
        }
286
}
287
 
288
var readResponseCloseInMiddleTests = []struct {
289
        chunked, compressed bool
290
}{
291
        {false, false},
292
        {true, false},
293
        {true, true},
294
}
295
 
296
// TestReadResponseCloseInMiddle tests that closing a body after
297
// reading only part of its contents advances the read to the end of
298
// the request, right up until the next request.
299
func TestReadResponseCloseInMiddle(t *testing.T) {
300
        for _, test := range readResponseCloseInMiddleTests {
301
                fatalf := func(format string, args ...interface{}) {
302
                        args = append([]interface{}{test.chunked, test.compressed}, args...)
303
                        t.Fatalf("on test chunked=%v, compressed=%v: "+format, args...)
304
                }
305
                checkErr := func(err error, msg string) {
306
                        if err == nil {
307
                                return
308
                        }
309
                        fatalf(msg+": %v", err)
310
                }
311
                var buf bytes.Buffer
312
                buf.WriteString("HTTP/1.1 200 OK\r\n")
313
                if test.chunked {
314
                        buf.WriteString("Transfer-Encoding: chunked\r\n")
315
                } else {
316
                        buf.WriteString("Content-Length: 1000000\r\n")
317
                }
318
                var wr io.Writer = &buf
319
                if test.chunked {
320
                        wr = newChunkedWriter(wr)
321
                }
322
                if test.compressed {
323
                        buf.WriteString("Content-Encoding: gzip\r\n")
324
                        var err error
325
                        wr, err = gzip.NewWriter(wr)
326
                        checkErr(err, "gzip.NewWriter")
327
                }
328
                buf.WriteString("\r\n")
329
 
330
                chunk := bytes.Repeat([]byte{'x'}, 1000)
331
                for i := 0; i < 1000; i++ {
332
                        if test.compressed {
333
                                // Otherwise this compresses too well.
334
                                _, err := io.ReadFull(rand.Reader, chunk)
335
                                checkErr(err, "rand.Reader ReadFull")
336
                        }
337
                        wr.Write(chunk)
338
                }
339
                if test.compressed {
340
                        err := wr.(*gzip.Compressor).Close()
341
                        checkErr(err, "compressor close")
342
                }
343
                if test.chunked {
344
                        buf.WriteString("0\r\n\r\n")
345
                }
346
                buf.WriteString("Next Request Here")
347
 
348
                bufr := bufio.NewReader(&buf)
349
                resp, err := ReadResponse(bufr, dummyReq("GET"))
350
                checkErr(err, "ReadResponse")
351
                expectedLength := int64(-1)
352
                if !test.chunked {
353
                        expectedLength = 1000000
354
                }
355
                if resp.ContentLength != expectedLength {
356
                        fatalf("expected response length %d, got %d", expectedLength, resp.ContentLength)
357
                }
358
                if resp.Body == nil {
359
                        fatalf("nil body")
360
                }
361
                if test.compressed {
362
                        gzReader, err := gzip.NewReader(resp.Body)
363
                        checkErr(err, "gzip.NewReader")
364
                        resp.Body = &readFirstCloseBoth{gzReader, resp.Body}
365
                }
366
 
367
                rbuf := make([]byte, 2500)
368
                n, err := io.ReadFull(resp.Body, rbuf)
369
                checkErr(err, "2500 byte ReadFull")
370
                if n != 2500 {
371
                        fatalf("ReadFull only read %d bytes", n)
372
                }
373
                if test.compressed == false && !bytes.Equal(bytes.Repeat([]byte{'x'}, 2500), rbuf) {
374
                        fatalf("ReadFull didn't read 2500 'x'; got %q", string(rbuf))
375
                }
376
                resp.Body.Close()
377
 
378
                rest, err := ioutil.ReadAll(bufr)
379
                checkErr(err, "ReadAll on remainder")
380
                if e, g := "Next Request Here", string(rest); e != g {
381
                        fatalf("remainder = %q, expected %q", g, e)
382
                }
383
        }
384
}
385
 
386
func diff(t *testing.T, prefix string, have, want interface{}) {
387
        hv := reflect.ValueOf(have).Elem()
388
        wv := reflect.ValueOf(want).Elem()
389
        if hv.Type() != wv.Type() {
390
                t.Errorf("%s: type mismatch %v want %v", prefix, hv.Type(), wv.Type())
391
        }
392
        for i := 0; i < hv.NumField(); i++ {
393
                hf := hv.Field(i).Interface()
394
                wf := wv.Field(i).Interface()
395
                if !reflect.DeepEqual(hf, wf) {
396
                        t.Errorf("%s: %s = %v want %v", prefix, hv.Type().Field(i).Name, hf, wf)
397
                }
398
        }
399
}
400
 
401
type responseLocationTest struct {
402
        location string // Response's Location header or ""
403
        requrl   string // Response.Request.URL or ""
404
        want     string
405
        wantErr  error
406
}
407
 
408
var responseLocationTests = []responseLocationTest{
409
        {"/foo", "http://bar.com/baz", "http://bar.com/foo", nil},
410
        {"http://foo.com/", "http://bar.com/baz", "http://foo.com/", nil},
411
        {"", "http://bar.com/baz", "", ErrNoLocation},
412
}
413
 
414
func TestLocationResponse(t *testing.T) {
415
        for i, tt := range responseLocationTests {
416
                res := new(Response)
417
                res.Header = make(Header)
418
                res.Header.Set("Location", tt.location)
419
                if tt.requrl != "" {
420
                        res.Request = &Request{}
421
                        var err error
422
                        res.Request.URL, err = url.Parse(tt.requrl)
423
                        if err != nil {
424
                                t.Fatalf("bad test URL %q: %v", tt.requrl, err)
425
                        }
426
                }
427
 
428
                got, err := res.Location()
429
                if tt.wantErr != nil {
430
                        if err == nil {
431
                                t.Errorf("%d. err=nil; want %q", i, tt.wantErr)
432
                                continue
433
                        }
434
                        if g, e := err.Error(), tt.wantErr.Error(); g != e {
435
                                t.Errorf("%d. err=%q; want %q", i, g, e)
436
                                continue
437
                        }
438
                        continue
439
                }
440
                if err != nil {
441
                        t.Errorf("%d. err=%q", i, err)
442
                        continue
443
                }
444
                if g, e := got.String(), tt.want; g != e {
445
                        t.Errorf("%d. Location=%q; want %q", i, g, e)
446
                }
447
        }
448
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.