diff --git a/examples/client.go b/examples/client.go index 21f09c5..c806a8f 100644 --- a/examples/client.go +++ b/examples/client.go @@ -102,7 +102,7 @@ func do(req *gemini.Request, via []*gemini.Request) (*gemini.Response, error) { return resp, err } - switch gemini.StatusClass(resp.Status) { + switch resp.Status.Class() { case gemini.StatusInput: input, ok := getInput(resp.Meta, resp.Status == gemini.StatusSensitiveInput) if !ok { @@ -155,7 +155,7 @@ func main() { defer resp.Body.Close() // Handle response - if gemini.StatusClass(resp.Status) == gemini.StatusSuccess { + if resp.Status.Class() == gemini.StatusSuccess { body, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) diff --git a/handler.go b/handler.go index a85ba3c..5698e88 100644 --- a/handler.go +++ b/handler.go @@ -38,19 +38,19 @@ func (f HandlerFunc) ServeGemini(ctx context.Context, w ResponseWriter, r *Reque // 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 +// The provided status code should be in the 3x range and is usually // StatusRedirect or StatusPermanentRedirect. -func RedirectHandler(code int, url string) Handler { - return &redirectHandler{code, url} +func RedirectHandler(status Status, url string) Handler { + return &redirectHandler{status, url} } type redirectHandler struct { - code int - url string + status Status + url string } func (h *redirectHandler) ServeGemini(ctx context.Context, w ResponseWriter, r *Request) { - w.WriteHeader(h.code, h.url) + w.WriteHeader(h.status, h.url) } // NotFound replies to the request with a Gemini 51 not found error. diff --git a/response.go b/response.go index 17e2155..d62b8cf 100644 --- a/response.go +++ b/response.go @@ -18,7 +18,7 @@ const defaultMediaType = "text/gemini; charset=utf-8" // as the Body field is read. type Response struct { // Status contains the response status code. - Status int + Status Status // Meta contains more information related to the response status. // For successful responses, Meta should contain the media type of the response. @@ -57,7 +57,7 @@ func ReadResponse(rc io.ReadCloser) (*Response, error) { if err != nil { return nil, ErrInvalidResponse } - resp.Status = status + resp.Status = Status(status) // Read one space if b, err := br.ReadByte(); err != nil { @@ -77,7 +77,7 @@ func ReadResponse(rc io.ReadCloser) (*Response, error) { if len(meta) > 1024 { return nil, ErrInvalidResponse } - if StatusClass(status) == StatusSuccess && meta == "" { + if resp.Status.Class() == StatusSuccess && meta == "" { // Use default media type meta = defaultMediaType } @@ -90,7 +90,7 @@ func ReadResponse(rc io.ReadCloser) (*Response, error) { return nil, ErrInvalidResponse } - if StatusClass(status) == StatusSuccess { + if resp.Status.Class() == StatusSuccess { resp.Body = newReadCloserBody(br, rc) } else { resp.Body = nopReadCloser{} @@ -186,7 +186,7 @@ type ResponseWriter interface { // The provided code must be a valid Gemini status code. // The provided meta must not be longer than 1024 bytes. // Only one header may be written. - WriteHeader(status int, meta string) + WriteHeader(status Status, meta string) } // The Flusher interface is implemented by ResponseWriters that allow a @@ -237,16 +237,16 @@ func (w *responseWriter) Write(b []byte) (int, error) { return w.b.Write(b) } -func (w *responseWriter) WriteHeader(status int, meta string) { +func (w *responseWriter) WriteHeader(status Status, meta string) { if w.wroteHeader { return } - if StatusClass(status) == StatusSuccess { + if status.Class() == StatusSuccess { w.bodyAllowed = true } - w.b.WriteString(strconv.Itoa(status)) + w.b.WriteString(strconv.Itoa(int(status))) w.b.WriteByte(' ') w.b.WriteString(meta) w.b.Write(crlf) diff --git a/response_test.go b/response_test.go index 889e1ab..a6226ee 100644 --- a/response_test.go +++ b/response_test.go @@ -9,7 +9,7 @@ import ( func TestReadWriteResponse(t *testing.T) { tests := []struct { Raw string - Status int + Status Status Meta string Body string Err error diff --git a/status.go b/status.go index 45eaed4..6e4f1bb 100644 --- a/status.go +++ b/status.go @@ -1,37 +1,40 @@ package gemini +// Status represents a Gemini status code. +type Status int + // Gemini status codes. const ( - StatusInput = 10 - StatusSensitiveInput = 11 - StatusSuccess = 20 - StatusRedirect = 30 - StatusPermanentRedirect = 31 - StatusTemporaryFailure = 40 - StatusServerUnavailable = 41 - StatusCGIError = 42 - StatusProxyError = 43 - StatusSlowDown = 44 - StatusPermanentFailure = 50 - StatusNotFound = 51 - StatusGone = 52 - StatusProxyRequestRefused = 53 - StatusBadRequest = 59 - StatusCertificateRequired = 60 - StatusCertificateNotAuthorized = 61 - StatusCertificateNotValid = 62 + StatusInput Status = 10 + StatusSensitiveInput Status = 11 + StatusSuccess Status = 20 + StatusRedirect Status = 30 + StatusPermanentRedirect Status = 31 + StatusTemporaryFailure Status = 40 + StatusServerUnavailable Status = 41 + StatusCGIError Status = 42 + StatusProxyError Status = 43 + StatusSlowDown Status = 44 + StatusPermanentFailure Status = 50 + StatusNotFound Status = 51 + StatusGone Status = 52 + StatusProxyRequestRefused Status = 53 + StatusBadRequest Status = 59 + StatusCertificateRequired Status = 60 + StatusCertificateNotAuthorized Status = 61 + StatusCertificateNotValid Status = 62 ) -// StatusClass returns the status class for the provided status code. +// Class returns the status class for the status code. // 1x becomes 10, 2x becomes 20, and so on. -func StatusClass(code int) int { - return (code / 10) * 10 +func (s Status) Class() Status { + return (s / 10) * 10 } -// StatusText returns a text for the provided status code. +// String returns a text for the status code. // It returns the empty string if the status code is unknown. -func StatusText(code int) string { - switch code { +func (s Status) String() string { + switch s { case StatusInput: return "Input" case StatusSensitiveInput: diff --git a/timeout.go b/timeout.go index 9d3dab6..b23a895 100644 --- a/timeout.go +++ b/timeout.go @@ -66,7 +66,7 @@ func (t *timeoutHandler) ServeGemini(ctx context.Context, w ResponseWriter, r *R type timeoutWriter struct { mu sync.Mutex b bytes.Buffer - status int + status Status meta string mediatype string wroteHeader bool @@ -91,7 +91,7 @@ func (w *timeoutWriter) Write(b []byte) (int, error) { return w.b.Write(b) } -func (w *timeoutWriter) WriteHeader(status int, meta string) { +func (w *timeoutWriter) WriteHeader(status Status, meta string) { w.mu.Lock() defer w.mu.Unlock() if w.timedOut { @@ -100,7 +100,7 @@ func (w *timeoutWriter) WriteHeader(status int, meta string) { w.writeHeaderLocked(status, meta) } -func (w *timeoutWriter) writeHeaderLocked(status int, meta string) { +func (w *timeoutWriter) writeHeaderLocked(status Status, meta string) { if w.wroteHeader { return }