github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/net/http/responsewrite_test.go (about)

     1  // 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  	"bytes"
     9  	"io/ioutil"
    10  	"strings"
    11  	"testing"
    12  )
    13  
    14  type respWriteTest struct {
    15  	Resp Response
    16  	Raw  string
    17  }
    18  
    19  func TestResponseWrite(t *testing.T) {
    20  	respWriteTests := []respWriteTest{
    21  		// HTTP/1.0, identity coding; no trailer
    22  		{
    23  			Response{
    24  				StatusCode:    503,
    25  				ProtoMajor:    1,
    26  				ProtoMinor:    0,
    27  				Request:       dummyReq("GET"),
    28  				Header:        Header{},
    29  				Body:          ioutil.NopCloser(strings.NewReader("abcdef")),
    30  				ContentLength: 6,
    31  			},
    32  
    33  			"HTTP/1.0 503 Service Unavailable\r\n" +
    34  				"Content-Length: 6\r\n\r\n" +
    35  				"abcdef",
    36  		},
    37  		// Unchunked response without Content-Length.
    38  		{
    39  			Response{
    40  				StatusCode:    200,
    41  				ProtoMajor:    1,
    42  				ProtoMinor:    0,
    43  				Request:       dummyReq("GET"),
    44  				Header:        Header{},
    45  				Body:          ioutil.NopCloser(strings.NewReader("abcdef")),
    46  				ContentLength: -1,
    47  			},
    48  			"HTTP/1.0 200 OK\r\n" +
    49  				"\r\n" +
    50  				"abcdef",
    51  		},
    52  		// HTTP/1.1 response with unknown length and Connection: close
    53  		{
    54  			Response{
    55  				StatusCode:    200,
    56  				ProtoMajor:    1,
    57  				ProtoMinor:    1,
    58  				Request:       dummyReq("GET"),
    59  				Header:        Header{},
    60  				Body:          ioutil.NopCloser(strings.NewReader("abcdef")),
    61  				ContentLength: -1,
    62  				Close:         true,
    63  			},
    64  			"HTTP/1.1 200 OK\r\n" +
    65  				"Connection: close\r\n" +
    66  				"\r\n" +
    67  				"abcdef",
    68  		},
    69  		// HTTP/1.1 response with unknown length and not setting connection: close
    70  		{
    71  			Response{
    72  				StatusCode:    200,
    73  				ProtoMajor:    1,
    74  				ProtoMinor:    1,
    75  				Request:       dummyReq11("GET"),
    76  				Header:        Header{},
    77  				Body:          ioutil.NopCloser(strings.NewReader("abcdef")),
    78  				ContentLength: -1,
    79  				Close:         false,
    80  			},
    81  			"HTTP/1.1 200 OK\r\n" +
    82  				"Connection: close\r\n" +
    83  				"\r\n" +
    84  				"abcdef",
    85  		},
    86  		// HTTP/1.1 response with unknown length and not setting connection: close, but
    87  		// setting chunked.
    88  		{
    89  			Response{
    90  				StatusCode:       200,
    91  				ProtoMajor:       1,
    92  				ProtoMinor:       1,
    93  				Request:          dummyReq11("GET"),
    94  				Header:           Header{},
    95  				Body:             ioutil.NopCloser(strings.NewReader("abcdef")),
    96  				ContentLength:    -1,
    97  				TransferEncoding: []string{"chunked"},
    98  				Close:            false,
    99  			},
   100  			"HTTP/1.1 200 OK\r\n" +
   101  				"Transfer-Encoding: chunked\r\n\r\n" +
   102  				"6\r\nabcdef\r\n0\r\n\r\n",
   103  		},
   104  		// HTTP/1.1 response 0 content-length, and nil body
   105  		{
   106  			Response{
   107  				StatusCode:    200,
   108  				ProtoMajor:    1,
   109  				ProtoMinor:    1,
   110  				Request:       dummyReq11("GET"),
   111  				Header:        Header{},
   112  				Body:          nil,
   113  				ContentLength: 0,
   114  				Close:         false,
   115  			},
   116  			"HTTP/1.1 200 OK\r\n" +
   117  				"Content-Length: 0\r\n" +
   118  				"\r\n",
   119  		},
   120  		// HTTP/1.1 response 0 content-length, and non-nil empty body
   121  		{
   122  			Response{
   123  				StatusCode:    200,
   124  				ProtoMajor:    1,
   125  				ProtoMinor:    1,
   126  				Request:       dummyReq11("GET"),
   127  				Header:        Header{},
   128  				Body:          ioutil.NopCloser(strings.NewReader("")),
   129  				ContentLength: 0,
   130  				Close:         false,
   131  			},
   132  			"HTTP/1.1 200 OK\r\n" +
   133  				"Content-Length: 0\r\n" +
   134  				"\r\n",
   135  		},
   136  		// HTTP/1.1 response 0 content-length, and non-nil non-empty body
   137  		{
   138  			Response{
   139  				StatusCode:    200,
   140  				ProtoMajor:    1,
   141  				ProtoMinor:    1,
   142  				Request:       dummyReq11("GET"),
   143  				Header:        Header{},
   144  				Body:          ioutil.NopCloser(strings.NewReader("foo")),
   145  				ContentLength: 0,
   146  				Close:         false,
   147  			},
   148  			"HTTP/1.1 200 OK\r\n" +
   149  				"Connection: close\r\n" +
   150  				"\r\nfoo",
   151  		},
   152  		// HTTP/1.1, chunked coding; empty trailer; close
   153  		{
   154  			Response{
   155  				StatusCode:       200,
   156  				ProtoMajor:       1,
   157  				ProtoMinor:       1,
   158  				Request:          dummyReq("GET"),
   159  				Header:           Header{},
   160  				Body:             ioutil.NopCloser(strings.NewReader("abcdef")),
   161  				ContentLength:    6,
   162  				TransferEncoding: []string{"chunked"},
   163  				Close:            true,
   164  			},
   165  
   166  			"HTTP/1.1 200 OK\r\n" +
   167  				"Connection: close\r\n" +
   168  				"Transfer-Encoding: chunked\r\n\r\n" +
   169  				"6\r\nabcdef\r\n0\r\n\r\n",
   170  		},
   171  
   172  		// Header value with a newline character (Issue 914).
   173  		// Also tests removal of leading and trailing whitespace.
   174  		{
   175  			Response{
   176  				StatusCode: 204,
   177  				ProtoMajor: 1,
   178  				ProtoMinor: 1,
   179  				Request:    dummyReq("GET"),
   180  				Header: Header{
   181  					"Foo": []string{" Bar\nBaz "},
   182  				},
   183  				Body:             nil,
   184  				ContentLength:    0,
   185  				TransferEncoding: []string{"chunked"},
   186  				Close:            true,
   187  			},
   188  
   189  			"HTTP/1.1 204 No Content\r\n" +
   190  				"Connection: close\r\n" +
   191  				"Foo: Bar Baz\r\n" +
   192  				"\r\n",
   193  		},
   194  
   195  		// Want a single Content-Length header. Fixing issue 8180 where
   196  		// there were two.
   197  		{
   198  			Response{
   199  				StatusCode:       StatusOK,
   200  				ProtoMajor:       1,
   201  				ProtoMinor:       1,
   202  				Request:          &Request{Method: "POST"},
   203  				Header:           Header{},
   204  				ContentLength:    0,
   205  				TransferEncoding: nil,
   206  				Body:             nil,
   207  			},
   208  			"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
   209  		},
   210  	}
   211  
   212  	for i := range respWriteTests {
   213  		tt := &respWriteTests[i]
   214  		var braw bytes.Buffer
   215  		err := tt.Resp.Write(&braw)
   216  		if err != nil {
   217  			t.Errorf("error writing #%d: %s", i, err)
   218  			continue
   219  		}
   220  		sraw := braw.String()
   221  		if sraw != tt.Raw {
   222  			t.Errorf("Test %d, expecting:\n%q\nGot:\n%q\n", i, tt.Raw, sraw)
   223  			continue
   224  		}
   225  	}
   226  }