Commit 6bac558c authored by Mike Pastore's avatar Mike Pastore Committed by Matt Holt

Add root option to fastcgi directive (#1337)

parent 8464020f
...@@ -23,7 +23,6 @@ type Handler struct { ...@@ -23,7 +23,6 @@ type Handler struct {
Next httpserver.Handler Next httpserver.Handler
Rules []Rule Rules []Rule
Root string Root string
AbsRoot string // same as root, but absolute path
FileSys http.FileSystem FileSys http.FileSystem
// These are sent to CGI scripts in env variables // These are sent to CGI scripts in env variables
...@@ -184,7 +183,7 @@ func (h Handler) buildEnv(r *http.Request, rule Rule, fpath string) (map[string] ...@@ -184,7 +183,7 @@ func (h Handler) buildEnv(r *http.Request, rule Rule, fpath string) (map[string]
var env map[string]string var env map[string]string
// Get absolute path of requested resource // Get absolute path of requested resource
absPath := filepath.Join(h.AbsRoot, fpath) absPath := filepath.Join(rule.Root, fpath)
// Separate remote IP and port; more lenient than net.SplitHostPort // Separate remote IP and port; more lenient than net.SplitHostPort
var ip, port string var ip, port string
...@@ -244,7 +243,7 @@ func (h Handler) buildEnv(r *http.Request, rule Rule, fpath string) (map[string] ...@@ -244,7 +243,7 @@ func (h Handler) buildEnv(r *http.Request, rule Rule, fpath string) (map[string]
"SERVER_SOFTWARE": h.SoftwareName + "/" + h.SoftwareVersion, "SERVER_SOFTWARE": h.SoftwareName + "/" + h.SoftwareVersion,
// Other variables // Other variables
"DOCUMENT_ROOT": h.AbsRoot, "DOCUMENT_ROOT": rule.Root,
"DOCUMENT_URI": docURI, "DOCUMENT_URI": docURI,
"HTTP_HOST": r.Host, // added here, since not always part of headers "HTTP_HOST": r.Host, // added here, since not always part of headers
"REQUEST_URI": reqURI, "REQUEST_URI": reqURI,
...@@ -256,7 +255,7 @@ func (h Handler) buildEnv(r *http.Request, rule Rule, fpath string) (map[string] ...@@ -256,7 +255,7 @@ func (h Handler) buildEnv(r *http.Request, rule Rule, fpath string) (map[string]
// should only exist if PATH_INFO is defined. // should only exist if PATH_INFO is defined.
// Info: https://www.ietf.org/rfc/rfc3875 Page 14 // Info: https://www.ietf.org/rfc/rfc3875 Page 14
if env["PATH_INFO"] != "" { if env["PATH_INFO"] != "" {
env["PATH_TRANSLATED"] = filepath.Join(h.AbsRoot, pathInfo) // Info: http://www.oreilly.com/openbook/cgi/ch02_04.html env["PATH_TRANSLATED"] = filepath.Join(rule.Root, pathInfo) // Info: http://www.oreilly.com/openbook/cgi/ch02_04.html
} }
// Some web apps rely on knowing HTTPS or not // Some web apps rely on knowing HTTPS or not
...@@ -295,6 +294,10 @@ type Rule struct { ...@@ -295,6 +294,10 @@ type Rule struct {
// Always process files with this extension with fastcgi. // Always process files with this extension with fastcgi.
Ext string Ext string
// Use this directory as the fastcgi root directory. Defaults to the root
// directory of the parent virtual host.
Root string
// The path in the URL will be split into two, with the first piece ending // The path in the URL will be split into two, with the first piece ending
// with the value of SplitPath. The first piece will be assumed as the // with the value of SplitPath. The first piece will be assumed as the
// actual resource (CGI script) name, and the second piece will be set to // actual resource (CGI script) name, and the second piece will be set to
......
...@@ -22,10 +22,6 @@ func init() { ...@@ -22,10 +22,6 @@ func init() {
// setup configures a new FastCGI middleware instance. // setup configures a new FastCGI middleware instance.
func setup(c *caddy.Controller) error { func setup(c *caddy.Controller) error {
cfg := httpserver.GetConfig(c) cfg := httpserver.GetConfig(c)
absRoot, err := filepath.Abs(cfg.Root)
if err != nil {
return err
}
rules, err := fastcgiParse(c) rules, err := fastcgiParse(c)
if err != nil { if err != nil {
...@@ -37,7 +33,6 @@ func setup(c *caddy.Controller) error { ...@@ -37,7 +33,6 @@ func setup(c *caddy.Controller) error {
Next: next, Next: next,
Rules: rules, Rules: rules,
Root: cfg.Root, Root: cfg.Root,
AbsRoot: absRoot,
FileSys: http.Dir(cfg.Root), FileSys: http.Dir(cfg.Root),
SoftwareName: caddy.AppName, SoftwareName: caddy.AppName,
SoftwareVersion: caddy.AppVersion, SoftwareVersion: caddy.AppVersion,
...@@ -52,6 +47,12 @@ func setup(c *caddy.Controller) error { ...@@ -52,6 +47,12 @@ func setup(c *caddy.Controller) error {
func fastcgiParse(c *caddy.Controller) ([]Rule, error) { func fastcgiParse(c *caddy.Controller) ([]Rule, error) {
var rules []Rule var rules []Rule
cfg := httpserver.GetConfig(c)
absRoot, err := filepath.Abs(cfg.Root)
if err != nil {
return nil, err
}
for c.Next() { for c.Next() {
args := c.RemainingArgs() args := c.RemainingArgs()
...@@ -59,7 +60,12 @@ func fastcgiParse(c *caddy.Controller) ([]Rule, error) { ...@@ -59,7 +60,12 @@ func fastcgiParse(c *caddy.Controller) ([]Rule, error) {
return rules, c.ArgErr() return rules, c.ArgErr()
} }
rule := Rule{Path: args[0], ReadTimeout: 60 * time.Second, SendTimeout: 60 * time.Second} rule := Rule{
Root: absRoot,
Path: args[0],
ReadTimeout: 60 * time.Second,
SendTimeout: 60 * time.Second,
}
upstreams := []string{args[1]} upstreams := []string{args[1]}
if len(args) == 3 { if len(args) == 3 {
...@@ -76,6 +82,12 @@ func fastcgiParse(c *caddy.Controller) ([]Rule, error) { ...@@ -76,6 +82,12 @@ func fastcgiParse(c *caddy.Controller) ([]Rule, error) {
for c.NextBlock() { for c.NextBlock() {
switch c.Val() { switch c.Val() {
case "root":
if !c.NextArg() {
return rules, c.ArgErr()
}
rule.Root = c.Val()
case "ext": case "ext":
if !c.NextArg() { if !c.NextArg() {
return rules, c.ArgErr() return rules, c.ArgErr()
......
...@@ -2,6 +2,7 @@ package fastcgi ...@@ -2,6 +2,7 @@ package fastcgi
import ( import (
"fmt" "fmt"
"os"
"reflect" "reflect"
"testing" "testing"
"time" "time"
...@@ -61,6 +62,11 @@ func (p *persistentDialer) Equals(q *persistentDialer) bool { ...@@ -61,6 +62,11 @@ func (p *persistentDialer) Equals(q *persistentDialer) bool {
} }
func TestFastcgiParse(t *testing.T) { func TestFastcgiParse(t *testing.T) {
rootPath, err := os.Getwd()
if err != nil {
t.Errorf("Can't determine current working directory; got '%v'", err)
}
defaultAddress := "127.0.0.1:9001" defaultAddress := "127.0.0.1:9001"
network, address := parseAddress(defaultAddress) network, address := parseAddress(defaultAddress)
t.Logf("Address '%v' was parsed to network '%v' and address '%v'", defaultAddress, network, address) t.Logf("Address '%v' was parsed to network '%v' and address '%v'", defaultAddress, network, address)
...@@ -73,6 +79,21 @@ func TestFastcgiParse(t *testing.T) { ...@@ -73,6 +79,21 @@ func TestFastcgiParse(t *testing.T) {
{`fastcgi /blog 127.0.0.1:9000 php`, {`fastcgi /blog 127.0.0.1:9000 php`,
false, []Rule{{ false, []Rule{{
Root: rootPath,
Path: "/blog",
Address: "127.0.0.1:9000",
Ext: ".php",
SplitPath: ".php",
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: "tcp", address: "127.0.0.1:9000", timeout: 60 * time.Second}}},
IndexFiles: []string{"index.php"},
ReadTimeout: 60 * time.Second,
SendTimeout: 60 * time.Second,
}}},
{`fastcgi /blog 127.0.0.1:9000 php {
root /tmp
}`,
false, []Rule{{
Root: "/tmp",
Path: "/blog", Path: "/blog",
Address: "127.0.0.1:9000", Address: "127.0.0.1:9000",
Ext: ".php", Ext: ".php",
...@@ -86,6 +107,7 @@ func TestFastcgiParse(t *testing.T) { ...@@ -86,6 +107,7 @@ func TestFastcgiParse(t *testing.T) {
upstream 127.0.0.1:9001 upstream 127.0.0.1:9001
}`, }`,
false, []Rule{{ false, []Rule{{
Root: rootPath,
Path: "/blog", Path: "/blog",
Address: "127.0.0.1:9000,127.0.0.1:9001", Address: "127.0.0.1:9000,127.0.0.1:9001",
Ext: ".php", Ext: ".php",
...@@ -99,6 +121,7 @@ func TestFastcgiParse(t *testing.T) { ...@@ -99,6 +121,7 @@ func TestFastcgiParse(t *testing.T) {
upstream 127.0.0.1:9001 upstream 127.0.0.1:9001
}`, }`,
false, []Rule{{ false, []Rule{{
Root: rootPath,
Path: "/blog", Path: "/blog",
Address: "127.0.0.1:9000,127.0.0.1:9001", Address: "127.0.0.1:9000,127.0.0.1:9001",
Ext: "", Ext: "",
...@@ -112,6 +135,7 @@ func TestFastcgiParse(t *testing.T) { ...@@ -112,6 +135,7 @@ func TestFastcgiParse(t *testing.T) {
split .html split .html
}`, }`,
false, []Rule{{ false, []Rule{{
Root: rootPath,
Path: "/", Path: "/",
Address: defaultAddress, Address: defaultAddress,
Ext: "", Ext: "",
...@@ -126,6 +150,7 @@ func TestFastcgiParse(t *testing.T) { ...@@ -126,6 +150,7 @@ func TestFastcgiParse(t *testing.T) {
except /admin /user except /admin /user
}`, }`,
false, []Rule{{ false, []Rule{{
Root: rootPath,
Path: "/", Path: "/",
Address: "127.0.0.1:9001", Address: "127.0.0.1:9001",
Ext: "", Ext: "",
...@@ -140,6 +165,7 @@ func TestFastcgiParse(t *testing.T) { ...@@ -140,6 +165,7 @@ func TestFastcgiParse(t *testing.T) {
pool 0 pool 0
}`, }`,
false, []Rule{{ false, []Rule{{
Root: rootPath,
Path: "/", Path: "/",
Address: defaultAddress, Address: defaultAddress,
Ext: "", Ext: "",
...@@ -154,6 +180,7 @@ func TestFastcgiParse(t *testing.T) { ...@@ -154,6 +180,7 @@ func TestFastcgiParse(t *testing.T) {
pool 5 pool 5
}`, }`,
false, []Rule{{ false, []Rule{{
Root: rootPath,
Path: "/", Path: "/",
Address: "127.0.0.1:8080,127.0.0.1:9000", Address: "127.0.0.1:8080,127.0.0.1:9000",
Ext: "", Ext: "",
...@@ -167,6 +194,7 @@ func TestFastcgiParse(t *testing.T) { ...@@ -167,6 +194,7 @@ func TestFastcgiParse(t *testing.T) {
split .php split .php
}`, }`,
false, []Rule{{ false, []Rule{{
Root: rootPath,
Path: "/", Path: "/",
Address: defaultAddress, Address: defaultAddress,
Ext: "", Ext: "",
...@@ -180,6 +208,7 @@ func TestFastcgiParse(t *testing.T) { ...@@ -180,6 +208,7 @@ func TestFastcgiParse(t *testing.T) {
connect_timeout 5s connect_timeout 5s
}`, }`,
false, []Rule{{ false, []Rule{{
Root: rootPath,
Path: "/", Path: "/",
Address: defaultAddress, Address: defaultAddress,
Ext: "", Ext: "",
...@@ -198,6 +227,7 @@ func TestFastcgiParse(t *testing.T) { ...@@ -198,6 +227,7 @@ func TestFastcgiParse(t *testing.T) {
read_timeout 5s read_timeout 5s
}`, }`,
false, []Rule{{ false, []Rule{{
Root: rootPath,
Path: "/", Path: "/",
Address: defaultAddress, Address: defaultAddress,
Ext: "", Ext: "",
...@@ -216,6 +246,7 @@ func TestFastcgiParse(t *testing.T) { ...@@ -216,6 +246,7 @@ func TestFastcgiParse(t *testing.T) {
send_timeout 5s send_timeout 5s
}`, }`,
false, []Rule{{ false, []Rule{{
Root: rootPath,
Path: "/", Path: "/",
Address: defaultAddress, Address: defaultAddress,
Ext: "", Ext: "",
...@@ -250,6 +281,11 @@ func TestFastcgiParse(t *testing.T) { ...@@ -250,6 +281,11 @@ func TestFastcgiParse(t *testing.T) {
} }
for j, actualFastcgiConfig := range actualFastcgiConfigs { for j, actualFastcgiConfig := range actualFastcgiConfigs {
if actualFastcgiConfig.Root != test.expectedFastcgiConfig[j].Root {
t.Errorf("Test %d expected %dth FastCGI Root to be %s , but got %s",
i, j, test.expectedFastcgiConfig[j].Root, actualFastcgiConfig.Root)
}
if actualFastcgiConfig.Path != test.expectedFastcgiConfig[j].Path { if actualFastcgiConfig.Path != test.expectedFastcgiConfig[j].Path {
t.Errorf("Test %d expected %dth FastCGI Path to be %s , but got %s", t.Errorf("Test %d expected %dth FastCGI Path to be %s , but got %s",
i, j, test.expectedFastcgiConfig[j].Path, actualFastcgiConfig.Path) i, j, test.expectedFastcgiConfig[j].Path, actualFastcgiConfig.Path)
......
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