code.gitea.io/gitea@v1.22.3/modules/lfs/transferadapter.go (about)

     1  // Copyright 2021 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package lfs
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"io"
    10  	"net/http"
    11  
    12  	"code.gitea.io/gitea/modules/json"
    13  	"code.gitea.io/gitea/modules/log"
    14  )
    15  
    16  // TransferAdapter represents an adapter for downloading/uploading LFS objects.
    17  type TransferAdapter interface {
    18  	Name() string
    19  	Download(ctx context.Context, l *Link) (io.ReadCloser, error)
    20  	Upload(ctx context.Context, l *Link, p Pointer, r io.Reader) error
    21  	Verify(ctx context.Context, l *Link, p Pointer) error
    22  }
    23  
    24  // BasicTransferAdapter implements the "basic" adapter.
    25  type BasicTransferAdapter struct {
    26  	client *http.Client
    27  }
    28  
    29  // Name returns the name of the adapter.
    30  func (a *BasicTransferAdapter) Name() string {
    31  	return "basic"
    32  }
    33  
    34  // Download reads the download location and downloads the data.
    35  func (a *BasicTransferAdapter) Download(ctx context.Context, l *Link) (io.ReadCloser, error) {
    36  	req, err := createRequest(ctx, http.MethodGet, l.Href, l.Header, nil)
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  	log.Debug("Download Request: %+v", req)
    41  	resp, err := performRequest(ctx, a.client, req)
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  	return resp.Body, nil
    46  }
    47  
    48  // Upload sends the content to the LFS server.
    49  func (a *BasicTransferAdapter) Upload(ctx context.Context, l *Link, p Pointer, r io.Reader) error {
    50  	req, err := createRequest(ctx, http.MethodPut, l.Href, l.Header, r)
    51  	if err != nil {
    52  		return err
    53  	}
    54  	if req.Header.Get("Content-Type") == "" {
    55  		req.Header.Set("Content-Type", "application/octet-stream")
    56  	}
    57  	if req.Header.Get("Transfer-Encoding") == "chunked" {
    58  		req.TransferEncoding = []string{"chunked"}
    59  	}
    60  	req.ContentLength = p.Size
    61  
    62  	res, err := performRequest(ctx, a.client, req)
    63  	if err != nil {
    64  		return err
    65  	}
    66  	defer res.Body.Close()
    67  	return nil
    68  }
    69  
    70  // Verify calls the verify handler on the LFS server
    71  func (a *BasicTransferAdapter) Verify(ctx context.Context, l *Link, p Pointer) error {
    72  	b, err := json.Marshal(p)
    73  	if err != nil {
    74  		log.Error("Error encoding json: %v", err)
    75  		return err
    76  	}
    77  
    78  	req, err := createRequest(ctx, http.MethodPost, l.Href, l.Header, bytes.NewReader(b))
    79  	if err != nil {
    80  		return err
    81  	}
    82  	req.Header.Set("Content-Type", MediaType)
    83  	res, err := performRequest(ctx, a.client, req)
    84  	if err != nil {
    85  		return err
    86  	}
    87  	defer res.Body.Close()
    88  	return nil
    89  }