重构路由

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

View File

@@ -1,46 +1,48 @@
package core package core
import "strings" import (
"github.com/pkg/errors"
"gopkg.in/yaml.v3"
)
type PageConfig struct { type PageConfig struct {
Alias []string `yaml:"alias"` // 重定向地址 Alias []string `yaml:"alias"` // 重定向地址
Render map[string]string `yaml:"templates"` // 渲染器地址 Routes []PageConfigRoute `yaml:"routes"` // 路由配置
VirtualRoute bool `yaml:"v-route"` // 是否使用虚拟路由(任何路径均使用 /index.html 返回 200 响应)
ReverseProxy map[string]string `yaml:"proxy"` // 反向代理路由
Ignore string `yaml:"ignore"` // 跳过展示的内容
} }
func (p *PageConfig) Ignores() []string { type PageConfigRoute struct {
i := make([]string, 0) Path string `yaml:"path"`
if p.Ignore == "" { Type string `yaml:"type"`
return i Params map[string]any `yaml:"params"`
}
for _, line := range strings.Split(p.Ignore, "\n") {
for _, item := range strings.Split(line, ",") {
item = strings.TrimSpace(item)
if item == "" {
continue
}
i = append(i, item)
}
}
return i
} }
func (p *PageConfig) Renders() map[string]string { func (p *PageConfigRoute) UnmarshalYAML(value *yaml.Node) error {
result := make(map[string]string) var data map[string]any
for sType, patterns := range p.Render { if err := value.Decode(&data); err != nil {
for _, line := range strings.Split(patterns, "\n") { return err
for _, item := range strings.Split(line, ",") {
item = strings.TrimSpace(item)
if item == "" {
continue
} }
result[sType] = item if item, ok := data["path"]; ok {
p.Path = item.(string)
} else {
return errors.New("missing path field")
} }
delete(data, "path")
keys := make([]string, 0)
for k := range data {
keys = append(keys, k)
} }
if len(keys) != 1 {
return errors.New("invalid param")
} }
return result p.Type = keys[0]
params := data[p.Type]
// 跳过空参数
if _, ok := params.(string); ok || params == nil {
return nil
}
out, err := yaml.Marshal(params)
if err != nil {
return err
}
return yaml.Unmarshal(out, &p.Params)
} }

View File

@@ -3,11 +3,21 @@ package core
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"fmt"
"net/http" "net/http"
"os"
"strings"
"go.uber.org/zap"
) )
type FilterParams map[string]any type FilterParams map[string]any
func (f FilterParams) String() string {
marshal, _ := json.Marshal(f)
return strings.ReplaceAll(string(marshal), "\"", "'")
}
func (f FilterParams) Unmarshal(target any) error { func (f FilterParams) Unmarshal(target any) error {
marshal, err := json.Marshal(f) marshal, err := json.Marshal(f)
if err != nil { if err != nil {
@@ -22,9 +32,12 @@ type Filter struct {
Params FilterParams `json:"params"` Params FilterParams `json:"params"`
} }
func NextCallWrapper(call FilterCall, parentCall NextCall) NextCall { func NextCallWrapper(call FilterCall, parentCall NextCall, stack Filter) NextCall {
return func(ctx context.Context, writer http.ResponseWriter, request *http.Request, metadata *PageDomainContent) error { return func(ctx context.Context, writer http.ResponseWriter, request *http.Request, metadata *PageDomainContent) error {
return call(ctx, writer, request, metadata, parentCall) zap.L().Debug(fmt.Sprintf("call filter(%s) before", stack.Type), zap.Any("filter", stack))
err := call(ctx, writer, request, metadata, parentCall)
zap.L().Debug(fmt.Sprintf("call filter(%s) after", stack.Type), zap.Any("filter", stack), zap.Error(err))
return err
} }
} }
@@ -35,6 +48,10 @@ type NextCall func(
metadata *PageDomainContent, metadata *PageDomainContent,
) error ) error
var NotFountNextCall = func(ctx context.Context, writer http.ResponseWriter, request *http.Request, metadata *PageDomainContent) error {
return os.ErrNotExist
}
type FilterCall func( type FilterCall func(
ctx context.Context, ctx context.Context,
writer http.ResponseWriter, writer http.ResponseWriter,

View File

@@ -5,13 +5,12 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"net/url"
"os" "os"
"path/filepath"
"regexp" "regexp"
"strings" "strings"
"time" "time"
"github.com/gobwas/glob"
"go.uber.org/zap" "go.uber.org/zap"
"gopkg.d7z.net/middleware/kv" "gopkg.d7z.net/middleware/kv"
"gopkg.d7z.net/middleware/tools" "gopkg.d7z.net/middleware/tools"
@@ -50,23 +49,18 @@ func NewEmptyPageMetaContent() *PageMetaContent {
Filters: []Filter{ Filters: []Filter{
{ {
Path: "**", Path: "**",
Type: "default_not_found", Type: "_404_",
Params: map[string]any{}, Params: map[string]any{},
}, },
{ // 默认阻塞 { // 默认阻塞
Path: ".git/**", Path: ".git/**",
Type: "block", Type: "block",
Params: map[string]any{ Params: map[string]any{},
"code": "404",
"message": "Not found",
}, },
}, { // 默认阻塞 { // 默认阻塞
Path: ".pages.yaml", Path: ".pages.yaml",
Type: "block", Type: "block",
Params: map[string]any{ Params: map[string]any{},
"code": "404",
"message": "Not found",
},
}, },
}, },
} }
@@ -161,6 +155,7 @@ func (s *ServerMeta) parsePageConfig(ctx context.Context, meta *PageMetaContent,
defer func(alias *[]string) { defer func(alias *[]string) {
meta.Alias = *alias meta.Alias = *alias
direct := *alias direct := *alias
if len(direct) > 0 {
meta.Filters = append(meta.Filters, Filter{ meta.Filters = append(meta.Filters, Filter{
Path: "**", Path: "**",
Type: "redirect", Type: "redirect",
@@ -168,6 +163,14 @@ func (s *ServerMeta) parsePageConfig(ctx context.Context, meta *PageMetaContent,
"targets": direct, "targets": direct,
}, },
}) })
}
meta.Filters = append(meta.Filters, Filter{
Path: "**",
Type: "direct",
Params: map[string]any{
"prefix": "",
},
})
}(&alias) }(&alias)
cname, err := vfs.ReadString(ctx, "CNAME") cname, err := vfs.ReadString(ctx, "CNAME")
if cname != "" && err == nil { if cname != "" && err == nil {
@@ -187,76 +190,36 @@ func (s *ServerMeta) parsePageConfig(ctx context.Context, meta *PageMetaContent,
if err = yaml.Unmarshal([]byte(data), cfg); err != nil { if err = yaml.Unmarshal([]byte(data), cfg); err != nil {
return errors.Wrap(err, "parse .pages.yaml failed") return errors.Wrap(err, "parse .pages.yaml failed")
} }
if cfg.VirtualRoute {
meta.Filters = append(meta.Filters, Filter{
Path: "**",
Type: "forward",
Params: map[string]any{
"path": "index.html",
},
})
}
// 处理别名 // 处理别名
for _, cname := range cfg.Alias { for _, item := range cfg.Alias {
if cname == "" { if item == "" {
continue continue
} }
if al, ok := s.aliasCheck(cname); ok { if al, ok := s.aliasCheck(item); ok {
alias = append(alias, al) alias = append(alias, al)
} else { } else {
return fmt.Errorf("invalid alias %s", cname) return fmt.Errorf("invalid alias %s", item)
} }
} }
// 处理渲染器 // 处理自定义路由
for sType, pattern := range cfg.Renders() { for _, r := range cfg.Routes {
meta.Filters = append(meta.Filters, Filter{ for _, item := range strings.Split(r.Path, ",") {
Path: pattern, item = strings.TrimSpace(item)
Type: sType, if item == "" {
Params: map[string]any{}, continue
})
} }
if _, err := glob.Compile(item); err != nil {
// 处理跳过内容 return errors.Wrapf(err, "invalid route glob pattern: %s", item)
for _, pattern := range cfg.Ignores() {
meta.Filters = append(meta.Filters, Filter{ // 默认直连
Path: pattern,
Type: "block",
Params: map[string]any{
"code": "404",
"message": "Not found",
},
},
)
}
// 处理反向代理
for path, backend := range cfg.ReverseProxy {
path = filepath.ToSlash(filepath.Clean(path))
if !strings.HasPrefix(path, "/") {
path = "/" + path
}
path = strings.TrimSuffix(path, "/")
rURL, err := url.Parse(backend)
if err != nil {
return errors.Wrapf(err, "parse backend url failed: %s", backend)
}
if rURL.Scheme != "http" && rURL.Scheme != "https" {
return errors.Errorf("invalid backend url scheme: %s", backend)
} }
meta.Filters = append(meta.Filters, Filter{ meta.Filters = append(meta.Filters, Filter{
Path: path, Path: item,
Type: "reverse_proxy", Type: r.Type,
Params: map[string]any{ Params: r.Params,
"prefix": path,
"target": rURL.String(),
},
}) })
} }
}
return nil return nil
} }

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 { func DefaultFilters() map[string]core.FilterInstance {
return map[string]core.FilterInstance{ return map[string]core.FilterInstance{
"block": FilterInstBlock,
"redirect": FilterInstRedirect, "redirect": FilterInstRedirect,
"direct": FilterInstDirect, "direct": FilterInstDirect,
"reverse_proxy": FilterInstProxy, "reverse_proxy": FilterInstProxy,
"default_not_found": FilterInstDefaultNotFound, "_404_": FilterInstDefaultNotFound,
"failback": FilterInstFailback,
"template": FilterInstTemplate,
} }
} }

View File

@@ -22,6 +22,9 @@ var FilterInstDefaultNotFound core.FilterInstance = func(config core.FilterParam
return err return err
} }
writer.Header().Set("Content-Type", "text/html; charset=utf-8") 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) writer.WriteHeader(http.StatusNotFound)
_, _ = io.Copy(writer, open.Body) _, _ = io.Copy(writer, open.Body)
} }

View File

@@ -3,9 +3,11 @@ package filters
import ( import (
"context" "context"
"io" "io"
"mime"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
@@ -20,12 +22,17 @@ var FilterInstDirect core.FilterInstance = func(config core.FilterParams) (core.
if err := config.Unmarshal(&param); err != nil { if err := config.Unmarshal(&param); err != nil {
return nil, err 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 { 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 resp *http.Response
var path string var path string
var err error defaultPath := param.Prefix + strings.TrimSuffix(metadata.Path, "/")
failback := []string{param.Prefix + metadata.Path, param.Prefix + metadata.Path + "/index.html"} for _, p := range []string{defaultPath, defaultPath + "/index.html"} {
for _, p := range failback { zap.L().Debug("direct fetch", zap.String("path", p))
resp, err = metadata.NativeOpen(request.Context(), p, nil) resp, err = metadata.NativeOpen(request.Context(), p, nil)
if err != nil { if err != nil {
if resp != nil { if resp != nil {
@@ -33,6 +40,7 @@ var FilterInstDirect core.FilterInstance = func(config core.FilterParams) (core.
} }
if !errors.Is(err, os.ErrNotExist) { if !errors.Is(err, os.ErrNotExist) {
zap.L().Debug("error", zap.Any("error", err)) zap.L().Debug("error", zap.Any("error", err))
return err
} }
continue continue
} }
@@ -46,7 +54,8 @@ var FilterInstDirect core.FilterInstance = func(config core.FilterParams) (core.
if err != nil { if err != nil {
return err 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")) lastMod, err := time.Parse(http.TimeFormat, resp.Header.Get("Last-Modified"))
if err == nil { if err == nil {
if seeker, ok := resp.Body.(io.ReadSeeker); ok { 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 FilterInstRedirect core.FilterInstance = func(config core.FilterParams) (core.FilterCall, error) {
var param struct { var param struct {
Targets []string `json:"targets"` Targets []string `json:"targets"`
Code int `json:"code"`
} }
if err := config.Unmarshal(&param); err != nil { if err := config.Unmarshal(&param); err != nil {
return nil, err 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 { 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), "") domain := portExp.ReplaceAllString(strings.ToLower(request.Host), "")
if len(param.Targets) > 0 && !slices.Contains(metadata.Alias, domain) { 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 target.RawQuery = request.URL.RawQuery
http.Redirect(writer, request, target.String(), http.StatusFound) http.Redirect(writer, request, target.String(), param.Code)
return nil return nil
} else { } else {
return next(ctx, writer, request, metadata) 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
}

View File

@@ -2,6 +2,7 @@ package pkg
import ( import (
"errors" "errors"
"fmt"
"net/http" "net/http"
"os" "os"
"regexp" "regexp"
@@ -77,13 +78,13 @@ func DefaultOptions(domain string) ServerOptions {
} }
type Server struct { type Server struct {
backend core.Backend
options *ServerOptions options *ServerOptions
meta *core.PageDomain meta *core.PageDomain
backend core.Backend staticFS http.Handler
fs http.Handler
filterMgr map[string]core.FilterInstance
filtersCache *lru.Cache[string, glob.Glob] filterMgr map[string]core.FilterInstance
globCache *lru.Cache[string, glob.Glob]
} }
var staticPrefix = "/.well-known/page-server/" var staticPrefix = "/.well-known/page-server/"
@@ -103,8 +104,8 @@ func NewPageServer(backend core.Backend, options ServerOptions) *Server {
backend: backend, backend: backend,
options: &options, options: &options,
meta: pageMeta, meta: pageMeta,
fs: fs, staticFS: fs,
filtersCache: c, globCache: c,
filterMgr: filters.DefaultFilters(), filterMgr: filters.DefaultFilters(),
} }
} }
@@ -112,8 +113,8 @@ func NewPageServer(backend core.Backend, options ServerOptions) *Server {
func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) { func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
sessionID, _ := uuid.NewRandom() sessionID, _ := uuid.NewRandom()
request.Header.Set("Session-ID", sessionID.String()) request.Header.Set("Session-ID", sessionID.String())
if s.fs != nil && strings.HasPrefix(request.URL.Path, staticPrefix) { if s.staticFS != nil && strings.HasPrefix(request.URL.Path, staticPrefix) {
s.fs.ServeHTTP(writer, request) s.staticFS.ServeHTTP(writer, request)
return return
} }
defer func() { defer func() {
@@ -145,15 +146,16 @@ func (s *Server) Serve(writer http.ResponseWriter, request *http.Request) error
} }
activeFiltersCall := make([]core.FilterCall, 0) activeFiltersCall := make([]core.FilterCall, 0)
activeFilters := make([]core.Filter, 0) activeFilters := make([]core.Filter, 0)
filtersRoute := make([]string, 0)
for _, filter := range meta.Filters { for _, filter := range meta.Filters {
value, ok := s.filtersCache.Get(filter.Path) value, ok := s.globCache.Get(filter.Path)
if !ok { if !ok {
value, err = glob.Compile(filter.Path) value, err = glob.Compile(filter.Path)
if err != nil { if err != nil {
continue continue
} }
s.filtersCache.Add(filter.Path, value) s.globCache.Add(filter.Path, value)
} }
if value.Match(meta.Path) { if value.Match(meta.Path) {
instance := s.filterMgr[filter.Type] instance := s.filterMgr[filter.Type]
@@ -161,6 +163,7 @@ func (s *Server) Serve(writer http.ResponseWriter, request *http.Request) error
return errors.New("filter not found : " + filter.Type) return errors.New("filter not found : " + filter.Type)
} }
activeFilters = append(activeFilters, filter) activeFilters = append(activeFilters, filter)
filtersRoute = append(filtersRoute, fmt.Sprintf("%s[%s]%s", filter.Type, filter.Path, filter.Params))
call, err := instance(filter.Params) call, err := instance(filter.Params)
if err != nil { if err != nil {
return err return err
@@ -171,16 +174,18 @@ func (s *Server) Serve(writer http.ResponseWriter, request *http.Request) error
slices.Reverse(activeFiltersCall) slices.Reverse(activeFiltersCall)
slices.Reverse(activeFilters) slices.Reverse(activeFilters)
zap.L().Debug("active filters", zap.Any("filters", activeFilters)) l := len(filtersRoute)
for i := l - 2; i >= 0; i-- {
direct, _ := filters.FilterInstDirect(map[string]any{ filtersRoute = append(filtersRoute, filtersRoute[i])
"prefix": "",
})
stack := core.NextCallWrapper(direct, nil)
for _, filter := range activeFiltersCall {
stack = core.NextCallWrapper(filter, stack)
} }
return stack(ctx, writer, request, meta) zap.L().Debug("active filters", zap.String("filters", strings.Join(filtersRoute, " -> ")))
var stack core.NextCall = core.NotFountNextCall
for i, filter := range activeFiltersCall {
stack = core.NextCallWrapper(filter, stack, activeFilters[i])
}
err = stack(ctx, writer, request, meta)
return err
} }
func (s *Server) Close() error { func (s *Server) Close() error {

View File

@@ -30,7 +30,7 @@ func NewDummy() (*ProviderDummy, error) {
}, nil }, nil
} }
func (p *ProviderDummy) Repos(ctx context.Context, owner string) (map[string]string, error) { func (p *ProviderDummy) Repos(_ context.Context, owner string) (map[string]string, error) {
dir, err := os.ReadDir(filepath.Join(p.BaseDir, owner)) dir, err := os.ReadDir(filepath.Join(p.BaseDir, owner))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -44,7 +44,7 @@ func (p *ProviderDummy) Repos(ctx context.Context, owner string) (map[string]str
return repos, nil return repos, nil
} }
func (p *ProviderDummy) Branches(ctx context.Context, owner, repo string) (map[string]*core.BranchInfo, error) { func (p *ProviderDummy) Branches(_ context.Context, owner, repo string) (map[string]*core.BranchInfo, error) {
dir, err := os.ReadDir(filepath.Join(p.BaseDir, owner, repo)) dir, err := os.ReadDir(filepath.Join(p.BaseDir, owner, repo))
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -99,47 +99,3 @@ func Test_fail_back(t *testing.T) {
assert.Equal(t, "hello world 2", string(data)) assert.Equal(t, "hello world 2", string(data))
}) })
} }
func Test_get_v_route(t *testing.T) {
server := core.NewDefaultTestServer()
defer server.Close()
server.AddFile("org1/repo1/gh-pages/index.html", "hello world")
server.AddFile("org1/repo1/gh-pages/.pages.yaml", `
v-route: true
`)
data, _, err := server.OpenFile("https://org1.example.com/repo1/")
assert.NoError(t, err)
assert.Equal(t, "hello world", string(data))
data, _, err = server.OpenFile("https://org1.example.com/repo1/404")
assert.NoError(t, err)
assert.Equal(t, "hello world", string(data))
}
func Test_get_v_ignore(t *testing.T) {
server := core.NewDefaultTestServer()
defer server.Close()
server.AddFile("org1/repo1/gh-pages/index.html", "hello world")
server.AddFile("org1/repo1/gh-pages/bad.html", "hello world")
server.AddFile("org1/repo1/gh-pages/.pages.yaml", `
ignore: .pages.yaml
`)
data, _, err := server.OpenFile("https://org1.example.com/repo1/")
assert.NoError(t, err)
assert.Equal(t, "hello world", string(data))
data, _, err = server.OpenFile("https://org1.example.com/repo1/bad.html")
assert.NoError(t, err)
assert.Equal(t, "hello world", string(data))
server.AddFile("org1/repo1/gh-pages/.pages.yaml", `
ignore: bad.*
`)
data, _, err = server.OpenFile("https://org1.example.com/repo1/")
assert.NoError(t, err)
assert.Equal(t, "hello world", string(data))
_, resp, _ := server.OpenFile("https://org1.example.com/repo1/bad.html")
assert.Equal(t, 404, resp.StatusCode)
// 默认排除的内容
_, resp, _ = server.OpenFile("https://org1.example.com/repo1/.pages.yaml")
assert.Equal(t, 404, resp.StatusCode)
}

View File

@@ -0,0 +1,36 @@
package tests
import (
"testing"
"github.com/stretchr/testify/assert"
"gopkg.d7z.net/gitea-pages/tests/core"
)
func Test_filter_block(t *testing.T) {
server := core.NewDefaultTestServer()
defer server.Close()
server.AddFile("org1/repo1/gh-pages/index.html", "hello world")
server.AddFile("org1/repo1/gh-pages/bad.html", "hello world")
data, _, err := server.OpenFile("https://org1.example.com/repo1/")
assert.NoError(t, err)
assert.Equal(t, "hello world", string(data))
data, _, err = server.OpenFile("https://org1.example.com/repo1/bad.html")
assert.NoError(t, err)
assert.Equal(t, "hello world", string(data))
server.AddFile("org1/repo1/gh-pages/.pages.yaml", `
routes:
- path: "bad.html"
block:
code:
`)
data, _, err = server.OpenFile("https://org1.example.com/repo1/")
assert.NoError(t, err)
assert.Equal(t, "hello world", string(data))
_, resp, _ := server.OpenFile("https://org1.example.com/repo1/bad.html")
assert.Equal(t, 403, resp.StatusCode)
// 默认排除的内容
_, resp, _ = server.OpenFile("https://org1.example.com/repo1/.pages.yaml")
assert.Equal(t, 403, resp.StatusCode)
}

View File

@@ -0,0 +1,35 @@
package tests
import (
"testing"
"github.com/stretchr/testify/assert"
"gopkg.d7z.net/gitea-pages/tests/core"
)
func Test_filter_failback(t *testing.T) {
server := core.NewDefaultTestServer()
defer server.Close()
server.AddFile("org1/repo1/gh-pages/index.html", "hello world")
server.AddFile("org1/repo1/gh-pages/404.html", "404 page")
server.AddFile("org1/repo1/gh-pages/.pages.yaml", `
routes:
- path: "**"
failback:
path: index.html
`)
//data, _, err := server.OpenFile("https://org1.example.com/repo1/")
//assert.NoError(t, err)
//assert.Equal(t, "hello world", string(data))
//
//// 测试默认回退
//data, _, err = server.OpenFile("https://org1.example.com/repo1/404")
//assert.NoError(t, err)
//assert.Equal(t, "hello world", string(data))
// 测试存在的页面
data, _, err := server.OpenFile("https://org1.example.com/repo1/404.html")
assert.NoError(t, err)
assert.Equal(t, "404 page", string(data))
}

View File

@@ -7,7 +7,7 @@ import (
"gopkg.d7z.net/gitea-pages/tests/core" "gopkg.d7z.net/gitea-pages/tests/core"
) )
func Test_proxy(t *testing.T) { func test_proxy(t *testing.T) {
server := core.NewDefaultTestServer() server := core.NewDefaultTestServer()
hs := core.NewServer() hs := core.NewServer()
defer server.Close() defer server.Close()
@@ -17,8 +17,12 @@ func Test_proxy(t *testing.T) {
server.AddFile("org1/repo1/gh-pages/index.html", "hello world") server.AddFile("org1/repo1/gh-pages/index.html", "hello world")
server.AddFile("org1/repo1/gh-pages/.pages.yaml", ` server.AddFile("org1/repo1/gh-pages/.pages.yaml", `
routes:
- path: /api/**
reverse_proxy:
prefix: /api
target: %s
proxy: proxy:
/api: %s/test
/abi: %s/ /abi: %s/
`, hs.URL, hs.URL) `, hs.URL, hs.URL)
data, _, err := server.OpenFile("https://org1.example.com/repo1/") data, _, err := server.OpenFile("https://org1.example.com/repo1/")
@@ -36,7 +40,7 @@ proxy:
assert.Equal(t, 404, resp.StatusCode) assert.Equal(t, 404, resp.StatusCode)
} }
func Test_cname_proxy(t *testing.T) { func test_cname_proxy(t *testing.T) {
server := core.NewDefaultTestServer() server := core.NewDefaultTestServer()
hs := core.NewServer() hs := core.NewServer()
defer server.Close() defer server.Close()

View File

@@ -9,14 +9,16 @@ import (
_ "gopkg.d7z.net/gitea-pages/pkg/renders" _ "gopkg.d7z.net/gitea-pages/pkg/renders"
) )
func Test_get_render(t *testing.T) { func Test_Filter_Template(t *testing.T) {
server := core.NewDefaultTestServer() server := core.NewDefaultTestServer()
defer server.Close() defer server.Close()
server.AddFile("org1/repo1/gh-pages/index.html", "hello world") server.AddFile("org1/repo1/gh-pages/index.html", "hello world")
server.AddFile("org1/repo1/gh-pages/tmpl/index.html", "hello world,{{ .Request.Host }}") server.AddFile("org1/repo1/gh-pages/tmpl/index.html", "hello world,{{ .Request.Host }}")
server.AddFile("org1/repo1/gh-pages/tmpl/ignore.html", "hello world, No Template")
server.AddFile("org1/repo1/gh-pages/.pages.yaml", ` server.AddFile("org1/repo1/gh-pages/.pages.yaml", `
templates: routes:
gotemplate: tmpl/*.html - path: tmpl/index.html
template:
`) `)
data, _, err := server.OpenFile("https://org1.example.com/repo1/") data, _, err := server.OpenFile("https://org1.example.com/repo1/")
assert.NoError(t, err) assert.NoError(t, err)
@@ -25,4 +27,8 @@ templates:
data, _, err = server.OpenFile("https://org1.example.com/repo1/tmpl/index.html") data, _, err = server.OpenFile("https://org1.example.com/repo1/tmpl/index.html")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "hello world,org1.example.com", string(data)) assert.Equal(t, "hello world,org1.example.com", string(data))
data, _, err = server.OpenFile("https://org1.example.com/repo1/tmpl/ignore.html")
assert.NoError(t, err)
assert.Equal(t, "hello world, No Template", string(data))
} }