error handling, url matching
This commit is contained in:
parent
0e87800ddc
commit
3abd71b6c0
|
@ -9,6 +9,8 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const basePath = "/files/"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
|
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
|
||||||
log.Printf("tusd started")
|
log.Printf("tusd started")
|
||||||
|
@ -36,20 +38,34 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config := tushttp.HandlerConfig{
|
tusConfig := tushttp.HandlerConfig{
|
||||||
Dir: dir,
|
Dir: dir,
|
||||||
MaxSize: maxSize,
|
MaxSize: maxSize,
|
||||||
|
BasePath: basePath,
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("handler config: %+v", config)
|
log.Printf("handler config: %+v", tusConfig)
|
||||||
|
|
||||||
handler, err := tushttp.NewHandler(config)
|
tusHandler, err := tushttp.NewHandler(tusConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
http.Handle(basePath, tusHandler)
|
||||||
|
|
||||||
|
go handleUploads(tusHandler)
|
||||||
|
|
||||||
log.Printf("servering clients at http://localhost%s", addr)
|
log.Printf("servering clients at http://localhost%s", addr)
|
||||||
if err := http.ListenAndServe(addr, handler); err != nil {
|
if err := http.ListenAndServe(addr, nil); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleUploads(tus *tushttp.Handler) {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case err := <-tus.Error:
|
||||||
|
log.Printf("error: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"errors"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HandlerConfig struct{
|
// HandlerConfig holds the configuration for a tus Handler.
|
||||||
|
type HandlerConfig struct {
|
||||||
// Dir points to a filesystem path used by tus to store uploaded and partial
|
// Dir points to a filesystem path used by tus to store uploaded and partial
|
||||||
// files. Will be created if does not exist yet. Required.
|
// files. Will be created if does not exist yet. Required.
|
||||||
Dir string
|
Dir string
|
||||||
|
@ -15,23 +18,76 @@ type HandlerConfig struct{
|
||||||
// limit will cause the oldest upload files to be deleted until enough space
|
// limit will cause the oldest upload files to be deleted until enough space
|
||||||
// is available again. Required.
|
// is available again. Required.
|
||||||
MaxSize int64
|
MaxSize int64
|
||||||
|
|
||||||
|
// BasePath defines the url path used for handling uploads, e.g. "/files/".
|
||||||
|
// Must contain a trailling "/". Requests not matching this base path will
|
||||||
|
// cause a 404, so make sure you dispatch only appropriate requests to the
|
||||||
|
// handler. Required.
|
||||||
|
BasePath string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewHandler returns an initialized Handler. An error may occur if the
|
||||||
|
// config.Dir is not writable.
|
||||||
func NewHandler(config HandlerConfig) (*Handler, error) {
|
func NewHandler(config HandlerConfig) (*Handler, error) {
|
||||||
// Ensure the data store directory exists
|
// Ensure the data store directory exists
|
||||||
if err := os.MkdirAll(config.Dir, 0777); err != nil {
|
if err := os.MkdirAll(config.Dir, 0777); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errChan := make(chan error)
|
||||||
|
|
||||||
return &Handler{
|
return &Handler{
|
||||||
store: newDataStore(config.Dir, config.MaxSize),
|
store: newDataStore(config.Dir, config.MaxSize),
|
||||||
|
basePath: config.BasePath,
|
||||||
|
Error: errChan,
|
||||||
|
sendError: errChan,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Handler struct{
|
// Handler is a http.Handler that implements tus resumable upload protocol.
|
||||||
store *DataStore
|
type Handler struct {
|
||||||
|
store *DataStore
|
||||||
|
basePath string
|
||||||
|
|
||||||
|
// Error provides error events for logging purposes.
|
||||||
|
Error <-chan error
|
||||||
|
// same chan as Error, used for sending.
|
||||||
|
sendError chan<- error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Printf("request: %s %s", r.Method, r.URL.RequestURI())
|
absPath := r.URL.Path
|
||||||
|
if !strings.HasPrefix(absPath, h.basePath) {
|
||||||
|
err := errors.New("invalid url path: " + absPath + " - does not match basePath: " + h.basePath)
|
||||||
|
h.err(err, w, http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
relPath := absPath[len(h.basePath)-1:]
|
||||||
|
|
||||||
|
// File creation request
|
||||||
|
if relPath == "/" {
|
||||||
|
// Must use POST method according to tus protocol
|
||||||
|
if r.Method != "POST" {
|
||||||
|
w.Header().Set("Allow", "POST")
|
||||||
|
err := errors.New(r.Method + " used against file creation url. Only POST is allowed.")
|
||||||
|
h.err(err, w, http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := errors.New("invalid url path: " + absPath + " - does not match file pattern")
|
||||||
|
h.err(err, w, http.StatusNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
// err sends a http error response and publishes to the Error channel.
|
||||||
|
func (h *Handler) err(err error, w http.ResponseWriter, status int) {
|
||||||
|
w.WriteHeader(status)
|
||||||
|
io.WriteString(w, err.Error()+"\n")
|
||||||
|
|
||||||
|
// non-blocking send
|
||||||
|
select {
|
||||||
|
case h.sendError <- err:
|
||||||
|
default:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue