Skip to content

net/http: cancelation semantics with custom round tripper have changed in 1.14 #36820

@ianlancetaylor

Description

@ianlancetaylor

The behavior of this program has changed in 1.14. This is, of course, cut down from a real program.

package main

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"time"
)

func main() {
	r, err := http.NewRequest("GET", "myproto://dummy", nil)
	if err != nil {
		log.Fatal(err)
	}
	var t http.Transport
	t.RegisterProtocol("myproto", &myRoundTripper{})
	c := &http.Client{
		Transport: &t,
		Timeout:   time.Second,
	}
	_, err = c.Do(r)
	if err == nil {
		log.Fatal("expected timeout")
	}
	fmt.Println(err)
}

type myRoundTripper struct{}

func (*myRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	select {
	case <-req.Cancel:
		return nil, errors.New("round trip canceled as expected")
	case <-time.After(5 * time.Second):
		log.Fatal("round trip was not canceled")
		return nil, errors.New("round trip was not canceled")
	}
}

With Go 1.13 I see this:

Get myproto://dummy: round trip canceled as expected (Client.Timeout exceeded while awaiting headers)

With tip I see this:

2020/01/27 16:12:46 round trip was not canceled
exit status 1

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.release-blocker

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions