mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-11-04 03:27:23 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			125 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			125 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Package markdown is middleware to render markdown files as HTML
 | 
						|
// on-the-fly.
 | 
						|
package markdown
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"io/ioutil"
 | 
						|
	"net/http"
 | 
						|
	"os"
 | 
						|
	"path"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/mholt/caddy/middleware"
 | 
						|
	"github.com/russross/blackfriday"
 | 
						|
)
 | 
						|
 | 
						|
// Markdown implements a layer of middleware that serves
 | 
						|
// markdown as HTML.
 | 
						|
type Markdown struct {
 | 
						|
	// Server root
 | 
						|
	Root string
 | 
						|
 | 
						|
	// Next HTTP handler in the chain
 | 
						|
	Next middleware.Handler
 | 
						|
 | 
						|
	// The list of markdown configurations
 | 
						|
	Configs []Config
 | 
						|
}
 | 
						|
 | 
						|
// Config stores markdown middleware configurations.
 | 
						|
type Config struct {
 | 
						|
	// Markdown renderer
 | 
						|
	Renderer blackfriday.Renderer
 | 
						|
 | 
						|
	// Base path to match
 | 
						|
	PathScope string
 | 
						|
 | 
						|
	// List of extensions to consider as markdown files
 | 
						|
	Extensions []string
 | 
						|
 | 
						|
	// List of style sheets to load for each markdown file
 | 
						|
	Styles []string
 | 
						|
 | 
						|
	// List of JavaScript files to load for each markdown file
 | 
						|
	Scripts []string
 | 
						|
}
 | 
						|
 | 
						|
// ServeHTTP implements the http.Handler interface.
 | 
						|
func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
 | 
						|
	for _, m := range md.Configs {
 | 
						|
		if !middleware.Path(r.URL.Path).Matches(m.PathScope) {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		for _, ext := range m.Extensions {
 | 
						|
			if strings.HasSuffix(r.URL.Path, ext) {
 | 
						|
				fpath := md.Root + r.URL.Path
 | 
						|
 | 
						|
				body, err := ioutil.ReadFile(fpath)
 | 
						|
				if err != nil {
 | 
						|
					if os.IsPermission(err) {
 | 
						|
						return http.StatusForbidden, err
 | 
						|
					}
 | 
						|
					return http.StatusNotFound, nil
 | 
						|
				}
 | 
						|
 | 
						|
				content := blackfriday.Markdown(body, m.Renderer, 0)
 | 
						|
 | 
						|
				var scripts, styles string
 | 
						|
				for _, style := range m.Styles {
 | 
						|
					styles += strings.Replace(cssTemplate, "{{url}}", style, 1) + "\r\n"
 | 
						|
				}
 | 
						|
				for _, script := range m.Scripts {
 | 
						|
					scripts += strings.Replace(jsTemplate, "{{url}}", script, 1) + "\r\n"
 | 
						|
				}
 | 
						|
 | 
						|
				// Title is first line (length-limited), otherwise filename
 | 
						|
				title := path.Base(fpath)
 | 
						|
				newline := bytes.Index(body, []byte("\n"))
 | 
						|
				if newline > -1 {
 | 
						|
					firstline := body[:newline]
 | 
						|
					newTitle := strings.TrimSpace(string(firstline))
 | 
						|
					if len(newTitle) > 1 {
 | 
						|
						if len(newTitle) > 128 {
 | 
						|
							title = newTitle[:128]
 | 
						|
						} else {
 | 
						|
							title = newTitle
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				html := htmlTemplate
 | 
						|
				html = strings.Replace(html, "{{title}}", title, 1)
 | 
						|
				html = strings.Replace(html, "{{css}}", styles, 1)
 | 
						|
				html = strings.Replace(html, "{{js}}", scripts, 1)
 | 
						|
				html = strings.Replace(html, "{{body}}", string(content), 1)
 | 
						|
 | 
						|
				w.Write([]byte(html))
 | 
						|
 | 
						|
				return http.StatusOK, nil
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Didn't qualify to serve as markdown; pass-thru
 | 
						|
	return md.Next.ServeHTTP(w, r)
 | 
						|
}
 | 
						|
 | 
						|
const (
 | 
						|
	htmlTemplate = `<!DOCTYPE html>
 | 
						|
<html>
 | 
						|
	<head>
 | 
						|
		<title>{{title}}</title>
 | 
						|
		<meta charset="utf-8">
 | 
						|
		{{css}}
 | 
						|
		{{js}}
 | 
						|
	</head>
 | 
						|
	<body>
 | 
						|
		{{body}}
 | 
						|
	</body>
 | 
						|
</html>`
 | 
						|
	cssTemplate = `<link rel="stylesheet" href="{{url}}">`
 | 
						|
	jsTemplate  = `<script src="{{url}}"></script>`
 | 
						|
)
 |