Initial commit

This commit is contained in:
2026-04-04 21:27:36 +02:00
commit f21c9cf919
13 changed files with 920 additions and 0 deletions

145
cmd/httpserver/main.go Normal file
View File

@@ -0,0 +1,145 @@
package main
import (
"crypto/sha256"
"fmt"
"net/http"
"log"
"os"
"os/signal"
"strings"
"syscall"
"httpfromtcp/internal/headers"
"httpfromtcp/internal/server"
"httpfromtcp/internal/request"
"httpfromtcp/internal/response"
)
const port = 42069
func respond200() []byte{
return []byte(`
<html>
<head>
<title>200 OK</title>
</head>
<body>
<h1>Success!</h1>
<p>Your request was an absolute banger.</p>
</body>
</html>
`)
}
func respond400() []byte{
return []byte(`
<html>
<head>
<title>400 Bad Request</title>
</head>
<body>
<h1>Bad Request</h1>
<p>Your request honestly kinda sucked.</p>
</body>
</html>
`)
}
func respond500() []byte{
return []byte(`
<html>
<head>
<title>500 Internal Server Error</title>
</head>
<body>
<h1>Internal Server Error</h1>
<p>Okay, you know what? This one is on me.</p>
</body>
</html>
`)
}
func toStr(bytes []byte) string{
out := ""
for _,b := range bytes {
out += fmt.Sprintf("%02x",b)
}
return out
}
func main() {
s, err := server.Serve(port, func(w *response.Writer, req *request.Request){
h := response.GetDefaultHeaders(0)
body := respond200()
status := response.StatusOK
if req.RequestLine.RequestTarget == "/yourproblem"{
body = respond400()
status = response.StatusBadRequest
}else if req.RequestLine.RequestTarget == "/myproblem"{
body = respond500()
status = response.StatusInternalServerError
}else if req.RequestLine.RequestTarget == "/video"{
f, _ := os.ReadFile("assets/vim.mp4")
h.Replace("content-type","video/mp4")
h.Replace("content-length", fmt.Sprintf("%d",len(f)))
w.WriteStatusLine(response.StatusOK)
w.WriteHeaders(*h)
w.WriteBody(f)
}else if strings.HasPrefix(req.RequestLine.RequestTarget, "/httpbin/"){
target := req.RequestLine.RequestTarget
res,err := http.Get("https://httpbin.org/" +target[len("/httpbin/"):])
if err != nil{
body = respond500()
status = response.StatusInternalServerError
}else {
w.WriteStatusLine(response.StatusOK)
h.Delete("Content-length")
h.Set("Transfer-Encoding","chunked")
h.Replace("Content-Type","text/plain")
h.Set("Trailer","X-Content-SHA256")
h.Set("Trailer","X-Content-Length")
w.WriteHeaders(*h)
fullBody := []byte{}
for {
data := make([]byte,32)
n,err := res.Body.Read(data)
if err != nil {
break
}
fullBody = append(fullBody, data[:n]...)
w.WriteBody([]byte(fmt.Sprintf("%x\r\n",n)))
w.WriteBody(data[:n])
w.WriteBody([]byte("\r\n"))
}
w.WriteBody([]byte("0\r\n"))
trailers := headers.NewHeaders()
out := sha256.Sum256(fullBody)
trailers.Set("X-Content-SHA256",toStr(out[:]))
trailers.Set("X-Content-Length",fmt.Sprintf("%d",len(fullBody)))
w.WriteHeaders(*trailers)
return
}
}
h.Replace("Content-length",fmt.Sprintf("%d",len(body)))
h.Replace("Content-Type","text/html")
w.WriteStatusLine(status)
w.WriteHeaders(*h)
w.WriteBody(body)
})
if err != nil {
log.Fatalf("Error starting server: %v", err)
}
defer s.Close()
log.Println("Server started on port", port)
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
<-sigChan
log.Println("Server gracefully stopped")
}

41
cmd/tcplistener/main.go Normal file
View File

@@ -0,0 +1,41 @@
package main
import (
"fmt"
"log"
"net"
"httpfromtcp/internal/request"
)
func main() {
listener, err := net.Listen("tcp", ":42069")
if err != nil {
fmt.Println("Couldn't open messages.txt:", err)
return
}
for {
conn, err := listener.Accept()
if err != nil {
log.Fatal("error", "error", err)
}
r, err := request.RequestFromReader(conn)
if err != nil {
log.Fatal("error", "error", err)
}
fmt.Printf("Request line: \n")
fmt.Printf("- Method: %s\n", r.RequestLine.Method)
fmt.Printf("- Target: %s\n", r.RequestLine.RequestTarget)
fmt.Printf("- Version: %s\n", r.RequestLine.HttpVersion)
fmt.Printf("Headers:\n")
r.Headers.ForEach(func(n, v string) {
fmt.Printf("- %s: %s\n", n, v)
})
fmt.Printf("Body:\n")
fmt.Printf("%s\n", r.Body)
}
}

63
cmd/udpsender/main.go Normal file
View File

@@ -0,0 +1,63 @@
package udpsender
import (
"bytes"
"fmt"
"io"
)
func getLinesChannel(f io.ReadCloser) <-chan string {
out := make(chan string, 1)
go func() {
defer f.Close()
defer close(out)
str := ""
for {
data := make([]byte, 8)
n, err := f.Read(data)
if err == io.EOF {
break
}
if err != nil {
fmt.Println("error reading file:", err)
return
}
data = data[:n]
if i := bytes.IndexByte(data, '\n'); i != -1 {
str += string(data[:i])
data = data[i+1:]
out <- str
str = ""
}
str += string(data)
}
if len(str) != 0 {
out <- str
}
}()
return out
}
//for line := range getLinesChannel(conn){
// fmt.Printf("read: %s\n",line)
// }
// var body []byte = nil
// var status response.StatusCode = response.StatusOK
// if handlerError != nil{
// status = handlerError.StatusCode
// body = []byte(handlerError.Message)
// }else{
// body = writer.Bytes()
// }
// headers.Replace("Content-Length", fmt.Sprintf("%d", len(body)))
// response.WriteStatusLine(conn,status)
// response.WriteHeaders(conn,headers)
// conn.Write(body)