aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdnan Maolood <[email protected]>2021-02-09 09:45:10 -0500
committerAdnan Maolood <[email protected]>2021-02-09 09:46:18 -0500
commitf6824bd813e1e9fbc78bb2b0a167926de6dab7ed (patch)
tree9b7c85e5b1d6ff20818949859478273ddbc597b5
parentUse plain integers to represent status codes (diff)
downloadarchived-go-gemini-f6824bd813e1e9fbc78bb2b0a167926de6dab7ed.tar.xz
archived-go-gemini-f6824bd813e1e9fbc78bb2b0a167926de6dab7ed.zip
Make ResponseWriter an interface
-rw-r--r--examples/auth.go4
-rw-r--r--examples/stream.go2
-rw-r--r--fs.go4
-rw-r--r--mux.go4
-rw-r--r--response.go69
-rw-r--r--server.go8
6 files changed, 52 insertions, 39 deletions
diff --git a/examples/auth.go b/examples/auth.go
index d9325ee..34d336a 100644
--- a/examples/auth.go
+++ b/examples/auth.go
@@ -54,7 +54,7 @@ func fingerprint(cert *x509.Certificate) string {
return string(b[:])
}
-func profile(w *gemini.ResponseWriter, r *gemini.Request) {
+func profile(w gemini.ResponseWriter, r *gemini.Request) {
if r.Certificate == nil {
w.Status(gemini.StatusCertificateRequired)
return
@@ -69,7 +69,7 @@ func profile(w *gemini.ResponseWriter, r *gemini.Request) {
fmt.Fprintln(w, "=> /username Change username")
}
-func changeUsername(w *gemini.ResponseWriter, r *gemini.Request) {
+func changeUsername(w gemini.ResponseWriter, r *gemini.Request) {
if r.Certificate == nil {
w.Status(gemini.StatusCertificateRequired)
return
diff --git a/examples/stream.go b/examples/stream.go
index 1a292fd..0c302bd 100644
--- a/examples/stream.go
+++ b/examples/stream.go
@@ -38,7 +38,7 @@ func main() {
}
// stream writes an infinite stream to w.
-func stream(w *gemini.ResponseWriter, r *gemini.Request) {
+func stream(w gemini.ResponseWriter, r *gemini.Request) {
ch := make(chan string)
ctx, cancel := context.WithCancel(context.Background())
diff --git a/fs.go b/fs.go
index ced8bd6..56d1432 100644
--- a/fs.go
+++ b/fs.go
@@ -26,7 +26,7 @@ type fsHandler struct {
FS
}
-func (fsh fsHandler) ServeGemini(w *ResponseWriter, r *Request) {
+func (fsh fsHandler) ServeGemini(w ResponseWriter, r *Request) {
p := path.Clean(r.URL.Path)
f, err := fsh.Open(p)
if err != nil {
@@ -73,7 +73,7 @@ func (d Dir) Open(name string) (File, error) {
// or directory.
//
// TODO: Use io/fs.FS when available.
-func ServeFile(w *ResponseWriter, fs FS, name string) {
+func ServeFile(w ResponseWriter, fs FS, name string) {
f, err := fs.Open(name)
if err != nil {
w.Status(StatusNotFound)
diff --git a/mux.go b/mux.go
index c2a8d28..7fd4113 100644
--- a/mux.go
+++ b/mux.go
@@ -132,7 +132,7 @@ func (mux *ServeMux) shouldRedirectRLocked(path string) bool {
// 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(w ResponseWriter, r *Request) {
path := cleanPath(r.URL.Path)
// If the given path is /tree and its handler is not registered,
@@ -202,7 +202,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(ResponseWriter, *Request)) {
if handler == nil {
panic("gemini: nil responder")
}
diff --git a/response.go b/response.go
index 686c7b8..4b71855 100644
--- a/response.go
+++ b/response.go
@@ -129,8 +129,39 @@ func (b *readCloserBody) Read(p []byte) (n int, err error) {
return b.ReadCloser.Read(p)
}
-// ResponseWriter is used to construct a Gemini response.
-type ResponseWriter struct {
+// A ResponseWriter interface is used by a Gemini handler
+// to construct a Gemini response.
+type ResponseWriter interface {
+ // Header sets the response header.
+ Header(status int, meta string)
+
+ // Status sets the response status code.
+ // It also sets the response meta to Meta(status).
+ Status(status int)
+
+ // Meta sets the response meta.
+ //
+ // For successful responses, meta should contain the media type of the response.
+ // For failure responses, meta should contain a short description of the failure.
+ // The response meta should not be greater than 1024 bytes.
+ Meta(meta string)
+
+ // Write writes data to the connection as part of the response body.
+ // If the response status does not allow for a response body, Write returns
+ // ErrBodyNotAllowed.
+ //
+ // Write writes the response header if it has not already been written.
+ // It writes a successful status code if one is not set.
+ Write([]byte) (int, error)
+
+ // Flush writes any buffered data to the underlying io.Writer.
+ //
+ // Flush writes the response header if it has not already been written.
+ // It writes a failure status code if one is not set.
+ Flush() error
+}
+
+type responseWriter struct {
b *bufio.Writer
status int
meta string
@@ -139,41 +170,27 @@ type ResponseWriter struct {
}
// NewResponseWriter returns a ResponseWriter that uses the provided io.Writer.
-func NewResponseWriter(w io.Writer) *ResponseWriter {
- return &ResponseWriter{
+func NewResponseWriter(w io.Writer) ResponseWriter {
+ return &responseWriter{
b: bufio.NewWriter(w),
}
}
-// Header sets the response header.
-func (w *ResponseWriter) Header(status int, meta string) {
+func (w *responseWriter) Header(status int, meta string) {
w.status = status
w.meta = meta
}
-// Status sets the response status code.
-// It also sets the response meta to Meta(status).
-func (w *ResponseWriter) Status(status int) {
+func (w *responseWriter) Status(status int) {
w.status = status
w.meta = Meta(status)
}
-// Meta sets the response meta.
-//
-// For successful responses, meta should contain the media type of the response.
-// For failure responses, meta should contain a short description of the failure.
-// The response meta should not be greater than 1024 bytes.
-func (w *ResponseWriter) Meta(meta string) {
+func (w *responseWriter) Meta(meta string) {
w.meta = meta
}
-// Write writes data to the connection as part of the response body.
-// If the response status does not allow for a response body, Write returns
-// ErrBodyNotAllowed.
-//
-// Write writes the response header if it has not already been written.
-// It writes a successful status code if one is not set.
-func (w *ResponseWriter) Write(b []byte) (int, error) {
+func (w *responseWriter) Write(b []byte) (int, error) {
if !w.wroteHeader {
w.writeHeader(StatusSuccess)
}
@@ -183,7 +200,7 @@ func (w *ResponseWriter) Write(b []byte) (int, error) {
return w.b.Write(b)
}
-func (w *ResponseWriter) writeHeader(defaultStatus int) {
+func (w *responseWriter) writeHeader(defaultStatus int) {
status := w.status
if status == 0 {
status = defaultStatus
@@ -205,11 +222,7 @@ func (w *ResponseWriter) writeHeader(defaultStatus int) {
w.wroteHeader = true
}
-// Flush writes any buffered data to the underlying io.Writer.
-//
-// Flush writes the response header if it has not already been written.
-// It writes a failure status code if one is not set.
-func (w *ResponseWriter) Flush() error {
+func (w *responseWriter) Flush() error {
if !w.wroteHeader {
w.writeHeader(StatusTemporaryFailure)
}
diff --git a/server.go b/server.go
index a72a840..095437e 100644
--- a/server.go
+++ b/server.go
@@ -83,7 +83,7 @@ func (s *Server) Handle(pattern string, handler Handler) {
}
// HandleFunc registers the handler function for the given pattern.
-func (s *Server) HandleFunc(pattern string, handler func(*ResponseWriter, *Request)) {
+func (s *Server) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
s.Handle(pattern, HandlerFunc(handler))
}
@@ -258,15 +258,15 @@ func (s *Server) logf(format string, args ...interface{}) {
// ServeGemini should write the response header and data to the ResponseWriter
// and then return.
type Handler interface {
- ServeGemini(*ResponseWriter, *Request)
+ 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)
+type HandlerFunc func(ResponseWriter, *Request)
// ServeGemini calls f(w, r).
-func (f HandlerFunc) ServeGemini(w *ResponseWriter, r *Request) {
+func (f HandlerFunc) ServeGemini(w ResponseWriter, r *Request) {
f(w, r)
}