github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/context/ctxhttp/ctxhttp.go (about) 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 5 // Package ctxhttp provides helper functions for performing context-aware HTTP requests. 6 package ctxhttp // import "golang.org/x/net/context/ctxhttp" 7 8 import ( 9 "io" 10 "net/http" 11 "net/url" 12 "strings" 13 14 "golang.org/x/net/context" 15 ) 16 17 // Do sends an HTTP request with the provided http.Client and returns an HTTP response. 18 // If the client is nil, http.DefaultClient is used. 19 // If the context is canceled or times out, ctx.Err() will be returned. 20 func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { 21 if client == nil { 22 client = http.DefaultClient 23 } 24 25 // Request cancelation changed in Go 1.5, see cancelreq.go and cancelreq_go14.go. 26 cancel := canceler(client, req) 27 28 type responseAndError struct { 29 resp *http.Response 30 err error 31 } 32 result := make(chan responseAndError, 1) 33 34 go func() { 35 resp, err := client.Do(req) 36 result <- responseAndError{resp, err} 37 }() 38 39 var resp *http.Response 40 41 select { 42 case <-ctx.Done(): 43 cancel() 44 return nil, ctx.Err() 45 case r := <-result: 46 var err error 47 resp, err = r.resp, r.err 48 if err != nil { 49 return resp, err 50 } 51 } 52 53 c := make(chan struct{}) 54 go func() { 55 select { 56 case <-ctx.Done(): 57 cancel() 58 case <-c: 59 // The response's Body is closed. 60 } 61 }() 62 resp.Body = ¬ifyingReader{resp.Body, c} 63 64 return resp, nil 65 } 66 67 // Get issues a GET request via the Do function. 68 func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) { 69 req, err := http.NewRequest("GET", url, nil) 70 if err != nil { 71 return nil, err 72 } 73 return Do(ctx, client, req) 74 } 75 76 // Head issues a HEAD request via the Do function. 77 func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) { 78 req, err := http.NewRequest("HEAD", url, nil) 79 if err != nil { 80 return nil, err 81 } 82 return Do(ctx, client, req) 83 } 84 85 // Post issues a POST request via the Do function. 86 func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) { 87 req, err := http.NewRequest("POST", url, body) 88 if err != nil { 89 return nil, err 90 } 91 req.Header.Set("Content-Type", bodyType) 92 return Do(ctx, client, req) 93 } 94 95 // PostForm issues a POST request via the Do function. 96 func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) { 97 return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) 98 } 99 100 // notifyingReader is an io.ReadCloser that closes the notify channel after 101 // Close is called or a Read fails on the underlying ReadCloser. 102 type notifyingReader struct { 103 io.ReadCloser 104 notify chan<- struct{} 105 } 106 107 func (r *notifyingReader) Read(p []byte) (int, error) { 108 n, err := r.ReadCloser.Read(p) 109 if err != nil && r.notify != nil { 110 close(r.notify) 111 r.notify = nil 112 } 113 return n, err 114 } 115 116 func (r *notifyingReader) Close() error { 117 err := r.ReadCloser.Close() 118 if r.notify != nil { 119 close(r.notify) 120 r.notify = nil 121 } 122 return err 123 }