github.com/lianghucheng/zrddz@v0.0.0-20200923083010-c71f680932e2/src/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.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 // +build !go1.7 6 7 package ctxhttp // import "golang.org/x/net/context/ctxhttp" 8 9 import ( 10 "io" 11 "net/http" 12 "net/url" 13 "strings" 14 15 "golang.org/x/net/context" 16 ) 17 18 func nop() {} 19 20 var ( 21 testHookContextDoneBeforeHeaders = nop 22 testHookDoReturned = nop 23 testHookDidBodyClose = nop 24 ) 25 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) { 30 if client == nil { 31 client = http.DefaultClient 32 } 33 34 // TODO(djd): Respect any existing value of req.Cancel. 35 cancel := make(chan struct{}) 36 req.Cancel = cancel 37 38 type responseAndError struct { 39 resp *http.Response 40 err error 41 } 42 result := make(chan responseAndError, 1) 43 44 // Make local copies of test hooks closed over by goroutines below. 45 // Prevents data races in tests. 46 testHookDoReturned := testHookDoReturned 47 testHookDidBodyClose := testHookDidBodyClose 48 49 go func() { 50 resp, err := client.Do(req) 51 testHookDoReturned() 52 result <- responseAndError{resp, err} 53 }() 54 55 var resp *http.Response 56 57 select { 58 case <-ctx.Done(): 59 testHookContextDoneBeforeHeaders() 60 close(cancel) 61 // Clean up after the goroutine calling client.Do: 62 go func() { 63 if r := <-result; r.resp != nil { 64 testHookDidBodyClose() 65 r.resp.Body.Close() 66 } 67 }() 68 return nil, ctx.Err() 69 case r := <-result: 70 var err error 71 resp, err = r.resp, r.err 72 if err != nil { 73 return resp, err 74 } 75 } 76 77 c := make(chan struct{}) 78 go func() { 79 select { 80 case <-ctx.Done(): 81 close(cancel) 82 case <-c: 83 // The response's Body is closed. 84 } 85 }() 86 resp.Body = ¬ifyingReader{resp.Body, c} 87 88 return resp, nil 89 } 90 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) 94 if err != nil { 95 return nil, err 96 } 97 return Do(ctx, client, req) 98 } 99 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) 103 if err != nil { 104 return nil, err 105 } 106 return Do(ctx, client, req) 107 } 108 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) 112 if err != nil { 113 return nil, err 114 } 115 req.Header.Set("Content-Type", bodyType) 116 return Do(ctx, client, req) 117 } 118 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())) 122 } 123 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 { 127 io.ReadCloser 128 notify chan<- struct{} 129 } 130 131 func (r *notifyingReader) Read(p []byte) (int, error) { 132 n, err := r.ReadCloser.Read(p) 133 if err != nil && r.notify != nil { 134 close(r.notify) 135 r.notify = nil 136 } 137 return n, err 138 } 139 140 func (r *notifyingReader) Close() error { 141 err := r.ReadCloser.Close() 142 if r.notify != nil { 143 close(r.notify) 144 r.notify = nil 145 } 146 return err 147 }