mirror of
https://codeberg.org/Codeberg/pages-server.git
synced 2025-01-19 17:07:54 +00:00
Merge branch 'move-more-logic-into-client' into std-http
This commit is contained in:
commit
48bc41938c
6 changed files with 90 additions and 10 deletions
11
cmd/flags.go
11
cmd/flags.go
|
@ -69,6 +69,17 @@ var ServeFlags = []cli.Flag{
|
||||||
// TODO: desc
|
// TODO: desc
|
||||||
EnvVars: []string{"ENABLE_HTTP_SERVER"},
|
EnvVars: []string{"ENABLE_HTTP_SERVER"},
|
||||||
},
|
},
|
||||||
|
// Server Options
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "enable-lfs-support",
|
||||||
|
Usage: "enable lfs support, require gitea v1.17.0 as backend",
|
||||||
|
EnvVars: []string{"ENABLE_LFS_SUPPORT"},
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "enable-symlink-support",
|
||||||
|
Usage: "follow symlinks if enabled, require gitea v1.18.0 as backend",
|
||||||
|
EnvVars: []string{"ENABLE_SYMLINK_SUPPORT"},
|
||||||
|
},
|
||||||
|
|
||||||
// ACME
|
// ACME
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
|
|
|
@ -82,7 +82,7 @@ func Serve(ctx *cli.Context) error {
|
||||||
// TODO: make this an MRU cache with a size limit
|
// TODO: make this an MRU cache with a size limit
|
||||||
fileResponseCache := cache.NewKeyValueCache()
|
fileResponseCache := cache.NewKeyValueCache()
|
||||||
|
|
||||||
giteaClient, err := gitea.NewClient(giteaRoot, giteaAPIToken, fileResponseCache)
|
giteaClient, err := gitea.NewClient(giteaRoot, giteaAPIToken, fileResponseCache, ctx.Bool("enable-symlink-support"), ctx.Bool("enable-lfs-support"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not create new gitea client: %v", err)
|
return fmt.Errorf("could not create new gitea client: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/cookiejar"
|
"net/http/cookiejar"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
@ -88,6 +89,34 @@ func TestGetNotFound(t *testing.T) {
|
||||||
assert.EqualValues(t, 37, getSize(resp.Body))
|
assert.EqualValues(t, 37, getSize(resp.Body))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFollowSymlink(t *testing.T) {
|
||||||
|
log.Printf("=== TestFollowSymlink ===\n")
|
||||||
|
|
||||||
|
resp, err := getTestHTTPSClient().Get("https://6543.localhost.mock.directory:4430/tests_for_pages-server/@main/link")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.EqualValues(t, http.StatusOK, resp.StatusCode) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
assert.EqualValues(t, "application/octet-stream", resp.Header.Get("Content-Type"))
|
||||||
|
assert.EqualValues(t, "4", resp.Header.Get("Content-Length"))
|
||||||
|
body := getBytes(resp.Body)
|
||||||
|
assert.EqualValues(t, 4, len(body))
|
||||||
|
assert.EqualValues(t, "abc\n", string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLFSSupport(t *testing.T) {
|
||||||
|
log.Printf("=== TestLFSSupport ===\n")
|
||||||
|
|
||||||
|
resp, err := getTestHTTPSClient().Get("https://6543.localhost.mock.directory:4430/tests_for_pages-server/@main/lfs.txt")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.EqualValues(t, http.StatusOK, resp.StatusCode) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
body := strings.TrimSpace(string(getBytes(resp.Body)))
|
||||||
|
assert.EqualValues(t, 12, len(body))
|
||||||
|
assert.EqualValues(t, "actual value", body)
|
||||||
|
}
|
||||||
|
|
||||||
func getTestHTTPSClient() *http.Client {
|
func getTestHTTPSClient() *http.Client {
|
||||||
cookieJar, _ := cookiejar.New(nil)
|
cookieJar, _ := cookiejar.New(nil)
|
||||||
return &http.Client{
|
return &http.Client{
|
||||||
|
@ -101,6 +130,12 @@ func getTestHTTPSClient() *http.Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getBytes(stream io.Reader) []byte {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
_, _ = buf.ReadFrom(stream)
|
||||||
|
return buf.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
func getSize(stream io.Reader) int {
|
func getSize(stream io.Reader) int {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
_, _ = buf.ReadFrom(stream)
|
_, _ = buf.ReadFrom(stream)
|
||||||
|
|
|
@ -8,13 +8,17 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
"github.com/valyala/fastjson"
|
"github.com/valyala/fastjson"
|
||||||
|
|
||||||
"codeberg.org/codeberg/pages/server/cache"
|
"codeberg.org/codeberg/pages/server/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
const giteaAPIRepos = "/api/v1/repos/"
|
const (
|
||||||
|
giteaAPIRepos = "/api/v1/repos/"
|
||||||
|
giteaObjectTypeHeader = "X-Gitea-Object-Type"
|
||||||
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
giteaRoot string
|
giteaRoot string
|
||||||
|
@ -23,9 +27,12 @@ type Client struct {
|
||||||
contentTimeout time.Duration
|
contentTimeout time.Duration
|
||||||
fastClient *fasthttp.Client
|
fastClient *fasthttp.Client
|
||||||
fileResponseCache cache.SetGetKey
|
fileResponseCache cache.SetGetKey
|
||||||
|
|
||||||
|
followSymlinks bool
|
||||||
|
supportLFS bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(giteaRoot, giteaAPIToken string, fileResponseCache cache.SetGetKey) (*Client, error) {
|
func NewClient(giteaRoot, giteaAPIToken string, fileResponseCache cache.SetGetKey, followSymlinks, supportLFS bool) (*Client, error) {
|
||||||
rootURL, err := url.Parse(giteaRoot)
|
rootURL, err := url.Parse(giteaRoot)
|
||||||
giteaRoot = strings.Trim(rootURL.String(), "/")
|
giteaRoot = strings.Trim(rootURL.String(), "/")
|
||||||
|
|
||||||
|
@ -36,6 +43,9 @@ func NewClient(giteaRoot, giteaAPIToken string, fileResponseCache cache.SetGetKe
|
||||||
contentTimeout: 10 * time.Second,
|
contentTimeout: 10 * time.Second,
|
||||||
fastClient: getFastHTTPClient(),
|
fastClient: getFastHTTPClient(),
|
||||||
fileResponseCache: fileResponseCache,
|
fileResponseCache: fileResponseCache,
|
||||||
|
|
||||||
|
followSymlinks: followSymlinks,
|
||||||
|
supportLFS: supportLFS,
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,19 +58,32 @@ func (client *Client) GiteaRawContent(targetOwner, targetRepo, ref, resource str
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) ServeRawContent(targetOwner, targetRepo, ref, resource string) (*fasthttp.Response, error) {
|
func (client *Client) ServeRawContent(targetOwner, targetRepo, ref, resource string) (*fasthttp.Response, error) {
|
||||||
url := joinURL(client.giteaRoot, giteaAPIRepos, targetOwner, targetRepo, "raw", resource+"?ref="+url.QueryEscape(ref))
|
var apiURL string
|
||||||
res, err := client.do(client.contentTimeout, url)
|
if client.supportLFS {
|
||||||
|
apiURL = joinURL(client.giteaRoot, giteaAPIRepos, targetOwner, targetRepo, "media", resource+"?ref="+url.QueryEscape(ref))
|
||||||
|
} else {
|
||||||
|
apiURL = joinURL(client.giteaRoot, giteaAPIRepos, targetOwner, targetRepo, "raw", resource+"?ref="+url.QueryEscape(ref))
|
||||||
|
}
|
||||||
|
resp, err := client.do(client.contentTimeout, apiURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch res.StatusCode() {
|
switch resp.StatusCode() {
|
||||||
case fasthttp.StatusOK:
|
case fasthttp.StatusOK:
|
||||||
return res, nil
|
if client.followSymlinks && string(resp.Header.Peek(giteaObjectTypeHeader)) == "symlink" {
|
||||||
|
linkDest := strings.TrimSpace(string(resp.Body()))
|
||||||
|
log.Debug().Msgf("follow symlink from '%s' to '%s'", resource, linkDest)
|
||||||
|
return client.ServeRawContent(targetOwner, targetRepo, ref, linkDest)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
|
||||||
case fasthttp.StatusNotFound:
|
case fasthttp.StatusNotFound:
|
||||||
return nil, ErrorNotFound
|
return nil, ErrorNotFound
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unexpected status code '%d'", res.StatusCode())
|
return nil, fmt.Errorf("unexpected status code '%d'", resp.StatusCode())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,12 @@ import (
|
||||||
type Client struct {
|
type Client struct {
|
||||||
sdkClient *gitea.Client
|
sdkClient *gitea.Client
|
||||||
fileResponseCache cache.SetGetKey
|
fileResponseCache cache.SetGetKey
|
||||||
|
|
||||||
|
followSymlinks bool
|
||||||
|
supportLFS bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(giteaRoot, giteaAPIToken string, fileResponseCache cache.SetGetKey) (*Client, error) {
|
func NewClient(giteaRoot, giteaAPIToken string, fileResponseCache cache.SetGetKey, followSymlinks, supportLFS bool) (*Client, error) {
|
||||||
rootURL, err := url.Parse(giteaRoot)
|
rootURL, err := url.Parse(giteaRoot)
|
||||||
giteaRoot = strings.Trim(rootURL.String(), "/")
|
giteaRoot = strings.Trim(rootURL.String(), "/")
|
||||||
|
|
||||||
|
@ -35,6 +38,14 @@ func NewClient(giteaRoot, giteaAPIToken string, fileResponseCache cache.SetGetKe
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) GiteaRawContent(targetOwner, targetRepo, ref, resource string) ([]byte, error) {
|
func (client *Client) GiteaRawContent(targetOwner, targetRepo, ref, resource string) ([]byte, error) {
|
||||||
|
// var apiURL string
|
||||||
|
// if client.supportLFS {
|
||||||
|
// apiURL = joinURL(client.giteaRoot, giteaAPIRepos, targetOwner, targetRepo, "media", resource+"?ref="+url.QueryEscape(ref))
|
||||||
|
// } else {
|
||||||
|
// apiURL = joinURL(client.giteaRoot, giteaAPIRepos, targetOwner, targetRepo, "raw", resource+"?ref="+url.QueryEscape(ref))
|
||||||
|
// }
|
||||||
|
// TODO: sdk client support media api!!!
|
||||||
|
|
||||||
rawBytes, resp, err := client.sdkClient.GetFile(targetOwner, targetRepo, ref, resource)
|
rawBytes, resp, err := client.sdkClient.GetFile(targetOwner, targetRepo, ref, resource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
|
|
||||||
func TestHandlerPerformance(t *testing.T) {
|
func TestHandlerPerformance(t *testing.T) {
|
||||||
giteaRoot := "https://codeberg.org"
|
giteaRoot := "https://codeberg.org"
|
||||||
giteaClient, _ := gitea.NewClient(giteaRoot, "", cache.NewKeyValueCache())
|
giteaClient, _ := gitea.NewClient(giteaRoot, "", cache.NewKeyValueCache(), false, false)
|
||||||
testHandler := Handler(
|
testHandler := Handler(
|
||||||
[]byte("codeberg.page"), []byte("raw.codeberg.org"),
|
[]byte("codeberg.page"), []byte("raw.codeberg.org"),
|
||||||
giteaClient,
|
giteaClient,
|
||||||
|
|
Loading…
Reference in a new issue