重构路由
This commit is contained in:
6
pkg/filters/README.md
Normal file
6
pkg/filters/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 拦截器路径
|
||||
|
||||
1. 404
|
||||
2. redirect
|
||||
3. failback
|
||||
4. direct
|
||||
31
pkg/filters/block.go
Normal file
31
pkg/filters/block.go
Normal 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(¶m); 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
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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(¶m); 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
49
pkg/filters/failback.go
Normal 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(¶m); 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
|
||||
}
|
||||
@@ -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(¶m); 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
45
pkg/filters/template.go
Normal 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(¶m); 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
|
||||
}
|
||||
Reference in New Issue
Block a user