158 lines
3.7 KiB
Go
Raw Normal View History

2023-07-18 19:48:38 +00:00
package server
2023-07-18 16:02:57 +00:00
import (
2023-07-21 21:23:49 +00:00
"errors"
2023-07-19 11:01:51 +00:00
"io"
2023-07-18 16:02:57 +00:00
"net/http"
2023-07-19 11:01:51 +00:00
"unsafe"
2023-07-18 16:02:57 +00:00
)
// maxParams defines the maximum number of parameters per route.
const maxParams = 16
// Context represents the interface for a request & response context.
type Context interface {
Bytes([]byte) error
2024-03-13 15:57:36 +00:00
Error(messages ...any) error
2023-07-22 09:48:35 +00:00
Get(param string) string
2024-03-13 19:18:01 +00:00
Header(key string, value string)
Host() string
Method() string
Next() error
Path() string
Protocol() string
2023-07-19 11:01:51 +00:00
Reader(io.Reader) error
2024-03-13 19:18:01 +00:00
RequestHeader(key string) string
ResponseHeader(key string) string
2024-03-14 11:52:03 +00:00
Scheme() string
2024-03-13 15:57:36 +00:00
Status(status int) Context
2023-07-19 11:01:51 +00:00
String(string) error
2024-03-13 21:49:57 +00:00
Write([]byte) (int, error)
2024-03-14 11:52:03 +00:00
WriteString(string) (int, error)
2023-07-18 16:02:57 +00:00
}
2024-03-12 21:31:45 +00:00
// ctx represents a request & response context.
type ctx struct {
2024-03-13 19:18:01 +00:00
request *http.Request
response http.ResponseWriter
2024-03-14 11:52:03 +00:00
server *server
2024-03-13 19:18:01 +00:00
paramNames [maxParams]string
paramValues [maxParams]string
paramCount int
handlerCount int
2023-07-18 16:02:57 +00:00
}
// Bytes responds with a raw byte slice.
2024-03-12 21:31:45 +00:00
func (ctx *ctx) Bytes(body []byte) error {
2023-07-18 16:02:57 +00:00
_, err := ctx.response.Write(body)
return err
}
// Error is used for sending error messages to the client.
2024-03-13 15:57:36 +00:00
func (ctx *ctx) Error(messages ...any) error {
2023-07-21 21:23:49 +00:00
var combined []error
for _, msg := range messages {
switch err := msg.(type) {
case error:
combined = append(combined, err)
case string:
combined = append(combined, errors.New(err))
}
}
return errors.Join(combined...)
2023-07-18 16:02:57 +00:00
}
2023-07-22 09:48:35 +00:00
// Get retrieves a parameter.
2024-03-12 21:31:45 +00:00
func (ctx *ctx) Get(param string) string {
2024-03-14 11:52:03 +00:00
for i := range ctx.paramCount {
2023-07-22 09:48:35 +00:00
if ctx.paramNames[i] == param {
return ctx.paramValues[i]
}
}
return ""
}
2024-03-13 19:18:01 +00:00
// Next executes the next handler in the middleware chain.
func (ctx *ctx) Next() error {
ctx.handlerCount++
return ctx.server.handlers[ctx.handlerCount](ctx)
}
// RequestHeader returns the request header value for the given key.
func (ctx *ctx) RequestHeader(key string) string {
return ctx.request.Header.Get(key)
}
// ResponseHeader returns the response header value for the given key.
func (ctx *ctx) ResponseHeader(key string) string {
return ctx.response.Header().Get(key)
}
// Header sets the header value for the given key.
func (ctx *ctx) Header(key string, value string) {
ctx.response.Header().Set(key, value)
2023-07-19 11:01:51 +00:00
}
2024-03-13 19:18:01 +00:00
// Method returns the request method.
func (ctx *ctx) Method() string {
return ctx.request.Method
2023-07-22 10:32:52 +00:00
}
2024-03-13 19:18:01 +00:00
// Protocol returns the request protocol.
func (ctx *ctx) Protocol() string {
return ctx.request.Proto
}
// Host returns the requested host.
func (ctx *ctx) Host() string {
return ctx.request.Host
}
// Path returns the requested path.
func (ctx *ctx) Path() string {
return ctx.request.URL.Path
}
// Reader sends the contents of the io.Reader without creating an in-memory copy.
func (ctx *ctx) Reader(reader io.Reader) error {
_, err := io.Copy(ctx.response, reader)
return err
2023-07-22 10:32:52 +00:00
}
2024-03-14 11:52:03 +00:00
// Scheme returns either `http` or `https`.
func (ctx *ctx) Scheme() string {
return ctx.request.URL.Scheme
}
2024-03-13 15:57:36 +00:00
// Status sets the HTTP status of the response.
func (ctx *ctx) Status(status int) Context {
ctx.response.WriteHeader(status)
return ctx
}
2023-07-19 11:01:51 +00:00
// String responds with the given string.
2024-03-12 21:31:45 +00:00
func (ctx *ctx) String(body string) error {
2023-07-19 11:01:51 +00:00
slice := unsafe.Slice(unsafe.StringData(body), len(body))
return ctx.Bytes(slice)
}
2024-03-13 21:49:57 +00:00
// Write implements the io.Writer interface.
func (ctx *ctx) Write(body []byte) (int, error) {
return ctx.response.Write(body)
}
2024-03-14 11:52:03 +00:00
// WriteString implements the io.StringWriter interface.
func (ctx *ctx) WriteString(body string) (int, error) {
return ctx.response.(io.StringWriter).WriteString(body)
}
2023-07-18 16:02:57 +00:00
// addParameter adds a new parameter to the context.
2024-03-12 21:31:45 +00:00
func (ctx *ctx) addParameter(name string, value string) {
2023-07-18 16:02:57 +00:00
ctx.paramNames[ctx.paramCount] = name
ctx.paramValues[ctx.paramCount] = value
ctx.paramCount++
}