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 }