Skip to content

Commit

Permalink
feat: Add request abstraction and test proper parsing. Ensure only su…
Browse files Browse the repository at this point in the history
…pported methods are allowed to be sent
  • Loading branch information
randuck-dev committed Nov 5, 2023
1 parent 1a94ef9 commit dcb27ab
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 7 deletions.
35 changes: 32 additions & 3 deletions internal/http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package http
import (
"bufio"
"errors"
"fmt"
"io"
"log/slog"
"net"
"net/textproto"
"slices"
"sync"
)

Expand All @@ -22,6 +22,8 @@ var ErrConnectionIsNil = errors.New("expected connection to be set, was nil")

var ErrInvalidHeaderFormat = errors.New("invalid header format detected. Expected format: \"key: value\"")

var ErrMethodNotImplemented = errors.New("the implementation does not support the method")

type Client interface {
Get(string) (Response, error)
}
Expand All @@ -41,8 +43,14 @@ type HttpClient struct {
net.Conn
}

func (hc *HttpClient) Get(uri string) (Response, error) {
written, err := hc.Write([]byte(fmt.Sprintf("GET %s HTTP/1.1\nHost: localhost \r\n\r\n", uri)))
var supported_methods = []string{"GET", "HEAD"}

func (hc *HttpClient) Do(request Request) (Response, error) {
if !slices.Contains(supported_methods, request.Method) {
return Response{}, ErrMethodNotImplemented
}

written, err := hc.Write([]byte(request.ToRaw()))
if err != nil {
slog.Error("Error while writing to connection", "err", err)
return Response{}, err
Expand All @@ -52,6 +60,27 @@ func (hc *HttpClient) Get(uri string) (Response, error) {
return Response{}, nil
}

func (hc *HttpClient) Get(uri string) (Response, error) {
request := Request{
Version: HTTP11,
Method: "GET",
Uri: uri,
}

return hc.Do(request)
}

func (hc *HttpClient) Head(uri string) (Response, error) {
// TODO: Is not allowed to have a body
request := Request{
Version: HTTP11,
Method: "HEAD",
Uri: uri,
}

return hc.Do(request)
}

func Raw_http_parsing_docker_socket(docker_socket string, wg *sync.WaitGroup) {

socket, err := dial(docker_socket)
Expand Down
47 changes: 43 additions & 4 deletions internal/http/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
)

func TestGet(t *testing.T) {

server, client := net.Pipe()
http_client := HttpClient{client}

Expand All @@ -27,16 +26,56 @@ func TestGet(t *testing.T) {
t.Errorf("Unexpected error %s", err)
}

expected := "GET xyz HTTP/1.1\nHost: localhost \r\n\r\n"
expected := "GET xyz HTTP/1.1\nHost: localhost\r\n\r\n"

if string(res) != expected {
t.Errorf("got %s want %s", string(res), expected)
}
}

func TestHead(t *testing.T) {
server, client := net.Pipe()
http_client := HttpClient{client}

go func() {
defer client.Close()
_, err := http_client.Head("xyz")

if err != nil {
t.Errorf("Unexpected error %s", err)
}
}()

res, err := io.ReadAll(server)

if err != nil {
t.Errorf("Unexpected error %s", err)
}

expected := "HEAD xyz HTTP/1.1\nHost: localhost\r\n\r\n"

if string(res) != expected {
t.Errorf("got %s want %s", string(res), expected)
}
}

func TestDo(t *testing.T) {
request := Request{
Method: "INVALID",
}

c := HttpClient{}

_, err := c.Do(request)

if err != ErrMethodNotImplemented {
t.Errorf("got %s want %s", err, ErrMethodNotImplemented)
}
}

func TestParseResponse(t *testing.T) {
t.Run("successfull response", func(t *testing.T) {
responseRaw := "HTTP/1.1 200 OK\nHost: localhost \r\n\r\n"
responseRaw := "HTTP/1.1 200 OK\nHost: localhost\r\n\r\n"

resp, err := parseResponse(strings.NewReader(responseRaw))
if err != nil {
Expand Down Expand Up @@ -66,7 +105,7 @@ func TestParseResponse(t *testing.T) {
})

t.Run("Failed response: UnsupportedHttpVersion", func(t *testing.T) {
responseRaw := "HTTP/2.0 200 OK\nHost: localhost \r\n\r\n"
responseRaw := "HTTP/2.0 200 OK\nHost: localhost\r\n\r\n"

_, err := parseResponse(strings.NewReader(responseRaw))
if err != ErrUnsupportedHTTPVersion {
Expand Down
16 changes: 16 additions & 0 deletions internal/http/request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package http

import "fmt"

type Request struct {
Method string
Uri string
Version string

requestHeader string
}

func (r Request) ToRaw() string {
host := "Host: localhost"
return fmt.Sprintf("%s %s %s\n%s%s", r.Method, r.Uri, r.Version, host, EndOfMessage)
}
3 changes: 3 additions & 0 deletions internal/http/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package http

var EndOfMessage = "\r\n\r\n"

0 comments on commit dcb27ab

Please sign in to comment.