PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/core/http/client.go

https://gitlab.com/lirao/azure-sdk-for-go
Go | 487 lines | 261 code | 45 blank | 181 comment | 77 complexity | b9da6019dae0f383e352816e29f33071 MD5 | raw file
  1. // Copyright 2009 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. // HTTP client. See RFC 2616.
  5. //
  6. // This is the high-level Client interface.
  7. // The low-level implementation is in transport.go.
  8. package http
  9. import (
  10. "encoding/base64"
  11. "errors"
  12. "fmt"
  13. "io"
  14. "io/ioutil"
  15. "log"
  16. "net/url"
  17. "strings"
  18. "sync"
  19. "time"
  20. )
  21. // A Client is an HTTP client. Its zero value (DefaultClient) is a
  22. // usable client that uses DefaultTransport.
  23. //
  24. // The Client's Transport typically has internal state (cached TCP
  25. // connections), so Clients should be reused instead of created as
  26. // needed. Clients are safe for concurrent use by multiple goroutines.
  27. //
  28. // A Client is higher-level than a RoundTripper (such as Transport)
  29. // and additionally handles HTTP details such as cookies and
  30. // redirects.
  31. type Client struct {
  32. // Transport specifies the mechanism by which individual
  33. // HTTP requests are made.
  34. // If nil, DefaultTransport is used.
  35. Transport RoundTripper
  36. // CheckRedirect specifies the policy for handling redirects.
  37. // If CheckRedirect is not nil, the client calls it before
  38. // following an HTTP redirect. The arguments req and via are
  39. // the upcoming request and the requests made already, oldest
  40. // first. If CheckRedirect returns an error, the Client's Get
  41. // method returns both the previous Response and
  42. // CheckRedirect's error (wrapped in a url.Error) instead of
  43. // issuing the Request req.
  44. //
  45. // If CheckRedirect is nil, the Client uses its default policy,
  46. // which is to stop after 10 consecutive requests.
  47. CheckRedirect func(req *Request, via []*Request) error
  48. // Jar specifies the cookie jar.
  49. // If Jar is nil, cookies are not sent in requests and ignored
  50. // in responses.
  51. Jar CookieJar
  52. // Timeout specifies a time limit for requests made by this
  53. // Client. The timeout includes connection time, any
  54. // redirects, and reading the response body. The timer remains
  55. // running after Get, Head, Post, or Do return and will
  56. // interrupt reading of the Response.Body.
  57. //
  58. // A Timeout of zero means no timeout.
  59. //
  60. // The Client's Transport must support the CancelRequest
  61. // method or Client will return errors when attempting to make
  62. // a request with Get, Head, Post, or Do. Client's default
  63. // Transport (DefaultTransport) supports CancelRequest.
  64. Timeout time.Duration
  65. }
  66. // DefaultClient is the default Client and is used by Get, Head, and Post.
  67. var DefaultClient = &Client{}
  68. // RoundTripper is an interface representing the ability to execute a
  69. // single HTTP transaction, obtaining the Response for a given Request.
  70. //
  71. // A RoundTripper must be safe for concurrent use by multiple
  72. // goroutines.
  73. type RoundTripper interface {
  74. // RoundTrip executes a single HTTP transaction, returning
  75. // the Response for the request req. RoundTrip should not
  76. // attempt to interpret the response. In particular,
  77. // RoundTrip must return err == nil if it obtained a response,
  78. // regardless of the response's HTTP status code. A non-nil
  79. // err should be reserved for failure to obtain a response.
  80. // Similarly, RoundTrip should not attempt to handle
  81. // higher-level protocol details such as redirects,
  82. // authentication, or cookies.
  83. //
  84. // RoundTrip should not modify the request, except for
  85. // consuming and closing the Body, including on errors. The
  86. // request's URL and Header fields are guaranteed to be
  87. // initialized.
  88. RoundTrip(*Request) (*Response, error)
  89. }
  90. // Given a string of the form "host", "host:port", or "[ipv6::address]:port",
  91. // return true if the string includes a port.
  92. func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
  93. // Used in Send to implement io.ReadCloser by bundling together the
  94. // bufio.Reader through which we read the response, and the underlying
  95. // network connection.
  96. type readClose struct {
  97. io.Reader
  98. io.Closer
  99. }
  100. func (c *Client) send(req *Request) (*Response, error) {
  101. if c.Jar != nil {
  102. for _, cookie := range c.Jar.Cookies(req.URL) {
  103. req.AddCookie(cookie)
  104. }
  105. }
  106. resp, err := send(req, c.transport())
  107. if err != nil {
  108. return nil, err
  109. }
  110. if c.Jar != nil {
  111. if rc := resp.Cookies(); len(rc) > 0 {
  112. c.Jar.SetCookies(req.URL, rc)
  113. }
  114. }
  115. return resp, err
  116. }
  117. // Do sends an HTTP request and returns an HTTP response, following
  118. // policy (e.g. redirects, cookies, auth) as configured on the client.
  119. //
  120. // An error is returned if caused by client policy (such as
  121. // CheckRedirect), or if there was an HTTP protocol error.
  122. // A non-2xx response doesn't cause an error.
  123. //
  124. // When err is nil, resp always contains a non-nil resp.Body.
  125. //
  126. // Callers should close resp.Body when done reading from it. If
  127. // resp.Body is not closed, the Client's underlying RoundTripper
  128. // (typically Transport) may not be able to re-use a persistent TCP
  129. // connection to the server for a subsequent "keep-alive" request.
  130. //
  131. // The request Body, if non-nil, will be closed by the underlying
  132. // Transport, even on errors.
  133. //
  134. // Generally Get, Post, or PostForm will be used instead of Do.
  135. func (c *Client) Do(req *Request) (resp *Response, err error) {
  136. if req.Method == "GET" || req.Method == "HEAD" {
  137. return c.doFollowingRedirects(req, shouldRedirectGet)
  138. }
  139. if req.Method == "POST" || req.Method == "PUT" {
  140. return c.doFollowingRedirects(req, shouldRedirectPost)
  141. }
  142. return c.send(req)
  143. }
  144. func (c *Client) transport() RoundTripper {
  145. if c.Transport != nil {
  146. return c.Transport
  147. }
  148. return DefaultTransport
  149. }
  150. // send issues an HTTP request.
  151. // Caller should close resp.Body when done reading from it.
  152. func send(req *Request, t RoundTripper) (resp *Response, err error) {
  153. if t == nil {
  154. req.closeBody()
  155. return nil, errors.New("http: no Client.Transport or DefaultTransport")
  156. }
  157. if req.URL == nil {
  158. req.closeBody()
  159. return nil, errors.New("http: nil Request.URL")
  160. }
  161. if req.RequestURI != "" {
  162. req.closeBody()
  163. return nil, errors.New("http: Request.RequestURI can't be set in client requests.")
  164. }
  165. // Most the callers of send (Get, Post, et al) don't need
  166. // Headers, leaving it uninitialized. We guarantee to the
  167. // Transport that this has been initialized, though.
  168. if req.Header == nil {
  169. req.Header = make(Header)
  170. }
  171. if u := req.URL.User; u != nil {
  172. username := u.Username()
  173. password, _ := u.Password()
  174. req.Header.Set("Authorization", "Basic "+basicAuth(username, password))
  175. }
  176. resp, err = t.RoundTrip(req)
  177. if err != nil {
  178. if resp != nil {
  179. log.Printf("RoundTripper returned a response & error; ignoring response")
  180. }
  181. return nil, err
  182. }
  183. return resp, nil
  184. }
  185. // See 2 (end of page 4) http://www.ietf.org/rfc/rfc2617.txt
  186. // "To receive authorization, the client sends the userid and password,
  187. // separated by a single colon (":") character, within a base64
  188. // encoded string in the credentials."
  189. // It is not meant to be urlencoded.
  190. func basicAuth(username, password string) string {
  191. auth := username + ":" + password
  192. return base64.StdEncoding.EncodeToString([]byte(auth))
  193. }
  194. // True if the specified HTTP status code is one for which the Get utility should
  195. // automatically redirect.
  196. func shouldRedirectGet(statusCode int) bool {
  197. switch statusCode {
  198. case StatusMovedPermanently, StatusFound, StatusSeeOther, StatusTemporaryRedirect:
  199. return true
  200. }
  201. return false
  202. }
  203. // True if the specified HTTP status code is one for which the Post utility should
  204. // automatically redirect.
  205. func shouldRedirectPost(statusCode int) bool {
  206. switch statusCode {
  207. case StatusFound, StatusSeeOther:
  208. return true
  209. }
  210. return false
  211. }
  212. // Get issues a GET to the specified URL. If the response is one of the following
  213. // redirect codes, Get follows the redirect, up to a maximum of 10 redirects:
  214. //
  215. // 301 (Moved Permanently)
  216. // 302 (Found)
  217. // 303 (See Other)
  218. // 307 (Temporary Redirect)
  219. //
  220. // An error is returned if there were too many redirects or if there
  221. // was an HTTP protocol error. A non-2xx response doesn't cause an
  222. // error.
  223. //
  224. // When err is nil, resp always contains a non-nil resp.Body.
  225. // Caller should close resp.Body when done reading from it.
  226. //
  227. // Get is a wrapper around DefaultClient.Get.
  228. func Get(url string) (resp *Response, err error) {
  229. return DefaultClient.Get(url)
  230. }
  231. // Get issues a GET to the specified URL. If the response is one of the
  232. // following redirect codes, Get follows the redirect after calling the
  233. // Client's CheckRedirect function.
  234. //
  235. // 301 (Moved Permanently)
  236. // 302 (Found)
  237. // 303 (See Other)
  238. // 307 (Temporary Redirect)
  239. //
  240. // An error is returned if the Client's CheckRedirect function fails
  241. // or if there was an HTTP protocol error. A non-2xx response doesn't
  242. // cause an error.
  243. //
  244. // When err is nil, resp always contains a non-nil resp.Body.
  245. // Caller should close resp.Body when done reading from it.
  246. func (c *Client) Get(url string) (resp *Response, err error) {
  247. req, err := NewRequest("GET", url, nil)
  248. if err != nil {
  249. return nil, err
  250. }
  251. return c.doFollowingRedirects(req, shouldRedirectGet)
  252. }
  253. func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bool) (resp *Response, err error) {
  254. var base *url.URL
  255. redirectChecker := c.CheckRedirect
  256. if redirectChecker == nil {
  257. redirectChecker = defaultCheckRedirect
  258. }
  259. var via []*Request
  260. if ireq.URL == nil {
  261. ireq.closeBody()
  262. return nil, errors.New("http: nil Request.URL")
  263. }
  264. var reqmu sync.Mutex // guards req
  265. req := ireq
  266. var timer *time.Timer
  267. if c.Timeout > 0 {
  268. type canceler interface {
  269. CancelRequest(*Request)
  270. }
  271. tr, ok := c.transport().(canceler)
  272. if !ok {
  273. return nil, fmt.Errorf("net/http: Client Transport of type %T doesn't support CancelRequest; Timeout not supported", c.transport())
  274. }
  275. timer = time.AfterFunc(c.Timeout, func() {
  276. reqmu.Lock()
  277. defer reqmu.Unlock()
  278. tr.CancelRequest(req)
  279. })
  280. }
  281. urlStr := "" // next relative or absolute URL to fetch (after first request)
  282. redirectFailed := false
  283. for redirect := 0; ; redirect++ {
  284. if redirect != 0 {
  285. nreq := new(Request)
  286. nreq.Method = ireq.Method
  287. if ireq.Method == "POST" || ireq.Method == "PUT" {
  288. nreq.Method = "GET"
  289. }
  290. nreq.Header = make(Header)
  291. nreq.URL, err = base.Parse(urlStr)
  292. if err != nil {
  293. break
  294. }
  295. if len(via) > 0 {
  296. // Add the Referer header.
  297. lastReq := via[len(via)-1]
  298. if lastReq.URL.Scheme != "https" {
  299. nreq.Header.Set("Referer", lastReq.URL.String())
  300. }
  301. err = redirectChecker(nreq, via)
  302. if err != nil {
  303. redirectFailed = true
  304. break
  305. }
  306. }
  307. reqmu.Lock()
  308. req = nreq
  309. reqmu.Unlock()
  310. }
  311. urlStr = req.URL.String()
  312. if resp, err = c.send(req); err != nil {
  313. break
  314. }
  315. if shouldRedirect(resp.StatusCode) {
  316. // Read the body if small so underlying TCP connection will be re-used.
  317. // No need to check for errors: if it fails, Transport won't reuse it anyway.
  318. const maxBodySlurpSize = 2 << 10
  319. if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize {
  320. io.CopyN(ioutil.Discard, resp.Body, maxBodySlurpSize)
  321. }
  322. resp.Body.Close()
  323. if urlStr = resp.Header.Get("Location"); urlStr == "" {
  324. err = errors.New(fmt.Sprintf("%d response missing Location header", resp.StatusCode))
  325. break
  326. }
  327. base = req.URL
  328. via = append(via, req)
  329. continue
  330. }
  331. if timer != nil {
  332. resp.Body = &cancelTimerBody{timer, resp.Body}
  333. }
  334. return resp, nil
  335. }
  336. method := ireq.Method
  337. urlErr := &url.Error{
  338. Op: method[0:1] + strings.ToLower(method[1:]),
  339. URL: urlStr,
  340. Err: err,
  341. }
  342. if redirectFailed {
  343. // Special case for Go 1 compatibility: return both the response
  344. // and an error if the CheckRedirect function failed.
  345. // See http://golang.org/issue/3795
  346. return resp, urlErr
  347. }
  348. if resp != nil {
  349. resp.Body.Close()
  350. }
  351. return nil, urlErr
  352. }
  353. func defaultCheckRedirect(req *Request, via []*Request) error {
  354. if len(via) >= 10 {
  355. return errors.New("stopped after 10 redirects")
  356. }
  357. return nil
  358. }
  359. // Post issues a POST to the specified URL.
  360. //
  361. // Caller should close resp.Body when done reading from it.
  362. //
  363. // Post is a wrapper around DefaultClient.Post
  364. func Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
  365. return DefaultClient.Post(url, bodyType, body)
  366. }
  367. // Post issues a POST to the specified URL.
  368. //
  369. // Caller should close resp.Body when done reading from it.
  370. //
  371. // If the provided body is also an io.Closer, it is closed after the
  372. // request.
  373. func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
  374. req, err := NewRequest("POST", url, body)
  375. if err != nil {
  376. return nil, err
  377. }
  378. req.Header.Set("Content-Type", bodyType)
  379. return c.doFollowingRedirects(req, shouldRedirectPost)
  380. }
  381. // PostForm issues a POST to the specified URL, with data's keys and
  382. // values URL-encoded as the request body.
  383. //
  384. // When err is nil, resp always contains a non-nil resp.Body.
  385. // Caller should close resp.Body when done reading from it.
  386. //
  387. // PostForm is a wrapper around DefaultClient.PostForm
  388. func PostForm(url string, data url.Values) (resp *Response, err error) {
  389. return DefaultClient.PostForm(url, data)
  390. }
  391. // PostForm issues a POST to the specified URL,
  392. // with data's keys and values urlencoded as the request body.
  393. //
  394. // When err is nil, resp always contains a non-nil resp.Body.
  395. // Caller should close resp.Body when done reading from it.
  396. func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) {
  397. return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
  398. }
  399. // Head issues a HEAD to the specified URL. If the response is one of the
  400. // following redirect codes, Head follows the redirect after calling the
  401. // Client's CheckRedirect function.
  402. //
  403. // 301 (Moved Permanently)
  404. // 302 (Found)
  405. // 303 (See Other)
  406. // 307 (Temporary Redirect)
  407. //
  408. // Head is a wrapper around DefaultClient.Head
  409. func Head(url string) (resp *Response, err error) {
  410. return DefaultClient.Head(url)
  411. }
  412. // Head issues a HEAD to the specified URL. If the response is one of the
  413. // following redirect codes, Head follows the redirect after calling the
  414. // Client's CheckRedirect function.
  415. //
  416. // 301 (Moved Permanently)
  417. // 302 (Found)
  418. // 303 (See Other)
  419. // 307 (Temporary Redirect)
  420. func (c *Client) Head(url string) (resp *Response, err error) {
  421. req, err := NewRequest("HEAD", url, nil)
  422. if err != nil {
  423. return nil, err
  424. }
  425. return c.doFollowingRedirects(req, shouldRedirectGet)
  426. }
  427. type cancelTimerBody struct {
  428. t *time.Timer
  429. rc io.ReadCloser
  430. }
  431. func (b *cancelTimerBody) Read(p []byte) (n int, err error) {
  432. n, err = b.rc.Read(p)
  433. if err == io.EOF {
  434. b.t.Stop()
  435. }
  436. return
  437. }
  438. func (b *cancelTimerBody) Close() error {
  439. err := b.rc.Close()
  440. b.t.Stop()
  441. return err
  442. }