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