github.com/yandex/pandora@v0.5.32/components/providers/http/decoders/raw/decoder_test.go (about)

     1  package raw
     2  
     3  import (
     4  	"errors"
     5  	"net/http"
     6  	"net/url"
     7  	"testing"
     8  	"testing/iotest"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  type DecoderHeaderWant struct {
    15  	reqSize int
    16  	tag     string
    17  	err     error
    18  }
    19  
    20  func TestDecodeHeader(t *testing.T) {
    21  	tests := []struct {
    22  		name  string
    23  		input string
    24  		want  DecoderHeaderWant
    25  	}{
    26  		{
    27  			name:  "should parse header with tag",
    28  			input: "123 tag",
    29  			want:  DecoderHeaderWant{123, "tag", nil},
    30  		},
    31  		{
    32  			name:  "should parse header without tag",
    33  			input: "123",
    34  			want:  DecoderHeaderWant{123, "", nil},
    35  		},
    36  	}
    37  	var ans DecoderHeaderWant
    38  	for _, tt := range tests {
    39  		t.Run(tt.name, func(t *testing.T) {
    40  			assert := assert.New(t)
    41  			ans.reqSize, ans.tag, ans.err = DecodeHeader(tt.input)
    42  			assert.Equal(tt.want, ans)
    43  		})
    44  	}
    45  }
    46  
    47  type DecoderRequestWant struct {
    48  	req  *http.Request
    49  	err  error
    50  	body []byte
    51  }
    52  
    53  func TestDecodeRequest(t *testing.T) {
    54  	tests := []struct {
    55  		name  string
    56  		input []byte
    57  		want  DecoderRequestWant
    58  	}{
    59  		{
    60  			name: "should parse GET request",
    61  			input: []byte("GET /some/path HTTP/1.0\r\n" +
    62  				"Host: foo.com\r\n" +
    63  				"Connection: close\r\n\r\n"),
    64  			want: DecoderRequestWant{
    65  				&http.Request{
    66  					Method:     "GET",
    67  					URL:        MustURL(t, "/some/path"),
    68  					Proto:      "HTTP/1.0",
    69  					ProtoMajor: 1,
    70  					ProtoMinor: 0,
    71  					Host:       "foo.com",
    72  					Header:     http.Header{"Connection": []string{"close"}},
    73  					Body:       http.NoBody,
    74  					Close:      true, // FIXME: BUG: should we say to close connection?
    75  				}, nil, nil,
    76  			},
    77  		},
    78  		{
    79  			name: "should parse POST request with body",
    80  			input: []byte("POST /some/path HTTP/1.1\r\n" +
    81  				"Host: foo.com\r\n" +
    82  				"Transfer-Encoding: chunked\r\n" +
    83  				"Foo: bar\r\n" +
    84  				"Content-Length: 9999\r\n\r\n" + // to be removed.
    85  				"3\r\nfoo\r\n" +
    86  				"3\r\nbar\r\n" +
    87  				"0\r\n" +
    88  				"\r\n"),
    89  			want: DecoderRequestWant{
    90  				&http.Request{
    91  					Method:           "POST",
    92  					URL:              MustURL(t, "/some/path"),
    93  					Proto:            "HTTP/1.1",
    94  					ProtoMajor:       1,
    95  					ProtoMinor:       1,
    96  					Host:             "foo.com",
    97  					Header:           http.Header{"Foo": []string{"bar"}},
    98  					Body:             nil,
    99  					ContentLength:    -1,
   100  					TransferEncoding: []string{"chunked"},
   101  				}, nil, []byte("foobar"),
   102  			},
   103  		},
   104  		{
   105  			name: "should return error on bad urls",
   106  			input: []byte("GET ../../../../etc/passwd HTTP/1.1\r\n" +
   107  				"Host: foo.com\r\n" +
   108  				"Content-Length: 0\r\n" +
   109  				"\r\n"),
   110  			want: DecoderRequestWant{
   111  				nil, &url.Error{
   112  					Op:  "parse",
   113  					URL: "../../../../etc/passwd",
   114  					Err: errors.New("invalid URI for request"),
   115  				},
   116  				nil,
   117  			},
   118  		},
   119  		{
   120  			name: "should replace header Host for URL if specified",
   121  			input: []byte("GET /etc/passwd HTTP/1.1\r\n" +
   122  				"Host: hostname.tld\r\n" +
   123  				"Content-Length: 0\r\n" +
   124  				"\r\n"),
   125  			want: DecoderRequestWant{
   126  				&http.Request{
   127  					Method:     "GET",
   128  					URL:        MustURL(t, "/etc/passwd"),
   129  					Proto:      "HTTP/1.1",
   130  					ProtoMajor: 1,
   131  					ProtoMinor: 1,
   132  					Host:       "hostname.tld",
   133  					Header:     http.Header{"Content-Length": []string{"0"}},
   134  					Body:       http.NoBody,
   135  				}, nil, nil,
   136  			},
   137  		},
   138  	}
   139  	var ans DecoderRequestWant
   140  	for _, tt := range tests {
   141  		t.Run(tt.name, func(t *testing.T) {
   142  			assert := assert.New(t)
   143  			ans.req, ans.err = DecodeRequest(tt.input)
   144  			if tt.want.body != nil {
   145  				assert.NotNil(ans.req)
   146  				assert.NoError(iotest.TestReader(ans.req.Body, tt.want.body))
   147  				ans.req.Body = nil
   148  				tt.want.body = nil
   149  			}
   150  			assert.Equal(tt.want, ans)
   151  		})
   152  	}
   153  }
   154  
   155  func MustURL(t *testing.T, rawURL string) *url.URL {
   156  	url, err := url.Parse(rawURL)
   157  	require.NoError(t, err)
   158  	return url
   159  }