http_util.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. package util
  2. import (
  3. "bytes"
  4. "compress/gzip"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "io"
  9. "io/ioutil"
  10. "math"
  11. "net"
  12. "net/http"
  13. "net/url"
  14. "strings"
  15. "github.com/golang/protobuf/proto"
  16. "github.com/chrislusf/seaweedfs/weed/glog"
  17. )
  18. var (
  19. client *http.Client
  20. Transport *http.Transport
  21. )
  22. func init() {
  23. Transport = &http.Transport{
  24. MaxIdleConnsPerHost: 1024,
  25. }
  26. client = &http.Client{
  27. Transport: Transport,
  28. }
  29. }
  30. func PostBytes(url string, body []byte) ([]byte, error) {
  31. r, err := client.Post(url, "", bytes.NewReader(body))
  32. if err != nil {
  33. return nil, fmt.Errorf("Post to %s: %v", url, err)
  34. }
  35. defer r.Body.Close()
  36. b, err := ioutil.ReadAll(r.Body)
  37. if err != nil {
  38. return nil, fmt.Errorf("Read response body: %v", err)
  39. }
  40. if r.StatusCode >= 400 {
  41. return nil, fmt.Errorf("%s: %s", url, r.Status)
  42. }
  43. return b, nil
  44. }
  45. func Post(url string, values url.Values) ([]byte, error) {
  46. r, err := client.PostForm(url, values)
  47. if err != nil {
  48. return nil, err
  49. }
  50. defer r.Body.Close()
  51. b, err := ioutil.ReadAll(r.Body)
  52. if r.StatusCode >= 400 {
  53. if err != nil {
  54. return nil, fmt.Errorf("%s: %d - %s", url, r.StatusCode, string(b))
  55. } else {
  56. return nil, fmt.Errorf("%s: %s", url, r.Status)
  57. }
  58. }
  59. if err != nil {
  60. return nil, err
  61. }
  62. return b, nil
  63. }
  64. // github.com/chrislusf/seaweedfs/unmaintained/repeated_vacuum/repeated_vacuum.go
  65. // may need increasing http.Client.Timeout
  66. func Get(url string) ([]byte, error) {
  67. r, err := client.Get(url)
  68. if err != nil {
  69. return nil, err
  70. }
  71. defer r.Body.Close()
  72. b, err := ioutil.ReadAll(r.Body)
  73. if r.StatusCode >= 400 {
  74. return nil, fmt.Errorf("%s: %s", url, r.Status)
  75. }
  76. if err != nil {
  77. return nil, err
  78. }
  79. return b, nil
  80. }
  81. func Head(url string) (http.Header, error) {
  82. r, err := client.Head(url)
  83. if err != nil {
  84. return nil, err
  85. }
  86. defer CloseResponse(r)
  87. if r.StatusCode >= 400 {
  88. return nil, fmt.Errorf("%s: %s", url, r.Status)
  89. }
  90. return r.Header, nil
  91. }
  92. func Delete(url string, jwt string) error {
  93. req, err := http.NewRequest("DELETE", url, nil)
  94. if jwt != "" {
  95. req.Header.Set("Authorization", "BEARER "+string(jwt))
  96. }
  97. if err != nil {
  98. return err
  99. }
  100. resp, e := client.Do(req)
  101. if e != nil {
  102. return e
  103. }
  104. defer resp.Body.Close()
  105. body, err := ioutil.ReadAll(resp.Body)
  106. if err != nil {
  107. return err
  108. }
  109. switch resp.StatusCode {
  110. case http.StatusNotFound, http.StatusAccepted, http.StatusOK:
  111. return nil
  112. }
  113. m := make(map[string]interface{})
  114. if e := json.Unmarshal(body, m); e == nil {
  115. if s, ok := m["error"].(string); ok {
  116. return errors.New(s)
  117. }
  118. }
  119. return errors.New(string(body))
  120. }
  121. func GetBufferStream(url string, values url.Values, allocatedBytes []byte, eachBuffer func([]byte)) error {
  122. r, err := client.PostForm(url, values)
  123. if err != nil {
  124. return err
  125. }
  126. defer CloseResponse(r)
  127. if r.StatusCode != 200 {
  128. return fmt.Errorf("%s: %s", url, r.Status)
  129. }
  130. for {
  131. n, err := r.Body.Read(allocatedBytes)
  132. if n > 0 {
  133. eachBuffer(allocatedBytes[:n])
  134. }
  135. if err != nil {
  136. if err == io.EOF {
  137. return nil
  138. }
  139. return err
  140. }
  141. }
  142. }
  143. func GetUrlStream(url string, values url.Values, readFn func(io.Reader) error) error {
  144. r, err := client.PostForm(url, values)
  145. if err != nil {
  146. return err
  147. }
  148. defer CloseResponse(r)
  149. if r.StatusCode != 200 {
  150. return fmt.Errorf("%s: %s", url, r.Status)
  151. }
  152. return readFn(r.Body)
  153. }
  154. func DownloadFile(fileUrl string) (filename string, header http.Header, rc io.ReadCloser, e error) {
  155. response, err := client.Get(fileUrl)
  156. if err != nil {
  157. return "", nil, nil, err
  158. }
  159. header = response.Header
  160. contentDisposition := response.Header["Content-Disposition"]
  161. if len(contentDisposition) > 0 {
  162. idx := strings.Index(contentDisposition[0], "filename=")
  163. if idx != -1 {
  164. filename = contentDisposition[0][idx+len("filename="):]
  165. filename = strings.Trim(filename, "\"")
  166. }
  167. }
  168. rc = response.Body
  169. return
  170. }
  171. func Do(req *http.Request) (resp *http.Response, err error) {
  172. return client.Do(req)
  173. }
  174. func NormalizeUrl(url string) string {
  175. if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") {
  176. return url
  177. }
  178. return "http://" + url
  179. }
  180. func ReadUrl(fileUrl string, offset int64, size int, buf []byte, isReadRange bool) (int64, error) {
  181. req, err := http.NewRequest("GET", fileUrl, nil)
  182. if err != nil {
  183. return 0, err
  184. }
  185. if isReadRange {
  186. req.Header.Add("Range", fmt.Sprintf("bytes=%d-%d", offset, offset+int64(size)-1))
  187. } else {
  188. req.Header.Set("Accept-Encoding", "gzip")
  189. }
  190. r, err := client.Do(req)
  191. if err != nil {
  192. return 0, err
  193. }
  194. defer r.Body.Close()
  195. if r.StatusCode >= 400 {
  196. return 0, fmt.Errorf("%s: %s", fileUrl, r.Status)
  197. }
  198. var reader io.ReadCloser
  199. contentEncoding := r.Header.Get("Content-Encoding")
  200. switch contentEncoding {
  201. case "gzip":
  202. reader, err = gzip.NewReader(r.Body)
  203. defer reader.Close()
  204. default:
  205. reader = r.Body
  206. }
  207. var (
  208. i, m int
  209. n int64
  210. )
  211. // refers to https://github.com/golang/go/blob/master/src/bytes/buffer.go#L199
  212. // commit id c170b14c2c1cfb2fd853a37add92a82fd6eb4318
  213. for {
  214. m, err = reader.Read(buf[i:])
  215. i += m
  216. n += int64(m)
  217. if err == io.EOF {
  218. return n, nil
  219. }
  220. if err != nil {
  221. return n, err
  222. }
  223. if n == int64(len(buf)) {
  224. break
  225. }
  226. }
  227. // drains the response body to avoid memory leak
  228. data, _ := ioutil.ReadAll(reader)
  229. if len(data) != 0 {
  230. glog.V(1).Infof("%s reader has remaining %d bytes", contentEncoding, len(data))
  231. }
  232. return n, err
  233. }
  234. func ReadUrlAsStream(fileUrl string, offset int64, size int, fn func(data []byte)) (int64, error) {
  235. req, err := http.NewRequest("GET", fileUrl, nil)
  236. if err != nil {
  237. return 0, err
  238. }
  239. req.Header.Add("Range", fmt.Sprintf("bytes=%d-%d", offset, offset+int64(size)-1))
  240. r, err := client.Do(req)
  241. if err != nil {
  242. return 0, err
  243. }
  244. defer CloseResponse(r)
  245. if r.StatusCode >= 400 {
  246. return 0, fmt.Errorf("%s: %s", fileUrl, r.Status)
  247. }
  248. var (
  249. m int
  250. n int64
  251. )
  252. buf := make([]byte, 64*1024)
  253. for {
  254. m, err = r.Body.Read(buf)
  255. fn(buf[:m])
  256. n += int64(m)
  257. if err == io.EOF {
  258. return n, nil
  259. }
  260. if err != nil {
  261. return n, err
  262. }
  263. }
  264. }
  265. func ReadUrlAsReaderCloser(fileUrl string, rangeHeader string) (io.ReadCloser, error) {
  266. req, err := http.NewRequest("GET", fileUrl, nil)
  267. if err != nil {
  268. return nil, err
  269. }
  270. if rangeHeader != "" {
  271. req.Header.Add("Range", rangeHeader)
  272. }
  273. r, err := client.Do(req)
  274. if err != nil {
  275. return nil, err
  276. }
  277. if r.StatusCode >= 400 {
  278. return nil, fmt.Errorf("%s: %s", fileUrl, r.Status)
  279. }
  280. return r.Body, nil
  281. }
  282. func CloseResponse(resp *http.Response) {
  283. io.Copy(ioutil.Discard, resp.Body)
  284. resp.Body.Close()
  285. }
  286. func WriteMessage(conn net.Conn, message proto.Message) error {
  287. data, err := proto.Marshal(message)
  288. if err != nil {
  289. glog.Fatalf("marshal: %v", err)
  290. }
  291. messageSizeBytes := make([]byte, 4)
  292. Uint32toBytes(messageSizeBytes, uint32(len(data)))
  293. _, err = conn.Write(messageSizeBytes)
  294. if err != nil {
  295. return err
  296. }
  297. _, err = conn.Write(data)
  298. return err
  299. }
  300. func WriteMessageEOF(conn net.Conn) error {
  301. messageSizeBytes := make([]byte, 4)
  302. Uint32toBytes(messageSizeBytes, math.MaxUint32)
  303. _, err := conn.Write(messageSizeBytes)
  304. return err
  305. }
  306. func ReadMessage(conn net.Conn, message proto.Message) error {
  307. messageSizeBuffer := make([]byte, 4)
  308. n, err := conn.Read(messageSizeBuffer)
  309. if err != nil {
  310. if err == io.EOF {
  311. // println("unexpected eof")
  312. return err
  313. }
  314. return fmt.Errorf("read message size byte length: %d %v", n, err)
  315. }
  316. if n != 4 {
  317. return fmt.Errorf("unexpected message size byte length: %d", n)
  318. }
  319. messageSize := BytesToUint32(messageSizeBuffer)
  320. if messageSize == math.MaxUint32 {
  321. // println("marked eof")
  322. return io.EOF
  323. }
  324. messageBytes := make([]byte, messageSize)
  325. readMessageLength, err := conn.Read(messageBytes)
  326. if readMessageLength != int(messageSize) {
  327. return fmt.Errorf("message size:%d, expected:%d", readMessageLength, messageSize)
  328. }
  329. if err := proto.Unmarshal(messageBytes, message); err != nil {
  330. return err
  331. }
  332. return nil
  333. }