forked from electricdusk/rushlink
Extract error rendering
This commit is contained in:
parent
ddd674e88a
commit
372d7c0487
@ -2,7 +2,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>{{block "title" .}}{{end}}</title>{{block "head-append" .}}{{end}}
|
<title>{{block "title" .}}rushlink{{end}}</title>{{block "head-append" .}}{{end}}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{{block "body" .}}{{end}}
|
{{block "body" .}}{{end}}
|
8
assets/templates/html/error.html.tmpl
Normal file
8
assets/templates/html/error.html.tmpl
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{{define "title"}}
|
||||||
|
Error - rushlink
|
||||||
|
{{end}}
|
||||||
|
{{define "body"}}
|
||||||
|
<pre>
|
||||||
|
{{.Message}}
|
||||||
|
</pre>
|
||||||
|
{{end}}
|
1
assets/templates/txt/error.txt.tmpl
Normal file
1
assets/templates/txt/error.txt.tmpl
Normal file
@ -0,0 +1 @@
|
|||||||
|
{{.Message}}
|
@ -6,7 +6,6 @@ import (
|
|||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -81,28 +80,23 @@ func IndexGetHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func IndexPostHandler(w http.ResponseWriter, r *http.Request) {
|
func IndexPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if err := r.ParseMultipartForm(50 * 1000 * 1000); err != nil {
|
if err := r.ParseMultipartForm(50 * 1000 * 1000); err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
log.Printf("error: %v\n", err)
|
||||||
fmt.Fprintf(w, "Internal server error: %v\n", err)
|
RenderInternalServerError(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine what kind of post this is, currently only `shorten=...`
|
// Determine what kind of post this is, currently only `shorten=...`
|
||||||
if len(r.PostForm) == 0 {
|
if len(r.PostForm) == 0 {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
RenderError(w, r, http.StatusBadRequest, "empty body in POST request\n")
|
||||||
var buf []byte
|
|
||||||
r.Body.Read(buf)
|
|
||||||
io.WriteString(w, "empty body in POST request\n")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
shorten_values, prs := r.PostForm["shorten"]
|
shorten_values, prs := r.PostForm["shorten"]
|
||||||
if !prs {
|
if !prs {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
RenderError(w, r, http.StatusBadRequest, "no 'shorten' param given\n")
|
||||||
io.WriteString(w, "no 'shorten' param supplied\n")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(shorten_values) != 1 {
|
if len(shorten_values) != 1 {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
RenderError(w, r, http.StatusBadRequest, "only one 'shorten' param is allowed per request\n")
|
||||||
io.WriteString(w, "only one 'shorten' param is allowed per request\n")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,30 +124,26 @@ func pasteGetHandlerInner(w http.ResponseWriter, r *http.Request, noRedirect, sh
|
|||||||
storedPaste, err = getURL(tx, []byte(key))
|
storedPaste, err = getURL(tx, []byte(key))
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
log.Printf("error: %v\n", err)
|
log.Printf("error: %v\n", err)
|
||||||
fmt.Fprintf(w, "internal server error: %v\n", err)
|
RenderInternalServerError(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if storedPaste == nil {
|
if storedPaste == nil {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
RenderError(w, r, http.StatusNotFound, "url key not found in the database")
|
||||||
fmt.Fprintf(w, "url key not found in the database\n")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if showMeta {
|
if showMeta {
|
||||||
typeString, err := storedPaste.Type.String()
|
typeString, err := storedPaste.Type.String()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
log.Printf("error: %v\n", err)
|
log.Printf("error: %v\n", err)
|
||||||
fmt.Fprintf(w, "internal server error: %v\n", err)
|
RenderInternalServerError(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
stateString, err := storedPaste.State.String()
|
stateString, err := storedPaste.State.String()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
log.Printf("error: %v\n", err)
|
log.Printf("error: %v\n", err)
|
||||||
fmt.Fprintf(w, "internal server error: %v\n", err)
|
RenderInternalServerError(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
isOwner := "no"
|
isOwner := "no"
|
||||||
@ -162,6 +152,7 @@ func pasteGetHandlerInner(w http.ResponseWriter, r *http.Request, noRedirect, sh
|
|||||||
isOwner = "yes"
|
isOwner = "yes"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(dsprenkels) This should be put into a template
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
fmt.Fprintf(w, "key: %v\n", string(storedPaste.Key))
|
fmt.Fprintf(w, "key: %v\n", string(storedPaste.Key))
|
||||||
fmt.Fprintf(w, "type: %v\n", typeString)
|
fmt.Fprintf(w, "type: %v\n", typeString)
|
||||||
@ -177,21 +168,19 @@ func pasteGetHandlerInner(w http.ResponseWriter, r *http.Request, noRedirect, sh
|
|||||||
rawurl := string(storedPaste.Content)
|
rawurl := string(storedPaste.Content)
|
||||||
urlParse, err := url.Parse(rawurl)
|
urlParse, err := url.Parse(rawurl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
log.Printf("error: invalid URL ('%v') in database for key '%v': %v\n", rawurl, storedPaste.Key, err)
|
log.Printf("error: invalid URL ('%v') in database for key '%v': %v\n", rawurl, storedPaste.Key, err)
|
||||||
fmt.Fprintf(w, "internal server error: invalid url in database\n")
|
RenderInternalServerError(w, r, "invalid url in database")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.Redirect(w, r, urlParse.String(), http.StatusSeeOther)
|
http.Redirect(w, r, urlParse.String(), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
w.Write(storedPaste.Content)
|
w.Write(storedPaste.Content)
|
||||||
case StateDeleted:
|
case StateDeleted:
|
||||||
w.WriteHeader(http.StatusGone)
|
RenderError(w, r, http.StatusGone, "key has been deleted")
|
||||||
fmt.Fprintf(w, "key has been deleted\n")
|
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
log.Printf("error: invalid storedPaste.State (%v) for key '%v'\n", storedPaste.State, storedPaste.Key)
|
log.Printf("error: invalid storedPaste.State (%v) for key '%v'\n", storedPaste.State, storedPaste.Key)
|
||||||
fmt.Fprintf(w, "internal server error: invalid storedPaste.State (%v\n)", storedPaste.State)
|
msg := fmt.Sprintf("internal server error: invalid storedPaste.State (%v\n)", storedPaste.State)
|
||||||
|
RenderInternalServerError(w, r, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,18 +188,16 @@ func ShortenPostHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
rawurl := r.PostForm.Get("shorten")
|
rawurl := r.PostForm.Get("shorten")
|
||||||
userURL, err := url.ParseRequestURI(rawurl)
|
userURL, err := url.ParseRequestURI(rawurl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
msg := fmt.Sprintf("invalid url (%v): %v", err, rawurl)
|
||||||
fmt.Fprintf(w, "invalid url (%v): %v\n", err, rawurl)
|
RenderError(w, r, http.StatusBadRequest, msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if userURL.Scheme == "" {
|
if userURL.Scheme == "" {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
RenderError(w, r, http.StatusBadRequest, "invalid url (unspecified scheme)")
|
||||||
fmt.Fprintf(w, "invalid url (unspecified scheme)\n", rawurl)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if userURL.Host == "" {
|
if userURL.Host == "" {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
RenderError(w, r, http.StatusBadRequest, "invalid url (unspecified host)")
|
||||||
fmt.Fprintf(w, "invalid url (unspecified host)\n", rawurl)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,9 +216,8 @@ func ShortenPostHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
storedPaste = sp
|
storedPaste = sp
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
log.Printf("error: %v\n", err)
|
log.Printf("error: %v\n", err)
|
||||||
fmt.Fprintf(w, "internal server error: %v\n", err)
|
RenderInternalServerError(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,12 +225,13 @@ func ShortenPostHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "parsing url")
|
err = errors.Wrap(err, "parsing url")
|
||||||
log.Printf("error: %v\n", err)
|
log.Printf("error: %v\n", err)
|
||||||
fmt.Fprintf(w, "internal server error: %v\n", err)
|
RenderInternalServerError(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var base64OwnerToken = make([]byte, 24)
|
var base64OwnerToken = make([]byte, 24)
|
||||||
base64Encoder.Encode(base64OwnerToken, storedPaste.OwnerToken[:])
|
base64Encoder.Encode(base64OwnerToken, storedPaste.OwnerToken[:])
|
||||||
|
|
||||||
|
// TODO(dsprenkels) Put this into a template
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
fmt.Fprintf(w, "URL saved at %v\n", saveURL)
|
fmt.Fprintf(w, "URL saved at %v\n", saveURL)
|
||||||
isNotPrint := func(r rune) bool { return !unicode.IsPrint(r) }
|
isNotPrint := func(r rune) bool { return !unicode.IsPrint(r) }
|
||||||
|
@ -22,8 +22,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Plain text templates
|
// Plain text templates
|
||||||
var TextBaseTemplate *text.Template = text.Must(text.New("Empty").Parse(string(MustAsset("templates/base.txt.tmpl"))))
|
var TextBaseTemplate *text.Template = text.Must(text.New("").Parse(string(MustAsset("templates/txt/base.txt.tmpl"))))
|
||||||
var HTMLBaseTemplate *html.Template = html.Must(html.New("Empty").Parse(string(MustAsset("templates/base.html.tmpl"))))
|
var HTMLBaseTemplate *html.Template = html.Must(html.New("").Parse(string(MustAsset("templates/html/base.html.tmpl"))))
|
||||||
|
|
||||||
// Template collections
|
// Template collections
|
||||||
var TextTemplates = make(map[string]*text.Template, 0)
|
var TextTemplates = make(map[string]*text.Template, 0)
|
||||||
@ -37,19 +37,26 @@ var acceptHeaderWeight = regexp.MustCompile(`^\s*q=0(?:\.([0-9]{0,3}))|1(?:\.0{0
|
|||||||
// HTML templates
|
// HTML templates
|
||||||
func init() {
|
func init() {
|
||||||
for _, tmplPath := range AssetNames() {
|
for _, tmplPath := range AssetNames() {
|
||||||
if mustMatch("templates/*.txt.tmpl", tmplPath) {
|
if mustMatch("templates/txt/*.txt.tmpl", tmplPath) {
|
||||||
tmpl := text.Must(TextBaseTemplate.Parse(string(MustAsset(tmplPath))))
|
base := text.Must(TextBaseTemplate.Clone())
|
||||||
|
tmpl := text.Must(base.Parse(string(MustAsset(tmplPath))))
|
||||||
tmplName := strings.TrimSuffix(filepath.Base(tmplPath), ".txt.tmpl")
|
tmplName := strings.TrimSuffix(filepath.Base(tmplPath), ".txt.tmpl")
|
||||||
TextTemplates[tmplName] = tmpl
|
TextTemplates[tmplName] = tmpl
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if mustMatch("templates/*.html.tmpl", tmplPath) {
|
if mustMatch("templates/html/*.html.tmpl", tmplPath) {
|
||||||
tmpl := html.Must(HTMLBaseTemplate.Parse(string(MustAsset(tmplPath))))
|
base := html.Must(HTMLBaseTemplate.Clone())
|
||||||
|
tmpl := html.Must(base.Parse(string(MustAsset(tmplPath))))
|
||||||
tmplName := strings.TrimSuffix(filepath.Base(tmplPath), ".html.tmpl")
|
tmplName := strings.TrimSuffix(filepath.Base(tmplPath), ".html.tmpl")
|
||||||
HTMLTemplates[tmplName] = tmpl
|
HTMLTemplates[tmplName] = tmpl
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sanity check. Both maps should not be empty
|
||||||
|
if len(TextTemplates) == 0 || len(HTMLTemplates) == 0 {
|
||||||
|
panic("template loading failed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustMatch(pattern, name string) bool {
|
func mustMatch(pattern, name string) bool {
|
||||||
@ -99,6 +106,16 @@ func Render(w http.ResponseWriter, r *http.Request, tmplName string, data interf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RenderError(w http.ResponseWriter, r *http.Request, status int, msg string) {
|
||||||
|
w.WriteHeader(status)
|
||||||
|
Render(w, r, "error", struct{ Message string }{msg})
|
||||||
|
}
|
||||||
|
|
||||||
|
func RenderInternalServerError(w http.ResponseWriter, r *http.Request, err interface{}) {
|
||||||
|
msg := fmt.Sprintf("internal server error: %v", err)
|
||||||
|
RenderError(w, r, http.StatusInternalServerError, msg)
|
||||||
|
}
|
||||||
|
|
||||||
// Try to resolve the preferred content-type for the response to this request.
|
// Try to resolve the preferred content-type for the response to this request.
|
||||||
//
|
//
|
||||||
// This is done by reading from the `types` argument. If one of them matches
|
// This is done by reading from the `types` argument. If one of them matches
|
||||||
|
Loading…
Reference in New Issue
Block a user