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
|
## 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.
|
// Request is an interface for HTTP requests.
|
||||||
type Request interface {
|
type Request interface {
|
||||||
|
Header(string) string
|
||||||
Host() string
|
Host() string
|
||||||
Method() string
|
Method() string
|
||||||
Path() string
|
Path() string
|
||||||
@ -18,9 +19,22 @@ type request struct {
|
|||||||
method string
|
method string
|
||||||
path string
|
path string
|
||||||
query string
|
query string
|
||||||
|
headers []header
|
||||||
|
body []byte
|
||||||
params []router.Parameter
|
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.
|
// Host returns the requested host.
|
||||||
func (req *request) Host() string {
|
func (req *request) Host() string {
|
||||||
return req.host
|
return req.host
|
||||||
|
@ -3,8 +3,6 @@ package web
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.akyoto.dev/go/router"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Response is the interface for an HTTP response.
|
// 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.
|
// response represents the HTTP response used in the given context.
|
||||||
type response struct {
|
type response struct {
|
||||||
body []byte
|
body []byte
|
||||||
|
headers []header
|
||||||
status uint16
|
status uint16
|
||||||
headers []router.Parameter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Body returns the response body.
|
// 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.
|
// 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()
|
defer conn.Close()
|
||||||
reader := bufio.NewReader(conn)
|
reader := bufio.NewReader(conn)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ctx *context
|
||||||
|
method string
|
||||||
|
url string
|
||||||
|
)
|
||||||
|
|
||||||
|
for {
|
||||||
|
// Search for a line containing HTTP method and url
|
||||||
for {
|
for {
|
||||||
message, err := reader.ReadString('\n')
|
message, err := reader.ReadString('\n')
|
||||||
|
|
||||||
@ -134,7 +142,7 @@ func (s *server) handleConnection(conn net.Conn) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
method := message[:space]
|
method = message[:space]
|
||||||
|
|
||||||
if method != "GET" {
|
if method != "GET" {
|
||||||
continue
|
continue
|
||||||
@ -146,11 +154,44 @@ func (s *server) handleConnection(conn net.Conn) {
|
|||||||
lastSpace = len(message)
|
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)
|
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.params = ctx.params[:0]
|
||||||
ctx.handlerCount = 0
|
ctx.handlerCount = 0
|
||||||
ctx.status = 200
|
ctx.status = 200
|
||||||
@ -169,7 +210,7 @@ func (s *server) handleRequest(ctx *context, method string, url string, writer i
|
|||||||
s.errorHandler(ctx, err)
|
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.
|
// newContext allocates a new context with the default state.
|
||||||
@ -177,39 +218,14 @@ func (s *server) newContext() *context {
|
|||||||
return &context{
|
return &context{
|
||||||
server: s,
|
server: s,
|
||||||
request: request{
|
request: request{
|
||||||
|
body: make([]byte, 0),
|
||||||
|
headers: make([]header, 0, 8),
|
||||||
params: make([]router.Parameter, 0, 8),
|
params: make([]router.Parameter, 0, 8),
|
||||||
},
|
},
|
||||||
response: response{
|
response: response{
|
||||||
body: make([]byte, 0, 1024),
|
body: make([]byte, 0, 1024),
|
||||||
|
headers: make([]header, 0, 8),
|
||||||
status: 200,
|
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