aboutsummaryrefslogtreecommitdiff
path: root/handler.go
diff options
context:
space:
mode:
authorAdnan Maolood <[email protected]>2021-02-17 19:26:56 -0500
committerAdnan Maolood <[email protected]>2021-02-17 19:27:25 -0500
commitb5a3c0adc534510885bd3e5aa5e910f05a95a590 (patch)
tree423cd2fc98c6b23e9d442538b983b694f63af631 /handler.go
parentexamples: Use new ResponseWriter interface (diff)
downloadgo-gemini-b5a3c0adc534510885bd3e5aa5e910f05a95a590.tar.xz
go-gemini-b5a3c0adc534510885bd3e5aa5e910f05a95a590.zip
Add utility Handler functions
Diffstat (limited to 'handler.go')
-rw-r--r--handler.go91
1 files changed, 91 insertions, 0 deletions
diff --git a/handler.go b/handler.go
new file mode 100644
index 0000000..e0edd90
--- /dev/null
+++ b/handler.go
@@ -0,0 +1,91 @@
+package gemini
+
+import (
+ "net/url"
+ "strings"
+)
+
+// A Handler responds to a Gemini request.
+//
+// ServeGemini should write the response header and data to the ResponseWriter
+// and then return. Returning signals that the request is finished; it is not
+// valid to use the ResponseWriter after or concurrently with the completion
+// of the ServeGemini call.
+//
+// Handlers should not modify the provided Request.
+//
+// If ServeGemini panics, the server (the caller of ServeGemini) assumes that
+// the effect of the panic was isolated to the active request. It recovers
+// the panic, logs a stack trace to the server error log, and closes the
+// network connection. To abort a handler so the client sees an interrupted
+// response but the server doesn't log an error, panic with the value
+// ErrAbortHandler.
+type Handler interface {
+ ServeGemini(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)
+
+// ServeGemini calls f(w, r).
+func (f HandlerFunc) ServeGemini(w ResponseWriter, r *Request) {
+ f(w, r)
+}
+
+// RedirectHandler returns a request handler that redirects each request it
+// receives to the given url using the given status code.
+//
+// The provided code should be in the 3x range and is usually
+// StatusRedirect or StatusPermanentRedirect.
+func RedirectHandler(url string, code int) Handler {
+ return &redirectHandler{url, code}
+}
+
+type redirectHandler struct {
+ url string
+ code int
+}
+
+func (h *redirectHandler) ServeGemini(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) {
+ w.WriteHeader(StatusNotFound, "Not found")
+}
+
+// NotFoundHandler returns a simple request handler that replies to each
+// request with a “51 Not found” reply.
+func NotFoundHandler() Handler {
+ return HandlerFunc(NotFound)
+}
+
+// StripPrefix returns a handler that serves Gemini requests by removing the
+// given prefix from the request URL's Path (and RawPath if set) and invoking
+// the handler h. StripPrefix handles a request for a path that doesn't begin
+// with prefix by replying with a Gemini 51 not found error. The prefix must
+// match exactly: if the prefix in the request contains escaped characters the
+// reply is also a Gemini 51 not found error.
+func StripPrefix(prefix string, h Handler) Handler {
+ if prefix == "" {
+ return h
+ }
+ return HandlerFunc(func(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)) {
+ r2 := new(Request)
+ *r2 = *r
+ r2.URL = new(url.URL)
+ *r2.URL = *r.URL
+ r2.URL.Path = p
+ r2.URL.RawPath = rp
+ h.ServeGemini(w, r2)
+ } else {
+ NotFound(w, r)
+ }
+ })
+}