Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
8207586a48 | ||
|
bcaceda711 | ||
|
5411c96ef3 | ||
|
baf4e7e326 | ||
|
fd24b4a2bc | ||
|
9076bc3f75 | ||
|
48a49f69a7 |
4
Justfile
4
Justfile
@@ -21,6 +21,10 @@ lint: tool-golangci tool-gofumpt
|
|||||||
fmt: tool-gofumpt
|
fmt: tool-gofumpt
|
||||||
gofumpt -w --extra .
|
gofumpt -w --extra .
|
||||||
|
|
||||||
|
clean:
|
||||||
|
go clean ./...
|
||||||
|
rm -rf build/
|
||||||
|
|
||||||
tool-golangci:
|
tool-golangci:
|
||||||
@hash golangci-lint> /dev/null 2>&1; if [ $? -ne 0 ]; then \
|
@hash golangci-lint> /dev/null 2>&1; if [ $? -ne 0 ]; then \
|
||||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest; \
|
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest; \
|
||||||
|
@@ -18,7 +18,8 @@ Mapping custom domains is not static anymore, but can be done with DNS:
|
|||||||
first line will be the canonical domain/URL; all other occurrences will be redirected to it.
|
first line will be the canonical domain/URL; all other occurrences will be redirected to it.
|
||||||
|
|
||||||
2) add a CNAME entry to your domain, pointing to `[[{branch}.]{repo}.]{owner}.codeberg.page` (repo defaults to
|
2) add a CNAME entry to your domain, pointing to `[[{branch}.]{repo}.]{owner}.codeberg.page` (repo defaults to
|
||||||
"pages", "branch" defaults to the default branch if "repo" is "pages", or to "pages" if "repo" is something else):
|
"pages", "branch" defaults to the default branch if "repo" is "pages", or to "pages" if "repo" is something else.
|
||||||
|
If the branch name contains slash characters, you need to replace "/" in the branch name to "~"):
|
||||||
`www.example.org. IN CNAME main.pages.example.codeberg.page.`
|
`www.example.org. IN CNAME main.pages.example.codeberg.page.`
|
||||||
|
|
||||||
3) if a CNAME is set for "www.example.org", you can redirect there from the naked domain by adding an ALIAS record
|
3) if a CNAME is set for "www.example.org", you can redirect there from the naked domain by adding an ALIAS record
|
||||||
|
@@ -23,11 +23,11 @@
|
|||||||
<body>
|
<body>
|
||||||
<i class="fa fa-search text-primary" style="font-size: 96px;"></i>
|
<i class="fa fa-search text-primary" style="font-size: 96px;"></i>
|
||||||
<h1 class="mb-0 text-primary">
|
<h1 class="mb-0 text-primary">
|
||||||
This page was not found!
|
Page not found!
|
||||||
</h1>
|
</h1>
|
||||||
<h5 class="text-center" style="max-width: 25em;">
|
<h5 class="text-center" style="max-width: 25em;">
|
||||||
Sorry, this page doesn't exist or is inaccessible for other reasons (%status).<br/>
|
Sorry, but this page couldn't be found or is inaccessible (%status).<br/>
|
||||||
We hope this is not our fault ;) - Make sure to check the <a href="https://docs.codeberg.org/codeberg-pages/troubleshooting/" target="_blank">troubleshooting section in the Docs</a>!
|
We hope this isn't a problem on our end ;) - Make sure to check the <a href="https://docs.codeberg.org/codeberg-pages/troubleshooting/" target="_blank">troubleshooting section in the Docs</a>!
|
||||||
</h5>
|
</h5>
|
||||||
<small class="text-muted">
|
<small class="text-muted">
|
||||||
<img src="https://design.codeberg.org/logo-kit/icon.svg" class="align-top">
|
<img src="https://design.codeberg.org/logo-kit/icon.svg" class="align-top">
|
||||||
|
@@ -49,6 +49,18 @@ func TestGetContent(t *testing.T) {
|
|||||||
assert.EqualValues(t, "text/html; charset=utf-8", resp.Header.Get("Content-Type"))
|
assert.EqualValues(t, "text/html; charset=utf-8", resp.Header.Get("Content-Type"))
|
||||||
assert.True(t, getSize(resp.Body) > 1000)
|
assert.True(t, getSize(resp.Body) > 1000)
|
||||||
assert.Len(t, resp.Header.Get("ETag"), 42)
|
assert.Len(t, resp.Header.Get("ETag"), 42)
|
||||||
|
|
||||||
|
// access branch name contains '/'
|
||||||
|
resp, err = getTestHTTPSClient().Get("https://blumia.localhost.mock.directory:4430/pages-server-integration-tests/@docs~main/")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.EqualValues(t, http.StatusOK, resp.StatusCode) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
assert.EqualValues(t, "text/html; charset=utf-8", resp.Header.Get("Content-Type"))
|
||||||
|
assert.True(t, getSize(resp.Body) > 100)
|
||||||
|
assert.Len(t, resp.Header.Get("ETag"), 42)
|
||||||
|
|
||||||
|
// TODO: test get of non cachable content (content size > fileCacheSizeLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCustomDomain(t *testing.T) {
|
func TestCustomDomain(t *testing.T) {
|
||||||
|
@@ -82,7 +82,6 @@ func (client *Client) ServeRawContent(uri string) (*fasthttp.Response, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// resp.SetBodyStream(&strings.Reader{}, -1)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@@ -89,6 +89,10 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Replace "~" to "/" so we can access branch that contains slash character
|
||||||
|
// Branch name cannot contain "~" so doing this is okay
|
||||||
|
branch = strings.ReplaceAll(branch, "~", "/")
|
||||||
|
|
||||||
// Check if the branch exists, otherwise treat it as a file path
|
// Check if the branch exists, otherwise treat it as a file path
|
||||||
branchTimestampResult := upstream.GetBranchTimestamp(giteaClient, targetOwner, repo, branch, branchTimestampCache)
|
branchTimestampResult := upstream.GetBranchTimestamp(giteaClient, targetOwner, repo, branch, branchTimestampCache)
|
||||||
if branchTimestampResult == nil {
|
if branchTimestampResult == nil {
|
||||||
|
@@ -5,12 +5,20 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
|
|
||||||
"codeberg.org/codeberg/pages/server/cache"
|
"codeberg.org/codeberg/pages/server/cache"
|
||||||
"codeberg.org/codeberg/pages/server/utils"
|
"codeberg.org/codeberg/pages/server/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type fasthttpLogger struct{}
|
||||||
|
|
||||||
|
func (fasthttpLogger) Printf(format string, args ...interface{}) {
|
||||||
|
log.Printf("[FASTHTTP] "+format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func SetupServer(handler fasthttp.RequestHandler) *fasthttp.Server {
|
func SetupServer(handler fasthttp.RequestHandler) *fasthttp.Server {
|
||||||
// Enable compression by wrapping the handler with the compression function provided by FastHTTP
|
// Enable compression by wrapping the handler with the compression function provided by FastHTTP
|
||||||
compressedHandler := fasthttp.CompressHandlerBrotliLevel(handler, fasthttp.CompressBrotliBestSpeed, fasthttp.CompressBestSpeed)
|
compressedHandler := fasthttp.CompressHandlerBrotliLevel(handler, fasthttp.CompressBrotliBestSpeed, fasthttp.CompressBestSpeed)
|
||||||
@@ -21,7 +29,7 @@ func SetupServer(handler fasthttp.RequestHandler) *fasthttp.Server {
|
|||||||
NoDefaultServerHeader: true,
|
NoDefaultServerHeader: true,
|
||||||
NoDefaultDate: true,
|
NoDefaultDate: true,
|
||||||
ReadTimeout: 30 * time.Second, // needs to be this high for ACME certificates with ZeroSSL & HTTP-01 challenge
|
ReadTimeout: 30 * time.Second, // needs to be this high for ACME certificates with ZeroSSL & HTTP-01 challenge
|
||||||
Concurrency: 1024 * 32, // TODO: adjust bottlenecks for best performance with Gitea!
|
Logger: fasthttpLogger{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -181,6 +181,9 @@ func (o *Options) Upstream(ctx *fasthttp.RequestCtx, giteaClient *gitea.Client,
|
|||||||
var cacheBodyWriter bytes.Buffer
|
var cacheBodyWriter bytes.Buffer
|
||||||
if res != nil {
|
if res != nil {
|
||||||
if res.Header.ContentLength() > fileCacheSizeLimit {
|
if res.Header.ContentLength() > fileCacheSizeLimit {
|
||||||
|
// fasthttp else will set "Content-Length: 0"
|
||||||
|
ctx.Response.SetBodyStream(&strings.Reader{}, -1)
|
||||||
|
|
||||||
err = res.BodyWriteTo(ctx.Response.BodyWriter())
|
err = res.BodyWriteTo(ctx.Response.BodyWriter())
|
||||||
} else {
|
} else {
|
||||||
// TODO: cache is half-empty if request is cancelled - does the ctx.Err() below do the trick?
|
// TODO: cache is half-empty if request is cancelled - does the ctx.Err() below do the trick?
|
||||||
@@ -196,7 +199,7 @@ func (o *Options) Upstream(ctx *fasthttp.RequestCtx, giteaClient *gitea.Client,
|
|||||||
}
|
}
|
||||||
log.Debug().Msg("response")
|
log.Debug().Msg("response")
|
||||||
|
|
||||||
if res != nil && ctx.Err() == nil {
|
if res != nil && res.Header.ContentLength() <= fileCacheSizeLimit && ctx.Err() == nil {
|
||||||
cachedResponse.Exists = true
|
cachedResponse.Exists = true
|
||||||
cachedResponse.MimeType = mimeType
|
cachedResponse.MimeType = mimeType
|
||||||
cachedResponse.Body = cacheBodyWriter.Bytes()
|
cachedResponse.Body = cacheBodyWriter.Bytes()
|
||||||
|
Reference in New Issue
Block a user