diff options
| author | Adnan Maolood <[email protected]> | 2021-02-20 15:49:07 -0500 |
|---|---|---|
| committer | Adnan Maolood <[email protected]> | 2021-02-20 15:49:14 -0500 |
| commit | e9a68917c9f47245ee4107157cff0a6dab83690b (patch) | |
| tree | dfcbb06b1e6ab70b8fd816f7e134a414f90d8cbe | |
| parent | examples/client: Remove dependency on go-xdg (diff) | |
| download | go-gemini-e9a68917c9f47245ee4107157cff0a6dab83690b.tar.xz go-gemini-e9a68917c9f47245ee4107157cff0a6dab83690b.zip | |
handler: Make ServeGemini accept a Context
| -rw-r--r-- | fs.go | 19 | ||||
| -rw-r--r-- | handler.go | 21 | ||||
| -rw-r--r-- | mux.go | 7 | ||||
| -rw-r--r-- | mux_test.go | 3 | ||||
| -rw-r--r-- | server.go | 4 | ||||
| -rw-r--r-- | timeout.go | 4 |
6 files changed, 32 insertions, 26 deletions
@@ -1,6 +1,7 @@ package gemini import ( + "context" "fmt" "io" "io/fs" @@ -31,8 +32,8 @@ type fileServer struct { fs.FS } -func (fs fileServer) ServeGemini(w ResponseWriter, r *Request) { - serveFile(w, r, fs, path.Clean(r.URL.Path), true) +func (fs fileServer) ServeGemini(ctx context.Context, w ResponseWriter, r *Request) { + serveFile(ctx, w, r, fs, path.Clean(r.URL.Path), true) } // ServeContent replies to the request using the content in the @@ -41,11 +42,11 @@ func (fs fileServer) ServeGemini(w ResponseWriter, r *Request) { // // ServeContent tries to deduce the type from name's file extension. // The name is otherwise unused; it is never sent in the response. -func ServeContent(w ResponseWriter, r *Request, name string, content io.Reader) { - serveContent(w, name, content) +func ServeContent(ctx context.Context, w ResponseWriter, r *Request, name string, content io.Reader) { + serveContent(ctx, w, name, content) } -func serveContent(w ResponseWriter, name string, content io.Reader) { +func serveContent(ctx context.Context, w ResponseWriter, name string, content io.Reader) { // Detect mimetype from file extension ext := path.Ext(name) mimetype := mime.TypeByExtension(ext) @@ -73,7 +74,7 @@ func serveContent(w ResponseWriter, name string, content io.Reader) { // Outside of those two special cases, ServeFile does not use r.URL.Path for // selecting the file or directory to serve; only the file or directory // provided in the name argument is used. -func ServeFile(w ResponseWriter, r *Request, fsys fs.FS, name string) { +func ServeFile(ctx context.Context, w ResponseWriter, r *Request, fsys fs.FS, name string) { if containsDotDot(r.URL.Path) { // Too many programs use r.URL.Path to construct the argument to // serveFile. Reject the request under the assumption that happened @@ -83,7 +84,7 @@ func ServeFile(w ResponseWriter, r *Request, fsys fs.FS, name string) { w.WriteHeader(StatusBadRequest, "invalid URL path") return } - serveFile(w, r, fsys, name, false) + serveFile(ctx, w, r, fsys, name, false) } func containsDotDot(v string) bool { @@ -100,7 +101,7 @@ func containsDotDot(v string) bool { func isSlashRune(r rune) bool { return r == '/' || r == '\\' } -func serveFile(w ResponseWriter, r *Request, fsys fs.FS, name string, redirect bool) { +func serveFile(ctx context.Context, w ResponseWriter, r *Request, fsys fs.FS, name string, redirect bool) { const indexPage = "/index.gmi" // Redirect .../index.gmi to .../ @@ -172,7 +173,7 @@ func serveFile(w ResponseWriter, r *Request, fsys fs.FS, name string, redirect b return } - serveContent(w, name, f) + serveContent(ctx, w, name, f) } func dirList(w ResponseWriter, f fs.File) { @@ -1,6 +1,7 @@ package gemini import ( + "context" "net/url" "strings" ) @@ -21,17 +22,17 @@ import ( // response but the server doesn't log an error, panic with the value // ErrAbortHandler. type Handler interface { - ServeGemini(ResponseWriter, *Request) + ServeGemini(context.Context, ResponseWriter, *Request) } // The HandlerFunc type is an adapter to allow the use of ordinary functions // as Gemini handlers. If f is a function with the appropriate signature, // HandlerFunc(f) is a Handler that calls f. -type HandlerFunc func(ResponseWriter, *Request) +type HandlerFunc func(context.Context, ResponseWriter, *Request) -// ServeGemini calls f(w, r). -func (f HandlerFunc) ServeGemini(w ResponseWriter, r *Request) { - f(w, r) +// ServeGemini calls f(ctx, w, r). +func (f HandlerFunc) ServeGemini(ctx context.Context, w ResponseWriter, r *Request) { + f(ctx, w, r) } // RedirectHandler returns a request handler that redirects each request it @@ -48,12 +49,12 @@ type redirectHandler struct { url string } -func (h *redirectHandler) ServeGemini(w ResponseWriter, r *Request) { +func (h *redirectHandler) ServeGemini(ctx context.Context, w ResponseWriter, r *Request) { w.WriteHeader(h.code, h.url) } // NotFound replies to the request with a Gemini 51 not found error. -func NotFound(w ResponseWriter, r *Request) { +func NotFound(ctx context.Context, w ResponseWriter, r *Request) { w.WriteHeader(StatusNotFound, "Not found") } @@ -73,7 +74,7 @@ func StripPrefix(prefix string, h Handler) Handler { if prefix == "" { return h } - return HandlerFunc(func(w ResponseWriter, r *Request) { + return HandlerFunc(func(ctx context.Context, w ResponseWriter, r *Request) { p := strings.TrimPrefix(r.URL.Path, prefix) rp := strings.TrimPrefix(r.URL.RawPath, prefix) if len(p) < len(r.URL.Path) && (r.URL.RawPath == "" || len(rp) < len(r.URL.RawPath)) { @@ -83,9 +84,9 @@ func StripPrefix(prefix string, h Handler) Handler { *r2.URL = *r.URL r2.URL.Path = p r2.URL.RawPath = rp - h.ServeGemini(w, r2) + h.ServeGemini(ctx, w, r2) } else { - NotFound(w, r) + NotFound(ctx, w, r) } }) } @@ -1,6 +1,7 @@ package gemini import ( + "context" "net" "net/url" "path" @@ -211,9 +212,9 @@ func (mux *ServeMux) Handler(r *Request) Handler { // ServeGemini dispatches the request to the handler whose // pattern most closely matches the request URL. -func (mux *ServeMux) ServeGemini(w ResponseWriter, r *Request) { +func (mux *ServeMux) ServeGemini(ctx context.Context, w ResponseWriter, r *Request) { h := mux.Handler(r) - h.ServeGemini(w, r) + h.ServeGemini(ctx, w, r) } // Handle registers the handler for the given pattern. @@ -293,7 +294,7 @@ func appendSorted(es []muxEntry, e muxEntry) []muxEntry { } // HandleFunc registers the handler function for the given pattern. -func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { +func (mux *ServeMux) HandleFunc(pattern string, handler func(context.Context, ResponseWriter, *Request)) { if handler == nil { panic("gemini: nil handler") } diff --git a/mux_test.go b/mux_test.go index f8dd988..858c1ba 100644 --- a/mux_test.go +++ b/mux_test.go @@ -1,13 +1,14 @@ package gemini import ( + "context" "net/url" "testing" ) type nopHandler struct{} -func (*nopHandler) ServeGemini(ResponseWriter, *Request) {} +func (*nopHandler) ServeGemini(context.Context, ResponseWriter, *Request) {} func TestServeMuxMatch(t *testing.T) { type Match struct { @@ -303,7 +303,9 @@ func (srv *Server) respond(conn net.Conn) { return } - h.ServeGemini(w, req) + // TODO: Allow configuring the server context + ctx := context.Background() + h.ServeGemini(ctx, w, req) w.Flush() } @@ -27,7 +27,7 @@ type timeoutHandler struct { dt time.Duration } -func (t *timeoutHandler) ServeGemini(w ResponseWriter, r *Request) { +func (t *timeoutHandler) ServeGemini(ctx context.Context, w ResponseWriter, r *Request) { ctx, cancel := context.WithTimeout(context.TODO(), t.dt) defer cancel() @@ -40,7 +40,7 @@ func (t *timeoutHandler) ServeGemini(w ResponseWriter, r *Request) { panicChan <- p } }() - t.h.ServeGemini(tw, r) + t.h.ServeGemini(ctx, tw, r) close(done) }() |