重构路由

This commit is contained in:
ExplodingDragon
2025-11-13 00:21:45 +08:00
parent 351e1c2ad1
commit c7c6180272
18 changed files with 381 additions and 201 deletions

6
pkg/filters/README.md Normal file
View File

@@ -0,0 +1,6 @@
# 拦截器路径
1. 404
2. redirect
3. failback
4. direct

31
pkg/filters/block.go Normal file
View File

@@ -0,0 +1,31 @@
package filters
import (
"context"
"net/http"
"gopkg.d7z.net/gitea-pages/pkg/core"
)
var FilterInstBlock core.FilterInstance = func(config core.FilterParams) (core.FilterCall, error) {
var param struct {
Code int `json:"code"`
Message string `json:"message"`
}
if err := config.Unmarshal(&param); nil != err {
return nil, err
}
if param.Code == 0 {
param.Code = http.StatusForbidden
}
if param.Message == "" {
param.Message = http.StatusText(param.Code)
}
return func(ctx context.Context, writer http.ResponseWriter, request *http.Request, metadata *core.PageDomainContent, next core.NextCall) error {
writer.WriteHeader(param.Code)
if param.Message != "" {
_, _ = writer.Write([]byte(param.Message))
}
return nil
}, nil
}

View File

@@ -4,9 +4,12 @@ import "gopkg.d7z.net/gitea-pages/pkg/core"
func DefaultFilters() map[string]core.FilterInstance {
return map[string]core.FilterInstance{
"redirect": FilterInstRedirect,
"direct": FilterInstDirect,
"reverse_proxy": FilterInstProxy,
"default_not_found": FilterInstDefaultNotFound,
"block": FilterInstBlock,
"redirect": FilterInstRedirect,
"direct": FilterInstDirect,
"reverse_proxy": FilterInstProxy,
"_404_": FilterInstDefaultNotFound,
"failback": FilterInstFailback,
"template": FilterInstTemplate,
}
}

View File

@@ -22,6 +22,9 @@ var FilterInstDefaultNotFound core.FilterInstance = func(config core.FilterParam
return err
}
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
if l := open.Header.Get("Content-Length"); l != "" {
writer.Header().Set("Content-Length", l)
}
writer.WriteHeader(http.StatusNotFound)
_, _ = io.Copy(writer, open.Body)
}

View File

@@ -3,9 +3,11 @@ package filters
import (
"context"
"io"
"mime"
"net/http"
"os"
"path/filepath"
"strings"
"time"
"github.com/pkg/errors"
@@ -20,12 +22,17 @@ var FilterInstDirect core.FilterInstance = func(config core.FilterParams) (core.
if err := config.Unmarshal(&param); err != nil {
return nil, err
}
param.Prefix = strings.Trim(param.Prefix, "/") + "/"
return func(ctx context.Context, writer http.ResponseWriter, request *http.Request, metadata *core.PageDomainContent, next core.NextCall) error {
err := next(ctx, writer, request, metadata)
if (err != nil && !errors.Is(err, os.ErrNotExist)) || err == nil {
return err
}
var resp *http.Response
var path string
var err error
failback := []string{param.Prefix + metadata.Path, param.Prefix + metadata.Path + "/index.html"}
for _, p := range failback {
defaultPath := param.Prefix + strings.TrimSuffix(metadata.Path, "/")
for _, p := range []string{defaultPath, defaultPath + "/index.html"} {
zap.L().Debug("direct fetch", zap.String("path", p))
resp, err = metadata.NativeOpen(request.Context(), p, nil)
if err != nil {
if resp != nil {
@@ -33,6 +40,7 @@ var FilterInstDirect core.FilterInstance = func(config core.FilterParams) (core.
}
if !errors.Is(err, os.ErrNotExist) {
zap.L().Debug("error", zap.Any("error", err))
return err
}
continue
}
@@ -46,7 +54,8 @@ var FilterInstDirect core.FilterInstance = func(config core.FilterParams) (core.
if err != nil {
return err
}
writer.Header().Set("Content-Type", resp.Header.Get("Content-Type"))
writer.Header().Set("Content-Type", mime.TypeByExtension(filepath.Ext(path)))
lastMod, err := time.Parse(http.TimeFormat, resp.Header.Get("Last-Modified"))
if err == nil {
if seeker, ok := resp.Body.(io.ReadSeeker); ok {

49
pkg/filters/failback.go Normal file
View File

@@ -0,0 +1,49 @@
package filters
import (
"context"
"io"
"mime"
"net/http"
"os"
"path/filepath"
"time"
"github.com/pkg/errors"
"gopkg.d7z.net/gitea-pages/pkg/core"
)
var FilterInstFailback core.FilterInstance = func(config core.FilterParams) (core.FilterCall, error) {
var param struct {
Path string `json:"path"`
}
if err := config.Unmarshal(&param); err != nil {
return nil, err
}
if param.Path == "" {
return nil, errors.Errorf("filter failback: path is empty")
}
return func(ctx context.Context, writer http.ResponseWriter, request *http.Request, metadata *core.PageDomainContent, next core.NextCall) error {
err := next(ctx, writer, request, metadata)
if (err != nil && !errors.Is(err, os.ErrNotExist)) || err == nil {
return err
}
resp, err := metadata.NativeOpen(ctx, param.Path, nil)
if resp != nil {
defer resp.Body.Close()
}
if err != nil {
return err
}
writer.Header().Set("Content-Type", mime.TypeByExtension(filepath.Ext(param.Path)))
lastMod, err := time.Parse(http.TimeFormat, resp.Header.Get("Last-Modified"))
if err == nil {
if seeker, ok := resp.Body.(io.ReadSeeker); ok {
http.ServeContent(writer, request, filepath.Base(param.Path), lastMod, seeker)
return nil
}
}
_, err = io.Copy(writer, resp.Body)
return err
}, nil
}

View File

@@ -18,10 +18,20 @@ var portExp = regexp.MustCompile(`:\d+$`)
var FilterInstRedirect core.FilterInstance = func(config core.FilterParams) (core.FilterCall, error) {
var param struct {
Targets []string `json:"targets"`
Code int `json:"code"`
}
if err := config.Unmarshal(&param); err != nil {
return nil, err
}
if len(param.Targets) == 0 {
return nil, fmt.Errorf("no targets")
}
if param.Code == 0 {
param.Code = http.StatusFound
}
if param.Code < 300 || param.Code > 399 {
return nil, fmt.Errorf("invalid code: %d", param.Code)
}
return func(ctx context.Context, writer http.ResponseWriter, request *http.Request, metadata *core.PageDomainContent, next core.NextCall) error {
domain := portExp.ReplaceAllString(strings.ToLower(request.Host), "")
if len(param.Targets) > 0 && !slices.Contains(metadata.Alias, domain) {
@@ -37,7 +47,7 @@ var FilterInstRedirect core.FilterInstance = func(config core.FilterParams) (cor
}
target.RawQuery = request.URL.RawQuery
http.Redirect(writer, request, target.String(), http.StatusFound)
http.Redirect(writer, request, target.String(), param.Code)
return nil
} else {
return next(ctx, writer, request, metadata)

45
pkg/filters/template.go Normal file
View File

@@ -0,0 +1,45 @@
package filters
import (
"bytes"
"context"
"net/http"
"strings"
"gopkg.d7z.net/gitea-pages/pkg/core"
"gopkg.d7z.net/gitea-pages/pkg/utils"
)
var FilterInstTemplate core.FilterInstance = func(config core.FilterParams) (core.FilterCall, error) {
var param struct {
Prefix string `json:"prefix"`
}
if err := config.Unmarshal(&param); err != nil {
return nil, err
}
param.Prefix = strings.Trim(param.Prefix, "/") + "/"
return func(ctx context.Context, writer http.ResponseWriter, request *http.Request, metadata *core.PageDomainContent, next core.NextCall) error {
data, err := metadata.ReadString(ctx, param.Prefix+metadata.Path)
if err != nil {
return err
}
if err != nil {
return err
}
out := &bytes.Buffer{}
parse, err := utils.NewTemplate().Funcs(map[string]any{
"template": func(path string) (any, error) {
return metadata.ReadString(ctx, param.Prefix+path)
},
}).Parse(data)
if err != nil {
return err
}
err = parse.Execute(out, utils.NewTemplateInject(request, nil))
if err != nil {
return err
}
_, _ = out.WriteTo(writer)
return nil
}, nil
}