forked from electricdusk/rushlink
parent
41f4de43ac
commit
0bffde1dc1
@ -9,10 +9,10 @@ the command line.
|
|||||||
## USAGE
|
## USAGE
|
||||||
|
|
||||||
# Upload a file
|
# Upload a file
|
||||||
curl -F'file=@yourfile.png' <a href="//{{.Request.Host}}">https://{{.Request.Host}}</a>
|
curl -F'file=@yourfile.png' <a href="{{.Host}}">{{.Host}}</a>
|
||||||
|
|
||||||
# Shorten a URL
|
# Shorten a URL
|
||||||
curl -F'shorten=http://example.com/some/long/url' <a href="//{{.Request.Host}}">https://{{.Request.Host}}</a>
|
curl -F'shorten=http://example.com/some/long/url' <a href="{{.Host}}">{{.Host}}</a>
|
||||||
|
|
||||||
# The first line of the result will contain the shortened URL.
|
# The first line of the result will contain the shortened URL.
|
||||||
#
|
#
|
||||||
@ -20,6 +20,6 @@ the command line.
|
|||||||
# information on how to delete the shortened object.
|
# information on how to delete the shortened object.
|
||||||
|
|
||||||
# To upload a file and only extract the shortened URL (i.e. throw away the rest)
|
# To upload a file and only extract the shortened URL (i.e. throw away the rest)
|
||||||
curl -F'file=@yourfile.png' <a href="//{{.Request.Host}}">https://{{.Request.Host}}</a> | head -n 1
|
curl -F'file=@yourfile.png' <a href="{{.Host}}">{{.Host}}</a> | head -n 1
|
||||||
</pre>
|
</pre>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -4,13 +4,13 @@ Success - rushlink
|
|||||||
|
|
||||||
{{define "body"}}
|
{{define "body"}}
|
||||||
<pre>
|
<pre>
|
||||||
https://{{.Request.Host}}/{{.Paste.Key}}{{.FileExt}}
|
{{.Host}}/{{.Paste.Key}}{{.FileExt}}
|
||||||
---
|
---
|
||||||
|
|
||||||
# View metadata
|
# View metadata
|
||||||
curl <a href="https://{{.Request.Host}}/{{.Paste.Key}}{{.FileExt}}/meta?deleteToken={{.Paste.DeleteToken | urlquery}}">https://{{.Request.Host}}/{{.Paste.Key}}{{.FileExt}}/meta?deleteToken={{.Paste.DeleteToken | urlquery}}</a>
|
curl <a href="{{.Host}}/{{.Paste.Key}}{{.FileExt}}/meta?deleteToken={{.Paste.DeleteToken | urlquery}}">{{.Host}}/{{.Paste.Key}}{{.FileExt}}/meta?deleteToken={{.Paste.DeleteToken | urlquery}}</a>
|
||||||
|
|
||||||
# Delete this object
|
# Delete this object
|
||||||
curl --request DELETE <a href="https://{{.Request.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken | urlquery}}">https://{{.Request.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken | urlquery}}</a>
|
curl --request DELETE <a href="{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken | urlquery}}">{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken | urlquery}}</a>
|
||||||
</pre>
|
</pre>
|
||||||
{{end}}
|
{{end}}
|
@ -4,13 +4,13 @@ Success - rushlink
|
|||||||
|
|
||||||
{{define "body"}}
|
{{define "body"}}
|
||||||
<pre>
|
<pre>
|
||||||
https://{{.Request.Host}}/{{.Paste.Key}}
|
{{.Host}}/{{.Paste.Key}}
|
||||||
---
|
---
|
||||||
|
|
||||||
# View metadata
|
# View metadata
|
||||||
curl <a href="https://{{.Request.Host}}/{{.Paste.Key}}/meta?deleteToken={{.Paste.DeleteToken | urlquery}}">https://{{.Request.Host}}/{{.Paste.Key}}/meta?deleteToken={{.Paste.DeleteToken | urlquery}}</a>
|
curl <a href="{{.Host}}/{{.Paste.Key}}/meta?deleteToken={{.Paste.DeleteToken | urlquery}}">{{.Host}}/{{.Paste.Key}}/meta?deleteToken={{.Paste.DeleteToken | urlquery}}</a>
|
||||||
|
|
||||||
# Delete this object
|
# Delete this object
|
||||||
curl --request DELETE <a href="https://{{.Request.Host}}/{{.Paste.Key}}?deleteToken={{.Paste.DeleteToken | urlquery}}">https://{{.Request.Host}}/{{.Paste.Key}}?deleteToken={{.Paste.DeleteToken | urlquery}}</a>
|
curl --request DELETE <a href="{{.Host}}/{{.Paste.Key}}?deleteToken={{.Paste.DeleteToken | urlquery}}">{{.Host}}/{{.Paste.Key}}?deleteToken={{.Paste.DeleteToken | urlquery}}</a>
|
||||||
</pre>
|
</pre>
|
||||||
{{end}}
|
{{end}}
|
@ -1 +1 @@
|
|||||||
<{{.Request.Host}}/{{.Paste.Key}}> was succesfully deleted
|
<{{.Host}}/{{.Paste.Key}}> was succesfully deleted
|
||||||
|
@ -7,10 +7,10 @@ the command line.
|
|||||||
## USAGE
|
## USAGE
|
||||||
|
|
||||||
# Upload a file
|
# Upload a file
|
||||||
curl -F'file=@yourfile.png' https://{{.Request.Host}}
|
curl -F'file=@yourfile.png' {{.Host}}
|
||||||
|
|
||||||
# Shorten a URL
|
# Shorten a URL
|
||||||
curl -F'shorten=http://example.com/some/long/url' https://{{.Request.Host}}
|
curl -F'shorten=http://example.com/some/long/url' {{.Host}}
|
||||||
|
|
||||||
# The first line of the result will contain the shortened URL.
|
# The first line of the result will contain the shortened URL.
|
||||||
#
|
#
|
||||||
@ -18,4 +18,4 @@ the command line.
|
|||||||
# information on how to delete the shortened object.
|
# information on how to delete the shortened object.
|
||||||
|
|
||||||
# To upload a file and only extract the shortened URL (i.e. throw away the rest)
|
# To upload a file and only extract the shortened URL (i.e. throw away the rest)
|
||||||
curl -F'file=@yourfile.png' https://{{.Request.Host}} | head -n 1
|
curl -F'file=@yourfile.png' {{.Host}} | head -n 1
|
@ -1,8 +1,8 @@
|
|||||||
https://{{.Request.Host}}/{{.Paste.Key}}{{.FileExt}}
|
{{.Host}}/{{.Paste.Key}}{{.FileExt}}
|
||||||
---
|
---
|
||||||
|
|
||||||
# View metadata
|
# View metadata
|
||||||
curl https://{{.Request.Host}}/{{.Paste.Key}}{{.FileExt}}/meta?deleteToken={{.Paste.DeleteToken | urlquery}}
|
curl {{.Host}}/{{.Paste.Key}}{{.FileExt}}/meta?deleteToken={{.Paste.DeleteToken | urlquery}}
|
||||||
|
|
||||||
# Delete this object
|
# Delete this object
|
||||||
curl --request DELETE https://{{.Request.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken | urlquery}}
|
curl --request DELETE {{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken | urlquery}}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
https://{{.Request.Host}}/{{.Paste.Key}}
|
{{.Host}}/{{.Paste.Key}}
|
||||||
---
|
---
|
||||||
|
|
||||||
# View metadata
|
# View metadata
|
||||||
curl https://{{.Request.Host}}/{{.Paste.Key}}/meta?deleteToken={{.Paste.DeleteToken | urlquery}}
|
curl {{.Host}}/{{.Paste.Key}}/meta?deleteToken={{.Paste.DeleteToken | urlquery}}
|
||||||
|
|
||||||
# Delete this object
|
# Delete this object
|
||||||
curl --request DELETE https://{{.Request.Host}}/{{.Paste.Key}}?deleteToken={{.Paste.DeleteToken | urlquery}}
|
curl --request DELETE {{.Host}}/{{.Paste.Key}}?deleteToken={{.Paste.DeleteToken | urlquery}}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
METADATA on <{{.Request.Host}}/{{.Paste.Key}}>:
|
METADATA on <{{.Host}}/{{.Paste.Key}}>:
|
||||||
|
|
||||||
TYPE: {{.Paste.Type}}
|
TYPE: {{.Paste.Type}}
|
||||||
STATE: {{.Paste.State}}
|
STATE: {{.Paste.State}}
|
||||||
@ -12,6 +12,6 @@ DELETE TOKEN: {{.CanDelete.String}}
|
|||||||
{{if and (ne .Paste.State.String "deleted") .CanDelete.Bool}}
|
{{if and (ne .Paste.State.String "deleted") .CanDelete.Bool}}
|
||||||
```
|
```
|
||||||
# To delete this {{.Paste.Type}}, execute:
|
# To delete this {{.Paste.Type}}, execute:
|
||||||
curl --request "DELETE" "{{.Request.Host}}/{{.Paste.Key}}?deleteToken={{.Request.URL.Query.Get "deleteToken"}}"
|
curl --request "DELETE" "{{.Host}}/{{.Paste.Key}}?deleteToken={{.Request.URL.Query.Get "deleteToken"}}"
|
||||||
```
|
```
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -13,6 +13,7 @@ var (
|
|||||||
fileStorePath = flag.String("file-store", "", "path to the directory where uploaded files will be stored")
|
fileStorePath = flag.String("file-store", "", "path to the directory where uploaded files will be stored")
|
||||||
httpListen = flag.String("listen", "127.0.0.1:8000", "listen address (host:port)")
|
httpListen = flag.String("listen", "127.0.0.1:8000", "listen address (host:port)")
|
||||||
metricsListen = flag.String("metrics_listen", "127.0.0.1:58614", "listen address for metrics (host:port)")
|
metricsListen = flag.String("metrics_listen", "127.0.0.1:58614", "listen address for metrics (host:port)")
|
||||||
|
hostURL = flag.String("host", "", "host root (defaults to using the request 'Host' header with HTTPS")
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -29,5 +30,5 @@ func main() {
|
|||||||
defer database.Close()
|
defer database.Close()
|
||||||
|
|
||||||
go rushlink.StartMetricsServer(*metricsListen, database, filestore)
|
go rushlink.StartMetricsServer(*metricsListen, database, filestore)
|
||||||
rushlink.StartMainServer(*httpListen, database, filestore)
|
rushlink.StartMainServer(*httpListen, database, filestore, hostURL)
|
||||||
}
|
}
|
||||||
|
34
handlers.go
34
handlers.go
@ -30,7 +30,7 @@ const (
|
|||||||
const cookieDeleteToken = "owner_token"
|
const cookieDeleteToken = "owner_token"
|
||||||
|
|
||||||
func (rl *rushlink) indexGetHandler(w http.ResponseWriter, r *http.Request) {
|
func (rl *rushlink) indexGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
render(w, r, "index", map[string]interface{}{})
|
rl.render(w, r, "index", map[string]interface{}{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rl *rushlink) uploadFileGetHandler(w http.ResponseWriter, r *http.Request) {
|
func (rl *rushlink) uploadFileGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -49,7 +49,7 @@ func (rl *rushlink) uploadFileGetHandler(w http.ResponseWriter, r *http.Request)
|
|||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
if badID {
|
if badID {
|
||||||
renderError(w, r, http.StatusNotFound, "malformed file id")
|
rl.renderError(w, r, http.StatusNotFound, "malformed file id")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// unexpected error
|
// unexpected error
|
||||||
@ -61,7 +61,7 @@ func (rl *rushlink) uploadFileGetHandler(w http.ResponseWriter, r *http.Request)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
log.Printf("error: '%v' should exist according to the database, but it doesn't", filePath)
|
log.Printf("error: '%v' should exist according to the database, but it doesn't", filePath)
|
||||||
renderError(w, r, http.StatusNotFound, "file not found")
|
rl.renderError(w, r, http.StatusNotFound, "file not found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// unexpected error
|
// unexpected error
|
||||||
@ -114,7 +114,7 @@ func (rl *rushlink) viewPasteHandlerInner(w http.ResponseWriter, r *http.Request
|
|||||||
}
|
}
|
||||||
|
|
||||||
if p == nil {
|
if p == nil {
|
||||||
renderError(w, r, http.StatusNotFound, "url key not found in the database")
|
rl.renderError(w, r, http.StatusNotFound, "url key not found in the database")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ func (rl *rushlink) viewPasteHandlerInner(w http.ResponseWriter, r *http.Request
|
|||||||
"Paste": p,
|
"Paste": p,
|
||||||
"CanDelete": canDelete,
|
"CanDelete": canDelete,
|
||||||
}
|
}
|
||||||
render(w, r, "pasteMeta", data)
|
rl.render(w, r, "pasteMeta", data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ func (rl *rushlink) viewPasteHandlerInner(w http.ResponseWriter, r *http.Request
|
|||||||
}
|
}
|
||||||
fmt.Fprint(w, location)
|
fmt.Fprint(w, location)
|
||||||
case db.PasteStateDeleted:
|
case db.PasteStateDeleted:
|
||||||
renderError(w, r, http.StatusGone, "paste has been deleted\n")
|
rl.renderError(w, r, http.StatusGone, "paste has been deleted\n")
|
||||||
default:
|
default:
|
||||||
panic(errors.Errorf("invalid paste.State (%v) for key '%v'", p.State, p.Key))
|
panic(errors.Errorf("invalid paste.State (%v) for key '%v'", p.State, p.Key))
|
||||||
}
|
}
|
||||||
@ -179,7 +179,7 @@ func (rl *rushlink) newPasteHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
// Fallthrough
|
// Fallthrough
|
||||||
} else {
|
} else {
|
||||||
msg := fmt.Sprintf("could not parse form: %v\n", err)
|
msg := fmt.Sprintf("could not parse form: %v\n", err)
|
||||||
renderError(w, r, http.StatusBadRequest, msg)
|
rl.renderError(w, r, http.StatusBadRequest, msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +189,7 @@ func (rl *rushlink) newPasteHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
renderError(w, r, http.StatusBadRequest, "no 'file' and no 'shorten' fields given in form\n")
|
rl.renderError(w, r, http.StatusBadRequest, "no 'file' and no 'shorten' fields given in form\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rl *rushlink) newFileUploadPasteHandler(w http.ResponseWriter, r *http.Request, file multipart.File, header multipart.FileHeader) {
|
func (rl *rushlink) newFileUploadPasteHandler(w http.ResponseWriter, r *http.Request, file multipart.File, header multipart.FileHeader) {
|
||||||
@ -214,7 +214,7 @@ func (rl *rushlink) newFileUploadPasteHandler(w http.ResponseWriter, r *http.Req
|
|||||||
"Paste": paste,
|
"Paste": paste,
|
||||||
"FileUpload": fu,
|
"FileUpload": fu,
|
||||||
"FileExt": filepath.Ext(fu.FileName)}
|
"FileExt": filepath.Ext(fu.FileName)}
|
||||||
render(w, r, "newFileUploadPasteSuccess", data)
|
rl.render(w, r, "newFileUploadPasteSuccess", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rl *rushlink) newPasteHandlerURLEncoded(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
func (rl *rushlink) newPasteHandlerURLEncoded(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||||
@ -224,7 +224,7 @@ func (rl *rushlink) newPasteHandlerURLEncoded(w http.ResponseWriter, r *http.Req
|
|||||||
}
|
}
|
||||||
shorten := r.PostFormValue("shorten")
|
shorten := r.PostFormValue("shorten")
|
||||||
if shorten == "" {
|
if shorten == "" {
|
||||||
renderError(w, r, http.StatusBadRequest, "no 'shorten' param given\n")
|
rl.renderError(w, r, http.StatusBadRequest, "no 'shorten' param given\n")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rl.newRedirectPasteHandler(w, r, shorten)
|
rl.newRedirectPasteHandler(w, r, shorten)
|
||||||
@ -234,15 +234,15 @@ func (rl *rushlink) newRedirectPasteHandler(w http.ResponseWriter, r *http.Reque
|
|||||||
userURL, err := url.ParseRequestURI(rawurl)
|
userURL, err := url.ParseRequestURI(rawurl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("invalid url (%v): %v", err, rawurl)
|
msg := fmt.Sprintf("invalid url (%v): %v", err, rawurl)
|
||||||
renderError(w, r, http.StatusBadRequest, msg)
|
rl.renderError(w, r, http.StatusBadRequest, msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if userURL.Scheme == "" {
|
if userURL.Scheme == "" {
|
||||||
renderError(w, r, http.StatusBadRequest, "invalid url (unspecified scheme)\n")
|
rl.renderError(w, r, http.StatusBadRequest, "invalid url (unspecified scheme)\n")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if userURL.Host == "" {
|
if userURL.Host == "" {
|
||||||
renderError(w, r, http.StatusBadRequest, "invalid url (unspecified host)\n")
|
rl.renderError(w, r, http.StatusBadRequest, "invalid url (unspecified host)\n")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,7 +255,7 @@ func (rl *rushlink) newRedirectPasteHandler(w http.ResponseWriter, r *http.Reque
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
data := map[string]interface{}{"Paste": paste}
|
data := map[string]interface{}{"Paste": paste}
|
||||||
render(w, r, "newRedirectPasteSuccess", data)
|
rl.render(w, r, "newRedirectPasteSuccess", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete a URL from the database
|
// Delete a URL from the database
|
||||||
@ -265,7 +265,7 @@ func (rl *rushlink) deletePasteHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
deleteToken := getDeleteTokenFromRequest(r)
|
deleteToken := getDeleteTokenFromRequest(r)
|
||||||
if deleteToken == "" {
|
if deleteToken == "" {
|
||||||
renderError(w, r, http.StatusBadRequest, "no delete token provided\n")
|
rl.renderError(w, r, http.StatusBadRequest, "no delete token provided\n")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,12 +293,12 @@ func (rl *rushlink) deletePasteHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Printf("error: %v\n", err)
|
log.Printf("error: %v\n", err)
|
||||||
renderError(w, r, errorCode, fmt.Sprintf("error: %v\n", err))
|
rl.renderError(w, r, errorCode, fmt.Sprintf("error: %v\n", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := map[string]interface{}{"Paste": paste}
|
data := map[string]interface{}{"Paste": paste}
|
||||||
render(w, r, "deletePasteSuccess", data)
|
rl.render(w, r, "deletePasteSuccess", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a new fileUpload redirect to the database
|
// Add a new fileUpload redirect to the database
|
||||||
|
44
router.go
44
router.go
@ -4,12 +4,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.hashru.nl/dsprenkels/rushlink/internal/db"
|
"gitea.hashru.nl/dsprenkels/rushlink/internal/db"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const urlKeyExpr = "{key:[A-Za-z0-9-_]{4,}}"
|
const urlKeyExpr = "{key:[A-Za-z0-9-_]{4,}}"
|
||||||
@ -18,9 +20,14 @@ const urlKeyWithExtExpr = urlKeyExpr + "{ext:\\.[A-Za-z0-9-_]+}"
|
|||||||
type rushlink struct {
|
type rushlink struct {
|
||||||
db *db.Database
|
db *db.Database
|
||||||
fs *db.FileStore
|
fs *db.FileStore
|
||||||
|
host *url.URL
|
||||||
}
|
}
|
||||||
|
|
||||||
func recoveryMiddleware(next http.Handler) http.Handler {
|
func (rl *rushlink) Host() *url.URL {
|
||||||
|
return rl.host
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rl *rushlink) recoveryMiddleware(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
defer func() {
|
defer func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -34,13 +41,22 @@ func recoveryMiddleware(next http.Handler) http.Handler {
|
|||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
log.Printf("error: %v\n", err)
|
log.Printf("error: %v\n", err)
|
||||||
debug.PrintStack()
|
debug.PrintStack()
|
||||||
renderInternalServerError(w, r, err)
|
rl.renderInternalServerError(w, r, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rl *rushlink) metricsMiddleware(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
srw := statusResponseWriter{Inner: w}
|
||||||
|
next.ServeHTTP(&srw, r)
|
||||||
|
status := strconv.Itoa(srw.StatusCode)
|
||||||
|
metricRequestsTotalCounter.WithLabelValues(status, r.Method).Inc()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type statusResponseWriter struct {
|
type statusResponseWriter struct {
|
||||||
Inner http.ResponseWriter
|
Inner http.ResponseWriter
|
||||||
StatusCode int
|
StatusCode int
|
||||||
@ -62,26 +78,26 @@ func (w *statusResponseWriter) WriteHeader(statusCode int) {
|
|||||||
w.Inner.WriteHeader(statusCode)
|
w.Inner.WriteHeader(statusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func metricsMiddleware(next http.Handler) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
srw := statusResponseWriter{Inner: w}
|
|
||||||
next.ServeHTTP(&srw, r)
|
|
||||||
status := strconv.Itoa(srw.StatusCode)
|
|
||||||
metricRequestsTotalCounter.WithLabelValues(status, r.Method).Inc()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartMainServer starts the main http server listening on addr.
|
// StartMainServer starts the main http server listening on addr.
|
||||||
func StartMainServer(addr string, db *db.Database, fs *db.FileStore) {
|
func StartMainServer(addr string, db *db.Database, fs *db.FileStore, rawhost *string) {
|
||||||
|
var host *url.URL
|
||||||
|
if rawhost != nil {
|
||||||
|
var err error
|
||||||
|
host, err = url.Parse(*rawhost)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(errors.Wrap(err, "could not parse host flag"))
|
||||||
|
}
|
||||||
|
}
|
||||||
rl := rushlink{
|
rl := rushlink{
|
||||||
db: db,
|
db: db,
|
||||||
fs: fs,
|
fs: fs,
|
||||||
|
host: host,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize Gorilla router
|
// Initialize Gorilla router
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
router.Use(recoveryMiddleware)
|
router.Use(rl.recoveryMiddleware)
|
||||||
router.Use(metricsMiddleware)
|
router.Use(rl.metricsMiddleware)
|
||||||
router.HandleFunc("/uploads/{id:[A-Za-z0-9-_]+}/{filename:.+}", rl.uploadFileGetHandler).Methods("GET", "HEAD")
|
router.HandleFunc("/uploads/{id:[A-Za-z0-9-_]+}/{filename:.+}", rl.uploadFileGetHandler).Methods("GET", "HEAD")
|
||||||
router.HandleFunc("/", rl.indexGetHandler).Methods("GET", "HEAD")
|
router.HandleFunc("/", rl.indexGetHandler).Methods("GET", "HEAD")
|
||||||
router.HandleFunc("/", rl.newPasteHandler).Methods("POST")
|
router.HandleFunc("/", rl.newPasteHandler).Methods("POST")
|
||||||
|
33
views.go
33
views.go
@ -76,7 +76,22 @@ func parseFail(tmplName string, err error) {
|
|||||||
panic(errors.Wrapf(err, "parsing of %v failed", tmplName))
|
panic(errors.Wrapf(err, "parsing of %v failed", tmplName))
|
||||||
}
|
}
|
||||||
|
|
||||||
func render(w http.ResponseWriter, r *http.Request, tmplName string, data map[string]interface{}) {
|
func mapExtend(m map[string]interface{}, key string, value interface{}) {
|
||||||
|
if m[key] != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rl *rushlink) resolveHost(r *http.Request) string {
|
||||||
|
rlHost := rl.Host()
|
||||||
|
if rlHost != nil {
|
||||||
|
return rlHost.String()
|
||||||
|
}
|
||||||
|
return r.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rl *rushlink) render(w http.ResponseWriter, r *http.Request, tmplName string, data map[string]interface{}) {
|
||||||
contentType, err := resolveResponseContentType(r, []string{"text/plain", "text/html"})
|
contentType, err := resolveResponseContentType(r, []string{"text/plain", "text/html"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusNotAcceptable)
|
w.WriteHeader(http.StatusNotAcceptable)
|
||||||
@ -84,7 +99,8 @@ func render(w http.ResponseWriter, r *http.Request, tmplName string, data map[st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add the request to the template data
|
// Add the request to the template data
|
||||||
data["Request"] = r
|
mapExtend(data, "Host", rl.resolveHost(r))
|
||||||
|
mapExtend(data, "Request", r)
|
||||||
|
|
||||||
switch contentType {
|
switch contentType {
|
||||||
case "text/plain":
|
case "text/plain":
|
||||||
@ -117,10 +133,9 @@ func render(w http.ResponseWriter, r *http.Request, tmplName string, data map[st
|
|||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
if r.Method == "HEAD" {
|
if r.Method != "HEAD" {
|
||||||
return
|
|
||||||
}
|
|
||||||
err = tmpl.Execute(w, data)
|
err = tmpl.Execute(w, data)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// Fall back to plain text without template
|
// Fall back to plain text without template
|
||||||
w.WriteHeader(http.StatusNotAcceptable)
|
w.WriteHeader(http.StatusNotAcceptable)
|
||||||
@ -132,14 +147,14 @@ func render(w http.ResponseWriter, r *http.Request, tmplName string, data map[st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderError(w http.ResponseWriter, r *http.Request, status int, msg string) {
|
func (rl *rushlink) renderError(w http.ResponseWriter, r *http.Request, status int, msg string) {
|
||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
render(w, r, "error", map[string]interface{}{"Message": msg})
|
rl.render(w, r, "error", map[string]interface{}{"Message": msg})
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderInternalServerError(w http.ResponseWriter, r *http.Request, err interface{}) {
|
func (rl *rushlink) renderInternalServerError(w http.ResponseWriter, r *http.Request, err interface{}) {
|
||||||
msg := fmt.Sprintf("internal server error: %v", err)
|
msg := fmt.Sprintf("internal server error: %v", err)
|
||||||
renderError(w, r, http.StatusInternalServerError, msg)
|
rl.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.
|
||||||
|
Loading…
Reference in New Issue
Block a user