github.com/alejandroEsc/spdy@v0.0.0-20200317064415-01a02f0eb389/client_test.go (about)

     1  // Copyright 2014 Jamie Hall. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package spdy_test
     6  
     7  import (
     8  	"crypto/tls"
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"log"
    13  	"net/http"
    14  	"net/http/httptest"
    15  	"strings"
    16  	"sync"
    17  	"testing"
    18  
    19  	"github.com/SlyMarbo/spdy"
    20  )
    21  
    22  func init() {
    23  	// spdy.EnableDebugOutput()
    24  }
    25  
    26  func TestClient(t *testing.T) {
    27  	ts := newServer(robotsTxtHandler)
    28  	defer ts.Close()
    29  
    30  	client := newClient()
    31  
    32  	r, err := client.Get(ts.URL)
    33  	var b []byte
    34  	if err == nil {
    35  		b, err = pedanticReadAll(r.Body)
    36  		r.Body.Close()
    37  	}
    38  	if err != nil {
    39  		t.Error(err)
    40  	} else if s := string(b); !strings.HasPrefix(s, "User-agent:") {
    41  		t.Errorf("Incorrect page body (did not begin with User-agent): %q", s)
    42  	}
    43  }
    44  
    45  func TestClientHead(t *testing.T) {
    46  	ts := newServer(robotsTxtHandler)
    47  	defer ts.Close()
    48  
    49  	client := newClient()
    50  	r, err := client.Head(ts.URL)
    51  	if err != nil {
    52  		t.Fatal(err)
    53  	}
    54  	if _, ok := r.Header["Last-Modified"]; !ok {
    55  		t.Error("Last-Modified header not found.")
    56  	}
    57  }
    58  
    59  func TestClientInGoroutines(t *testing.T) {
    60  	ts := newServer(robotsTxtHandler)
    61  	ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0) // ignore messages
    62  	defer ts.Close()
    63  
    64  	client := spdy.NewClient(false)
    65  
    66  	var wg sync.WaitGroup
    67  
    68  	for i := 0; i < 10; i++ {
    69  		wg.Add(1)
    70  		go func() {
    71  			defer wg.Done()
    72  			var b []byte
    73  			r, err := client.Get(ts.URL)
    74  			if err == nil {
    75  				b, err = pedanticReadAll(r.Body)
    76  				r.Body.Close()
    77  			}
    78  			if err != nil {
    79  				// We've turned off InsecureSkipVerify, so
    80  				// ignore bad cert warnings.
    81  				if !strings.Contains(err.Error(), "certificate signed by unknown authority") {
    82  					t.Error(err)
    83  				}
    84  			} else if s := string(b); !strings.HasPrefix(s, "User-agent:") {
    85  				t.Errorf("Incorrect page body (did not begin with User-agent): %q", s)
    86  			}
    87  		}()
    88  	}
    89  
    90  	wg.Wait()
    91  }
    92  
    93  // FIXME: Fails
    94  // func TestClientRedirects(t *testing.T) {
    95  // 	defer afterTest(t)
    96  // 	var ts *httptest.Server
    97  // 	ts = newServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    98  // 		n, _ := strconv.Atoi(r.FormValue("n"))
    99  // 		// Test Referer header. (7 is arbitrary position to test at)
   100  // 		if n == 7 {
   101  // 			if g, e := r.Referer(), ts.URL+"/?n=6"; e != g {
   102  // 				t.Errorf("on request ?n=7, expected referer of %q; got %q", e, g)
   103  // 			}
   104  // 		}
   105  // 		if n < 15 {
   106  // 			http.Redirect(w, r, fmt.Sprintf("/?n=%d", n+1), http.StatusFound)
   107  // 			return
   108  // 		}
   109  // 		fmt.Fprintf(w, "n=%d", n)
   110  // 	}))
   111  // 	defer ts.Close()
   112  
   113  // 	c := newClient()
   114  // 	_, err := c.Get(ts.URL)
   115  // 	if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
   116  // 		t.Errorf("with default client Get, expected error %q, got %q", e, g)
   117  // 	}
   118  
   119  // 	// HEAD request should also have the ability to follow redirects.
   120  // 	_, err = c.Head(ts.URL)
   121  // 	if e, g := "Head /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
   122  // 		t.Errorf("with default client Head, expected error %q, got %q", e, g)
   123  // 	}
   124  
   125  // 	// Do should also follow redirects.
   126  // 	greq, _ := http.NewRequest("GET", ts.URL, nil)
   127  // 	_, err = c.Do(greq)
   128  // 	if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
   129  // 		t.Errorf("with default client Do, expected error %q, got %q", e, g)
   130  // 	}
   131  
   132  // 	var checkErr error
   133  // 	var lastVia []*http.Request
   134  // 	c = newClient()
   135  // 	c.CheckRedirect = func(_ *http.Request, via []*http.Request) error {
   136  // 		lastVia = via
   137  // 		return checkErr
   138  // 	}
   139  // 	res, err := c.Get(ts.URL)
   140  // 	if err != nil {
   141  // 		t.Fatalf("Get error: %v", err)
   142  // 	}
   143  // 	res.Body.Close()
   144  // 	finalUrl := res.Request.URL.String()
   145  // 	if e, g := "<nil>", fmt.Sprintf("%v", err); e != g {
   146  // 		t.Errorf("with custom client, expected error %q, got %q", e, g)
   147  // 	}
   148  // 	if !strings.HasSuffix(finalUrl, "/?n=15") {
   149  // 		t.Errorf("expected final url to end in /?n=15; got url %q", finalUrl)
   150  // 	}
   151  // 	if e, g := 15, len(lastVia); e != g {
   152  // 		t.Errorf("expected lastVia to have contained %d elements; got %d", e, g)
   153  // 	}
   154  
   155  // 	checkErr = errors.New("no redirects allowed")
   156  // 	res, err = c.Get(ts.URL)
   157  // 	if urlError, ok := err.(*url.Error); !ok || urlError.Err != checkErr {
   158  // 		t.Errorf("with redirects forbidden, expected a *url.Error with our 'no redirects allowed' error inside; got %#v (%q)", err, err)
   159  // 	}
   160  // 	if res == nil {
   161  // 		t.Fatalf("Expected a non-nil Response on CheckRedirect failure (http://golang.org/issue/3795)")
   162  // 	}
   163  // 	res.Body.Close()
   164  // 	if res.Header.Get("Location") == "" {
   165  // 		t.Errorf("no Location header in Response")
   166  // 	}
   167  // }
   168  
   169  // FIXME: Deadlocks
   170  // func TestPostRedirects(t *testing.T) {
   171  //	defer afterTest(t)
   172  // 	var log struct {
   173  // 		sync.Mutex
   174  // 		bytes.Buffer
   175  // 	}
   176  // 	var ts *httptest.Server
   177  // 	ts = newServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   178  // 		log.Lock()
   179  // 		fmt.Fprintf(&log.Buffer, "%s %s ", r.Method, r.RequestURI)
   180  // 		log.Unlock()
   181  // 		if v := r.URL.Query().Get("code"); v != "" {
   182  // 			code, _ := strconv.Atoi(v)
   183  // 			if code/100 == 3 {
   184  // 				w.Header().Set("Location", ts.URL)
   185  // 			}
   186  // 			w.WriteHeader(code)
   187  // 		}
   188  // 	}))
   189  // 	defer ts.Close()
   190  // 	tests := []struct {
   191  // 		suffix string
   192  // 		want   int // response code
   193  // 	}{
   194  // 		{"/", 200},
   195  // 		{"/?code=301", 301},
   196  // 		{"/?code=302", 200},
   197  // 		{"/?code=303", 200},
   198  // 		{"/?code=404", 404},
   199  // 	}
   200  // 	client := newClient()
   201  // 	for _, tt := range tests {
   202  // 		res, err := client.Post(ts.URL+tt.suffix, "text/plain", strings.NewReader("Some content"))
   203  // 		if err != nil {
   204  // 			t.Fatal(err)
   205  // 		}
   206  // 		if res.StatusCode != tt.want {
   207  // 			t.Errorf("POST %s: status code = %d; want %d", tt.suffix, res.StatusCode, tt.want)
   208  // 		}
   209  // 	}
   210  // 	log.Lock()
   211  // 	got := log.String()
   212  // 	log.Unlock()
   213  // 	want := "POST / POST /?code=301 POST /?code=302 GET / POST /?code=303 GET / POST /?code=404 "
   214  // 	if got != want {
   215  // 		t.Errorf("Log differs.\n Got: %q\nWant: %q", got, want)
   216  // 	}
   217  // }
   218  
   219  // FIXME: Fails (not a Flusher)
   220  // func TestStreamingGet(t *testing.T) {
   221  // 	defer afterTest(t)
   222  // 	say := make(chan string)
   223  // 	ts := newServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   224  // 		w.(http.Flusher).Flush()
   225  // 		for str := range say {
   226  // 			w.Write([]byte(str))
   227  // 			w.(http.Flusher).Flush()
   228  // 		}
   229  // 	}))
   230  // 	defer ts.Close()
   231  
   232  // 	c := newClient()
   233  // 	res, err := c.Get(ts.URL + "/")
   234  // 	if err != nil {
   235  // 		t.Fatal(err)
   236  // 	}
   237  // 	var buf [10]byte
   238  // 	for _, str := range []string{"i", "am", "also", "known", "as", "comet"} {
   239  // 		say <- str
   240  // 		n, err := io.ReadFull(res.Body, buf[0:len(str)])
   241  // 		if err != nil {
   242  // 			t.Fatalf("ReadFull on %q: %v", str, err)
   243  // 		}
   244  // 		if n != len(str) {
   245  // 			t.Fatalf("Receiving %q, only read %d bytes", str, n)
   246  // 		}
   247  // 		got := string(buf[0:n])
   248  // 		if got != str {
   249  // 			t.Fatalf("Expected %q, got %q", str, got)
   250  // 		}
   251  // 	}
   252  // 	close(say)
   253  // 	_, err = io.ReadFull(res.Body, buf[0:1])
   254  // 	if err != io.EOF {
   255  // 		t.Fatalf("at end expected EOF, got %v", err)
   256  // 	}
   257  // }
   258  
   259  //
   260  // HELPERS
   261  //
   262  
   263  var robotsTxtHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   264  	w.Header().Set("Last-Modified", "sometime")
   265  	fmt.Fprintf(w, "User-agent: go\nDisallow: /something/")
   266  })
   267  
   268  // pedanticReadAll works like ioutil.ReadAll but additionally
   269  // verifies that r obeys the documented io.Reader contract.
   270  func pedanticReadAll(r io.Reader) (b []byte, err error) {
   271  	var bufa [64]byte
   272  	buf := bufa[:]
   273  	for {
   274  		n, err := r.Read(buf)
   275  		if n == 0 && err == nil {
   276  			return nil, fmt.Errorf("Read: n=0 with err=nil")
   277  		}
   278  		b = append(b, buf[:n]...)
   279  		if err == io.EOF {
   280  			n, err := r.Read(buf)
   281  			if n != 0 || err != io.EOF {
   282  				return nil, fmt.Errorf("Read: n=%d err=%#v after EOF", n, err)
   283  			}
   284  			return b, nil
   285  		}
   286  		if err != nil {
   287  			return b, err
   288  		}
   289  	}
   290  }
   291  
   292  func newServer(handler http.Handler) *httptest.Server {
   293  	ts := httptest.NewUnstartedServer(handler)
   294  	spdy.AddSPDY(ts.Config)
   295  	ts.TLS = ts.Config.TLSConfig
   296  	ts.StartTLS()
   297  	return ts
   298  }
   299  
   300  func newClient() *http.Client {
   301  	tr := spdy.Transport{
   302  		TLSClientConfig: &tls.Config{
   303  			InsecureSkipVerify: true,
   304  			NextProtos:         []string{"spdy/3.1"},
   305  		},
   306  	}
   307  	return &http.Client{Transport: &tr}
   308  }