This commit is contained in:
Niccolo Borgioli 2024-05-26 02:04:59 +02:00
parent 899f7828a5
commit de8a68ac05
No known key found for this signature in database
GPG Key ID: 4897ACD13A65977C
6 changed files with 44 additions and 45 deletions

View File

@ -5,7 +5,7 @@ import (
"compress/gzip"
)
func gzipCompress(data []byte) *bytes.Buffer {
func gzipCompress(data []byte) []byte {
buf := &bytes.Buffer{}
gz := gzip.NewWriter(buf)
if _, err := gz.Write(data); err != nil {
@ -14,7 +14,5 @@ func gzipCompress(data []byte) *bytes.Buffer {
if err := gz.Close(); err != nil {
panic(err)
}
// fmt.Println("Hexadecimal Representation:", hex.EncodeToString(buf.Bytes()))
return buf
return buf.Bytes()
}

View File

@ -9,8 +9,8 @@ import (
var DIR string = ""
func getFilepath(filename string) string {
// Set the DIR if not already set
if DIR == "" {
if len(os.Args) != 3 {
log.Fatal("Not enough args")
}

View File

@ -13,10 +13,6 @@ const (
HTTPDelimiter = "\r\n"
)
// type Header struct {
// Name string
// Value string
// }
type Request struct {
Method string
Path string
@ -64,37 +60,44 @@ type Routes struct {
}
func Respond(conn net.Conn, req Request, res Response) {
// Create headers if not existent
if res.Headers == nil {
res.Headers = make(map[string]string)
}
// isGzip := false
isGzip := strings.Contains(req.Headers["Accept-Encoding"], "gzip")
// if isGzip {
// res.Headers["Content-Encoding"] = "gzip"
// }
// Base response line
fmt.Fprintf(conn, "%s %d %s%s", res.Version, res.Code.Code, res.Code.Message, HTTPDelimiter)
var body []byte
if res.Body != "" {
body = []byte(res.Body)
} else {
body = res.BodyRaw
}
if isGzip && len(body) > 0 {
res.Headers["Content-Encoding"] = "gzip"
body = gzipCompress(body).Bytes()
}
bodySize := len(body)
// Check if gzip is accepted and encode the body
isGzip := strings.Contains(req.Headers["Accept-Encoding"], "gzip")
if isGzip && bodySize > 0 {
body = gzipCompress(body)
bodySize = len(body)
res.Headers["Content-Encoding"] = "gzip"
}
// Set the size of the content
if bodySize > 0 {
res.Headers["Content-Length"] = strconv.Itoa(bodySize)
}
// Write headers
for header, value := range res.Headers {
fmt.Fprintf(conn, "%s: %s%s", header, value, HTTPDelimiter)
}
// Delimiter for the body, always present
fmt.Fprint(conn, HTTPDelimiter)
// Write body if available
if bodySize > 0 {
conn.Write(body)
}
@ -112,6 +115,7 @@ func parseRequest(conn net.Conn) (Request, bool) {
request := Request{Headers: map[string]string{}}
isBody := false
for i, part := range parts {
// The first part is always the basic information
if i == 0 {
head := strings.Split(part, " ")
if len(head) != 3 {
@ -123,6 +127,7 @@ func parseRequest(conn net.Conn) (Request, bool) {
continue
}
// Body
if isBody {
request.Body = part
break
@ -130,6 +135,7 @@ func parseRequest(conn net.Conn) (Request, bool) {
// Headers
if part == "" {
// If the header is "empty" it means that we have arrived at the body, and we'll skip to it
isBody = true
continue
}

View File

@ -43,6 +43,7 @@ var routes = Routes{
},
},
// Read file
{
regex: regexp.MustCompile(`^/files/([A-Za-z0-9_\-.]+)`),
method: "GET",
@ -60,6 +61,7 @@ var routes = Routes{
},
},
// Write file
{
regex: regexp.MustCompile(`^/files/([A-Za-z0-9_\-.]+)`),
method: "POST",

View File

@ -6,17 +6,6 @@ import (
"os"
)
// type Handler = func(req Request, res Response)
// type Middleware = func(next Handler) Handler
// var m Middleware = func(next Handler) Handler {
// return func(req Request, res Response) {
// fmt.Println("Start")
// next(req, res)
// fmt.Println("End")
// }
// }
func handleConnection(conn net.Conn, routes Routes) {
defer conn.Close()
@ -28,6 +17,7 @@ func handleConnection(conn net.Conn, routes Routes) {
fmt.Println(req)
// Loop over the available routes. First string, then regexp
for _, route := range routes.stringRoutes {
if req.Path == route.path && req.Method == route.method {
Respond(conn, req, route.handler(req))
@ -45,12 +35,11 @@ func handleConnection(conn net.Conn, routes Routes) {
}
}
// Catch all 404
Respond(conn, req, Response{Version: req.Version, Code: NotFound})
}
func main() {
fmt.Println("Logs from your program will appear here!")
l, err := net.Listen("tcp", "0.0.0.0:4221")
if err != nil {
fmt.Println("Failed to bind to port 4221")

View File

@ -38,8 +38,11 @@ func checkResponse(t *testing.T, res *http.Response, expected Expected) {
t.Errorf(`Expected body to be "%s" but got "%s"`, expected.body, body)
}
log.Println("HEADERS", res.Header)
for header, value := range expected.headers {
if actual := res.Header[header][0]; actual != value {
if res.Header[header] == nil {
t.Errorf(`Expected "%s" header to be present`, header)
} else if actual := res.Header[header][0]; actual != value {
t.Errorf(`Expected "%s" header to be "%s" but got "%s"`, header, value, actual)
}
}
@ -64,23 +67,24 @@ func TestEcho(t *testing.T) {
}})
}
// func TestEchoGzip(t *testing.T) {
// input := "abc"
// req, _ := http.NewRequest("GET", fmt.Sprintf("http://localhost:4221/echo/%s", input), nil)
// req.Header.Set("Accept-Encoding", "gzip")
// client := &http.Client{}
// res, _ := client.Do(req)
func TestEchoGzip(t *testing.T) {
input := "abc"
req, _ := http.NewRequest("GET", fmt.Sprintf("http://localhost:4221/echo/%s", input), nil)
req.Header.Set("Accept-Encoding", "gzip")
client := &http.Client{}
res, _ := client.Do(req)
// checkResponse(t, res, Expected{status: 200, body: input, headers: map[string]string{
// "Content-Length": strconv.Itoa(len(input)),
// "Content-Type": "text/plain",
// "Content-Encoding": "gzip",
// }})
// }
checkResponse(t, res, Expected{status: 200, body: input, headers: map[string]string{
"Content-Length": "27", // Size of gzip "abc"
"Content-Type": "text/plain",
"Content-Encoding": "gzip",
}})
}
func TestUserAgent(t *testing.T) {
input := "CodeCrafters/1.0"
req, _ := http.NewRequest("GET", "http://localhost:4221/user-agent", nil)
req.Header.Del("")
req.Header.Set("User-Agent", input)
client := &http.Client{}
res, _ := client.Do(req)