✨ Static files support clean url
All checks were successful
release-nightly / build-docker (push) Successful in 1m1s
All checks were successful
release-nightly / build-docker (push) Successful in 1m1s
This commit is contained in:
parent
78c51bb432
commit
ad3b36bc2a
128
pkg/sign/responder.go
Normal file
128
pkg/sign/responder.go
Normal file
@ -0,0 +1,128 @@
|
||||
package sign
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/proxy"
|
||||
"github.com/gofiber/fiber/v2/utils"
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
func makeHypertextResponse(ctx *fiber.Ctx, upstream *UpstreamConfig) error {
|
||||
timeout := time.Duration(viper.GetInt64("performance.network_timeout")) * time.Millisecond
|
||||
return proxy.Do(ctx, upstream.MakeURI(ctx), &fasthttp.Client{
|
||||
ReadTimeout: timeout,
|
||||
WriteTimeout: timeout,
|
||||
})
|
||||
}
|
||||
|
||||
func makeFileResponse(ctx *fiber.Ctx, upstream *UpstreamConfig) error {
|
||||
uri, queries := upstream.GetRawURI()
|
||||
root := http.Dir(uri)
|
||||
|
||||
method := ctx.Method()
|
||||
|
||||
// We only serve static assets for GET and HEAD methods
|
||||
if method != fiber.MethodGet && method != fiber.MethodHead {
|
||||
return ctx.Next()
|
||||
}
|
||||
|
||||
// Strip prefix
|
||||
prefix := ctx.Route().Path
|
||||
path := strings.TrimPrefix(ctx.Path(), prefix)
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
|
||||
// Add prefix
|
||||
if queries.Get("prefix") != "" {
|
||||
path = queries.Get("prefix") + path
|
||||
}
|
||||
|
||||
if len(path) > 1 {
|
||||
path = utils.TrimRight(path, '/')
|
||||
}
|
||||
|
||||
file, err := root.Open(path)
|
||||
if err != nil && errors.Is(err, fs.ErrNotExist) {
|
||||
if queries.Get("suffix") != "" {
|
||||
file, err = root.Open(path + queries.Get("suffix"))
|
||||
}
|
||||
if err != nil && queries.Get("fallback") != "" {
|
||||
file, err = root.Open(queries.Get("fallback"))
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return ctx.Status(fiber.StatusNotFound).Next()
|
||||
}
|
||||
return fmt.Errorf("failed to open: %w", err)
|
||||
}
|
||||
|
||||
stat, err := file.Stat()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to stat: %w", err)
|
||||
}
|
||||
|
||||
// Serve index if path is directory
|
||||
if stat.IsDir() {
|
||||
indexPath := utils.TrimRight(path, '/') + queries.Get("index")
|
||||
index, err := root.Open(indexPath)
|
||||
if err == nil {
|
||||
indexStat, err := index.Stat()
|
||||
if err == nil {
|
||||
file = index
|
||||
stat = indexStat
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Status(fiber.StatusOK)
|
||||
|
||||
modTime := stat.ModTime()
|
||||
contentLength := int(stat.Size())
|
||||
|
||||
// Set Content-Type header
|
||||
if queries.Get("charset") == "" {
|
||||
ctx.Type(filepath.Ext(stat.Name()))
|
||||
} else {
|
||||
ctx.Type(filepath.Ext(stat.Name()), queries.Get("charset"))
|
||||
}
|
||||
|
||||
// Set Last-Modified header
|
||||
if !modTime.IsZero() {
|
||||
ctx.Set(fiber.HeaderLastModified, modTime.UTC().Format(http.TimeFormat))
|
||||
}
|
||||
|
||||
// Set Cache-Control header
|
||||
if method == fiber.MethodGet {
|
||||
maxAge, err := strconv.Atoi(queries.Get("maxAge"))
|
||||
if lo.Ternary(err != nil, maxAge, 0) > 0 {
|
||||
ctx.Set(fiber.HeaderCacheControl, "public, max-age="+queries.Get("maxAge"))
|
||||
}
|
||||
ctx.Response().SetBodyStream(file, contentLength)
|
||||
return nil
|
||||
}
|
||||
if method == fiber.MethodHead {
|
||||
ctx.Request().ResetBody()
|
||||
ctx.Response().SkipBody = true
|
||||
ctx.Response().Header.SetContentLength(contentLength)
|
||||
if err := file.Close(); err != nil {
|
||||
return fmt.Errorf("failed to close: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return ctx.Next()
|
||||
}
|
@ -2,16 +2,9 @@ package sign
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
||||
"github.com/gofiber/fiber/v2/middleware/proxy"
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/valyala/fasthttp"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type AppConfig struct {
|
||||
@ -28,34 +21,9 @@ func (v *AppConfig) Forward(ctx *fiber.Ctx, site SiteConfig) error {
|
||||
|
||||
switch upstream.GetType() {
|
||||
case UpstreamTypeHypertext:
|
||||
timeout := time.Duration(viper.GetInt64("performance.network_timeout")) * time.Millisecond
|
||||
return proxy.Do(ctx, upstream.MakeURI(ctx), &fasthttp.Client{
|
||||
ReadTimeout: timeout,
|
||||
WriteTimeout: timeout,
|
||||
})
|
||||
return makeHypertextResponse(ctx, upstream)
|
||||
case UpstreamTypeFile:
|
||||
uri, queries := upstream.GetRawURI()
|
||||
fs := filesystem.New(filesystem.Config{
|
||||
Root: http.Dir(uri),
|
||||
ContentTypeCharset: queries.Get("charset"),
|
||||
Index: func() string {
|
||||
val := queries.Get("index")
|
||||
return lo.Ternary(len(val) > 0, val, "index.html")
|
||||
}(),
|
||||
NotFoundFile: func() string {
|
||||
val := queries.Get("fallback")
|
||||
return lo.Ternary(len(val) > 0, val, "404.html")
|
||||
}(),
|
||||
Browse: func() bool {
|
||||
browse, err := strconv.ParseBool(queries.Get("browse"))
|
||||
return lo.Ternary(err == nil, browse, false)
|
||||
}(),
|
||||
MaxAge: func() int {
|
||||
age, err := strconv.Atoi(queries.Get("maxAge"))
|
||||
return lo.Ternary(err == nil, age, 3600)
|
||||
}(),
|
||||
})
|
||||
return fs(ctx)
|
||||
return makeFileResponse(ctx, upstream)
|
||||
default:
|
||||
return fiber.ErrBadGateway
|
||||
}
|
||||
@ -63,8 +31,6 @@ func (v *AppConfig) Forward(ctx *fiber.Ctx, site SiteConfig) error {
|
||||
|
||||
type SiteConfig struct {
|
||||
ID string `json:"id"`
|
||||
|
||||
Name string `json:"name"`
|
||||
Rules []RouterRuleConfig `json:"rules"`
|
||||
Transformers []RequestTransformerConfig `json:"transformers"`
|
||||
Upstreams []UpstreamConfig `json:"upstreams"`
|
||||
|
@ -16,8 +16,6 @@ const (
|
||||
|
||||
type UpstreamConfig struct {
|
||||
ID string `json:"id"`
|
||||
|
||||
Name string `json:"name"`
|
||||
URI string `json:"uri"`
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user