OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / net / context / ctxhttp / ctxhttp_pre17.go
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 = &notifyingReader{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 }