transfer.sh/vendor/github.com/PuerkitoBio/ghost/ghostest/main.go
Remco cb6e5cb0c7 Major rewrite
* use dep for vendoring
* lets encrypt
* moved web to transfer.sh-web repo
* single command install
* added first tests
2017-03-22 18:09:21 +01:00

169 lines
5 KiB
Go

// Ghostest is an interactive end-to-end Web site application to test
// the ghost packages. It serves the following URLs, with the specified
// features (handlers):
//
// / : panic;log;gzip;static; -> serve file index.html
// /public/styles.css : panic;log;gzip;StripPrefix;FileServer; -> serve directory public/
// /public/script.js : panic;log;gzip;StripPrefix;FileServer; -> serve directory public/
// /public/logo.pn : panic;log;gzip;StripPrefix;FileServer; -> serve directory public/
// /session : panic;log;gzip;session;context;Custom; -> serve dynamic Go template
// /session/auth : panic;log;gzip;session;context;basicAuth;Custom; -> serve dynamic template
// /panic : panic;log;gzip;Custom; -> panics
// /context : panic;log;gzip;context;Custom1;Custom2; -> serve dynamic Amber template
package main
import (
"log"
"net/http"
"time"
"github.com/PuerkitoBio/ghost/handlers"
"github.com/PuerkitoBio/ghost/templates"
_ "github.com/PuerkitoBio/ghost/templates/amber"
_ "github.com/PuerkitoBio/ghost/templates/gotpl"
"github.com/bmizerany/pat"
)
const (
sessionPageTitle = "Session Page"
sessionPageAuthTitle = "Authenticated Session Page"
sessionPageKey = "txt"
contextPageKey = "time"
sessionExpiration = 10 // Session expires after 10 seconds
)
var (
// Create the common session store and secret
memStore = handlers.NewMemoryStore(1)
secret = "testimony of the ancients"
)
// The struct used to pass data to the session template.
type sessionPageInfo struct {
SessionID string
Title string
Text string
}
// Authenticate the Basic Auth credentials.
func authenticate(u, p string) (interface{}, bool) {
if u == "user" && p == "pwd" {
return u + p, true
}
return nil, false
}
// Handle the session page requests.
func sessionPageRenderer(w handlers.GhostWriter, r *http.Request) {
var (
txt interface{}
data sessionPageInfo
title string
)
ssn := w.Session()
if r.Method == "GET" {
txt = ssn.Data[sessionPageKey]
} else {
txt = r.FormValue(sessionPageKey)
ssn.Data[sessionPageKey] = txt
}
if r.URL.Path == "/session/auth" {
title = sessionPageAuthTitle
} else {
title = sessionPageTitle
}
if txt != nil {
data = sessionPageInfo{ssn.ID(), title, txt.(string)}
} else {
data = sessionPageInfo{ssn.ID(), title, "[nil]"}
}
err := templates.Render("templates/session.tmpl", w, data)
if err != nil {
panic(err)
}
}
// Prepare the context value for the chained handlers context page.
func setContext(w handlers.GhostWriter, r *http.Request) {
w.Context()[contextPageKey] = time.Now().String()
}
// Retrieve the context value and render the chained handlers context page.
func renderContextPage(w handlers.GhostWriter, r *http.Request) {
err := templates.Render("templates/amber/context.amber",
w, &struct{ Val string }{w.Context()[contextPageKey].(string)})
if err != nil {
panic(err)
}
}
// Prepare the web server and kick it off.
func main() {
// Blank the default logger's prefixes
log.SetFlags(0)
// Compile the dynamic templates (native Go templates and Amber
// templates are both registered via the for-side-effects-only imports)
err := templates.CompileDir("./templates/")
if err != nil {
panic(err)
}
// Set the simple routes for static files
mux := pat.New()
mux.Get("/", handlers.StaticFileHandler("./index.html"))
mux.Get("/public/", http.StripPrefix("/public/", http.FileServer(http.Dir("./public/"))))
// Set the more complex routes for session handling and dynamic page (same
// handler is used for both GET and POST).
ssnOpts := handlers.NewSessionOptions(memStore, secret)
ssnOpts.CookieTemplate.MaxAge = sessionExpiration
hSsn := handlers.SessionHandler(
handlers.ContextHandlerFunc(
handlers.GhostHandlerFunc(sessionPageRenderer),
1),
ssnOpts)
mux.Get("/session", hSsn)
mux.Post("/session", hSsn)
hAuthSsn := handlers.BasicAuthHandler(hSsn, authenticate, "")
mux.Get("/session/auth", hAuthSsn)
mux.Post("/session/auth", hAuthSsn)
// Set the handler for the chained context route
mux.Get("/context", handlers.ContextHandler(handlers.ChainHandlerFuncs(
handlers.GhostHandlerFunc(setContext),
handlers.GhostHandlerFunc(renderContextPage)),
1))
// Set the panic route, which simply panics
mux.Get("/panic", http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
panic("explicit panic")
}))
// Combine the top level handlers, that wrap around the muxer.
// Panic is the outermost, so that any panic is caught and responded to with a code 500.
// Log is next, so that every request is logged along with the URL, status code and response time.
// GZIP is then applied, so that content is compressed.
// Finally, the muxer finds the specific handler that applies to the route.
h := handlers.FaviconHandler(
handlers.PanicHandler(
handlers.LogHandler(
handlers.GZIPHandler(
mux,
nil),
handlers.NewLogOptions(nil, handlers.Ltiny)),
nil),
"./public/favicon.ico",
48*time.Hour)
// Assign the combined handler to the server.
http.Handle("/", h)
// Start it up.
if err := http.ListenAndServe(":9000", nil); err != nil {
panic(err)
}
}