parent
5e6ce9c2be
commit
245dd64f82
96
handlers.go
96
handlers.go
@ -8,6 +8,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.hashru.nl/dsprenkels/rushlink/internal/db"
|
"gitea.hashru.nl/dsprenkels/rushlink/internal/db"
|
||||||
@ -60,53 +61,6 @@ func (rl *rushlink) indexGetHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
rl.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) {
|
|
||||||
vars := mux.Vars(r)
|
|
||||||
id := vars["id"]
|
|
||||||
|
|
||||||
var fu *db.FileUpload
|
|
||||||
var badID bool
|
|
||||||
if err := rl.db.Bolt.View(func(tx *bolt.Tx) error {
|
|
||||||
fuID, err := uuid.Parse(id)
|
|
||||||
if err != nil {
|
|
||||||
badID = true
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fu, err = db.GetFileUpload(tx, fuID)
|
|
||||||
return err
|
|
||||||
}); err != nil {
|
|
||||||
if badID {
|
|
||||||
rl.renderError(w, r, http.StatusNotFound, "malformed file id")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// unexpected error
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
filePath := fu.Path(rl.fs)
|
|
||||||
file, err := os.Open(filePath)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
log.Printf("error: '%v' should exist according to the database, but it doesn't", filePath)
|
|
||||||
rl.renderError(w, r, http.StatusNotFound, "file not found")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// unexpected error
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
info, err := file.Stat()
|
|
||||||
var modtime time.Time
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error: %v", errors.Wrapf(err, "could not stat file '%v'", filePath))
|
|
||||||
} else {
|
|
||||||
modtime = info.ModTime()
|
|
||||||
}
|
|
||||||
// We use http.ServeContent (instead of http.ServeFile) because we cannot
|
|
||||||
// use http.ServeFile together with the assertion that the file exists,
|
|
||||||
// without introducing a TOCTOU flaw.
|
|
||||||
http.ServeContent(w, r, fu.FileName, modtime, file)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rl *rushlink) viewPasteHandler(w http.ResponseWriter, r *http.Request) {
|
func (rl *rushlink) viewPasteHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
rl.viewPasteHandlerFlags(w, r, 0)
|
rl.viewPasteHandlerFlags(w, r, 0)
|
||||||
}
|
}
|
||||||
@ -158,31 +112,61 @@ func (rl *rushlink) viewPasteHandlerInner(w http.ResponseWriter, r *http.Request
|
|||||||
|
|
||||||
switch p.State {
|
switch p.State {
|
||||||
case db.PasteStatePresent:
|
case db.PasteStatePresent:
|
||||||
var location string
|
|
||||||
switch p.Type {
|
switch p.Type {
|
||||||
case db.PasteTypeFileUpload:
|
case db.PasteTypeFileUpload:
|
||||||
if fu == nil {
|
if fu == nil {
|
||||||
panic(fmt.Sprintf("file for id %v does not exist in database\n", string(p.Content)))
|
panic(fmt.Sprintf("file for id %v does not exist in database\n", string(p.Content)))
|
||||||
}
|
}
|
||||||
location = fu.URL().String()
|
rl.viewFileUploadHandler(w, r, fu)
|
||||||
break
|
return
|
||||||
case db.PasteTypeRedirect:
|
case db.PasteTypeRedirect:
|
||||||
location = p.RedirectURL().String()
|
if flags&viewNoRedirect == 0 {
|
||||||
break
|
http.Redirect(w, r, p.RedirectURL().String(), http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
return
|
||||||
default:
|
default:
|
||||||
panic("paste type unsupported")
|
panic("paste type unsupported")
|
||||||
}
|
}
|
||||||
if flags&viewNoRedirect == 0 {
|
|
||||||
http.Redirect(w, r, location, http.StatusSeeOther)
|
|
||||||
}
|
|
||||||
fmt.Fprint(w, location)
|
|
||||||
case db.PasteStateDeleted:
|
case db.PasteStateDeleted:
|
||||||
rl.renderError(w, r, http.StatusGone, "paste has been deleted\n")
|
rl.renderError(w, r, http.StatusGone, "paste has been deleted\n")
|
||||||
|
return
|
||||||
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rl *rushlink) viewFileUploadHandler(w http.ResponseWriter, r *http.Request, fu *db.FileUpload) {
|
||||||
|
filePath := fu.Path(rl.fs)
|
||||||
|
file, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
log.Printf("error: '%v' should exist according to the database, but it doesn't", filePath)
|
||||||
|
rl.renderError(w, r, http.StatusNotFound, "file not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// unexpected error
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var modtime time.Time
|
||||||
|
info, err := file.Stat()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error: %v", errors.Wrapf(err, "could not stat file '%v'", filePath))
|
||||||
|
} else {
|
||||||
|
modtime = info.ModTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provide the real filename to the client (to be used in Ctrl+S etc.)
|
||||||
|
quotedName := strings.ReplaceAll(fu.FileName, "\"", "\\\"")
|
||||||
|
w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", quotedName))
|
||||||
|
|
||||||
|
// We use http.ServeContent (instead of http.ServeFile) because we cannot
|
||||||
|
// use http.ServeFile together with the assertion that the file exists,
|
||||||
|
// without introducing a TOCTOU flaw.
|
||||||
|
http.ServeContent(w, r, fu.FileName, modtime, file)
|
||||||
|
}
|
||||||
|
|
||||||
func (rl *rushlink) viewPasteHandlerInnerMeta(w http.ResponseWriter, r *http.Request, p *db.Paste, fu *db.FileUpload) {
|
func (rl *rushlink) viewPasteHandlerInnerMeta(w http.ResponseWriter, r *http.Request, p *db.Paste, fu *db.FileUpload) {
|
||||||
var cd canDelete
|
var cd canDelete
|
||||||
deleteToken := getDeleteTokenFromRequest(r)
|
deleteToken := getDeleteTokenFromRequest(r)
|
||||||
|
@ -99,7 +99,6 @@ func StartMainServer(addr string, db *db.Database, fs *db.FileStore, rawRootURL
|
|||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
router.Use(rl.recoveryMiddleware)
|
router.Use(rl.recoveryMiddleware)
|
||||||
router.Use(rl.metricsMiddleware)
|
router.Use(rl.metricsMiddleware)
|
||||||
router.HandleFunc("/uploads/{id:[A-Za-z0-9-_]+}/{filename:.+}", rl.uploadFileGetHandler).Methods("GET", "HEAD")
|
|
||||||
router.HandleFunc("/{path:img/"+staticFilenameExpr+"}", rl.staticGetHandler).Methods("GET", "HEAD")
|
router.HandleFunc("/{path:img/"+staticFilenameExpr+"}", rl.staticGetHandler).Methods("GET", "HEAD")
|
||||||
router.HandleFunc("/{path:css/"+staticFilenameExpr+"}", rl.staticGetHandler).Methods("GET", "HEAD")
|
router.HandleFunc("/{path:css/"+staticFilenameExpr+"}", rl.staticGetHandler).Methods("GET", "HEAD")
|
||||||
router.HandleFunc("/{path:js/"+staticFilenameExpr+"}", rl.staticGetHandler).Methods("GET", "HEAD")
|
router.HandleFunc("/{path:js/"+staticFilenameExpr+"}", rl.staticGetHandler).Methods("GET", "HEAD")
|
||||||
|
Loading…
Reference in New Issue
Block a user