github.com/MetalBlockchain/subnet-evm@v0.4.9/rpc/http_test.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2017 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package rpc 28 29 import ( 30 "net/http" 31 "net/http/httptest" 32 "strings" 33 "testing" 34 ) 35 36 func confirmStatusCode(t *testing.T, got, want int) { 37 t.Helper() 38 if got == want { 39 return 40 } 41 if gotName := http.StatusText(got); len(gotName) > 0 { 42 if wantName := http.StatusText(want); len(wantName) > 0 { 43 t.Fatalf("response status code: got %d (%s), want %d (%s)", got, gotName, want, wantName) 44 } 45 } 46 t.Fatalf("response status code: got %d, want %d", got, want) 47 } 48 49 func confirmRequestValidationCode(t *testing.T, method, contentType, body string, expectedStatusCode int) { 50 t.Helper() 51 request := httptest.NewRequest(method, "http://url.com", strings.NewReader(body)) 52 if len(contentType) > 0 { 53 request.Header.Set("Content-Type", contentType) 54 } 55 code, err := validateRequest(request) 56 if code == 0 { 57 if err != nil { 58 t.Errorf("validation: got error %v, expected nil", err) 59 } 60 } else if err == nil { 61 t.Errorf("validation: code %d: got nil, expected error", code) 62 } 63 confirmStatusCode(t, code, expectedStatusCode) 64 } 65 66 func TestHTTPErrorResponseWithDelete(t *testing.T) { 67 confirmRequestValidationCode(t, http.MethodDelete, contentType, "", http.StatusMethodNotAllowed) 68 } 69 70 func TestHTTPErrorResponseWithPut(t *testing.T) { 71 confirmRequestValidationCode(t, http.MethodPut, contentType, "", http.StatusMethodNotAllowed) 72 } 73 74 func TestHTTPErrorResponseWithMaxContentLength(t *testing.T) { 75 body := make([]rune, maxRequestContentLength+1) 76 confirmRequestValidationCode(t, 77 http.MethodPost, contentType, string(body), http.StatusRequestEntityTooLarge) 78 } 79 80 func TestHTTPErrorResponseWithEmptyContentType(t *testing.T) { 81 confirmRequestValidationCode(t, http.MethodPost, "", "", http.StatusUnsupportedMediaType) 82 } 83 84 func TestHTTPErrorResponseWithValidRequest(t *testing.T) { 85 confirmRequestValidationCode(t, http.MethodPost, contentType, "", 0) 86 } 87 88 func confirmHTTPRequestYieldsStatusCode(t *testing.T, method, contentType, body string, expectedStatusCode int) { 89 t.Helper() 90 s := Server{} 91 ts := httptest.NewServer(&s) 92 defer ts.Close() 93 94 request, err := http.NewRequest(method, ts.URL, strings.NewReader(body)) 95 if err != nil { 96 t.Fatalf("failed to create a valid HTTP request: %v", err) 97 } 98 if len(contentType) > 0 { 99 request.Header.Set("Content-Type", contentType) 100 } 101 resp, err := http.DefaultClient.Do(request) 102 if err != nil { 103 t.Fatalf("request failed: %v", err) 104 } 105 confirmStatusCode(t, resp.StatusCode, expectedStatusCode) 106 } 107 108 func TestHTTPResponseWithEmptyGet(t *testing.T) { 109 confirmHTTPRequestYieldsStatusCode(t, http.MethodGet, "", "", http.StatusOK) 110 } 111 112 // This checks that maxRequestContentLength is not applied to the response of a request. 113 func TestHTTPRespBodyUnlimited(t *testing.T) { 114 const respLength = maxRequestContentLength * 3 115 116 s := NewServer(0) 117 defer s.Stop() 118 s.RegisterName("test", largeRespService{respLength}) 119 ts := httptest.NewServer(s) 120 defer ts.Close() 121 122 c, err := DialHTTP(ts.URL) 123 if err != nil { 124 t.Fatal(err) 125 } 126 defer c.Close() 127 128 var r string 129 if err := c.Call(&r, "test_largeResp"); err != nil { 130 t.Fatal(err) 131 } 132 if len(r) != respLength { 133 t.Fatalf("response has wrong length %d, want %d", len(r), respLength) 134 } 135 } 136 137 // Tests that an HTTP error results in an HTTPError instance 138 // being returned with the expected attributes. 139 func TestHTTPErrorResponse(t *testing.T) { 140 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 141 http.Error(w, "error has occurred!", http.StatusTeapot) 142 })) 143 defer ts.Close() 144 145 c, err := DialHTTP(ts.URL) 146 if err != nil { 147 t.Fatal(err) 148 } 149 150 var r string 151 err = c.Call(&r, "test_method") 152 if err == nil { 153 t.Fatal("error was expected") 154 } 155 156 httpErr, ok := err.(HTTPError) 157 if !ok { 158 t.Fatalf("unexpected error type %T", err) 159 } 160 161 if httpErr.StatusCode != http.StatusTeapot { 162 t.Error("unexpected status code", httpErr.StatusCode) 163 } 164 if httpErr.Status != "418 I'm a teapot" { 165 t.Error("unexpected status text", httpErr.Status) 166 } 167 if body := string(httpErr.Body); body != "error has occurred!\n" { 168 t.Error("unexpected body", body) 169 } 170 171 if errMsg := httpErr.Error(); errMsg != "418 I'm a teapot: error has occurred!\n" { 172 t.Error("unexpected error message", errMsg) 173 } 174 } 175 176 func TestHTTPPeerInfo(t *testing.T) { 177 s := newTestServer() 178 defer s.Stop() 179 ts := httptest.NewServer(s) 180 defer ts.Close() 181 182 c, err := Dial(ts.URL) 183 if err != nil { 184 t.Fatal(err) 185 } 186 c.SetHeader("user-agent", "ua-testing") 187 c.SetHeader("origin", "origin.example.com") 188 189 // Request peer information. 190 var info PeerInfo 191 if err := c.Call(&info, "test_peerInfo"); err != nil { 192 t.Fatal(err) 193 } 194 195 if info.RemoteAddr == "" { 196 t.Error("RemoteAddr not set") 197 } 198 if info.Transport != "http" { 199 t.Errorf("wrong Transport %q", info.Transport) 200 } 201 if info.HTTP.Version != "HTTP/1.1" { 202 t.Errorf("wrong HTTP.Version %q", info.HTTP.Version) 203 } 204 if info.HTTP.UserAgent != "ua-testing" { 205 t.Errorf("wrong HTTP.UserAgent %q", info.HTTP.UserAgent) 206 } 207 if info.HTTP.Origin != "origin.example.com" { 208 t.Errorf("wrong HTTP.Origin %q", info.HTTP.UserAgent) 209 } 210 }