mirror of
https://github.com/yusing/godoxy.git
synced 2025-06-09 13:02:33 +02:00
add help messages to rules, updat url validation
This commit is contained in:
parent
4aee44fe11
commit
9d701ad671
4 changed files with 126 additions and 8 deletions
|
@ -36,10 +36,18 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var commands = map[string]struct {
|
var commands = map[string]struct {
|
||||||
|
help Help
|
||||||
validate ValidateFunc
|
validate ValidateFunc
|
||||||
build func(args any) *CommandExecutor
|
build func(args any) *CommandExecutor
|
||||||
}{
|
}{
|
||||||
CommandRewrite: {
|
CommandRewrite: {
|
||||||
|
help: Help{
|
||||||
|
command: CommandRewrite,
|
||||||
|
args: map[string]string{
|
||||||
|
"from": "the path to rewrite, must start with /",
|
||||||
|
"to": "the path to rewrite to, must start with /",
|
||||||
|
},
|
||||||
|
},
|
||||||
validate: func(args []string) (any, E.Error) {
|
validate: func(args []string) (any, E.Error) {
|
||||||
if len(args) != 2 {
|
if len(args) != 2 {
|
||||||
return nil, ErrExpectTwoArgs
|
return nil, ErrExpectTwoArgs
|
||||||
|
@ -68,6 +76,12 @@ var commands = map[string]struct {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CommandServe: {
|
CommandServe: {
|
||||||
|
help: Help{
|
||||||
|
command: CommandServe,
|
||||||
|
args: map[string]string{
|
||||||
|
"root": "the file system path to serve, must be an existing directory",
|
||||||
|
},
|
||||||
|
},
|
||||||
validate: validateFSPath,
|
validate: validateFSPath,
|
||||||
build: func(args any) *CommandExecutor {
|
build: func(args any) *CommandExecutor {
|
||||||
root := args.(string)
|
root := args.(string)
|
||||||
|
@ -80,6 +94,12 @@ var commands = map[string]struct {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CommandRedirect: {
|
CommandRedirect: {
|
||||||
|
help: Help{
|
||||||
|
command: CommandRedirect,
|
||||||
|
args: map[string]string{
|
||||||
|
"to": "the url to redirect to, can be relative or absolute URL",
|
||||||
|
},
|
||||||
|
},
|
||||||
validate: validateURL,
|
validate: validateURL,
|
||||||
build: func(args any) *CommandExecutor {
|
build: func(args any) *CommandExecutor {
|
||||||
target := args.(types.URL).String()
|
target := args.(types.URL).String()
|
||||||
|
@ -92,6 +112,13 @@ var commands = map[string]struct {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CommandError: {
|
CommandError: {
|
||||||
|
help: Help{
|
||||||
|
command: CommandError,
|
||||||
|
args: map[string]string{
|
||||||
|
"code": "the http status code to return",
|
||||||
|
"text": "the error message to return",
|
||||||
|
},
|
||||||
|
},
|
||||||
validate: func(args []string) (any, E.Error) {
|
validate: func(args []string) (any, E.Error) {
|
||||||
if len(args) != 2 {
|
if len(args) != 2 {
|
||||||
return nil, ErrExpectTwoArgs
|
return nil, ErrExpectTwoArgs
|
||||||
|
@ -118,7 +145,13 @@ var commands = map[string]struct {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CommandProxy: {
|
CommandProxy: {
|
||||||
validate: validateURL,
|
help: Help{
|
||||||
|
command: CommandProxy,
|
||||||
|
args: map[string]string{
|
||||||
|
"to": "the url to proxy to, must be an absolute URL",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
validate: validateAbsoluteURL,
|
||||||
build: func(args any) *CommandExecutor {
|
build: func(args any) *CommandExecutor {
|
||||||
target := args.(types.URL)
|
target := args.(types.URL)
|
||||||
if target.Scheme == "" {
|
if target.Scheme == "" {
|
||||||
|
@ -166,7 +199,7 @@ func (cmd *Command) Parse(v string) error {
|
||||||
}
|
}
|
||||||
validArgs, err := builder.validate(args)
|
validArgs, err := builder.validate(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err.Subject(directive)
|
return err.Subject(directive).Withf("%s", builder.help.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
exec := builder.build(validArgs)
|
exec := builder.build(validArgs)
|
||||||
|
|
35
internal/route/rules/help.go
Normal file
35
internal/route/rules/help.go
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package rules
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
type Help struct {
|
||||||
|
command string
|
||||||
|
args map[string]string // args[arg] -> description
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Generate help string, e.g.
|
||||||
|
|
||||||
|
rewrite <from> <to>
|
||||||
|
from: the path to rewrite, must start with /
|
||||||
|
to: the path to rewrite to, must start with /
|
||||||
|
*/
|
||||||
|
func (h *Help) String() string {
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteString(h.command)
|
||||||
|
sb.WriteString(" ")
|
||||||
|
for arg := range h.args {
|
||||||
|
sb.WriteRune('<')
|
||||||
|
sb.WriteString(arg)
|
||||||
|
sb.WriteString("> ")
|
||||||
|
}
|
||||||
|
sb.WriteRune('\n')
|
||||||
|
for arg, desc := range h.args {
|
||||||
|
sb.WriteRune('\t')
|
||||||
|
sb.WriteString(arg)
|
||||||
|
sb.WriteString(": ")
|
||||||
|
sb.WriteString(desc)
|
||||||
|
sb.WriteRune('\n')
|
||||||
|
}
|
||||||
|
return sb.String()
|
||||||
|
}
|
|
@ -26,28 +26,55 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var checkers = map[string]struct {
|
var checkers = map[string]struct {
|
||||||
|
help Help
|
||||||
validate ValidateFunc
|
validate ValidateFunc
|
||||||
check func(r *http.Request, args any) bool
|
check func(r *http.Request, args any) bool
|
||||||
}{
|
}{
|
||||||
OnHeader: { // header <key> <value>
|
OnHeader: {
|
||||||
|
help: Help{
|
||||||
|
command: OnHeader,
|
||||||
|
args: map[string]string{
|
||||||
|
"key": "the header key",
|
||||||
|
"value": "the header value",
|
||||||
|
},
|
||||||
|
},
|
||||||
validate: toStrTuple,
|
validate: toStrTuple,
|
||||||
check: func(r *http.Request, args any) bool {
|
check: func(r *http.Request, args any) bool {
|
||||||
return r.Header.Get(args.(StrTuple).First) == args.(StrTuple).Second
|
return r.Header.Get(args.(StrTuple).First) == args.(StrTuple).Second
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
OnQuery: { // query <key> <value>
|
OnQuery: {
|
||||||
|
help: Help{
|
||||||
|
command: OnQuery,
|
||||||
|
args: map[string]string{
|
||||||
|
"key": "the query key",
|
||||||
|
"value": "the query value",
|
||||||
|
},
|
||||||
|
},
|
||||||
validate: toStrTuple,
|
validate: toStrTuple,
|
||||||
check: func(r *http.Request, args any) bool {
|
check: func(r *http.Request, args any) bool {
|
||||||
return r.URL.Query().Get(args.(StrTuple).First) == args.(StrTuple).Second
|
return r.URL.Query().Get(args.(StrTuple).First) == args.(StrTuple).Second
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
OnMethod: { // method <method>
|
OnMethod: {
|
||||||
|
help: Help{
|
||||||
|
command: OnMethod,
|
||||||
|
args: map[string]string{
|
||||||
|
"method": "the http method",
|
||||||
|
},
|
||||||
|
},
|
||||||
validate: validateMethod,
|
validate: validateMethod,
|
||||||
check: func(r *http.Request, method any) bool {
|
check: func(r *http.Request, method any) bool {
|
||||||
return r.Method == method.(string)
|
return r.Method == method.(string)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
OnPath: { // path <path>
|
OnPath: {
|
||||||
|
help: Help{
|
||||||
|
command: OnPath,
|
||||||
|
args: map[string]string{
|
||||||
|
"path": "the request path, must start with /",
|
||||||
|
},
|
||||||
|
},
|
||||||
validate: validateURLPath,
|
validate: validateURLPath,
|
||||||
check: func(r *http.Request, globPath any) bool {
|
check: func(r *http.Request, globPath any) bool {
|
||||||
reqPath := r.URL.Path
|
reqPath := r.URL.Path
|
||||||
|
@ -57,7 +84,13 @@ var checkers = map[string]struct {
|
||||||
return strutils.GlobMatch(globPath.(string), reqPath)
|
return strutils.GlobMatch(globPath.(string), reqPath)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
OnRemote: { // remote <ip|cidr>
|
OnRemote: {
|
||||||
|
help: Help{
|
||||||
|
command: OnRemote,
|
||||||
|
args: map[string]string{
|
||||||
|
"ip|cidr": "the remote ip or cidr",
|
||||||
|
},
|
||||||
|
},
|
||||||
validate: validateCIDR,
|
validate: validateCIDR,
|
||||||
check: func(r *http.Request, cidr any) bool {
|
check: func(r *http.Request, cidr any) bool {
|
||||||
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||||
|
@ -137,7 +170,7 @@ func parseOn(line string) (Checkers, E.Error) {
|
||||||
|
|
||||||
validArgs, err := checker.validate(args)
|
validArgs, err := checker.validate(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err.Subject(subject)
|
return nil, err.Subject(subject).Withf("%s", checker.help.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
return Checkers{
|
return Checkers{
|
||||||
|
|
|
@ -35,6 +35,23 @@ func validateURL(args []string) (any, E.Error) {
|
||||||
return u, nil
|
return u, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateAbsoluteURL(args []string) (any, E.Error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, ErrExpectOneArg
|
||||||
|
}
|
||||||
|
u, err := types.ParseURL(args[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrInvalidArguments.With(err)
|
||||||
|
}
|
||||||
|
if u.Scheme == "" {
|
||||||
|
u.Scheme = "http"
|
||||||
|
}
|
||||||
|
if u.Host == "" {
|
||||||
|
return nil, ErrInvalidArguments.Withf("missing host")
|
||||||
|
}
|
||||||
|
return u, nil
|
||||||
|
}
|
||||||
|
|
||||||
func validateCIDR(args []string) (any, E.Error) {
|
func validateCIDR(args []string) (any, E.Error) {
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
return nil, ErrExpectOneArg
|
return nil, ErrExpectOneArg
|
||||||
|
|
Loading…
Add table
Reference in a new issue