@@ -1185,94 +1185,142 @@ func testTransportGzip(t *testing.T, mode testMode) {
11851185 }
11861186}
11871187
1188- // If a request has Expect:100-continue header, the request blocks sending body until the first response.
1189- // Premature consumption of the request body should not be occurred.
1190- func TestTransportExpect100Continue (t * testing.T ) {
1191- run (t , testTransportExpect100Continue , []testMode {http1Mode })
1188+ // A transport100Continue test exercises Transport behaviors when sending a
1189+ // request with an Expect: 100-continue header.
1190+ type transport100ContinueTest struct {
1191+ t * testing.T
1192+
1193+ reqdone chan struct {}
1194+ resp * Response
1195+ respErr error
1196+
1197+ conn net.Conn
1198+ reader * bufio.Reader
11921199}
1193- func testTransportExpect100Continue (t * testing.T , mode testMode ) {
1194- ts := newClientServerTest (t , mode , HandlerFunc (func (rw ResponseWriter , req * Request ) {
1195- switch req .URL .Path {
1196- case "/100" :
1197- // This endpoint implicitly responds 100 Continue and reads body.
1198- if _ , err := io .Copy (io .Discard , req .Body ); err != nil {
1199- t .Error ("Failed to read Body" , err )
1200- }
1201- rw .WriteHeader (StatusOK )
1202- case "/200" :
1203- // Go 1.5 adds Connection: close header if the client expect
1204- // continue but not entire request body is consumed.
1205- rw .WriteHeader (StatusOK )
1206- case "/500" :
1207- rw .WriteHeader (StatusInternalServerError )
1208- case "/keepalive" :
1209- // This hijacked endpoint responds error without Connection:close.
1210- _ , bufrw , err := rw .(Hijacker ).Hijack ()
1211- if err != nil {
1212- log .Fatal (err )
1213- }
1214- bufrw .WriteString ("HTTP/1.1 500 Internal Server Error\r \n " )
1215- bufrw .WriteString ("Content-Length: 0\r \n \r \n " )
1216- bufrw .Flush ()
1217- case "/timeout" :
1218- // This endpoint tries to read body without 100 (Continue) response.
1219- // After ExpectContinueTimeout, the reading will be started.
1220- conn , bufrw , err := rw .(Hijacker ).Hijack ()
1221- if err != nil {
1222- log .Fatal (err )
1223- }
1224- if _ , err := io .CopyN (io .Discard , bufrw , req .ContentLength ); err != nil {
1225- t .Error ("Failed to read Body" , err )
1226- }
1227- bufrw .WriteString ("HTTP/1.1 200 OK\r \n \r \n " )
1228- bufrw .Flush ()
1229- conn .Close ()
1230- }
12311200
1232- })). ts
1201+ const transport100ContinueTestBody = "request body"
12331202
1234- tests := []struct {
1235- path string
1236- body []byte
1237- sent int
1238- status int
1239- }{
1240- {path : "/100" , body : []byte ("hello" ), sent : 5 , status : 200 }, // Got 100 followed by 200, entire body is sent.
1241- {path : "/200" , body : []byte ("hello" ), sent : 0 , status : 200 }, // Got 200 without 100. body isn't sent.
1242- {path : "/500" , body : []byte ("hello" ), sent : 0 , status : 500 }, // Got 500 without 100. body isn't sent.
1243- {path : "/keepalive" , body : []byte ("hello" ), sent : 0 , status : 500 }, // Although without Connection:close, body isn't sent.
1244- {path : "/timeout" , body : []byte ("hello" ), sent : 5 , status : 200 }, // Timeout exceeded and entire body is sent.
1203+ // newTransport100ContinueTest creates a Transport and sends an Expect: 100-continue
1204+ // request on it.
1205+ func newTransport100ContinueTest (t * testing.T , timeout time.Duration ) * transport100ContinueTest {
1206+ ln := newLocalListener (t )
1207+ defer ln .Close ()
1208+
1209+ test := & transport100ContinueTest {
1210+ t : t ,
1211+ reqdone : make (chan struct {}),
12451212 }
12461213
1247- c := ts .Client ()
1248- for i , v := range tests {
1249- tr := & Transport {
1250- ExpectContinueTimeout : 2 * time .Second ,
1251- }
1252- defer tr .CloseIdleConnections ()
1253- c .Transport = tr
1254- body := bytes .NewReader (v .body )
1255- req , err := NewRequest ("PUT" , ts .URL + v .path , body )
1256- if err != nil {
1257- t .Fatal (err )
1258- }
1214+ tr := & Transport {
1215+ ExpectContinueTimeout : timeout ,
1216+ }
1217+ go func () {
1218+ defer close (test .reqdone )
1219+ body := strings .NewReader (transport100ContinueTestBody )
1220+ req , _ := NewRequest ("PUT" , "http://" + ln .Addr ().String (), body )
12591221 req .Header .Set ("Expect" , "100-continue" )
1260- req .ContentLength = int64 (len (v .body ))
1222+ req .ContentLength = int64 (len (transport100ContinueTestBody ))
1223+ test .resp , test .respErr = tr .RoundTrip (req )
1224+ test .resp .Body .Close ()
1225+ }()
12611226
1262- resp , err := c .Do (req )
1263- if err != nil {
1264- t .Fatal (err )
1227+ c , err := ln .Accept ()
1228+ if err != nil {
1229+ t .Fatalf ("Accept: %v" , err )
1230+ }
1231+ t .Cleanup (func () {
1232+ c .Close ()
1233+ })
1234+ br := bufio .NewReader (c )
1235+ _ , err = ReadRequest (br )
1236+ if err != nil {
1237+ t .Fatalf ("ReadRequest: %v" , err )
1238+ }
1239+ test .conn = c
1240+ test .reader = br
1241+ t .Cleanup (func () {
1242+ <- test .reqdone
1243+ tr .CloseIdleConnections ()
1244+ got , _ := io .ReadAll (test .reader )
1245+ if len (got ) > 0 {
1246+ t .Fatalf ("Transport sent unexpected bytes: %q" , got )
12651247 }
1266- resp . Body . Close ( )
1248+ } )
12671249
1268- sent := len (v .body ) - body .Len ()
1269- if v .status != resp .StatusCode {
1270- t .Errorf ("test %d: status code should be %d but got %d. (%s)" , i , v .status , resp .StatusCode , v .path )
1271- }
1272- if v .sent != sent {
1273- t .Errorf ("test %d: sent body should be %d but sent %d. (%s)" , i , v .sent , sent , v .path )
1250+ return test
1251+ }
1252+
1253+ // respond sends response lines from the server to the transport.
1254+ func (test * transport100ContinueTest ) respond (lines ... string ) {
1255+ for _ , line := range lines {
1256+ if _ , err := test .conn .Write ([]byte (line + "\r \n " )); err != nil {
1257+ test .t .Fatalf ("Write: %v" , err )
12741258 }
12751259 }
1260+ if _ , err := test .conn .Write ([]byte ("\r \n " )); err != nil {
1261+ test .t .Fatalf ("Write: %v" , err )
1262+ }
1263+ }
1264+
1265+ // wantBodySent ensures the transport has sent the request body to the server.
1266+ func (test * transport100ContinueTest ) wantBodySent () {
1267+ got , err := io .ReadAll (io .LimitReader (test .reader , int64 (len (transport100ContinueTestBody ))))
1268+ if err != nil {
1269+ test .t .Fatalf ("unexpected error reading body: %v" , err )
1270+ }
1271+ if got , want := string (got ), transport100ContinueTestBody ; got != want {
1272+ test .t .Fatalf ("unexpected body: got %q, want %q" , got , want )
1273+ }
1274+ }
1275+
1276+ // wantRequestDone ensures the Transport.RoundTrip has completed with the expected status.
1277+ func (test * transport100ContinueTest ) wantRequestDone (want int ) {
1278+ <- test .reqdone
1279+ if test .respErr != nil {
1280+ test .t .Fatalf ("unexpected RoundTrip error: %v" , test .respErr )
1281+ }
1282+ if got := test .resp .StatusCode ; got != want {
1283+ test .t .Fatalf ("unexpected response code: got %v, want %v" , got , want )
1284+ }
1285+ }
1286+
1287+ func TestTransportExpect100ContinueSent (t * testing.T ) {
1288+ test := newTransport100ContinueTest (t , 1 * time .Hour )
1289+ // Server sends a 100 Continue response, and the client sends the request body.
1290+ test .respond ("HTTP/1.1 100 Continue" )
1291+ test .wantBodySent ()
1292+ test .respond ("HTTP/1.1 200" , "Content-Length: 0" )
1293+ test .wantRequestDone (200 )
1294+ }
1295+
1296+ func TestTransportExpect100Continue200ResponseNoConnClose (t * testing.T ) {
1297+ test := newTransport100ContinueTest (t , 1 * time .Hour )
1298+ // No 100 Continue response, no Connection: close header.
1299+ test .respond ("HTTP/1.1 200" , "Content-Length: 0" )
1300+ test .wantBodySent ()
1301+ test .wantRequestDone (200 )
1302+ }
1303+
1304+ func TestTransportExpect100Continue200ResponseWithConnClose (t * testing.T ) {
1305+ test := newTransport100ContinueTest (t , 1 * time .Hour )
1306+ // No 100 Continue response, Connection: close header set.
1307+ test .respond ("HTTP/1.1 200" , "Connection: close" , "Content-Length: 0" )
1308+ test .wantRequestDone (200 )
1309+ }
1310+
1311+ func TestTransportExpect100Continue500ResponseNoConnClose (t * testing.T ) {
1312+ test := newTransport100ContinueTest (t , 1 * time .Hour )
1313+ // No 100 Continue response, no Connection: close header.
1314+ test .respond ("HTTP/1.1 500" , "Content-Length: 0" )
1315+ test .wantBodySent ()
1316+ test .wantRequestDone (500 )
1317+ }
1318+
1319+ func TestTransportExpect100Continue500ResponseTimeout (t * testing.T ) {
1320+ test := newTransport100ContinueTest (t , 5 * time .Millisecond ) // short timeout
1321+ test .wantBodySent () // after timeout
1322+ test .respond ("HTTP/1.1 200" , "Content-Length: 0" )
1323+ test .wantRequestDone (200 )
12761324}
12771325
12781326func TestSOCKS5Proxy (t * testing.T ) {
0 commit comments