rules: updated help message, make values optional, fixes tests

This commit is contained in:
yusing 2025-02-06 05:12:49 +08:00
parent bcf2dde091
commit 43ed860e18
6 changed files with 130 additions and 47 deletions

View file

@ -2,19 +2,19 @@ package http
import "net/http"
var validMethods = map[string]struct{}{
http.MethodGet: {},
http.MethodHead: {},
http.MethodPost: {},
http.MethodPut: {},
http.MethodPatch: {},
http.MethodDelete: {},
http.MethodConnect: {},
http.MethodOptions: {},
http.MethodTrace: {},
}
func IsMethodValid(method string) bool {
_, ok := validMethods[method]
return ok
switch method {
case http.MethodGet,
http.MethodHead,
http.MethodPost,
http.MethodPut,
http.MethodPatch,
http.MethodDelete,
http.MethodConnect,
http.MethodOptions,
http.MethodTrace:
return true
default:
return false
}
}

View file

@ -11,7 +11,8 @@ var (
ErrInvalidCommandSequence = E.New("invalid command sequence")
ErrInvalidSetTarget = E.New("invalid `rule.set` target")
ErrExpectNoArg = ErrInvalidArguments.Withf("expect no arg")
ErrExpectOneArg = ErrInvalidArguments.Withf("expect 1 arg")
ErrExpectTwoArgs = ErrInvalidArguments.Withf("expect 2 args")
ErrExpectNoArg = E.New("expect no arg")
ErrExpectOneArg = E.New("expect 1 arg")
ErrExpectTwoArgs = E.New("expect 2 args")
ErrExpectKVOptionalV = E.New("expect 'key' or 'key value'")
)

View file

@ -20,9 +20,8 @@ func (h *Help) String() string {
sb.WriteString(h.command)
sb.WriteString(" ")
for arg := range h.args {
sb.WriteRune('<')
sb.WriteString(arg)
sb.WriteString("> ")
sb.WriteString(strings.ToUpper(arg))
sb.WriteRune(' ')
}
if h.description != "" {
sb.WriteString("\n\t")
@ -32,7 +31,7 @@ func (h *Help) String() string {
sb.WriteRune('\n')
for arg, desc := range h.args {
sb.WriteRune('\t')
sb.WriteString(arg)
sb.WriteString(strings.ToUpper(arg))
sb.WriteString(": ")
sb.WriteString(desc)
sb.WriteRune('\n')

View file

@ -34,15 +34,25 @@ var checkers = map[string]struct {
help: Help{
command: OnHeader,
args: map[string]string{
"key": "the header key",
"value": "the header value",
"key": "the header key",
"[value]": "the header value",
},
},
validate: toStrTuple,
validate: toKVOptionalV,
builder: func(args any) CheckFunc {
k, v := args.(*StrTuple).Unpack()
if v == "" {
return func(cached Cache, r *http.Request) bool {
return len(r.Header[k]) > 0
}
}
return func(cached Cache, r *http.Request) bool {
return r.Header.Get(k) == v
for _, vv := range r.Header[k] {
if v == vv {
return true
}
}
return false
}
},
},
@ -50,13 +60,18 @@ var checkers = map[string]struct {
help: Help{
command: OnQuery,
args: map[string]string{
"key": "the query key",
"value": "the query value",
"key": "the query key",
"[value]": "the query value",
},
},
validate: toStrTuple,
validate: toKVOptionalV,
builder: func(args any) CheckFunc {
k, v := args.(*StrTuple).Unpack()
if v == "" {
return func(cached Cache, r *http.Request) bool {
return len(cached.GetQueries(r)[k]) > 0
}
}
return func(cached Cache, r *http.Request) bool {
queries := cached.GetQueries(r)[k]
for _, query := range queries {
@ -72,13 +87,24 @@ var checkers = map[string]struct {
help: Help{
command: OnCookie,
args: map[string]string{
"key": "the cookie key",
"value": "the cookie value",
"key": "the cookie key",
"[value]": "the cookie value",
},
},
validate: toStrTuple,
validate: toKVOptionalV,
builder: func(args any) CheckFunc {
k, v := args.(*StrTuple).Unpack()
if v == "" {
return func(cached Cache, r *http.Request) bool {
cookies := cached.GetCookies(r)
for _, cookie := range cookies {
if cookie.Name == k {
return true
}
}
return false
}
}
return func(cached Cache, r *http.Request) bool {
cookies := cached.GetCookies(r)
for _, cookie := range cookies {
@ -95,13 +121,18 @@ var checkers = map[string]struct {
help: Help{
command: OnForm,
args: map[string]string{
"key": "the form key",
"value": "the form value",
"key": "the form key",
"[value]": "the form value",
},
},
validate: toStrTuple,
validate: toKVOptionalV,
builder: func(args any) CheckFunc {
k, v := args.(*StrTuple).Unpack()
if v == "" {
return func(cached Cache, r *http.Request) bool {
return r.FormValue(k) != ""
}
}
return func(cached Cache, r *http.Request) bool {
return r.FormValue(k) == v
}
@ -111,13 +142,18 @@ var checkers = map[string]struct {
help: Help{
command: OnPostForm,
args: map[string]string{
"key": "the form key",
"value": "the form value",
"key": "the form key",
"[value]": "the form value",
},
},
validate: toStrTuple,
validate: toKVOptionalV,
builder: func(args any) CheckFunc {
k, v := args.(*StrTuple).Unpack()
if v == "" {
return func(cached Cache, r *http.Request) bool {
return r.PostFormValue(k) != ""
}
}
return func(cached Cache, r *http.Request) bool {
return r.PostFormValue(k) == v
}

View file

@ -15,25 +15,50 @@ func TestParseOn(t *testing.T) {
}{
// header
{
name: "header_valid",
name: "header_valid_kv",
input: "header Connection Upgrade",
wantErr: nil,
},
{
name: "header_invalid",
name: "header_valid_k",
input: "header Connection",
wantErr: ErrInvalidArguments,
wantErr: nil,
},
{
name: "header_missing_arg",
input: "header",
wantErr: ErrExpectKVOptionalV,
},
// query
{
name: "query_valid",
name: "query_valid_kv",
input: "query key value",
wantErr: nil,
},
{
name: "query_invalid",
name: "query_valid_k",
input: "query key",
wantErr: ErrInvalidArguments,
wantErr: nil,
},
{
name: "query_missing_arg",
input: "query",
wantErr: ErrExpectKVOptionalV,
},
{
name: "cookie_valid_kv",
input: "cookie key value",
wantErr: nil,
},
{
name: "cookie_valid_k",
input: "cookie key",
wantErr: nil,
},
{
name: "cookie_missing_arg",
input: "cookie",
wantErr: ErrExpectKVOptionalV,
},
// method
{
@ -43,9 +68,14 @@ func TestParseOn(t *testing.T) {
},
{
name: "method_invalid",
input: "method",
input: "method invalid",
wantErr: ErrInvalidArguments,
},
{
name: "method_missing_arg",
input: "method",
wantErr: ErrExpectOneArg,
},
// path
{
name: "path_valid",
@ -53,9 +83,9 @@ func TestParseOn(t *testing.T) {
wantErr: nil,
},
{
name: "path_invalid",
name: "path_missing_arg",
input: "path",
wantErr: ErrInvalidArguments,
wantErr: ErrExpectOneArg,
},
// remote
{
@ -65,9 +95,14 @@ func TestParseOn(t *testing.T) {
},
{
name: "remote_invalid",
input: "remote",
input: "remote abcd",
wantErr: ErrInvalidArguments,
},
{
name: "remote_missing_arg",
input: "remote",
wantErr: ErrExpectOneArg,
},
{
name: "unknown_target",
input: "unknown",

View file

@ -36,6 +36,18 @@ func toStrTuple(args []string) (any, E.Error) {
return &StrTuple{args[0], args[1]}, nil
}
// toKVOptionalV returns *StrTuple that value is optional.
func toKVOptionalV(args []string) (any, E.Error) {
switch len(args) {
case 1:
return &StrTuple{args[0], ""}, nil
case 2:
return &StrTuple{args[0], args[1]}, nil
default:
return nil, ErrExpectKVOptionalV
}
}
// validateURL returns types.URL with the URL validated.
func validateURL(args []string) (any, E.Error) {
if len(args) != 1 {