Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
caddy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Łukasz Nowak
caddy
Commits
47717fee
Commit
47717fee
authored
May 05, 2015
by
Matthew Holt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Expanded index file support to other middlewares (fixes #27)
parent
a9064a78
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
117 additions
and
52 deletions
+117
-52
config/setup/fastcgi.go
config/setup/fastcgi.go
+9
-5
config/setup/markdown.go
config/setup/markdown.go
+6
-2
config/setup/templates.go
config/setup/templates.go
+10
-3
middleware/fastcgi/fastcgi.go
middleware/fastcgi/fastcgi.go
+33
-31
middleware/markdown/markdown.go
middleware/markdown/markdown.go
+18
-4
middleware/middleware.go
middleware/middleware.go
+25
-1
middleware/templates/templates.go
middleware/templates/templates.go
+16
-6
No files found.
config/setup/fastcgi.go
View file @
47717fee
...
...
@@ -2,6 +2,7 @@ package setup
import
(
"errors"
"net/http"
"path/filepath"
"github.com/mholt/caddy/middleware"
...
...
@@ -10,7 +11,7 @@ import (
// FastCGI configures a new FastCGI middleware instance.
func
FastCGI
(
c
*
Controller
)
(
middleware
.
Middleware
,
error
)
{
r
oot
,
err
:=
filepath
.
Abs
(
c
.
Root
)
absR
oot
,
err
:=
filepath
.
Abs
(
c
.
Root
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -24,7 +25,9 @@ func FastCGI(c *Controller) (middleware.Middleware, error) {
return
fastcgi
.
Handler
{
Next
:
next
,
Rules
:
rules
,
Root
:
root
,
Root
:
c
.
Root
,
AbsRoot
:
absRoot
,
FileSys
:
http
.
Dir
(
c
.
Root
),
SoftwareName
:
c
.
AppName
,
SoftwareVersion
:
c
.
AppVersion
,
ServerName
:
c
.
Host
,
...
...
@@ -72,10 +75,11 @@ func fastcgiParse(c *Controller) ([]fastcgi.Rule, error) {
}
rule
.
SplitPath
=
c
.
Val
()
case
"index"
:
if
!
c
.
NextArg
()
{
args
:=
c
.
RemainingArgs
()
if
len
(
args
)
==
0
{
return
rules
,
c
.
ArgErr
()
}
rule
.
IndexFile
=
c
.
Val
()
rule
.
IndexFile
s
=
args
case
"env"
:
envArgs
:=
c
.
RemainingArgs
()
if
len
(
envArgs
)
<
2
{
...
...
@@ -98,7 +102,7 @@ func fastcgiPreset(name string, rule *fastcgi.Rule) error {
case
"php"
:
rule
.
Ext
=
".php"
rule
.
SplitPath
=
".php"
rule
.
IndexFile
=
"index.php"
rule
.
IndexFile
s
=
[]
string
{
"index.php"
}
default
:
return
errors
.
New
(
name
+
" is not a valid preset name"
)
}
...
...
config/setup/markdown.go
View file @
47717fee
package
setup
import
(
"net/http"
"github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware/markdown"
"github.com/russross/blackfriday"
...
...
@@ -14,8 +16,10 @@ func Markdown(c *Controller) (middleware.Middleware, error) {
}
md
:=
markdown
.
Markdown
{
Root
:
c
.
Root
,
Configs
:
mdconfigs
,
Root
:
c
.
Root
,
FileSys
:
http
.
Dir
(
c
.
Root
),
Configs
:
mdconfigs
,
IndexFiles
:
[]
string
{
"index.md"
},
}
return
func
(
next
middleware
.
Handler
)
middleware
.
Handler
{
...
...
config/setup/templates.go
View file @
47717fee
package
setup
import
(
"net/http"
"github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware/templates"
)
...
...
@@ -13,8 +15,9 @@ func Templates(c *Controller) (middleware.Middleware, error) {
}
tmpls
:=
templates
.
Templates
{
Root
:
c
.
Root
,
Rules
:
rules
,
Rules
:
rules
,
Root
:
c
.
Root
,
FileSys
:
http
.
Dir
(
c
.
Root
),
}
return
func
(
next
middleware
.
Handler
)
middleware
.
Handler
{
...
...
@@ -43,6 +46,10 @@ func templatesParse(c *Controller) ([]templates.Rule, error) {
rule
.
Extensions
=
defaultExtensions
}
for
_
,
ext
:=
range
rule
.
Extensions
{
rule
.
IndexFiles
=
append
(
rule
.
IndexFiles
,
"index"
+
ext
)
}
rules
=
append
(
rules
,
rule
)
}
...
...
@@ -51,4 +58,4 @@ func templatesParse(c *Controller) ([]templates.Rule, error) {
const
defaultPath
=
"/"
var
defaultExtensions
=
[]
string
{
".html"
,
".htm"
,
".txt"
}
var
defaultExtensions
=
[]
string
{
".html"
,
".htm"
,
".t
mpl"
,
".tpl"
,
".t
xt"
}
middleware/fastcgi/fastcgi.go
View file @
47717fee
...
...
@@ -16,9 +16,11 @@ import (
// Handler is a middleware type that can handle requests as a FastCGI client.
type
Handler
struct
{
Next
middleware
.
Handler
Root
string
// must be absolute path to site root
Rules
[]
Rule
Next
middleware
.
Handler
Rules
[]
Rule
Root
string
AbsRoot
string
// same as root, but absolute path
FileSys
http
.
FileSystem
// These are sent to CGI scripts in env variables
SoftwareName
string
...
...
@@ -30,26 +32,27 @@ type Handler struct {
// ServeHTTP satisfies the middleware.Handler interface.
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
)
{
continue
}
// In addition to matching the path, a request must meet some
// other criteria before being proxied as FastCGI. For example,
// we probably want to exclude static assets (CSS, JS, images...)
// but we also want to be flexible for the script we proxy to.
path
:=
r
.
URL
.
Path
fpath
:=
r
.
URL
.
Path
if
idx
,
ok
:=
middleware
.
IndexFile
(
h
.
FileSys
,
fpath
,
rule
.
IndexFiles
);
ok
{
fpath
=
idx
}
// These criteria work well in this order for PHP sites
if
middleware
.
Path
(
path
)
.
Matches
(
rule
.
Path
)
&&
(
path
[
len
(
path
)
-
1
]
==
'/'
||
strings
.
HasSuffix
(
path
,
rule
.
Ext
)
||
!
h
.
exists
(
path
))
{
if
path
[
len
(
path
)
-
1
]
==
'/'
&&
h
.
exists
(
path
+
rule
.
IndexFile
)
{
// If index file in specified folder exists, send request to it
path
+=
rule
.
IndexFile
}
if
fpath
[
len
(
fpath
)
-
1
]
==
'/'
||
strings
.
HasSuffix
(
fpath
,
rule
.
Ext
)
||
!
h
.
exists
(
fpath
)
{
// Create environment for CGI script
env
,
err
:=
h
.
buildEnv
(
r
,
rule
,
path
)
env
,
err
:=
h
.
buildEnv
(
r
,
rule
,
f
path
)
if
err
!=
nil
{
return
http
.
StatusInternalServerError
,
err
}
...
...
@@ -115,14 +118,12 @@ func (h Handler) exists(path string) bool {
return
false
}
func
(
h
Handler
)
buildEnv
(
r
*
http
.
Request
,
rule
Rule
,
path
string
)
(
map
[
string
]
string
,
error
)
{
// buildEnv returns a set of CGI environment variables for the request.
func
(
h
Handler
)
buildEnv
(
r
*
http
.
Request
,
rule
Rule
,
fpath
string
)
(
map
[
string
]
string
,
error
)
{
var
env
map
[
string
]
string
// Get absolute path of requested resource
absPath
,
err
:=
filepath
.
Abs
(
h
.
Root
+
path
)
if
err
!=
nil
{
return
env
,
err
}
absPath
:=
filepath
.
Join
(
h
.
AbsRoot
,
fpath
)
// Separate remote IP and port; more lenient than net.SplitHostPort
var
ip
,
port
string
...
...
@@ -134,19 +135,19 @@ func (h Handler) buildEnv(r *http.Request, rule Rule, path string) (map[string]s
}
// Split path in preparation for env variables
splitPos
:=
strings
.
Index
(
path
,
rule
.
SplitPath
)
splitPos
:=
strings
.
Index
(
f
path
,
rule
.
SplitPath
)
var
docURI
,
scriptName
,
scriptFilename
,
pathInfo
string
if
splitPos
==
-
1
{
// Request doesn't have the extension, so assume index file in root
docURI
=
"/"
+
rule
.
IndexFile
scriptName
=
"/"
+
rule
.
IndexFile
scriptFilename
=
h
.
Root
+
"/"
+
rule
.
IndexFile
pathInfo
=
path
docURI
=
"/"
+
rule
.
IndexFile
s
[
0
]
scriptName
=
"/"
+
rule
.
IndexFile
s
[
0
]
scriptFilename
=
filepath
.
Join
(
h
.
AbsRoot
,
rule
.
IndexFiles
[
0
])
pathInfo
=
f
path
}
else
{
// Request has the extension; path was split successfully
docURI
=
path
[
:
splitPos
+
len
(
rule
.
SplitPath
)]
pathInfo
=
path
[
splitPos
+
len
(
rule
.
SplitPath
)
:
]
scriptName
=
path
docURI
=
f
path
[
:
splitPos
+
len
(
rule
.
SplitPath
)]
pathInfo
=
f
path
[
splitPos
+
len
(
rule
.
SplitPath
)
:
]
scriptName
=
f
path
scriptFilename
=
absPath
}
...
...
@@ -160,7 +161,7 @@ func (h Handler) buildEnv(r *http.Request, rule Rule, path string) (map[string]s
"CONTENT_TYPE"
:
r
.
Header
.
Get
(
"Content-Type"
),
"GATEWAY_INTERFACE"
:
"CGI/1.1"
,
"PATH_INFO"
:
pathInfo
,
"PATH_TRANSLATED"
:
h
.
Root
+
"/"
+
pathInfo
,
// Source for path_translated
: http://www.oreilly.com/openbook/cgi/ch02_04.html
"PATH_TRANSLATED"
:
filepath
.
Join
(
h
.
AbsRoot
,
pathInfo
),
// Info
: http://www.oreilly.com/openbook/cgi/ch02_04.html
"QUERY_STRING"
:
r
.
URL
.
RawQuery
,
"REMOTE_ADDR"
:
ip
,
"REMOTE_HOST"
:
ip
,
// For speed, remote host lookups disabled
...
...
@@ -174,7 +175,7 @@ func (h Handler) buildEnv(r *http.Request, rule Rule, path string) (map[string]s
"SERVER_SOFTWARE"
:
h
.
SoftwareName
+
"/"
+
h
.
SoftwareVersion
,
// Other variables
"DOCUMENT_ROOT"
:
h
.
Root
,
"DOCUMENT_ROOT"
:
h
.
Abs
Root
,
"DOCUMENT_URI"
:
docURI
,
"HTTP_HOST"
:
r
.
Host
,
// added here, since not always part of headers
"REQUEST_URI"
:
r
.
URL
.
RequestURI
(),
...
...
@@ -214,8 +215,9 @@ type Rule struct {
// PATH_INFO for the CGI script to use.
SplitPath
string
// If the URL does not indicate a file, an index file with this name will be assumed.
IndexFile
string
// If the URL ends with '/' (which indicates a directory), these index
// files will be tried instead.
IndexFiles
[]
string
// Environment Variables
EnvVars
[][
2
]
string
...
...
middleware/markdown/markdown.go
View file @
47717fee
...
...
@@ -20,11 +20,17 @@ type Markdown struct {
// Server root
Root
string
// Jail the requests to site root with a mock file system
FileSys
http
.
FileSystem
// Next HTTP handler in the chain
Next
middleware
.
Handler
// The list of markdown configurations
Configs
[]
Config
// The list of index files to try
IndexFiles
[]
string
}
// Config stores markdown middleware configurations.
...
...
@@ -52,11 +58,14 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
continue
}
for
_
,
ext
:=
range
m
.
Extensions
{
if
strings
.
HasSuffix
(
r
.
URL
.
Path
,
ext
)
{
fpath
:=
md
.
Root
+
r
.
URL
.
Path
fpath
:=
r
.
URL
.
Path
if
idx
,
ok
:=
middleware
.
IndexFile
(
md
.
FileSys
,
fpath
,
md
.
IndexFiles
);
ok
{
fpath
=
idx
}
body
,
err
:=
ioutil
.
ReadFile
(
fpath
)
for
_
,
ext
:=
range
m
.
Extensions
{
if
strings
.
HasSuffix
(
fpath
,
ext
)
{
f
,
err
:=
md
.
FileSys
.
Open
(
fpath
)
if
err
!=
nil
{
if
os
.
IsPermission
(
err
)
{
return
http
.
StatusForbidden
,
err
...
...
@@ -64,6 +73,11 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
return
http
.
StatusNotFound
,
nil
}
body
,
err
:=
ioutil
.
ReadAll
(
f
)
if
err
!=
nil
{
return
http
.
StatusInternalServerError
,
err
}
content
:=
blackfriday
.
Markdown
(
body
,
m
.
Renderer
,
0
)
var
scripts
,
styles
string
...
...
middleware/middleware.go
View file @
47717fee
// Package middleware provides some types and functions common among middleware.
package
middleware
import
"net/http"
import
(
"net/http"
"path/filepath"
)
type
(
// Middleware is the middle layer which represents the traditional
...
...
@@ -47,3 +50,24 @@ type (
func
(
f
HandlerFunc
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
(
int
,
error
)
{
return
f
(
w
,
r
)
}
// IndexFile looks for a file in /root/fpath/indexFile for each string
// in indexFiles. If an index file is found, it returns the root-relative
// path to the file and true. If no index file is found, empty string
// and false is returned. fpath must end in a forward slash '/'
// otherwise no index files will be tried (directory paths must end
// in a forward slash according to HTTP).
func
IndexFile
(
root
http
.
FileSystem
,
fpath
string
,
indexFiles
[]
string
)
(
string
,
bool
)
{
if
fpath
[
len
(
fpath
)
-
1
]
!=
'/'
||
root
==
nil
{
return
""
,
false
}
for
_
,
indexFile
:=
range
indexFiles
{
fp
:=
filepath
.
Join
(
fpath
,
indexFile
)
f
,
err
:=
root
.
Open
(
fp
)
if
err
==
nil
{
f
.
Close
()
return
fp
,
true
}
}
return
""
,
false
}
middleware/templates/templates.go
View file @
47717fee
...
...
@@ -5,6 +5,7 @@ import (
"bytes"
"net/http"
"path"
"path/filepath"
"text/template"
"github.com/mholt/caddy/middleware"
...
...
@@ -17,15 +18,22 @@ func (t Templates) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
continue
}
reqExt
:=
path
.
Ext
(
r
.
URL
.
Path
)
// Check for index files
fpath
:=
r
.
URL
.
Path
if
idx
,
ok
:=
middleware
.
IndexFile
(
t
.
FileSys
,
fpath
,
rule
.
IndexFiles
);
ok
{
fpath
=
idx
}
// Check the extension
reqExt
:=
path
.
Ext
(
fpath
)
for
_
,
ext
:=
range
rule
.
Extensions
{
if
reqExt
==
ext
{
// Create execution context
ctx
:=
context
{
root
:
http
.
Dir
(
t
.
Root
)
,
req
:
r
,
URL
:
r
.
URL
}
ctx
:=
context
{
root
:
t
.
FileSys
,
req
:
r
,
URL
:
r
.
URL
}
// Build the template
tpl
,
err
:=
template
.
ParseFiles
(
t
.
Root
+
r
.
URL
.
Path
)
tpl
,
err
:=
template
.
ParseFiles
(
filepath
.
Join
(
t
.
Root
,
fpath
)
)
if
err
!=
nil
{
return
http
.
StatusInternalServerError
,
err
}
...
...
@@ -48,9 +56,10 @@ func (t Templates) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
// Templates is middleware to render templated files as the HTTP response.
type
Templates
struct
{
Next
middleware
.
Handler
Root
string
Rules
[]
Rule
Next
middleware
.
Handler
Rules
[]
Rule
Root
string
FileSys
http
.
FileSystem
}
// Rule represents a template rule. A template will only execute
...
...
@@ -59,4 +68,5 @@ type Templates struct {
type
Rule
struct
{
Path
string
Extensions
[]
string
IndexFiles
[]
string
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment