Black Lives Matter. Support the Equal Justice Initiative.

Source file src/net/http/responsewrite_test.go

Documentation: net/http

     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"
    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:          io.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:          io.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:          io.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:          io.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:             io.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:          io.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:          io.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:             io.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  		// When a response to a POST has Content-Length: -1, make sure we don't
   212  		// write the Content-Length as -1.
   213  		{
   214  			Response{
   215  				StatusCode:    StatusOK,
   216  				ProtoMajor:    1,
   217  				ProtoMinor:    1,
   218  				Request:       &Request{Method: "POST"},
   219  				Header:        Header{},
   220  				ContentLength: -1,
   221  				Body:          io.NopCloser(strings.NewReader("abcdef")),
   222  			},
   223  			"HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nabcdef",
   224  		},
   225  
   226  		// Status code under 100 should be zero-padded to
   227  		// three digits.  Still bogus, but less bogus. (be
   228  		// consistent with generating three digits, since the
   229  		// Transport requires it)
   230  		{
   231  			Response{
   232  				StatusCode: 7,
   233  				Status:     "license to violate specs",
   234  				ProtoMajor: 1,
   235  				ProtoMinor: 0,
   236  				Request:    dummyReq("GET"),
   237  				Header:     Header{},
   238  				Body:       nil,
   239  			},
   240  
   241  			"HTTP/1.0 007 license to violate specs\r\nContent-Length: 0\r\n\r\n",
   242  		},
   243  
   244  		// No stutter.  Status code in 1xx range response should
   245  		// not include a Content-Length header.  See issue #16942.
   246  		{
   247  			Response{
   248  				StatusCode: 123,
   249  				Status:     "123 Sesame Street",
   250  				ProtoMajor: 1,
   251  				ProtoMinor: 0,
   252  				Request:    dummyReq("GET"),
   253  				Header:     Header{},
   254  				Body:       nil,
   255  			},
   256  
   257  			"HTTP/1.0 123 Sesame Street\r\n\r\n",
   258  		},
   259  
   260  		// Status code 204 (No content) response should not include a
   261  		// Content-Length header.  See issue #16942.
   262  		{
   263  			Response{
   264  				StatusCode: 204,
   265  				Status:     "No Content",
   266  				ProtoMajor: 1,
   267  				ProtoMinor: 0,
   268  				Request:    dummyReq("GET"),
   269  				Header:     Header{},
   270  				Body:       nil,
   271  			},
   272  
   273  			"HTTP/1.0 204 No Content\r\n\r\n",
   274  		},
   275  	}
   276  
   277  	for i := range respWriteTests {
   278  		tt := &respWriteTests[i]
   279  		var braw bytes.Buffer
   280  		err := tt.Resp.Write(&braw)
   281  		if err != nil {
   282  			t.Errorf("error writing #%d: %s", i, err)
   283  			continue
   284  		}
   285  		sraw := braw.String()
   286  		if sraw != tt.Raw {
   287  			t.Errorf("Test %d, expecting:\n%q\nGot:\n%q\n", i, tt.Raw, sraw)
   288  			continue
   289  		}
   290  	}
   291  }
   292  

View as plain text