Added request headers
This commit is contained in:
parent
b6c208c75b
commit
c3bb8336a3
@ -64,4 +64,4 @@ Please see the [license documentation](https://akyoto.dev/license).
|
||||
|
||||
## Copyright
|
||||
|
||||
© 2023 Eduard Urbach
|
||||
© 2024 Eduard Urbach
|
||||
|
14
Request.go
14
Request.go
@ -4,6 +4,7 @@ import "git.akyoto.dev/go/router"
|
||||
|
||||
// Request is an interface for HTTP requests.
|
||||
type Request interface {
|
||||
Header(string) string
|
||||
Host() string
|
||||
Method() string
|
||||
Path() string
|
||||
@ -18,9 +19,22 @@ type request struct {
|
||||
method string
|
||||
path string
|
||||
query string
|
||||
headers []header
|
||||
body []byte
|
||||
params []router.Parameter
|
||||
}
|
||||
|
||||
// Header returns the header value for the given key.
|
||||
func (req *request) Header(key string) string {
|
||||
for _, header := range req.headers {
|
||||
if header.Key == key {
|
||||
return header.Value
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// Host returns the requested host.
|
||||
func (req *request) Host() string {
|
||||
return req.host
|
||||
|
@ -3,8 +3,6 @@ package web
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"git.akyoto.dev/go/router"
|
||||
)
|
||||
|
||||
// Response is the interface for an HTTP response.
|
||||
@ -22,8 +20,8 @@ type Response interface {
|
||||
// response represents the HTTP response used in the given context.
|
||||
type response struct {
|
||||
body []byte
|
||||
headers []header
|
||||
status uint16
|
||||
headers []router.Parameter
|
||||
}
|
||||
|
||||
// Body returns the response body.
|
||||
@ -51,7 +49,7 @@ func (res *response) SetHeader(key string, value string) {
|
||||
}
|
||||
}
|
||||
|
||||
res.headers = append(res.headers, router.Parameter{Key: key, Value: value})
|
||||
res.headers = append(res.headers, header{Key: key, Value: value})
|
||||
}
|
||||
|
||||
// SetBody replaces the response body with the new contents.
|
||||
|
82
Server.go
82
Server.go
@ -121,6 +121,14 @@ func (s *server) handleConnection(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
reader := bufio.NewReader(conn)
|
||||
|
||||
var (
|
||||
ctx *context
|
||||
method string
|
||||
url string
|
||||
)
|
||||
|
||||
for {
|
||||
// Search for a line containing HTTP method and url
|
||||
for {
|
||||
message, err := reader.ReadString('\n')
|
||||
|
||||
@ -134,7 +142,7 @@ func (s *server) handleConnection(conn net.Conn) {
|
||||
continue
|
||||
}
|
||||
|
||||
method := message[:space]
|
||||
method = message[:space]
|
||||
|
||||
if method != "GET" {
|
||||
continue
|
||||
@ -146,11 +154,44 @@ func (s *server) handleConnection(conn net.Conn) {
|
||||
lastSpace = len(message)
|
||||
}
|
||||
|
||||
url := message[space+1 : lastSpace]
|
||||
ctx = s.pool.Get().(*context)
|
||||
url = message[space+1 : lastSpace]
|
||||
break
|
||||
}
|
||||
|
||||
ctx := s.pool.Get().(*context)
|
||||
// Add headers until we meet an empty line
|
||||
for {
|
||||
message, err := reader.ReadString('\n')
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if message == "\r\n" {
|
||||
break
|
||||
}
|
||||
|
||||
colon := strings.IndexByte(message, ':')
|
||||
|
||||
if colon <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
key := message[:colon]
|
||||
value := message[colon+2 : len(message)-2]
|
||||
|
||||
ctx.request.headers = append(ctx.request.headers, header{
|
||||
Key: key,
|
||||
Value: value,
|
||||
})
|
||||
}
|
||||
|
||||
// Handle the request
|
||||
s.handleRequest(ctx, method, url, conn)
|
||||
ctx.body = ctx.body[:0]
|
||||
ctx.request.headers = ctx.request.headers[:0]
|
||||
ctx.request.body = ctx.request.body[:0]
|
||||
ctx.response.headers = ctx.response.headers[:0]
|
||||
ctx.response.body = ctx.response.body[:0]
|
||||
ctx.params = ctx.params[:0]
|
||||
ctx.handlerCount = 0
|
||||
ctx.status = 200
|
||||
@ -169,7 +210,7 @@ func (s *server) handleRequest(ctx *context, method string, url string, writer i
|
||||
s.errorHandler(ctx, err)
|
||||
}
|
||||
|
||||
fmt.Fprintf(writer, "HTTP/1.1 %d %s\r\nContent-Length: %d\r\n%s\r\n%s", ctx.status, "OK", len(ctx.body), ctx.response.headerText(), ctx.body)
|
||||
fmt.Fprintf(writer, "HTTP/1.1 %d %s\r\nContent-Length: %d\r\n%s\r\n%s", ctx.status, "OK", len(ctx.response.body), ctx.response.headerText(), ctx.response.body)
|
||||
}
|
||||
|
||||
// newContext allocates a new context with the default state.
|
||||
@ -177,39 +218,14 @@ func (s *server) newContext() *context {
|
||||
return &context{
|
||||
server: s,
|
||||
request: request{
|
||||
body: make([]byte, 0),
|
||||
headers: make([]header, 0, 8),
|
||||
params: make([]router.Parameter, 0, 8),
|
||||
},
|
||||
response: response{
|
||||
body: make([]byte, 0, 1024),
|
||||
headers: make([]header, 0, 8),
|
||||
status: 200,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// parseURL parses a URL and returns the scheme, host, path and query.
|
||||
func parseURL(url string) (scheme string, host string, path string, query string) {
|
||||
schemePos := strings.Index(url, "://")
|
||||
|
||||
if schemePos != -1 {
|
||||
scheme = url[:schemePos]
|
||||
url = url[schemePos+len("://"):]
|
||||
}
|
||||
|
||||
pathPos := strings.IndexByte(url, '/')
|
||||
|
||||
if pathPos != -1 {
|
||||
host = url[:pathPos]
|
||||
url = url[pathPos:]
|
||||
}
|
||||
|
||||
queryPos := strings.IndexByte(url, '?')
|
||||
|
||||
if queryPos != -1 {
|
||||
path = url[:queryPos]
|
||||
query = url[queryPos+1:]
|
||||
return
|
||||
}
|
||||
|
||||
path = url
|
||||
return
|
||||
}
|
||||
|
7
header.go
Normal file
7
header.go
Normal file
@ -0,0 +1,7 @@
|
||||
package web
|
||||
|
||||
// header is used to store HTTP headers.
|
||||
type header struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
31
parseURL.go
Normal file
31
parseURL.go
Normal file
@ -0,0 +1,31 @@
|
||||
package web
|
||||
|
||||
import "strings"
|
||||
|
||||
// parseURL parses a URL and returns the scheme, host, path and query.
|
||||
func parseURL(url string) (scheme string, host string, path string, query string) {
|
||||
schemePos := strings.Index(url, "://")
|
||||
|
||||
if schemePos != -1 {
|
||||
scheme = url[:schemePos]
|
||||
url = url[schemePos+len("://"):]
|
||||
}
|
||||
|
||||
pathPos := strings.IndexByte(url, '/')
|
||||
|
||||
if pathPos != -1 {
|
||||
host = url[:pathPos]
|
||||
url = url[pathPos:]
|
||||
}
|
||||
|
||||
queryPos := strings.IndexByte(url, '?')
|
||||
|
||||
if queryPos != -1 {
|
||||
path = url[:queryPos]
|
||||
query = url[queryPos+1:]
|
||||
return
|
||||
}
|
||||
|
||||
path = url
|
||||
return
|
||||
}
|
Loading…
Reference in New Issue
Block a user