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.

271 lines
5.4 KiB

9 years ago
7 years ago
10 years ago
  1. package util
  2. import (
  3. "bytes"
  4. "compress/gzip"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "io"
  9. "io/ioutil"
  10. "net/http"
  11. "net/url"
  12. "strings"
  13. "time"
  14. )
  15. var (
  16. client *http.Client
  17. Transport *http.Transport
  18. )
  19. func init() {
  20. Transport = &http.Transport{
  21. MaxIdleConnsPerHost: 1024,
  22. }
  23. client = &http.Client{
  24. Transport: Transport,
  25. Timeout: 5 * time.Second,
  26. }
  27. }
  28. func PostBytes(url string, body []byte) ([]byte, error) {
  29. r, err := client.Post(url, "application/octet-stream", bytes.NewReader(body))
  30. if err != nil {
  31. return nil, fmt.Errorf("Post to %s: %v", url, err)
  32. }
  33. defer r.Body.Close()
  34. if r.StatusCode >= 400 {
  35. return nil, fmt.Errorf("%s: %s", url, r.Status)
  36. }
  37. b, err := ioutil.ReadAll(r.Body)
  38. if err != nil {
  39. return nil, fmt.Errorf("Read response body: %v", err)
  40. }
  41. return b, nil
  42. }
  43. func Post(url string, values url.Values) ([]byte, error) {
  44. r, err := client.PostForm(url, values)
  45. if err != nil {
  46. return nil, err
  47. }
  48. defer r.Body.Close()
  49. b, err := ioutil.ReadAll(r.Body)
  50. if r.StatusCode >= 400 {
  51. if err != nil {
  52. return nil, fmt.Errorf("%s: %d - %s", url, r.StatusCode, string(b))
  53. } else {
  54. return nil, fmt.Errorf("%s: %s", url, r.Status)
  55. }
  56. }
  57. if err != nil {
  58. return nil, err
  59. }
  60. return b, nil
  61. }
  62. // github.com/chrislusf/seaweedfs/unmaintained/repeated_vacuum/repeated_vacuum.go
  63. // may need increasing http.Client.Timeout
  64. func Get(url string) ([]byte, error) {
  65. r, err := client.Get(url)
  66. if err != nil {
  67. return nil, err
  68. }
  69. defer r.Body.Close()
  70. b, err := ioutil.ReadAll(r.Body)
  71. if r.StatusCode >= 400 {
  72. return nil, fmt.Errorf("%s: %s", url, r.Status)
  73. }
  74. if err != nil {
  75. return nil, err
  76. }
  77. return b, nil
  78. }
  79. func Head(url string) (http.Header, error) {
  80. r, err := client.Head(url)
  81. if err != nil {
  82. return nil, err
  83. }
  84. defer r.Body.Close()
  85. if r.StatusCode >= 400 {
  86. return nil, fmt.Errorf("%s: %s", url, r.Status)
  87. }
  88. return r.Header, nil
  89. }
  90. func Delete(url string, jwt string) error {
  91. req, err := http.NewRequest("DELETE", url, nil)
  92. if jwt != "" {
  93. req.Header.Set("Authorization", "BEARER "+string(jwt))
  94. }
  95. if err != nil {
  96. return err
  97. }
  98. resp, e := client.Do(req)
  99. if e != nil {
  100. return e
  101. }
  102. defer resp.Body.Close()
  103. body, err := ioutil.ReadAll(resp.Body)
  104. if err != nil {
  105. return err
  106. }
  107. switch resp.StatusCode {
  108. case http.StatusNotFound, http.StatusAccepted, http.StatusOK:
  109. return nil
  110. }
  111. m := make(map[string]interface{})
  112. if e := json.Unmarshal(body, m); e == nil {
  113. if s, ok := m["error"].(string); ok {
  114. return errors.New(s)
  115. }
  116. }
  117. return errors.New(string(body))
  118. }
  119. func GetBufferStream(url string, values url.Values, allocatedBytes []byte, eachBuffer func([]byte)) error {
  120. r, err := client.PostForm(url, values)
  121. if err != nil {
  122. return err
  123. }
  124. defer r.Body.Close()
  125. if r.StatusCode != 200 {
  126. return fmt.Errorf("%s: %s", url, r.Status)
  127. }
  128. for {
  129. n, err := r.Body.Read(allocatedBytes)
  130. if n > 0 {
  131. eachBuffer(allocatedBytes[:n])
  132. }
  133. if err != nil {
  134. if err == io.EOF {
  135. return nil
  136. }
  137. return err
  138. }
  139. }
  140. }
  141. func GetUrlStream(url string, values url.Values, readFn func(io.Reader) error) error {
  142. r, err := client.PostForm(url, values)
  143. if err != nil {
  144. return err
  145. }
  146. defer r.Body.Close()
  147. if r.StatusCode != 200 {
  148. return fmt.Errorf("%s: %s", url, r.Status)
  149. }
  150. return readFn(r.Body)
  151. }
  152. func DownloadFile(fileUrl string) (filename string, header http.Header, rc io.ReadCloser, e error) {
  153. response, err := client.Get(fileUrl)
  154. if err != nil {
  155. return "", nil, nil, err
  156. }
  157. header = response.Header
  158. contentDisposition := response.Header["Content-Disposition"]
  159. if len(contentDisposition) > 0 {
  160. idx := strings.Index(contentDisposition[0], "filename=")
  161. if idx != -1 {
  162. filename = contentDisposition[0][idx+len("filename="):]
  163. filename = strings.Trim(filename, "\"")
  164. }
  165. }
  166. rc = response.Body
  167. return
  168. }
  169. func Do(req *http.Request) (resp *http.Response, err error) {
  170. return client.Do(req)
  171. }
  172. func NormalizeUrl(url string) string {
  173. if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") {
  174. return url
  175. }
  176. return "http://" + url
  177. }
  178. func ReadUrl(fileUrl string, offset int64, size int, buf []byte, isReadRange bool) (n int64, e error) {
  179. req, _ := http.NewRequest("GET", fileUrl, nil)
  180. if isReadRange {
  181. req.Header.Add("Range", fmt.Sprintf("bytes=%d-%d", offset, offset+int64(size)))
  182. } else {
  183. req.Header.Set("Accept-Encoding", "gzip")
  184. }
  185. r, err := client.Do(req)
  186. if err != nil {
  187. return 0, err
  188. }
  189. defer r.Body.Close()
  190. if r.StatusCode >= 400 {
  191. return 0, fmt.Errorf("%s: %s", fileUrl, r.Status)
  192. }
  193. var reader io.ReadCloser
  194. switch r.Header.Get("Content-Encoding") {
  195. case "gzip":
  196. reader, err = gzip.NewReader(r.Body)
  197. defer reader.Close()
  198. default:
  199. reader = r.Body
  200. }
  201. var i, m int
  202. for {
  203. m, err = reader.Read(buf[i:])
  204. if m == 0 {
  205. return
  206. }
  207. i += m
  208. n += int64(m)
  209. if err == io.EOF {
  210. return n, nil
  211. }
  212. if e != nil {
  213. return n, e
  214. }
  215. }
  216. }
  217. func ReadUrlAsStream(fileUrl string, offset int64, size int, fn func(data []byte)) (n int64, e error) {
  218. req, _ := http.NewRequest("GET", fileUrl, nil)
  219. req.Header.Add("Range", fmt.Sprintf("bytes=%d-%d", offset, offset+int64(size)))
  220. r, err := client.Do(req)
  221. if err != nil {
  222. return 0, err
  223. }
  224. defer r.Body.Close()
  225. if r.StatusCode >= 400 {
  226. return 0, fmt.Errorf("%s: %s", fileUrl, r.Status)
  227. }
  228. var m int
  229. buf := make([]byte, 64*1024)
  230. for {
  231. m, err = r.Body.Read(buf)
  232. if m == 0 {
  233. return
  234. }
  235. fn(buf[:m])
  236. n += int64(m)
  237. if err == io.EOF {
  238. return n, nil
  239. }
  240. if e != nil {
  241. return n, e
  242. }
  243. }
  244. }