github.com/bcnmy/go-ethereum@v1.10.27/rpc/http_test.go (about)

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