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.
7 package ctxhttp // import "golang.org/x/net/context/ctxhttp"
15 "golang.org/x/net/context"
21 testHookContextDoneBeforeHeaders = nop
22 testHookDoReturned = nop
23 testHookDidBodyClose = nop
26 // Do sends an HTTP request with the provided http.Client and returns an HTTP response.
27 // If the client is nil, http.DefaultClient is used.
28 // If the context is canceled or times out, ctx.Err() will be returned.
29 func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
31 client = http.DefaultClient
34 // TODO(djd): Respect any existing value of req.Cancel.
35 cancel := make(chan struct{})
38 type responseAndError struct {
42 result := make(chan responseAndError, 1)
44 // Make local copies of test hooks closed over by goroutines below.
45 // Prevents data races in tests.
46 testHookDoReturned := testHookDoReturned
47 testHookDidBodyClose := testHookDidBodyClose
50 resp, err := client.Do(req)
52 result <- responseAndError{resp, err}
55 var resp *http.Response
59 testHookContextDoneBeforeHeaders()
61 // Clean up after the goroutine calling client.Do:
63 if r := <-result; r.resp != nil {
64 testHookDidBodyClose()
71 resp, err = r.resp, r.err
77 c := make(chan struct{})
83 // The response's Body is closed.
86 resp.Body = ¬ifyingReader{resp.Body, c}
91 // Get issues a GET request via the Do function.
92 func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
93 req, err := http.NewRequest("GET", url, nil)
97 return Do(ctx, client, req)
100 // Head issues a HEAD request via the Do function.
101 func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
102 req, err := http.NewRequest("HEAD", url, nil)
106 return Do(ctx, client, req)
109 // Post issues a POST request via the Do function.
110 func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
111 req, err := http.NewRequest("POST", url, body)
115 req.Header.Set("Content-Type", bodyType)
116 return Do(ctx, client, req)
119 // PostForm issues a POST request via the Do function.
120 func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
121 return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
124 // notifyingReader is an io.ReadCloser that closes the notify channel after
125 // Close is called or a Read fails on the underlying ReadCloser.
126 type notifyingReader struct {
128 notify chan<- struct{}
131 func (r *notifyingReader) Read(p []byte) (int, error) {
132 n, err := r.ReadCloser.Read(p)
133 if err != nil && r.notify != nil {
140 func (r *notifyingReader) Close() error {
141 err := r.ReadCloser.Close()