Skip to content
This repository has been archived by the owner on Mar 20, 2023. It is now read-only.

Commit

Permalink
Check all matching rules before checking for exceptions; add addition…
Browse files Browse the repository at this point in the history
…al exception tests
  • Loading branch information
jung-kurt committed May 10, 2018
1 parent 6e286b5 commit 72bd95b
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 38 deletions.
92 changes: 63 additions & 29 deletions cgi.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,34 +33,67 @@ import (
// patternStr uses glob notation; see path/Match for matching details. If the
// pattern is invalid (for example, contains an unpaired "["), false is
// returned.
func match(reqStr, patternStr string) (ok bool, prefixStr, suffixStr string) {
func match(requestStr string, patterns []string) (ok bool, prefixStr, suffixStr string) {
var str, last string
var err error
str = reqStr
last = ""
for last != str && !ok && err == nil {
ok, err = path.Match(patternStr, str)
if err == nil {
if !ok {
last = str
str = filepath.Dir(str)
ln := len(patterns)
for j := 0; j < ln && !ok; j++ {
pattern := patterns[j]
str = requestStr
last = ""
for last != str && !ok && err == nil {
ok, err = path.Match(pattern, str)
if err == nil {
if ok {
prefixStr = str
suffixStr = requestStr[len(str):]
} else {
last = str
str = filepath.Dir(str)
}
}
}
}
if ok && err == nil {
return true, str, reqStr[len(str):]
}
return false, "", ""
return
}

// func match(reqStr, patternStr string) (ok bool, prefixStr, suffixStr string) {
// var str, last string
// var err error
// str = reqStr
// last = ""
// for last != str && !ok && err == nil {
// ok, err = path.Match(patternStr, str)
// if err == nil {
// if !ok {
// last = str
// str = filepath.Dir(str)
// }
// }
// }
// if ok && err == nil {
// return true, str, reqStr[len(str):]
// }
// return false, "", ""
// }

// excluded returns true if the request string (reqStr) matches any of the
// pattern strings (patterns), false otherwise. patterns use glob notation; see
// path/Match for matching details. If the pattern is invalid (for example,
// contains an unpaired "["), false is returned.
func excluded(reqStr string, patterns []string) (ok bool) {
var err error
var match bool

ln := len(patterns)
for j := 0; j < ln && !ok; j++ {
ok, _, _ = match(reqStr, patterns[j])
match, err = path.Match(patterns[j], reqStr)
if err == nil {
if match {
ok = true
// fmt.Printf("[%s] is excluded by rule [%s]\n", reqStr, patterns[j])
}
}
}
return
}
Expand Down Expand Up @@ -107,25 +140,26 @@ func setupCall(h handlerType, rule ruleType, lfStr, rtStr string,
func (h handlerType) ServeHTTP(w http.ResponseWriter, r *http.Request) (code int, err error) {
rep := httpserver.NewReplacer(r, nil, "")
for _, rule := range h.rules {
for _, matchStr := range rule.matches {
ok, lfStr, rtStr := match(r.URL.Path, matchStr)
// for _, matchStr := range rule.matches {
// ok, lfStr, rtStr := match(r.URL.Path, matchStr)
ok, lfStr, rtStr := match(r.URL.Path, rule.matches)
if ok {
ok = !excluded(r.URL.Path, rule.exceptions)
if ok {
ok = !excluded(r.URL.Path, rule.exceptions)
if ok {
var buf bytes.Buffer
// Retrieve name of remote user that was set by some downstream middleware,
// possibly basicauth.
remoteUser, _ := r.Context().Value(httpserver.RemoteUserCtxKey).(string) // Blank if not set
cgiHnd := setupCall(h, rule, lfStr, rtStr, rep, r.Header, remoteUser)
cgiHnd.Stderr = &buf
cgiHnd.ServeHTTP(w, r)
if buf.Len() > 0 {
err = errors.New(trim(buf.String()))
}
return
var buf bytes.Buffer
// Retrieve name of remote user that was set by some downstream middleware,
// possibly basicauth.
remoteUser, _ := r.Context().Value(httpserver.RemoteUserCtxKey).(string) // Blank if not set
cgiHnd := setupCall(h, rule, lfStr, rtStr, rep, r.Header, remoteUser)
cgiHnd.Stderr = &buf
cgiHnd.ServeHTTP(w, r)
if buf.Len() > 0 {
err = errors.New(trim(buf.String()))
}
return
}
}
// }
}
return h.next.ServeHTTP(w, r)
}
31 changes: 25 additions & 6 deletions cgi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func TestServe(t *testing.T) {
`cgi /servertime {.}/test/example`,
`cgi {
match /servertime
except /servertime/1934
except /servertime/1934/*/*
exec {.}/test/example --example
env CGI_GLOBAL=12
empty_env CGI_LOCAL
Expand Down Expand Up @@ -96,7 +96,7 @@ CGI_LOCAL is unset
=== Directive 1 ===
cgi {
match /servertime
except /servertime/1934
except /servertime/1934/*/*
exec {.}/test/example --example
env CGI_GLOBAL=12
empty_env CGI_LOCAL
Expand Down Expand Up @@ -164,7 +164,7 @@ CGI_LOCAL is set to []
func TestMatches(t *testing.T) {
var ok bool
var prefixStr, suffixStr string
// [request, pattern, expected success:0/expected error:1, prefix, suffix]
// [request, pattern, expected success:1/expected error:0, prefix, suffix]
list := [][]string{
{"/foo/bar/baz", "/foo", "1", "/foo", "/bar/baz"},
{"/foo/bar/baz", "/foo/*/baz", "1", "/foo/bar/baz", ""},
Expand All @@ -173,15 +173,34 @@ func TestMatches(t *testing.T) {
}

for _, rec := range list {
ok, prefixStr, suffixStr = match(rec[0], rec[1])
ok, prefixStr, suffixStr = match(rec[0], []string{rec[1]})
if ok {
if rec[2] != "1" || rec[3] != prefixStr || rec[4] != suffixStr {
if rec[2] == "0" || rec[3] != prefixStr || rec[4] != suffixStr {
t.Fatalf("expected mismatch for \"%s\" and \"%s\"", rec[0], rec[1])
}
} else {
if rec[2] != "0" {
if rec[2] == "1" {
t.Fatalf("expected match for \"%s\" and \"%s\"", rec[0], rec[1])
}
}
}
}

func TestExceptions(t *testing.T) {
// [request, except pattern, expected success:1/expected error:0]
list := [][]string{
{"/foo/bar/baz.png", "/*/*/*.png", "1"},
{"/foo/bar/baz.png", "/foo/*/baz*", "1"},
{"/foo/bar/baz.png", "/foo/bar/baz.jpg", "0"},
{"/foo/bar/baz.png", "foo/bar", "0"},
}

for _, rec := range list {
ok := excluded(rec[0], []string{rec[1]})
if ok && rec[2] == "0" {
t.Fatalf("unexpected exception for \"%s\" and \"%s\"", rec[0], rec[1])
} else if !ok && rec[2] == "1" {
t.Fatalf("expected exception for \"%s\" and \"%s\"", rec[0], rec[1])
}
}
}
9 changes: 6 additions & 3 deletions doc/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,12 @@ With the advanced syntax, the `exec` subdirective must appear exactly once. The
times.

The `except` subdirective uses the same pattern matching logic that is used
with the `match` subdirective. Any request that matches a `match` pattern is
then checked with the patterns in `except`, if any. If any matches are made
with the `except` pattern, the request is rejected.
with the `match` subdirective except that the request must match a rule fully;
no request path prefix matching is performed. Any request that matches a
`match` pattern is then checked with the patterns in `except`, if any. If any
matches are made with the `except` pattern, the request is rejected and passed
along to subsequent handlers. This is a convenient way to have static file
resources served properly rather than being confused as CGI applications.

The `empty_env` subdirective is used to pass one or more empty environment
variables. Some CGI scripts may expect the server to pass certain empty
Expand Down

0 comments on commit 72bd95b

Please sign in to comment.