ctxhttp_pre17_test.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // Copyright 2015 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. // +build !plan9,!go1.7
  5. package ctxhttp
  6. import (
  7. "net"
  8. "net/http"
  9. "net/http/httptest"
  10. "sync"
  11. "testing"
  12. "time"
  13. "golang.org/x/net/context"
  14. )
  15. // golang.org/issue/14065
  16. func TestClosesResponseBodyOnCancel(t *testing.T) {
  17. defer func() { testHookContextDoneBeforeHeaders = nop }()
  18. defer func() { testHookDoReturned = nop }()
  19. defer func() { testHookDidBodyClose = nop }()
  20. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
  21. defer ts.Close()
  22. ctx, cancel := context.WithCancel(context.Background())
  23. // closed when Do enters select case <-ctx.Done()
  24. enteredDonePath := make(chan struct{})
  25. testHookContextDoneBeforeHeaders = func() {
  26. close(enteredDonePath)
  27. }
  28. testHookDoReturned = func() {
  29. // We now have the result (the Flush'd headers) at least,
  30. // so we can cancel the request.
  31. cancel()
  32. // But block the client.Do goroutine from sending
  33. // until Do enters into the <-ctx.Done() path, since
  34. // otherwise if both channels are readable, select
  35. // picks a random one.
  36. <-enteredDonePath
  37. }
  38. sawBodyClose := make(chan struct{})
  39. testHookDidBodyClose = func() { close(sawBodyClose) }
  40. tr := &http.Transport{}
  41. defer tr.CloseIdleConnections()
  42. c := &http.Client{Transport: tr}
  43. req, _ := http.NewRequest("GET", ts.URL, nil)
  44. _, doErr := Do(ctx, c, req)
  45. select {
  46. case <-sawBodyClose:
  47. case <-time.After(5 * time.Second):
  48. t.Fatal("timeout waiting for body to close")
  49. }
  50. if doErr != ctx.Err() {
  51. t.Errorf("Do error = %v; want %v", doErr, ctx.Err())
  52. }
  53. }
  54. type noteCloseConn struct {
  55. net.Conn
  56. onceClose sync.Once
  57. closefn func()
  58. }
  59. func (c *noteCloseConn) Close() error {
  60. c.onceClose.Do(c.closefn)
  61. return c.Conn.Close()
  62. }