client_test.go (3706B)
1 // GoToSocial 2 // Copyright (C) GoToSocial Authors admin@gotosocial.org 3 // SPDX-License-Identifier: AGPL-3.0-or-later 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package httpclient_test 19 20 import ( 21 "bytes" 22 "errors" 23 "io" 24 "net/http" 25 "net/http/httptest" 26 "net/netip" 27 "testing" 28 29 "github.com/superseriousbusiness/gotosocial/internal/httpclient" 30 ) 31 32 var privateIPs = []string{ 33 "http://127.0.0.1:80", 34 "http://0.0.0.0:80", 35 "http://192.168.0.1:80", 36 "http://192.168.1.0:80", 37 "http://10.0.0.0:80", 38 "http://172.16.0.0:80", 39 "http://10.255.255.255:80", 40 "http://172.31.255.255:80", 41 "http://255.255.255.255:80", 42 } 43 44 var bodies = []string{ 45 "hello world!", 46 "{}", 47 `{"key": "value", "some": "kinda bullshit"}`, 48 "body with\r\nnewlines", 49 } 50 51 func TestHTTPClientSmallBody(t *testing.T) { 52 for _, body := range bodies { 53 _TestHTTPClientWithBody(t, []byte(body), int(^uint16(0))) 54 } 55 } 56 57 func TestHTTPClientExactBody(t *testing.T) { 58 for _, body := range bodies { 59 _TestHTTPClientWithBody(t, []byte(body), len(body)) 60 } 61 } 62 63 func TestHTTPClientLargeBody(t *testing.T) { 64 for _, body := range bodies { 65 _TestHTTPClientWithBody(t, []byte(body), len(body)-1) 66 } 67 } 68 69 func _TestHTTPClientWithBody(t *testing.T, body []byte, max int) { 70 var ( 71 handler http.HandlerFunc 72 73 expect []byte 74 75 expectErr error 76 ) 77 78 // If this is a larger body, reslice and 79 // set error so we know what to expect 80 expect = body 81 if max < len(body) { 82 expect = expect[:max] 83 expectErr = httpclient.ErrBodyTooLarge 84 } 85 86 // Create new HTTP client with maximum body size 87 client := httpclient.New(httpclient.Config{ 88 MaxBodySize: int64(max), 89 DisableCompression: true, 90 AllowRanges: []netip.Prefix{ 91 // Loopback (used by server) 92 netip.MustParsePrefix("127.0.0.1/8"), 93 }, 94 }) 95 96 // Set simple body-writing test handler 97 handler = func(rw http.ResponseWriter, r *http.Request) { 98 _, _ = rw.Write(body) 99 } 100 101 // Start the test server 102 srv := httptest.NewServer(handler) 103 defer srv.Close() 104 105 // Wrap body to provide reader iface 106 rbody := bytes.NewReader(body) 107 108 // Create the test HTTP request 109 req, _ := http.NewRequest("POST", srv.URL, rbody) 110 111 // Perform the test request 112 rsp, err := client.Do(req) 113 if !errors.Is(err, expectErr) { 114 t.Fatalf("error performing client request: %v", err) 115 } else if err != nil { 116 return // expected error 117 } 118 defer rsp.Body.Close() 119 120 // Read response body into memory 121 check, err := io.ReadAll(rsp.Body) 122 if err != nil { 123 t.Fatalf("error reading response body: %v", err) 124 } 125 126 // Check actual response body matches expected 127 if !bytes.Equal(expect, check) { 128 t.Errorf("response body did not match expected: expect=%q actual=%q", string(expect), string(check)) 129 } 130 } 131 132 func TestHTTPClientPrivateIP(t *testing.T) { 133 client := httpclient.New(httpclient.Config{}) 134 135 for _, addr := range privateIPs { 136 // Prepare request to private IP 137 req, _ := http.NewRequest("GET", addr, nil) 138 139 // Perform the HTTP request 140 _, err := client.Do(req) 141 if !errors.Is(err, httpclient.ErrReservedAddr) { 142 t.Errorf("dialing private address did not return expected error: %v", err) 143 } 144 } 145 }