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  }