...
Run Format

Source file src/net/http/transport_internal_test.go

Documentation: net/http

     1  // Copyright 2016 The Go Authors. 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  // White-box tests for transport.go (in package http instead of http_test).
     6  
     7  package http
     8  
     9  import (
    10  	"errors"
    11  	"net"
    12  	"strings"
    13  	"testing"
    14  )
    15  
    16  // Issue 15446: incorrect wrapping of errors when server closes an idle connection.
    17  func TestTransportPersistConnReadLoopEOF(t *testing.T) {
    18  	ln := newLocalListener(t)
    19  	defer ln.Close()
    20  
    21  	connc := make(chan net.Conn, 1)
    22  	go func() {
    23  		defer close(connc)
    24  		c, err := ln.Accept()
    25  		if err != nil {
    26  			t.Error(err)
    27  			return
    28  		}
    29  		connc <- c
    30  	}()
    31  
    32  	tr := new(Transport)
    33  	req, _ := NewRequest("GET", "http://"+ln.Addr().String(), nil)
    34  	req = req.WithT(t)
    35  	treq := &transportRequest{Request: req}
    36  	cm := connectMethod{targetScheme: "http", targetAddr: ln.Addr().String()}
    37  	pc, err := tr.getConn(treq, cm)
    38  	if err != nil {
    39  		t.Fatal(err)
    40  	}
    41  	defer pc.close(errors.New("test over"))
    42  
    43  	conn := <-connc
    44  	if conn == nil {
    45  		// Already called t.Error in the accept goroutine.
    46  		return
    47  	}
    48  	conn.Close() // simulate the server hanging up on the client
    49  
    50  	_, err = pc.roundTrip(treq)
    51  	if !isTransportReadFromServerError(err) && err != errServerClosedIdle {
    52  		t.Errorf("roundTrip = %#v, %v; want errServerClosedIdle or transportReadFromServerError", err, err)
    53  	}
    54  
    55  	<-pc.closech
    56  	err = pc.closed
    57  	if !isTransportReadFromServerError(err) && err != errServerClosedIdle {
    58  		t.Errorf("pc.closed = %#v, %v; want errServerClosedIdle or transportReadFromServerError", err, err)
    59  	}
    60  }
    61  
    62  func isTransportReadFromServerError(err error) bool {
    63  	_, ok := err.(transportReadFromServerError)
    64  	return ok
    65  }
    66  
    67  func newLocalListener(t *testing.T) net.Listener {
    68  	ln, err := net.Listen("tcp", "127.0.0.1:0")
    69  	if err != nil {
    70  		ln, err = net.Listen("tcp6", "[::1]:0")
    71  	}
    72  	if err != nil {
    73  		t.Fatal(err)
    74  	}
    75  	return ln
    76  }
    77  
    78  func dummyRequest(method string) *Request {
    79  	req, err := NewRequest(method, "http://fake.tld/", nil)
    80  	if err != nil {
    81  		panic(err)
    82  	}
    83  	return req
    84  }
    85  func dummyRequestWithBody(method string) *Request {
    86  	req, err := NewRequest(method, "http://fake.tld/", strings.NewReader("foo"))
    87  	if err != nil {
    88  		panic(err)
    89  	}
    90  	return req
    91  }
    92  
    93  func dummyRequestWithBodyNoGetBody(method string) *Request {
    94  	req := dummyRequestWithBody(method)
    95  	req.GetBody = nil
    96  	return req
    97  }
    98  
    99  // issue22091Error acts like a golang.org/x/net/http2.ErrNoCachedConn.
   100  type issue22091Error struct{}
   101  
   102  func (issue22091Error) IsHTTP2NoCachedConnError() {}
   103  func (issue22091Error) Error() string             { return "issue22091Error" }
   104  
   105  func TestTransportShouldRetryRequest(t *testing.T) {
   106  	tests := []struct {
   107  		pc  *persistConn
   108  		req *Request
   109  
   110  		err  error
   111  		want bool
   112  	}{
   113  		0: {
   114  			pc:   &persistConn{reused: false},
   115  			req:  dummyRequest("POST"),
   116  			err:  nothingWrittenError{},
   117  			want: false,
   118  		},
   119  		1: {
   120  			pc:   &persistConn{reused: true},
   121  			req:  dummyRequest("POST"),
   122  			err:  nothingWrittenError{},
   123  			want: true,
   124  		},
   125  		2: {
   126  			pc:   &persistConn{reused: true},
   127  			req:  dummyRequest("POST"),
   128  			err:  http2ErrNoCachedConn,
   129  			want: true,
   130  		},
   131  		3: {
   132  			pc:   nil,
   133  			req:  nil,
   134  			err:  issue22091Error{}, // like an external http2ErrNoCachedConn
   135  			want: true,
   136  		},
   137  		4: {
   138  			pc:   &persistConn{reused: true},
   139  			req:  dummyRequest("POST"),
   140  			err:  errMissingHost,
   141  			want: false,
   142  		},
   143  		5: {
   144  			pc:   &persistConn{reused: true},
   145  			req:  dummyRequest("POST"),
   146  			err:  transportReadFromServerError{},
   147  			want: false,
   148  		},
   149  		6: {
   150  			pc:   &persistConn{reused: true},
   151  			req:  dummyRequest("GET"),
   152  			err:  transportReadFromServerError{},
   153  			want: true,
   154  		},
   155  		7: {
   156  			pc:   &persistConn{reused: true},
   157  			req:  dummyRequest("GET"),
   158  			err:  errServerClosedIdle,
   159  			want: true,
   160  		},
   161  		8: {
   162  			pc:   &persistConn{reused: true},
   163  			req:  dummyRequestWithBody("POST"),
   164  			err:  nothingWrittenError{},
   165  			want: true,
   166  		},
   167  		9: {
   168  			pc:   &persistConn{reused: true},
   169  			req:  dummyRequestWithBodyNoGetBody("POST"),
   170  			err:  nothingWrittenError{},
   171  			want: false,
   172  		},
   173  	}
   174  	for i, tt := range tests {
   175  		got := tt.pc.shouldRetryRequest(tt.req, tt.err)
   176  		if got != tt.want {
   177  			t.Errorf("%d. shouldRetryRequest = %v; want %v", i, got, tt.want)
   178  		}
   179  	}
   180  }
   181  

View as plain text