This commit is contained in:
Sky Johnson 2025-03-05 12:23:12 -06:00
parent 3bc0920f09
commit 9295e5445e
5 changed files with 65 additions and 25 deletions

View File

@ -53,7 +53,7 @@ func (ctx *context) Next() error {
// Redirects the client to a different location with the specified status code. // Redirects the client to a different location with the specified status code.
func (ctx *context) Redirect(status int, location string) error { func (ctx *context) Redirect(status int, location string) error {
ctx.response.SetStatus(status) ctx.response.SetStatus(status)
ctx.response.SetHeader("Location", location) ctx.response.SetHeader(HeaderLocation, location)
return nil return nil
} }

View File

@ -1,6 +1,63 @@
package web package web
// Header represents an HTTP header with key and value
type Header struct { type Header struct {
Key string Key string
Value string Value string
} }
// Common HTTP header keys
const (
HeaderContentType = "Content-Type"
HeaderContentLength = "Content-Length"
HeaderHost = "Host"
HeaderAccept = "Accept"
HeaderUserAgent = "User-Agent"
HeaderAcceptEncoding = "Accept-Encoding"
HeaderAcceptLanguage = "Accept-Language"
HeaderConnection = "Connection"
HeaderCookie = "Cookie"
HeaderSetCookie = "Set-Cookie"
HeaderLocation = "Location"
HeaderAuthorization = "Authorization"
HeaderCacheControl = "Cache-Control"
HeaderOrigin = "Origin"
HeaderReferer = "Referer"
HeaderTransferEncoding = "Transfer-Encoding"
)
// Pre-allocated common headers
var (
// Content type headers
HeaderContentTypeJSON = Header{Key: HeaderContentType, Value: "application/json"}
HeaderContentTypeHTML = Header{Key: HeaderContentType, Value: "text/html"}
HeaderContentTypePlain = Header{Key: HeaderContentType, Value: "text/plain"}
HeaderContentTypeXML = Header{Key: HeaderContentType, Value: "application/xml"}
HeaderContentTypeForm = Header{Key: HeaderContentType, Value: "application/x-www-form-urlencoded"}
HeaderContentTypeMultipart = Header{Key: HeaderContentType, Value: "multipart/form-data"}
// Connection headers
HeaderConnectionClose = Header{Key: HeaderConnection, Value: "close"}
HeaderConnectionKeepAlive = Header{Key: HeaderConnection, Value: "keep-alive"}
)
// FindHeader looks for a header by key in a slice of headers
func FindHeader(headers []Header, key string) (string, bool) {
for _, h := range headers {
if h.Key == key {
return h.Value, true
}
}
return "", false
}
// SetHeader sets a header value in a slice of headers
func SetHeader(headers *[]Header, key string, value string) {
for i, h := range *headers {
if h.Key == key {
(*headers)[i].Value = value
return
}
}
*headers = append(*headers, Header{Key: key, Value: value})
}

View File

@ -32,13 +32,8 @@ type request struct {
// Returns the header value for the given key. // Returns the header value for the given key.
func (req *request) Header(key string) string { func (req *request) Header(key string) string {
for _, header := range req.headers { value, _ := FindHeader(req.headers, key)
if header.Key == key { return value
return header.Value
}
}
return ""
} }
// Returns the requested host. // Returns the requested host.

View File

@ -28,25 +28,13 @@ func (res *response) Body() []byte {
// Returns the header value for the given key. // Returns the header value for the given key.
func (res *response) Header(key string) string { func (res *response) Header(key string) string {
for _, header := range res.headers { value, _ := FindHeader(res.headers, key)
if header.Key == key { return value
return header.Value
}
}
return ""
} }
// Sets the header value for the given key. // Sets the header value for the given key.
func (res *response) SetHeader(key string, value string) { func (res *response) SetHeader(key string, value string) {
for i, header := range res.headers { SetHeader(&res.headers, key, value)
if header.Key == key {
res.headers[i].Value = value
return
}
}
res.headers = append(res.headers, Header{Key: key, Value: value})
} }
// Replaces the response body with the new contents. // Replaces the response body with the new contents.

View File

@ -210,7 +210,7 @@ func (s *server) handleConnection(conn net.Conn) {
} }
// Read the body, if any // Read the body, if any
if contentLength := ctx.request.Header("Content-Length"); contentLength != "" { if contentLength := ctx.request.Header(HeaderContentLength); contentLength != "" {
length, _ := strconv.Atoi(contentLength) length, _ := strconv.Atoi(contentLength)
ctx.request.body = make([]byte, length) ctx.request.body = make([]byte, length)
ctx.reader.Read(ctx.request.body) ctx.reader.Read(ctx.request.body)
@ -244,7 +244,7 @@ func (s *server) handleRequest(ctx *context, method string, url string, writer i
tmp := bytes.Buffer{} tmp := bytes.Buffer{}
tmp.WriteString("HTTP/1.1 ") tmp.WriteString("HTTP/1.1 ")
tmp.WriteString(strconv.Itoa(int(ctx.status))) tmp.WriteString(strconv.Itoa(int(ctx.status)))
tmp.WriteString("\r\nContent-Length: ") tmp.WriteString("\r\n" + HeaderContentLength + ": ")
tmp.WriteString(strconv.Itoa(len(ctx.response.body))) tmp.WriteString(strconv.Itoa(len(ctx.response.body)))
tmp.WriteString("\r\n") tmp.WriteString("\r\n")