diff --git a/Context.go b/Context.go index 7afb303..46b3b8c 100644 --- a/Context.go +++ b/Context.go @@ -9,7 +9,6 @@ type Context interface { Bytes([]byte) error Error(...any) error Next() error - Redirect(int, string) error Request() Request Response() Response Status(int) Context @@ -52,14 +51,6 @@ func (ctx *context) Next() error { return ctx.server.handlers[ctx.handlerCount](ctx) } -// Redirect redirects the client to a different location -// with the specified status code. -func (ctx *context) Redirect(status int, location string) error { - ctx.response.SetStatus(status) - ctx.response.SetHeader("Location", location) - return nil -} - // Request returns the HTTP request. func (ctx *context) Request() Request { return &ctx.request diff --git a/Context_test.go b/Context_test.go index b3a6005..05bc24f 100644 --- a/Context_test.go +++ b/Context_test.go @@ -4,8 +4,8 @@ import ( "errors" "testing" - "git.urbach.dev/go/assert" - "git.urbach.dev/go/web" + "git.akyoto.dev/go/assert" + "git.akyoto.dev/go/web" ) func TestBytes(t *testing.T) { @@ -55,15 +55,3 @@ func TestErrorMultiple(t *testing.T) { assert.Equal(t, response.Status(), 401) assert.Equal(t, string(response.Body()), "") } - -func TestRedirect(t *testing.T) { - s := web.NewServer() - - s.Get("/", func(ctx web.Context) error { - return ctx.Redirect(301, "/target") - }) - - response := s.Request("GET", "/", nil, nil) - assert.Equal(t, response.Status(), 301) - assert.Equal(t, response.Header("Location"), "/target") -} diff --git a/README.md b/README.md index 149eb93..9b912f2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # web -A minimal HTTP/1.1 web server that sits behind a reverse proxy like `caddy` or `nginx` for HTTP 1/2/3 support. +A fast HTTP/1.1 web server that can sit behind a reverse proxy like `caddy` or `nginx` for HTTP 1/2/3 support. ## Features @@ -11,7 +11,7 @@ A minimal HTTP/1.1 web server that sits behind a reverse proxy like `caddy` or ` ## Installation ```shell -go get git.urbach.dev/go/web +go get git.akyoto.dev/go/web ``` ## Usage @@ -26,23 +26,12 @@ s.Get("/", func(ctx web.Context) error { // Parameter route s.Get("/blog/:post", func(ctx web.Context) error { - return ctx.String(ctx.Request().Param("post")) + return ctx.String(ctx.Get("post")) }) // Wildcard route s.Get("/images/*file", func(ctx web.Context) error { - return ctx.String(ctx.Request().Param("file")) -}) - -// Middleware -s.Use(func(ctx web.Context) error { - start := time.Now() - - defer func() { - fmt.Println(ctx.Request().Path(), time.Since(start)) - }() - - return ctx.Next() + return ctx.String(ctx.Get("file")) }) s.Run(":8080") @@ -55,7 +44,6 @@ PASS: TestBytes PASS: TestString PASS: TestError PASS: TestErrorMultiple -PASS: TestRedirect PASS: TestRequest PASS: TestRequestHeader PASS: TestRequestParam @@ -69,9 +57,7 @@ PASS: TestRun PASS: TestBadRequest PASS: TestBadRequestHeader PASS: TestBadRequestMethod -PASS: TestBadRequestPath PASS: TestBadRequestProtocol -PASS: TestConnectionClose PASS: TestEarlyClose PASS: TestUnavailablePort coverage: 100.0% of statements @@ -83,7 +69,7 @@ coverage: 100.0% of statements ## License -Please see the [license documentation](https://urbach.dev/license). +Please see the [license documentation](https://akyoto.dev/license). ## Copyright diff --git a/Request.go b/Request.go index 6c7ef3c..9ec8ef9 100644 --- a/Request.go +++ b/Request.go @@ -3,7 +3,7 @@ package web import ( "bufio" - "git.urbach.dev/go/router" + "git.akyoto.dev/go/router" ) // Request is an interface for HTTP requests. diff --git a/Request_test.go b/Request_test.go index 1e079a8..6a08fd0 100644 --- a/Request_test.go +++ b/Request_test.go @@ -4,8 +4,8 @@ import ( "fmt" "testing" - "git.urbach.dev/go/assert" - "git.urbach.dev/go/web" + "git.akyoto.dev/go/assert" + "git.akyoto.dev/go/web" ) func TestRequest(t *testing.T) { diff --git a/Response_test.go b/Response_test.go index 9028acf..dc62965 100644 --- a/Response_test.go +++ b/Response_test.go @@ -6,8 +6,8 @@ import ( "io" "testing" - "git.urbach.dev/go/assert" - "git.urbach.dev/go/web" + "git.akyoto.dev/go/assert" + "git.akyoto.dev/go/web" ) func TestWrite(t *testing.T) { diff --git a/Server.go b/Server.go index ba163a0..f987c51 100644 --- a/Server.go +++ b/Server.go @@ -13,7 +13,7 @@ import ( "sync" "syscall" - "git.urbach.dev/go/router" + "git.akyoto.dev/go/router" ) // Server is the interface for an HTTP server. @@ -121,7 +121,6 @@ func (s *server) handleConnection(conn net.Conn) { ctx = s.contextPool.Get().(*context) method string url string - close bool ) ctx.reader.Reset(conn) @@ -129,7 +128,7 @@ func (s *server) handleConnection(conn net.Conn) { defer conn.Close() defer s.contextPool.Put(ctx) - for !close { + for { // Read the HTTP request line message, err := ctx.reader.ReadString('\n') @@ -157,14 +156,7 @@ func (s *server) handleConnection(conn net.Conn) { lastSpace = len(message) - len("\r\n") } - space += 1 - - if space > lastSpace { - io.WriteString(conn, "HTTP/1.1 400 Bad Request\r\n\r\n") - return - } - - url = message[space:lastSpace] + url = message[space+1 : lastSpace] // Add headers until we meet an empty line for { @@ -184,10 +176,6 @@ func (s *server) handleConnection(conn net.Conn) { continue } - if colon > len(message)-4 { - continue - } - key := message[:colon] value := message[colon+2 : len(message)-2] @@ -195,10 +183,6 @@ func (s *server) handleConnection(conn net.Conn) { Key: key, Value: value, }) - - if value == "close" && strings.EqualFold(key, "connection") { - close = true - } } // Handle the request diff --git a/Server_test.go b/Server_test.go index f2c142b..9793aef 100644 --- a/Server_test.go +++ b/Server_test.go @@ -7,8 +7,8 @@ import ( "syscall" "testing" - "git.urbach.dev/go/assert" - "git.urbach.dev/go/web" + "git.akyoto.dev/go/assert" + "git.akyoto.dev/go/web" ) func TestPanic(t *testing.T) { @@ -77,7 +77,7 @@ func TestBadRequestHeader(t *testing.T) { assert.Nil(t, err) defer conn.Close() - _, err = io.WriteString(conn, "GET / HTTP/1.1\r\nBad\r\nBad:\r\nGood: Header\r\n\r\n") + _, err = io.WriteString(conn, "GET / HTTP/1.1\r\nBadHeader\r\nGood: Header\r\n\r\n") assert.Nil(t, err) buffer := make([]byte, len("HTTP/1.1 200")) @@ -110,27 +110,6 @@ func TestBadRequestMethod(t *testing.T) { s.Run(":8080") } -func TestBadRequestPath(t *testing.T) { - s := web.NewServer() - - go func() { - defer syscall.Kill(syscall.Getpid(), syscall.SIGTERM) - - conn, err := net.Dial("tcp", ":8080") - assert.Nil(t, err) - defer conn.Close() - - _, err = io.WriteString(conn, "GET \n") - assert.Nil(t, err) - - response, err := io.ReadAll(conn) - assert.Nil(t, err) - assert.Equal(t, string(response), "HTTP/1.1 400 Bad Request\r\n\r\n") - }() - - s.Run(":8080") -} - func TestBadRequestProtocol(t *testing.T) { s := web.NewServer() @@ -157,26 +136,6 @@ func TestBadRequestProtocol(t *testing.T) { s.Run(":8080") } -func TestConnectionClose(t *testing.T) { - s := web.NewServer() - - go func() { - defer syscall.Kill(syscall.Getpid(), syscall.SIGTERM) - - conn, err := net.Dial("tcp", ":8080") - assert.Nil(t, err) - defer conn.Close() - - _, err = io.WriteString(conn, "GET / HTTP/1.1\r\nConnection: close\r\n\r\n") - assert.Nil(t, err) - - _, err = io.ReadAll(conn) - assert.Nil(t, err) - }() - - s.Run(":8080") -} - func TestEarlyClose(t *testing.T) { s := web.NewServer() diff --git a/send/send.go b/content/content.go similarity index 97% rename from send/send.go rename to content/content.go index 9c4c2ca..2eca461 100644 --- a/send/send.go +++ b/content/content.go @@ -1,9 +1,9 @@ -package send +package content import ( "encoding/json" - "git.urbach.dev/go/web" + "git.akyoto.dev/go/web" ) // CSS sends the body with the content type set to `text/css`. diff --git a/send/send_test.go b/content/content_test.go similarity index 79% rename from send/send_test.go rename to content/content_test.go index fec22c3..5d4d2ca 100644 --- a/send/send_test.go +++ b/content/content_test.go @@ -1,42 +1,42 @@ -package send_test +package content_test import ( "testing" - "git.urbach.dev/go/assert" - "git.urbach.dev/go/web" - "git.urbach.dev/go/web/send" + "git.akyoto.dev/go/assert" + "git.akyoto.dev/go/web" + "git.akyoto.dev/go/web/content" ) func TestContentTypes(t *testing.T) { s := web.NewServer() s.Get("/css", func(ctx web.Context) error { - return send.CSS(ctx, "body{}") + return content.CSS(ctx, "body{}") }) s.Get("/csv", func(ctx web.Context) error { - return send.CSV(ctx, "ID;Name\n") + return content.CSV(ctx, "ID;Name\n") }) s.Get("/html", func(ctx web.Context) error { - return send.HTML(ctx, "") + return content.HTML(ctx, "") }) s.Get("/js", func(ctx web.Context) error { - return send.JS(ctx, "console.log(42)") + return content.JS(ctx, "console.log(42)") }) s.Get("/json", func(ctx web.Context) error { - return send.JSON(ctx, struct{ Name string }{Name: "User 1"}) + return content.JSON(ctx, struct{ Name string }{Name: "User 1"}) }) s.Get("/text", func(ctx web.Context) error { - return send.Text(ctx, "Hello") + return content.Text(ctx, "Hello") }) s.Get("/xml", func(ctx web.Context) error { - return send.XML(ctx, "") + return content.XML(ctx, "") }) tests := []struct { diff --git a/examples/hello/main.go b/examples/hello/main.go index b42db84..c9853da 100644 --- a/examples/hello/main.go +++ b/examples/hello/main.go @@ -1,7 +1,7 @@ package main import ( - "git.urbach.dev/go/web" + "git.akyoto.dev/go/web" ) func main() { diff --git a/go.mod b/go.mod index f2bf46e..a4d4a7c 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ -module git.urbach.dev/go/web +module git.akyoto.dev/go/web -go 1.24 +go 1.22 require ( - git.urbach.dev/go/assert v0.0.0-20250225153414-fc1f84f19edf - git.urbach.dev/go/router v0.0.0-20250601162231-e35d5715d1a5 + git.akyoto.dev/go/assert v0.1.3 + git.akyoto.dev/go/router v0.1.4 ) diff --git a/go.sum b/go.sum index 4c3db0c..a12e1ec 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,4 @@ -git.urbach.dev/go/assert v0.0.0-20250225153414-fc1f84f19edf h1:BQWa5GKNUsA5CSUa/+UlFWYCEVe3IDDKRbVqBLK0mAE= -git.urbach.dev/go/assert v0.0.0-20250225153414-fc1f84f19edf/go.mod h1:y9jGII9JFiF1HNIju0u87OyPCt82xKCtqnAFyEreCDo= -git.urbach.dev/go/router v0.0.0-20250601162231-e35d5715d1a5 h1:3qlZjgWbrHw4LWM4uBzOTldbpqCLJdeSgvcYK6f3xpc= -git.urbach.dev/go/router v0.0.0-20250601162231-e35d5715d1a5/go.mod h1:O+doTe0DZdT2XMsTY5pe6qUMqEEIAbwtX6Xp6EqHw34= +git.akyoto.dev/go/assert v0.1.3 h1:QwCUbmG4aZYsNk/OuRBz1zWVKmGlDUHhOnnDBfn8Qw8= +git.akyoto.dev/go/assert v0.1.3/go.mod h1:0GzMaM0eURuDwtGkJJkCsI7r2aUKr+5GmWNTFPgDocM= +git.akyoto.dev/go/router v0.1.4 h1:ZL5HPl4aNn4QKihf3VVs0Mm9R6ZGn2StAHGRQxjEbws= +git.akyoto.dev/go/router v0.1.4/go.mod h1:rbHbkLJlQOafuOuvBalO3O8E0JtMFPT3zzTKX3h9T08=