github.com/useflyent/fhttp@v0.0.0-20211004035111-333f430cfbbf/http2/fhttp_test.go (about)

     1  package http2_test
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/tls"
     6  	"crypto/x509"
     7  	"errors"
     8  	"fmt"
     9  	"github.com/useflyent/fhttp/cookiejar"
    10  	"github.com/useflyent/fhttp/httptest"
    11  	"golang.org/x/net/publicsuffix"
    12  	"log"
    13  	ghttp "net/http"
    14  	"net/url"
    15  	"os"
    16  	"strings"
    17  	"testing"
    18  
    19  	http "github.com/useflyent/fhttp"
    20  	"github.com/useflyent/fhttp/http2"
    21  )
    22  
    23  // Tests if connection settings are written correctly
    24  func TestConnectionSettings(t *testing.T) {
    25  	settings := []http2.Setting{
    26  		{ID: http2.SettingHeaderTableSize, Val: 65536},
    27  		{ID: http2.SettingMaxConcurrentStreams, Val: 1000},
    28  		{ID: http2.SettingInitialWindowSize, Val: 6291456},
    29  		{ID: http2.SettingMaxFrameSize, Val: 16384},
    30  		{ID: http2.SettingMaxHeaderListSize, Val: 262144},
    31  	}
    32  	buf := new(bytes.Buffer)
    33  	fr := http2.NewFramer(buf, buf)
    34  	err := fr.WriteSettings(settings...)
    35  
    36  	if err != nil {
    37  		t.Fatalf(err.Error())
    38  	}
    39  
    40  	f, err := fr.ReadFrame()
    41  	if err != nil {
    42  		t.Fatal(err.Error())
    43  	}
    44  
    45  	sf := f.(*http2.SettingsFrame)
    46  	n := sf.NumSettings()
    47  	if n != len(settings) {
    48  		t.Fatalf("Expected %d settings, got %d", len(settings), n)
    49  	}
    50  
    51  	for i := 0; i < n; i++ {
    52  		s := sf.Setting(i)
    53  		var err error
    54  		switch s.ID {
    55  		case http2.SettingHeaderTableSize:
    56  			err = compareSettings(s.ID, s.Val, 65536)
    57  		case http2.SettingMaxConcurrentStreams:
    58  			err = compareSettings(s.ID, s.Val, 1000)
    59  		case http2.SettingInitialWindowSize:
    60  			err = compareSettings(s.ID, s.Val, 6291456)
    61  		case http2.SettingMaxFrameSize:
    62  			err = compareSettings(s.ID, s.Val, 16384)
    63  		case http2.SettingMaxHeaderListSize:
    64  			err = compareSettings(s.ID, s.Val, 262144)
    65  		}
    66  
    67  		if err != nil {
    68  			t.Fatal(err.Error())
    69  		}
    70  	}
    71  }
    72  
    73  func compareSettings(ID http2.SettingID, output uint32, expected uint32) error {
    74  	if output != expected {
    75  		return errors.New(fmt.Sprintf("Setting %v, expected %d got %d", ID, expected, output))
    76  	}
    77  	return nil
    78  }
    79  
    80  // Round trip test, makes sure that the changes made doesn't break the library
    81  func TestRoundTrip(t *testing.T) {
    82  	settings := []http2.Setting{
    83  		{ID: http2.SettingHeaderTableSize, Val: 65536},
    84  		{ID: http2.SettingMaxConcurrentStreams, Val: 1000},
    85  		{ID: http2.SettingInitialWindowSize, Val: 6291456},
    86  		{ID: http2.SettingMaxFrameSize, Val: 16384},
    87  		{ID: http2.SettingMaxHeaderListSize, Val: 262144},
    88  	}
    89  	tr := http2.Transport{
    90  		Settings: settings,
    91  	}
    92  	req, err := http.NewRequest("GET", "www.google.com", nil)
    93  	if err != nil {
    94  		t.Fatalf(err.Error())
    95  	}
    96  	tr.RoundTrip(req)
    97  }
    98  
    99  // Tests if content-length header is present in request headers during POST
   100  func TestContentLength(t *testing.T) {
   101  	ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   102  		if hdr, ok := r.Header["Content-Length"]; ok {
   103  			if len(hdr) != 1 {
   104  				t.Fatalf("Got %v content-length headers, should only be 1", len(hdr))
   105  			}
   106  			return
   107  		}
   108  		log.Printf("Proto: %v", r.Proto)
   109  		for name, value := range r.Header {
   110  			log.Printf("%v: %v", name, value)
   111  		}
   112  		t.Fatalf("Could not find content-length header")
   113  	}))
   114  	ts.EnableHTTP2 = true
   115  	ts.StartTLS()
   116  	defer ts.Close()
   117  
   118  	u := ts.URL
   119  	form := url.Values{}
   120  	form.Add("Hello", "World")
   121  	req, err := http.NewRequest("POST", u, strings.NewReader(form.Encode()))
   122  	if err != nil {
   123  		t.Fatalf(err.Error())
   124  	}
   125  	req.Header.Add("user-agent", "Go Testing")
   126  
   127  	resp, err := ts.Client().Do(req)
   128  	if err != nil {
   129  		t.Fatalf(err.Error())
   130  	}
   131  	defer resp.Body.Close()
   132  }
   133  
   134  // TestClient_Cookies tests whether set cookies are being sent
   135  func TestClient_SendsCookies(t *testing.T) {
   136  	ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   137  		cookie, err := r.Cookie("cookie")
   138  		if err != nil {
   139  			t.Fatalf(err.Error())
   140  		}
   141  		if cookie.Value == "" {
   142  			t.Fatalf("Cookie value is empty")
   143  		}
   144  	}))
   145  	ts.EnableHTTP2 = true
   146  	ts.StartTLS()
   147  	defer ts.Close()
   148  	c := ts.Client()
   149  	jar, err := cookiejar.New(&cookiejar.Options{
   150  		PublicSuffixList: publicsuffix.List,
   151  	})
   152  	if err != nil {
   153  		t.Fatalf(err.Error())
   154  	}
   155  	c.Jar = jar
   156  	ur := ts.URL
   157  	u, err := url.Parse(ur)
   158  	if err != nil {
   159  		t.Fatalf(err.Error())
   160  	}
   161  	cookies := []*http.Cookie{{Name: "cookie", Value: "Hello world"}}
   162  	jar.SetCookies(u, cookies)
   163  	resp, err := c.Get(ur)
   164  	if err != nil {
   165  		t.Fatalf(err.Error())
   166  	}
   167  	defer resp.Body.Close()
   168  }
   169  
   170  // TestClient_Load is a dumb man's load test with charles :P
   171  func TestClient_Load(t *testing.T) {
   172  	u, err := url.Parse("http://localhost:8888")
   173  	if err != nil {
   174  		t.Fatalf(err.Error())
   175  	}
   176  
   177  	pool, err := getCharlesCert()
   178  	if err != nil {
   179  		t.Fatalf(err.Error())
   180  	}
   181  	c := http.Client{
   182  		Transport: &http.Transport{
   183  			ForceAttemptHTTP2: true,
   184  			Proxy:             http.ProxyURL(u),
   185  			TLSClientConfig: &tls.Config{
   186  				RootCAs: pool,
   187  			},
   188  		},
   189  	}
   190  	req, err := http.NewRequest("GET", "https://golang.org/pkg/net/mail/#Address", nil)
   191  	if err != nil {
   192  		t.Fatalf(err.Error())
   193  	}
   194  	for i := 0; i < 10; i++ {
   195  		resp, err := c.Do(req)
   196  		if err != nil {
   197  			t.Fatalf(err.Error())
   198  		}
   199  		resp.Body.Close()
   200  	}
   201  }
   202  
   203  func TestGClient_Load(t *testing.T) {
   204  	u, err := url.Parse("http://localhost:8888")
   205  	if err != nil {
   206  		t.Fatalf(err.Error())
   207  	}
   208  
   209  	pool, err := getCharlesCert()
   210  	if err != nil {
   211  		t.Fatalf(err.Error())
   212  	}
   213  	c := ghttp.Client{
   214  		Transport: &ghttp.Transport{
   215  			ForceAttemptHTTP2: true,
   216  			Proxy:             ghttp.ProxyURL(u),
   217  			TLSClientConfig: &tls.Config{
   218  				RootCAs: pool,
   219  			},
   220  		},
   221  	}
   222  	req, err := ghttp.NewRequest("GET", "https://golang.org/pkg/net/mail/#Address", nil)
   223  	if err != nil {
   224  		t.Fatalf(err.Error())
   225  	}
   226  	for i := 0; i < 10; i++ {
   227  		err := do(&c, req)
   228  		if err != nil {
   229  			t.Fatalf(err.Error())
   230  		}
   231  	}
   232  }
   233  
   234  func do(c *ghttp.Client, req *ghttp.Request) error {
   235  	resp, err := c.Do(req)
   236  	if err != nil {
   237  		return err
   238  	}
   239  	resp.Body.Close()
   240  	return nil
   241  }
   242  
   243  func getCharlesCert() (*x509.CertPool, error) {
   244  	home, err := os.UserHomeDir()
   245  	if err != nil {
   246  		return nil, err
   247  	}
   248  	caCert, err := os.ReadFile(fmt.Sprintf("%v/charles_cert.pem", home))
   249  	if err != nil {
   250  		return nil, err
   251  	}
   252  	certPool := x509.NewCertPool()
   253  	certPool.AppendCertsFromPEM(caCert)
   254  	return certPool, nil
   255  }