Commit e7001e65 authored by Abiola Ibrahim's avatar Abiola Ibrahim

Add `except` to FastCGI. Minor refactor in proxy.

parent 4d9741dd
......@@ -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)
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment