mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-23 22:27:38 -05:00
Better search for config.
Handle LastModifiedHeader better. Handle HEAD/GET.
This commit is contained in:
parent
19a85d08c6
commit
dd4de698cf
1 changed files with 92 additions and 55 deletions
|
@ -8,6 +8,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mholt/caddy/middleware"
|
"github.com/mholt/caddy/middleware"
|
||||||
"github.com/russross/blackfriday"
|
"github.com/russross/blackfriday"
|
||||||
|
@ -65,75 +66,111 @@ type Config struct {
|
||||||
|
|
||||||
// ServeHTTP implements the http.Handler interface.
|
// ServeHTTP implements the http.Handler interface.
|
||||||
func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
|
func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
for _, cfg := range md.Configs {
|
var cfg *Config
|
||||||
if !middleware.Path(r.URL.Path).Matches(cfg.PathScope) {
|
for _, c := range md.Configs {
|
||||||
continue
|
if middleware.Path(r.URL.Path).Matches(c.PathScope) { // not negated
|
||||||
|
cfg = c
|
||||||
|
break // or goto
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cfg == nil {
|
||||||
|
return md.Next.ServeHTTP(w, r) // exit early
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only deal with HEAD/GET
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodGet, http.MethodHead:
|
||||||
|
default:
|
||||||
|
return http.StatusMethodNotAllowed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var dirents []os.FileInfo
|
||||||
|
var lastModTime time.Time
|
||||||
|
fpath := r.URL.Path
|
||||||
|
if idx, ok := middleware.IndexFile(md.FileSys, fpath, md.IndexFiles); ok {
|
||||||
|
// We're serving a directory index file, which may be a markdown
|
||||||
|
// file with a template. Let's grab a list of files this directory
|
||||||
|
// URL points to, and pass that in to any possible template invocations,
|
||||||
|
// so that templates can customize the look and feel of a directory.
|
||||||
|
fdp, err := md.FileSys.Open(fpath)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsPermission(err) {
|
||||||
|
return http.StatusForbidden, err
|
||||||
|
}
|
||||||
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var dirents []os.FileInfo
|
// Grab a possible set of directory entries. Note, we do not check
|
||||||
fpath := r.URL.Path
|
// for errors here (unreadable directory, for example). It may
|
||||||
if idx, ok := middleware.IndexFile(md.FileSys, fpath, md.IndexFiles); ok {
|
// still be useful to have a directory template file, without the
|
||||||
// We're serving a directory index file, which may be a markdown
|
// directory contents being present.
|
||||||
// file with a template. Let's grab a list of files this directory
|
dirents, _ = fdp.Readdir(-1)
|
||||||
// URL points to, and pass that in to any possible template invocations,
|
for _, d := range dirents {
|
||||||
// so that templates can customize the look and feel of a directory.
|
lastModTime = latest(lastModTime, d.ModTime())
|
||||||
|
|
||||||
fdp, err := md.FileSys.Open(fpath)
|
|
||||||
if err != nil {
|
|
||||||
return http.StatusInternalServerError, err
|
|
||||||
}
|
|
||||||
dirents, err = fdp.Readdir(-1)
|
|
||||||
if err != nil {
|
|
||||||
return http.StatusInternalServerError, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set path to found index file
|
|
||||||
fpath = idx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If supported extension, process it
|
// Set path to found index file
|
||||||
if _, ok := cfg.Extensions[path.Ext(fpath)]; ok {
|
fpath = idx
|
||||||
f, err := md.FileSys.Open(fpath)
|
}
|
||||||
if err != nil {
|
|
||||||
if os.IsPermission(err) {
|
|
||||||
return http.StatusForbidden, err
|
|
||||||
}
|
|
||||||
return http.StatusNotFound, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
fs, err := f.Stat()
|
// If supported extension, process it
|
||||||
if err != nil {
|
if _, ok := cfg.Extensions[path.Ext(fpath)]; ok {
|
||||||
return http.StatusNotFound, nil
|
f, err := md.FileSys.Open(fpath)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsPermission(err) {
|
||||||
|
return http.StatusForbidden, err
|
||||||
}
|
}
|
||||||
|
return http.StatusNotFound, nil
|
||||||
|
}
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(f)
|
fs, err := f.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusNotFound, nil
|
||||||
}
|
}
|
||||||
|
lastModTime = latest(lastModTime, fs.ModTime())
|
||||||
|
|
||||||
ctx := middleware.Context{
|
body, err := ioutil.ReadAll(f)
|
||||||
Root: md.FileSys,
|
if err != nil {
|
||||||
Req: r,
|
return http.StatusInternalServerError, err
|
||||||
URL: r.URL,
|
}
|
||||||
}
|
|
||||||
html, err := cfg.Markdown(fpath, body, dirents, ctx)
|
|
||||||
if err != nil {
|
|
||||||
return http.StatusInternalServerError, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(weingart): move template execution here, something like:
|
ctx := middleware.Context{
|
||||||
//
|
Root: md.FileSys,
|
||||||
// html, err = md.execTemplate(cfg, html, ctx)
|
Req: r,
|
||||||
// if err != nil {
|
URL: r.URL,
|
||||||
// return http.StatusInternalServerError, err
|
}
|
||||||
// }
|
html, err := cfg.Markdown(fpath, body, dirents, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusInternalServerError, err
|
||||||
|
}
|
||||||
|
|
||||||
middleware.SetLastModifiedHeader(w, fs.ModTime())
|
// TODO(weingart): move template execution here, something like:
|
||||||
|
//
|
||||||
|
// html, err = md.execTemplate(cfg, html, ctx)
|
||||||
|
// if err != nil {
|
||||||
|
// return http.StatusInternalServerError, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
middleware.SetLastModifiedHeader(w, lastModTime)
|
||||||
|
if r.Method == "GET" {
|
||||||
w.Write(html)
|
w.Write(html)
|
||||||
return http.StatusOK, nil
|
|
||||||
}
|
}
|
||||||
|
return http.StatusOK, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Didn't qualify to serve as markdown; pass-thru
|
// Didn't qualify to serve as markdown; pass-thru
|
||||||
return md.Next.ServeHTTP(w, r)
|
return md.Next.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// latest returns the latest time.Time
|
||||||
|
func latest(t ...time.Time) time.Time {
|
||||||
|
var last time.Time
|
||||||
|
|
||||||
|
for _, tt := range t {
|
||||||
|
if tt.After(last) {
|
||||||
|
last = tt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return last
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue