mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-23 22:27:38 -05:00
Merge pull request #687 from abiosoft/fastcgi-except
fastcgi: Add `except` to FastCGI. Minor refactor in proxy.
This commit is contained in:
commit
9e0b1b4216
8 changed files with 79 additions and 11 deletions
|
@ -86,6 +86,12 @@ func fastcgiParse(c *Controller) ([]fastcgi.Rule, error) {
|
|||
return rules, c.ArgErr()
|
||||
}
|
||||
rule.EnvVars = append(rule.EnvVars, [2]string{envArgs[0], envArgs[1]})
|
||||
case "except":
|
||||
ignoredPaths := c.RemainingArgs()
|
||||
if len(ignoredPaths) == 0 {
|
||||
return rules, c.ArgErr()
|
||||
}
|
||||
rule.IgnoredSubPaths = ignoredPaths
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,9 @@ package setup
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mholt/caddy/middleware/fastcgi"
|
||||
"testing"
|
||||
|
||||
"github.com/mholt/caddy/middleware/fastcgi"
|
||||
)
|
||||
|
||||
func TestFastCGI(t *testing.T) {
|
||||
|
@ -61,6 +62,18 @@ func TestFastcgiParse(t *testing.T) {
|
|||
SplitPath: ".html",
|
||||
IndexFiles: []string{},
|
||||
}}},
|
||||
{`fastcgi / 127.0.0.1:9001 {
|
||||
split .html
|
||||
except /admin /user
|
||||
}`,
|
||||
false, []fastcgi.Rule{{
|
||||
Path: "/",
|
||||
Address: "127.0.0.1:9001",
|
||||
Ext: "",
|
||||
SplitPath: ".html",
|
||||
IndexFiles: []string{},
|
||||
IgnoredSubPaths: []string{"/admin", "/user"},
|
||||
}}},
|
||||
}
|
||||
for i, test := range tests {
|
||||
c := NewTestController(test.inputFastcgiConfig)
|
||||
|
@ -101,6 +114,11 @@ func TestFastcgiParse(t *testing.T) {
|
|||
t.Errorf("Test %d expected %dth FastCGI IndexFiles to be %s , but got %s",
|
||||
i, j, test.expectedFastcgiConfig[j].IndexFiles, actualFastcgiConfig.IndexFiles)
|
||||
}
|
||||
|
||||
if fmt.Sprint(actualFastcgiConfig.IgnoredSubPaths) != fmt.Sprint(test.expectedFastcgiConfig[j].IgnoredSubPaths) {
|
||||
t.Errorf("Test %d expected %dth FastCGI IgnoredSubPaths to be %s , but got %s",
|
||||
i, j, test.expectedFastcgiConfig[j].IgnoredSubPaths, actualFastcgiConfig.IgnoredSubPaths)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -34,8 +35,8 @@ type Handler struct {
|
|||
func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||
for _, rule := range h.Rules {
|
||||
|
||||
// First requirement: Base path must match
|
||||
if !middleware.Path(r.URL.Path).Matches(rule.Path) {
|
||||
// First requirement: Base path must match and the path must be allowed.
|
||||
if !middleware.Path(r.URL.Path).Matches(rule.Path) || !rule.AllowedPath(r.URL.Path) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -287,6 +288,9 @@ type Rule struct {
|
|||
|
||||
// Environment Variables
|
||||
EnvVars [][2]string
|
||||
|
||||
// Ignored paths
|
||||
IgnoredSubPaths []string
|
||||
}
|
||||
|
||||
// canSplit checks if path can split into two based on rule.SplitPath.
|
||||
|
@ -303,6 +307,16 @@ func (r Rule) splitPos(path string) int {
|
|||
return strings.Index(strings.ToLower(path), strings.ToLower(r.SplitPath))
|
||||
}
|
||||
|
||||
// AllowedPath checks if requestPath is not an ignored path.
|
||||
func (r Rule) AllowedPath(requestPath string) bool {
|
||||
for _, ignoredSubPath := range r.IgnoredSubPaths {
|
||||
if middleware.Path(path.Clean(requestPath)).Matches(path.Join(r.Path, ignoredSubPath)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var (
|
||||
headerNameReplacer = strings.NewReplacer(" ", "_", "-", "_")
|
||||
// ErrIndexMissingSplit describes an index configuration error.
|
||||
|
|
|
@ -73,6 +73,36 @@ func TestRuleParseAddress(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRuleIgnoredPath(t *testing.T) {
|
||||
rule := &Rule{
|
||||
Path: "/fastcgi",
|
||||
IgnoredSubPaths: []string{"/download", "/static"},
|
||||
}
|
||||
tests := []struct {
|
||||
url string
|
||||
expected bool
|
||||
}{
|
||||
{"/fastcgi", true},
|
||||
{"/fastcgi/dl", true},
|
||||
{"/fastcgi/download", false},
|
||||
{"/fastcgi/download/static", false},
|
||||
{"/fastcgi/static", false},
|
||||
{"/fastcgi/static/download", false},
|
||||
{"/fastcgi/something/download", true},
|
||||
{"/fastcgi/something/static", true},
|
||||
{"/fastcgi//static", false},
|
||||
{"/fastcgi//static//download", false},
|
||||
{"/fastcgi//download", false},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
allowed := rule.AllowedPath(test.url)
|
||||
if test.expected != allowed {
|
||||
t.Errorf("Test %d: expected %v found %v", i, test.expected, allowed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildEnv(t *testing.T) {
|
||||
testBuildEnv := func(r *http.Request, rule Rule, fpath string, envExpected map[string]string) {
|
||||
var h Handler
|
||||
|
|
|
@ -27,7 +27,7 @@ type Upstream interface {
|
|||
// Selects an upstream host to be routed to.
|
||||
Select() *UpstreamHost
|
||||
// Checks if subpath is not an ignored path
|
||||
IsAllowedPath(string) bool
|
||||
AllowedPath(string) bool
|
||||
}
|
||||
|
||||
// UpstreamHostDownFunc can be used to customize how Down behaves.
|
||||
|
@ -75,7 +75,7 @@ var tryDuration = 60 * time.Second
|
|||
// ServeHTTP satisfies the middleware.Handler interface.
|
||||
func (p Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||
for _, upstream := range p.Upstreams {
|
||||
if middleware.Path(r.URL.Path).Matches(upstream.From()) && upstream.IsAllowedPath(r.URL.Path) {
|
||||
if middleware.Path(r.URL.Path).Matches(upstream.From()) && upstream.AllowedPath(r.URL.Path) {
|
||||
var replacer middleware.Replacer
|
||||
start := time.Now()
|
||||
requestHost := r.Host
|
||||
|
|
|
@ -254,7 +254,7 @@ func (u *fakeUpstream) Select() *UpstreamHost {
|
|||
return u.host
|
||||
}
|
||||
|
||||
func (u *fakeUpstream) IsAllowedPath(requestPath string) bool {
|
||||
func (u *fakeUpstream) AllowedPath(requestPath string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -287,7 +287,7 @@ func (u *fakeWsUpstream) Select() *UpstreamHost {
|
|||
}
|
||||
}
|
||||
|
||||
func (u *fakeWsUpstream) IsAllowedPath(requestPath string) bool {
|
||||
func (u *fakeWsUpstream) AllowedPath(requestPath string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -263,7 +263,7 @@ func (u *staticUpstream) Select() *UpstreamHost {
|
|||
return u.Policy.Select(pool)
|
||||
}
|
||||
|
||||
func (u *staticUpstream) IsAllowedPath(requestPath string) bool {
|
||||
func (u *staticUpstream) AllowedPath(requestPath string) bool {
|
||||
for _, ignoredSubPath := range u.IgnoredSubPaths {
|
||||
if middleware.Path(path.Clean(requestPath)).Matches(path.Join(u.From(), ignoredSubPath)) {
|
||||
return false
|
||||
|
|
|
@ -127,9 +127,9 @@ func TestAllowedPaths(t *testing.T) {
|
|||
}
|
||||
|
||||
for i, test := range tests {
|
||||
isAllowed := upstream.IsAllowedPath(test.url)
|
||||
if test.expected != isAllowed {
|
||||
t.Errorf("Test %d: expected %v found %v", i+1, test.expected, isAllowed)
|
||||
allowed := upstream.AllowedPath(test.url)
|
||||
if test.expected != allowed {
|
||||
t.Errorf("Test %d: expected %v found %v", i+1, test.expected, allowed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue