Make Status a type
Using a type is better than using an integer.
This commit is contained in:
parent
99a8f09c22
commit
8938038797
@ -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)
|
||||
|
12
handler.go
12
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.
|
||||
|
16
response.go
16
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)
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
func TestReadWriteResponse(t *testing.T) {
|
||||
tests := []struct {
|
||||
Raw string
|
||||
Status int
|
||||
Status Status
|
||||
Meta string
|
||||
Body string
|
||||
Err error
|
||||
|
51
status.go
51
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:
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user