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.

transferadapter.go 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package lfs
  4. import (
  5. "bytes"
  6. "context"
  7. "errors"
  8. "fmt"
  9. "io"
  10. "net/http"
  11. "code.gitea.io/gitea/modules/json"
  12. "code.gitea.io/gitea/modules/log"
  13. )
  14. // TransferAdapter represents an adapter for downloading/uploading LFS objects
  15. type TransferAdapter interface {
  16. Name() string
  17. Download(ctx context.Context, l *Link) (io.ReadCloser, error)
  18. Upload(ctx context.Context, l *Link, p Pointer, r io.Reader) error
  19. Verify(ctx context.Context, l *Link, p Pointer) error
  20. }
  21. // BasicTransferAdapter implements the "basic" adapter
  22. type BasicTransferAdapter struct {
  23. client *http.Client
  24. }
  25. // Name returns the name of the adapter
  26. func (a *BasicTransferAdapter) Name() string {
  27. return "basic"
  28. }
  29. // Download reads the download location and downloads the data
  30. func (a *BasicTransferAdapter) Download(ctx context.Context, l *Link) (io.ReadCloser, error) {
  31. resp, err := a.performRequest(ctx, "GET", l, nil, nil)
  32. if err != nil {
  33. return nil, err
  34. }
  35. return resp.Body, nil
  36. }
  37. // Upload sends the content to the LFS server
  38. func (a *BasicTransferAdapter) Upload(ctx context.Context, l *Link, p Pointer, r io.Reader) error {
  39. _, err := a.performRequest(ctx, "PUT", l, r, func(req *http.Request) {
  40. if len(req.Header.Get("Content-Type")) == 0 {
  41. req.Header.Set("Content-Type", "application/octet-stream")
  42. }
  43. if req.Header.Get("Transfer-Encoding") == "chunked" {
  44. req.TransferEncoding = []string{"chunked"}
  45. }
  46. req.ContentLength = p.Size
  47. })
  48. if err != nil {
  49. return err
  50. }
  51. return nil
  52. }
  53. // Verify calls the verify handler on the LFS server
  54. func (a *BasicTransferAdapter) Verify(ctx context.Context, l *Link, p Pointer) error {
  55. b, err := json.Marshal(p)
  56. if err != nil {
  57. log.Error("Error encoding json: %v", err)
  58. return err
  59. }
  60. _, err = a.performRequest(ctx, "POST", l, bytes.NewReader(b), func(req *http.Request) {
  61. req.Header.Set("Content-Type", MediaType)
  62. })
  63. if err != nil {
  64. return err
  65. }
  66. return nil
  67. }
  68. func (a *BasicTransferAdapter) performRequest(ctx context.Context, method string, l *Link, body io.Reader, callback func(*http.Request)) (*http.Response, error) {
  69. log.Trace("Calling: %s %s", method, l.Href)
  70. req, err := http.NewRequestWithContext(ctx, method, l.Href, body)
  71. if err != nil {
  72. log.Error("Error creating request: %v", err)
  73. return nil, err
  74. }
  75. for key, value := range l.Header {
  76. req.Header.Set(key, value)
  77. }
  78. req.Header.Set("Accept", MediaType)
  79. if callback != nil {
  80. callback(req)
  81. }
  82. res, err := a.client.Do(req)
  83. if err != nil {
  84. select {
  85. case <-ctx.Done():
  86. return res, ctx.Err()
  87. default:
  88. }
  89. log.Error("Error while processing request: %v", err)
  90. return res, err
  91. }
  92. if res.StatusCode != http.StatusOK {
  93. return res, handleErrorResponse(res)
  94. }
  95. return res, nil
  96. }
  97. func handleErrorResponse(resp *http.Response) error {
  98. defer resp.Body.Close()
  99. er, err := decodeResponseError(resp.Body)
  100. if err != nil {
  101. return fmt.Errorf("Request failed with status %s", resp.Status)
  102. }
  103. log.Trace("ErrorRespone: %v", er)
  104. return errors.New(er.Message)
  105. }
  106. func decodeResponseError(r io.Reader) (ErrorResponse, error) {
  107. var er ErrorResponse
  108. err := json.NewDecoder(r).Decode(&er)
  109. if err != nil {
  110. log.Error("Error decoding json: %v", err)
  111. }
  112. return er, err
  113. }