重构项目
This commit is contained in:
12
pkg/filters/common.go
Normal file
12
pkg/filters/common.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package filters
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
30
pkg/filters/default.go
Normal file
30
pkg/filters/default.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package filters
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.d7z.net/gitea-pages/pkg/core"
|
||||
)
|
||||
|
||||
var FilterInstDefaultNotFound core.FilterInstance = func(config core.FilterParams) (core.FilterCall, error) {
|
||||
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) {
|
||||
open, err := metadata.NativeOpen(ctx, "/404.html", nil)
|
||||
if open != nil {
|
||||
defer open.Body.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
writer.WriteHeader(http.StatusNotFound)
|
||||
_, _ = io.Copy(writer, open.Body)
|
||||
}
|
||||
return nil
|
||||
}, nil
|
||||
}
|
||||
60
pkg/filters/direct.go
Normal file
60
pkg/filters/direct.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package filters
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
"gopkg.d7z.net/gitea-pages/pkg/core"
|
||||
)
|
||||
|
||||
var FilterInstDirect 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
|
||||
}
|
||||
return func(ctx context.Context, writer http.ResponseWriter, request *http.Request, metadata *core.PageDomainContent, next core.NextCall) error {
|
||||
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 {
|
||||
resp, err = metadata.NativeOpen(request.Context(), p, nil)
|
||||
if err != nil {
|
||||
if resp != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
zap.L().Debug("error", zap.Any("error", err))
|
||||
}
|
||||
continue
|
||||
}
|
||||
path = p
|
||||
break
|
||||
}
|
||||
if resp == nil {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
writer.Header().Set("Content-Type", resp.Header.Get("Content-Type"))
|
||||
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(path), lastMod, seeker)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
_, err = io.Copy(writer, resp.Body)
|
||||
return err
|
||||
}, nil
|
||||
}
|
||||
49
pkg/filters/proxy.go
Normal file
49
pkg/filters/proxy.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package filters
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gopkg.d7z.net/gitea-pages/pkg/core"
|
||||
"gopkg.d7z.net/gitea-pages/pkg/utils"
|
||||
)
|
||||
|
||||
var FilterInstProxy core.FilterInstance = func(config core.FilterParams) (core.FilterCall, error) {
|
||||
var param struct {
|
||||
Prefix string `json:"prefix"`
|
||||
Target string `json:"target"`
|
||||
}
|
||||
if err := config.Unmarshal(¶m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return func(ctx context.Context, writer http.ResponseWriter, request *http.Request, metadata *core.PageDomainContent, next core.NextCall) error {
|
||||
proxyPath := "/" + metadata.Path
|
||||
targetPath := strings.TrimPrefix(proxyPath, param.Prefix)
|
||||
if !strings.HasPrefix(targetPath, "/") {
|
||||
targetPath = "/" + targetPath
|
||||
}
|
||||
u, _ := url.Parse(param.Target)
|
||||
request.URL.Path = targetPath
|
||||
request.RequestURI = request.URL.RequestURI()
|
||||
proxy := httputil.NewSingleHostReverseProxy(u)
|
||||
// todo: 处理透传
|
||||
// proxy.Transport = s.options.HTTPClient.Transport
|
||||
if host, _, err := net.SplitHostPort(request.RemoteAddr); err == nil {
|
||||
request.Header.Set("X-Real-IP", host)
|
||||
}
|
||||
request.Header.Set("X-Page-IP", utils.GetRemoteIP(request))
|
||||
request.Header.Set("X-Page-Refer", fmt.Sprintf("%s/%s/%s", metadata.Owner, metadata.Repo, metadata.Path))
|
||||
request.Header.Set("X-Page-Host", request.Host)
|
||||
zap.L().Debug("命中反向代理", zap.Any("prefix", param.Prefix), zap.Any("target", param.Target),
|
||||
zap.Any("path", proxyPath), zap.Any("target", fmt.Sprintf("%s%s", u, targetPath)))
|
||||
// todo(security): 处理 websocket
|
||||
proxy.ServeHTTP(writer, request)
|
||||
return nil
|
||||
}, nil
|
||||
}
|
||||
46
pkg/filters/redirect.go
Normal file
46
pkg/filters/redirect.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package filters
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gopkg.d7z.net/gitea-pages/pkg/core"
|
||||
)
|
||||
|
||||
var portExp = regexp.MustCompile(`:\d+$`)
|
||||
|
||||
var FilterInstRedirect core.FilterInstance = func(config core.FilterParams) (core.FilterCall, error) {
|
||||
var param struct {
|
||||
Targets []string `json:"targets"`
|
||||
}
|
||||
if err := config.Unmarshal(¶m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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) {
|
||||
// 重定向到配置的地址
|
||||
zap.L().Debug("redirect", zap.Any("src", request.Host), zap.Any("dst", param.Targets[0]))
|
||||
path := metadata.Path
|
||||
if strings.HasSuffix(path, "/index.html") || path == "index.html" {
|
||||
path = strings.TrimSuffix(path, "index.html")
|
||||
}
|
||||
target, err := url.Parse(fmt.Sprintf("https://%s/%s", param.Targets[0], path))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
target.RawQuery = request.URL.RawQuery
|
||||
|
||||
http.Redirect(writer, request, target.String(), http.StatusFound)
|
||||
return nil
|
||||
} else {
|
||||
return next(ctx, writer, request, metadata)
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user