mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-11-03 19:17:29 -05:00 
			
		
		
		
	Better search for config.
Handle LastModifiedHeader better. Handle HEAD/GET.
This commit is contained in:
		
							parent
							
								
									19a85d08c6
								
							
						
					
					
						commit
						dd4de698cf
					
				@ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user