diff --git a/internal/front/server.go b/internal/front/server.go index fec64f7..82bc696 100644 --- a/internal/front/server.go +++ b/internal/front/server.go @@ -1,7 +1,6 @@ package front import ( - "context" "errors" "fmt" "io" @@ -9,6 +8,7 @@ import ( "net/http" "net/url" "strconv" + "time" "github.com/rickb777/date" hm "gitlab.codemonkeysoftware.net/b/hatmill" @@ -33,12 +33,14 @@ type handler struct { store *back.Store title string baseURL string + timeout time.Duration } type HandlerParams struct { Title string Store *back.Store BaseURL string + Timeout time.Duration } func NewHandler(params HandlerParams) http.Handler { @@ -47,18 +49,23 @@ func NewHandler(params HandlerParams) http.Handler { title: params.Title, baseURL: params.BaseURL, mux: http.NewServeMux(), + timeout: params.Timeout, } - h.mux.HandleFunc(pathRoot, h.handleRoot) - h.mux.HandleFunc(pathCreate, h.handleCreate) - h.mux.HandleFunc(pathDoCreate, h.handleDoCreate) - h.mux.HandleFunc(pathAdmin, h.handleAdmin) - h.mux.HandleFunc(pathVote, h.handleVote) - h.mux.HandleFunc(pathDoVote, h.handleDoVote) - h.mux.HandleFunc(pathVoteSuccess, h.handleVoteSuccess) - h.mux.HandleFunc(pathCreateSuccess, h.handleCreateSuccess) + h.handleFunc(pathRoot, h.handleRoot) + h.handleFunc(pathCreate, h.handleCreate) + h.handleFunc(pathDoCreate, h.handleDoCreate) + h.handleFunc(pathAdmin, h.handleAdmin) + h.handleFunc(pathVote, h.handleVote) + h.handleFunc(pathDoVote, h.handleDoVote) + h.handleFunc(pathVoteSuccess, h.handleVoteSuccess) + h.handleFunc(pathCreateSuccess, h.handleCreateSuccess) return h } +func (h *handler) handleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) { + h.mux.Handle(pattern, http.TimeoutHandler(http.HandlerFunc(handler), h.timeout, "")) +} + func (h *handler) handleRoot(w http.ResponseWriter, r *http.Request) { body := hm.Terms{ e.A(a.Href(pathCreate))( @@ -154,7 +161,7 @@ func internalServerError(w http.ResponseWriter, err error) bool { func (h *handler) handleVote(w http.ResponseWriter, r *http.Request) { eventAlphaID := r.URL.Query().Get(fieldNameEventID) - event, err := h.store.GetEventMetadata(context.Background(), back.GetEventMetadataQuery{ + event, err := h.store.GetEventMetadata(r.Context(), back.GetEventMetadataQuery{ EventID: eventAlphaID, }) if notFound(w, err, "Event not found") || internalServerError(w, err) { @@ -284,7 +291,7 @@ func (h *handler) handleDoCreate(w http.ResponseWriter, r *http.Request) { } description := r.FormValue(fieldNameDescription) - event, err := h.store.CreateEvent(context.Background(), back.CreateEventCommand{ + event, err := h.store.CreateEvent(r.Context(), back.CreateEventCommand{ Name: eventName, Description: description, Earliest: earliest, @@ -305,7 +312,7 @@ func (h *handler) blockUnauthorizedAdmin(w http.ResponseWriter, r *http.Request) eventID := r.URL.Query().Get(fieldNameEventID) adminCode := r.URL.Query().Get(fieldNameAdminCode) - err := h.store.AuthorizeEventAdmin(context.Background(), back.CheckEventAdminCodeQuery{ + err := h.store.AuthorizeEventAdmin(r.Context(), back.CheckEventAdminCodeQuery{ EventID: eventID, AdminCode: adminCode, }) @@ -377,14 +384,14 @@ func (h *handler) handleAdmin(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() eventID := query.Get(fieldNameEventID) - metadata, err := h.store.GetEventMetadata(context.Background(), back.GetEventMetadataQuery{ + metadata, err := h.store.GetEventMetadata(r.Context(), back.GetEventMetadataQuery{ EventID: eventID, }) if notFound(w, err, "Event not found") || internalServerError(w, err) { return } - summary, err := h.store.GetEventResponseSummary(context.Background(), back.GetEventResponseSummaryQuery{ + summary, err := h.store.GetEventResponseSummary(r.Context(), back.GetEventResponseSummaryQuery{ EventID: eventID, }) if err != nil { diff --git a/main.go b/main.go index 84a0c5e..3c479bf 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "flag" "log" "net/http" + "time" "gitlab.codemonkeysoftware.net/b/henwen/internal/back" "gitlab.codemonkeysoftware.net/b/henwen/internal/front" @@ -14,6 +15,7 @@ func main() { title := flag.String("title", "Henwen", "website title") baseURL := flag.String("baseURL", "http://localhost:8080", "base URL for HTTP routes") dbFileName := flag.String("db", "./henwen.db", "name of database file") + httpTimeout := flag.Int("httpTimeout", 5000, "HTTP server timeout in ms") flag.Parse() store, err := back.NewStore(*dbFileName, back.SecureGenString) @@ -27,6 +29,7 @@ func main() { Store: store, Title: *title, BaseURL: *baseURL, + Timeout: time.Millisecond * time.Duration(*httpTimeout), }), } diff --git a/todo.txt b/todo.txt index 9341f33..1b39070 100644 --- a/todo.txt +++ b/todo.txt @@ -5,7 +5,6 @@ Add a schema ID to the DB Require earliest and latest dates for creation Ensure latest date is at least earliest date Ensure date span is within a maximum -Add timeout to request context Prevent blank event names and guest names Cleanup: