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
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch gemini.StatusClass(resp.Status) {
|
switch resp.Status.Class() {
|
||||||
case gemini.StatusInput:
|
case gemini.StatusInput:
|
||||||
input, ok := getInput(resp.Meta, resp.Status == gemini.StatusSensitiveInput)
|
input, ok := getInput(resp.Meta, resp.Status == gemini.StatusSensitiveInput)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -155,7 +155,7 @@ func main() {
|
|||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
// Handle response
|
// Handle response
|
||||||
if gemini.StatusClass(resp.Status) == gemini.StatusSuccess {
|
if resp.Status.Class() == gemini.StatusSuccess {
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
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
|
// RedirectHandler returns a request handler that redirects each request it
|
||||||
// receives to the given url using the given status code.
|
// 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.
|
// StatusRedirect or StatusPermanentRedirect.
|
||||||
func RedirectHandler(code int, url string) Handler {
|
func RedirectHandler(status Status, url string) Handler {
|
||||||
return &redirectHandler{code, url}
|
return &redirectHandler{status, url}
|
||||||
}
|
}
|
||||||
|
|
||||||
type redirectHandler struct {
|
type redirectHandler struct {
|
||||||
code int
|
status Status
|
||||||
url string
|
url string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *redirectHandler) ServeGemini(ctx context.Context, w ResponseWriter, r *Request) {
|
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.
|
// 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.
|
// as the Body field is read.
|
||||||
type Response struct {
|
type Response struct {
|
||||||
// Status contains the response status code.
|
// Status contains the response status code.
|
||||||
Status int
|
Status Status
|
||||||
|
|
||||||
// Meta contains more information related to the response status.
|
// Meta contains more information related to the response status.
|
||||||
// For successful responses, Meta should contain the media type of the response.
|
// 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 {
|
if err != nil {
|
||||||
return nil, ErrInvalidResponse
|
return nil, ErrInvalidResponse
|
||||||
}
|
}
|
||||||
resp.Status = status
|
resp.Status = Status(status)
|
||||||
|
|
||||||
// Read one space
|
// Read one space
|
||||||
if b, err := br.ReadByte(); err != nil {
|
if b, err := br.ReadByte(); err != nil {
|
||||||
@ -77,7 +77,7 @@ func ReadResponse(rc io.ReadCloser) (*Response, error) {
|
|||||||
if len(meta) > 1024 {
|
if len(meta) > 1024 {
|
||||||
return nil, ErrInvalidResponse
|
return nil, ErrInvalidResponse
|
||||||
}
|
}
|
||||||
if StatusClass(status) == StatusSuccess && meta == "" {
|
if resp.Status.Class() == StatusSuccess && meta == "" {
|
||||||
// Use default media type
|
// Use default media type
|
||||||
meta = defaultMediaType
|
meta = defaultMediaType
|
||||||
}
|
}
|
||||||
@ -90,7 +90,7 @@ func ReadResponse(rc io.ReadCloser) (*Response, error) {
|
|||||||
return nil, ErrInvalidResponse
|
return nil, ErrInvalidResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
if StatusClass(status) == StatusSuccess {
|
if resp.Status.Class() == StatusSuccess {
|
||||||
resp.Body = newReadCloserBody(br, rc)
|
resp.Body = newReadCloserBody(br, rc)
|
||||||
} else {
|
} else {
|
||||||
resp.Body = nopReadCloser{}
|
resp.Body = nopReadCloser{}
|
||||||
@ -186,7 +186,7 @@ type ResponseWriter interface {
|
|||||||
// The provided code must be a valid Gemini status code.
|
// The provided code must be a valid Gemini status code.
|
||||||
// The provided meta must not be longer than 1024 bytes.
|
// The provided meta must not be longer than 1024 bytes.
|
||||||
// Only one header may be written.
|
// 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
|
// 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)
|
return w.b.Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *responseWriter) WriteHeader(status int, meta string) {
|
func (w *responseWriter) WriteHeader(status Status, meta string) {
|
||||||
if w.wroteHeader {
|
if w.wroteHeader {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if StatusClass(status) == StatusSuccess {
|
if status.Class() == StatusSuccess {
|
||||||
w.bodyAllowed = true
|
w.bodyAllowed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
w.b.WriteString(strconv.Itoa(status))
|
w.b.WriteString(strconv.Itoa(int(status)))
|
||||||
w.b.WriteByte(' ')
|
w.b.WriteByte(' ')
|
||||||
w.b.WriteString(meta)
|
w.b.WriteString(meta)
|
||||||
w.b.Write(crlf)
|
w.b.Write(crlf)
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
func TestReadWriteResponse(t *testing.T) {
|
func TestReadWriteResponse(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
Raw string
|
Raw string
|
||||||
Status int
|
Status Status
|
||||||
Meta string
|
Meta string
|
||||||
Body string
|
Body string
|
||||||
Err error
|
Err error
|
||||||
|
51
status.go
51
status.go
@ -1,37 +1,40 @@
|
|||||||
package gemini
|
package gemini
|
||||||
|
|
||||||
|
// Status represents a Gemini status code.
|
||||||
|
type Status int
|
||||||
|
|
||||||
// Gemini status codes.
|
// Gemini status codes.
|
||||||
const (
|
const (
|
||||||
StatusInput = 10
|
StatusInput Status = 10
|
||||||
StatusSensitiveInput = 11
|
StatusSensitiveInput Status = 11
|
||||||
StatusSuccess = 20
|
StatusSuccess Status = 20
|
||||||
StatusRedirect = 30
|
StatusRedirect Status = 30
|
||||||
StatusPermanentRedirect = 31
|
StatusPermanentRedirect Status = 31
|
||||||
StatusTemporaryFailure = 40
|
StatusTemporaryFailure Status = 40
|
||||||
StatusServerUnavailable = 41
|
StatusServerUnavailable Status = 41
|
||||||
StatusCGIError = 42
|
StatusCGIError Status = 42
|
||||||
StatusProxyError = 43
|
StatusProxyError Status = 43
|
||||||
StatusSlowDown = 44
|
StatusSlowDown Status = 44
|
||||||
StatusPermanentFailure = 50
|
StatusPermanentFailure Status = 50
|
||||||
StatusNotFound = 51
|
StatusNotFound Status = 51
|
||||||
StatusGone = 52
|
StatusGone Status = 52
|
||||||
StatusProxyRequestRefused = 53
|
StatusProxyRequestRefused Status = 53
|
||||||
StatusBadRequest = 59
|
StatusBadRequest Status = 59
|
||||||
StatusCertificateRequired = 60
|
StatusCertificateRequired Status = 60
|
||||||
StatusCertificateNotAuthorized = 61
|
StatusCertificateNotAuthorized Status = 61
|
||||||
StatusCertificateNotValid = 62
|
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.
|
// 1x becomes 10, 2x becomes 20, and so on.
|
||||||
func StatusClass(code int) int {
|
func (s Status) Class() Status {
|
||||||
return (code / 10) * 10
|
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.
|
// It returns the empty string if the status code is unknown.
|
||||||
func StatusText(code int) string {
|
func (s Status) String() string {
|
||||||
switch code {
|
switch s {
|
||||||
case StatusInput:
|
case StatusInput:
|
||||||
return "Input"
|
return "Input"
|
||||||
case StatusSensitiveInput:
|
case StatusSensitiveInput:
|
||||||
|
@ -66,7 +66,7 @@ func (t *timeoutHandler) ServeGemini(ctx context.Context, w ResponseWriter, r *R
|
|||||||
type timeoutWriter struct {
|
type timeoutWriter struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
b bytes.Buffer
|
b bytes.Buffer
|
||||||
status int
|
status Status
|
||||||
meta string
|
meta string
|
||||||
mediatype string
|
mediatype string
|
||||||
wroteHeader bool
|
wroteHeader bool
|
||||||
@ -91,7 +91,7 @@ func (w *timeoutWriter) Write(b []byte) (int, error) {
|
|||||||
return w.b.Write(b)
|
return w.b.Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *timeoutWriter) WriteHeader(status int, meta string) {
|
func (w *timeoutWriter) WriteHeader(status Status, meta string) {
|
||||||
w.mu.Lock()
|
w.mu.Lock()
|
||||||
defer w.mu.Unlock()
|
defer w.mu.Unlock()
|
||||||
if w.timedOut {
|
if w.timedOut {
|
||||||
@ -100,7 +100,7 @@ func (w *timeoutWriter) WriteHeader(status int, meta string) {
|
|||||||
w.writeHeaderLocked(status, meta)
|
w.writeHeaderLocked(status, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *timeoutWriter) writeHeaderLocked(status int, meta string) {
|
func (w *timeoutWriter) writeHeaderLocked(status Status, meta string) {
|
||||||
if w.wroteHeader {
|
if w.wroteHeader {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user