mirror of
https://github.com/dutchcoders/transfer.sh.git
synced 2024-12-11 13:20:19 +01:00
cb6e5cb0c7
* use dep for vendoring * lets encrypt * moved web to transfer.sh-web repo * single command install * added first tests
169 lines
5 KiB
Go
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)
|
|
}
|
|
}
|