You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

146 lines
3.2 KiB

  1. // Copyright 2013 The Go Authors. All rights reserved.
  2. //
  3. // Use of this source code is governed by a BSD-style
  4. // license that can be found in the LICENSE file or at
  5. // https://developers.google.com/open-source/licenses/bsd.
  6. package gosrc
  7. import (
  8. "encoding/json"
  9. "fmt"
  10. "io"
  11. "io/ioutil"
  12. "net/http"
  13. )
  14. type httpClient struct {
  15. errFn func(*http.Response) error
  16. header http.Header
  17. client *http.Client
  18. }
  19. func (c *httpClient) err(resp *http.Response) error {
  20. if resp.StatusCode == 404 {
  21. return NotFoundError{Message: "Resource not found: " + resp.Request.URL.String()}
  22. }
  23. if c.errFn != nil {
  24. return c.errFn(resp)
  25. }
  26. return &RemoteError{resp.Request.URL.Host, fmt.Errorf("%d: (%s)", resp.StatusCode, resp.Request.URL.String())}
  27. }
  28. // get issues a GET to the specified URL.
  29. func (c *httpClient) get(url string) (*http.Response, error) {
  30. req, err := http.NewRequest("GET", url, nil)
  31. if err != nil {
  32. return nil, err
  33. }
  34. for k, vs := range c.header {
  35. req.Header[k] = vs
  36. }
  37. resp, err := c.client.Do(req)
  38. if err != nil {
  39. return nil, &RemoteError{req.URL.Host, err}
  40. }
  41. return resp, err
  42. }
  43. // getNoFollow issues a GET to the specified URL without following redirects.
  44. func (c *httpClient) getNoFollow(url string) (*http.Response, error) {
  45. req, err := http.NewRequest("GET", url, nil)
  46. if err != nil {
  47. return nil, err
  48. }
  49. for k, vs := range c.header {
  50. req.Header[k] = vs
  51. }
  52. t := c.client.Transport
  53. if t == nil {
  54. t = http.DefaultTransport
  55. }
  56. resp, err := t.RoundTrip(req)
  57. if err != nil {
  58. return nil, &RemoteError{req.URL.Host, err}
  59. }
  60. return resp, err
  61. }
  62. func (c *httpClient) getBytes(url string) ([]byte, error) {
  63. resp, err := c.get(url)
  64. if err != nil {
  65. return nil, err
  66. }
  67. defer resp.Body.Close()
  68. if resp.StatusCode != 200 {
  69. return nil, c.err(resp)
  70. }
  71. p, err := ioutil.ReadAll(resp.Body)
  72. return p, err
  73. }
  74. func (c *httpClient) getReader(url string) (io.ReadCloser, error) {
  75. resp, err := c.get(url)
  76. if err != nil {
  77. return nil, err
  78. }
  79. if resp.StatusCode != 200 {
  80. err = c.err(resp)
  81. resp.Body.Close()
  82. return nil, err
  83. }
  84. return resp.Body, nil
  85. }
  86. func (c *httpClient) getJSON(url string, v interface{}) (*http.Response, error) {
  87. resp, err := c.get(url)
  88. if err != nil {
  89. return resp, err
  90. }
  91. defer resp.Body.Close()
  92. if resp.StatusCode != 200 {
  93. return resp, c.err(resp)
  94. }
  95. err = json.NewDecoder(resp.Body).Decode(v)
  96. if _, ok := err.(*json.SyntaxError); ok {
  97. err = NotFoundError{Message: "JSON syntax error at " + url}
  98. }
  99. return resp, err
  100. }
  101. func (c *httpClient) getFiles(urls []string, files []*File) error {
  102. ch := make(chan error, len(files))
  103. for i := range files {
  104. go func(i int) {
  105. resp, err := c.get(urls[i])
  106. if err != nil {
  107. ch <- err
  108. return
  109. }
  110. defer resp.Body.Close()
  111. if resp.StatusCode != 200 {
  112. var err error
  113. if c.errFn != nil {
  114. err = c.errFn(resp)
  115. } else {
  116. err = &RemoteError{resp.Request.URL.Host, fmt.Errorf("get %s -> %d", urls[i], resp.StatusCode)}
  117. }
  118. ch <- err
  119. return
  120. }
  121. files[i].Data, err = ioutil.ReadAll(resp.Body)
  122. if err != nil {
  123. ch <- &RemoteError{resp.Request.URL.Host, err}
  124. return
  125. }
  126. ch <- nil
  127. }(i)
  128. }
  129. for range files {
  130. if err := <-ch; err != nil {
  131. return err
  132. }
  133. }
  134. return nil
  135. }