package parser import ( "strings" "testing" ) func TestIsHTTP1RequestTrue(t *testing.T) { cases := [][]byte{ []byte("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"), []byte("POST /api/data HTTP/1.1\r\n"), []byte("PUT /resource HTTP/1.0\r\n"), []byte("HEAD /ping HTTP/1.1\r\n"), []byte("DELETE /item/1 HTTP/1.1\r\n"), } for _, c := range cases { if !IsHTTP1Request(c) { t.Errorf("attendu true pour %q", c[:20]) } } } func TestIsHTTP1RequestFalse(t *testing.T) { cases := [][]byte{ []byte("HTTP/1.1 200 OK\r\n"), []byte(H2Magic), []byte("INVALID /path HTTP/1.1\r\n"), []byte{0x16, 0x03, 0x01}, // TLS handshake } for _, c := range cases { if IsHTTP1Request(c) { t.Errorf("attendu false pour %q", c[:min(20, len(c))]) } } } func TestParseHTTP1RequestBasic(t *testing.T) { raw := "GET /path/to/resource HTTP/1.1\r\n" + "Host: example.com\r\n" + "User-Agent: Go-http-client/1.1\r\n" + "Accept: */*\r\n" + "\r\n" req := ParseHTTP1Request([]byte(raw)) if req == nil { t.Fatal("attendu non-nil") } if req.Method != "GET" { t.Errorf("method: attendu GET, obtenu %q", req.Method) } if req.Path != "/path/to/resource" { t.Errorf("path: %q", req.Path) } if req.Protocol != "HTTP/1.1" { t.Errorf("protocol: %q", req.Protocol) } if len(req.Headers) != 3 { t.Errorf("nb headers: attendu 3, obtenu %d", len(req.Headers)) } if req.Headers[0] != "Host" { t.Errorf("premier header: attendu Host, obtenu %q", req.Headers[0]) } expected := "Host;User-Agent;Accept" if req.HeaderSig != expected { t.Errorf("HeaderSig: attendu %q, obtenu %q", expected, req.HeaderSig) } } func TestParseHTTP1RequestWithQueryString(t *testing.T) { raw := "GET /search?q=ebpf&page=2 HTTP/1.1\r\nHost: test.com\r\n\r\n" req := ParseHTTP1Request([]byte(raw)) if req == nil { t.Fatal("attendu non-nil") } if req.Path != "/search" { t.Errorf("path: attendu /search, obtenu %q", req.Path) } if req.Query != "q=ebpf&page=2" { t.Errorf("query: %q", req.Query) } } func TestParseHTTP1RequestHTTP10(t *testing.T) { raw := "GET / HTTP/1.0\r\nHost: legacy.com\r\n\r\n" req := ParseHTTP1Request([]byte(raw)) if req == nil { t.Fatal("attendu non-nil") } if req.Protocol != "HTTP/1.0" { t.Errorf("protocol: %q", req.Protocol) } } func TestParseHTTP1RequestPostBody(t *testing.T) { raw := "POST /api/submit HTTP/1.1\r\n" + "Host: api.example.com\r\n" + "Content-Type: application/json\r\n" + "Content-Length: 42\r\n" + "\r\n" + `{"key":"value"}` req := ParseHTTP1Request([]byte(raw)) if req == nil { t.Fatal("attendu non-nil") } if req.Method != "POST" { t.Errorf("method: %q", req.Method) } if len(req.Headers) != 3 { t.Errorf("nb headers: attendu 3, obtenu %d", len(req.Headers)) } } func TestParseHTTP1RequestInvalid(t *testing.T) { cases := [][]byte{ []byte("HTTP/1.1 200 OK\r\n"), []byte("NOTAMETHOD /path HTTP/1.1\r\n"), []byte(""), {0xFF, 0xFE, 0xFD}, } for _, c := range cases { req := ParseHTTP1Request(c) if req != nil { t.Errorf("attendu nil pour %q, obtenu non-nil", c) } } } func TestIsHTTP1Response(t *testing.T) { if !IsHTTP1Response([]byte("HTTP/1.1 200 OK\r\n")) { t.Error("attendu true pour HTTP/1.1 200") } if !IsHTTP1Response([]byte("HTTP/1.0 404 Not Found\r\n")) { t.Error("attendu true pour HTTP/1.0 404") } if IsHTTP1Response([]byte("GET / HTTP/1.1\r\n")) { t.Error("attendu false pour une requĂȘte") } } func TestParseHTTP1Response(t *testing.T) { cases := []struct { raw string code int }{ {"HTTP/1.1 200 OK\r\n", 200}, {"HTTP/1.0 404 Not Found\r\n", 404}, {"HTTP/1.1 301 Moved Permanently\r\n", 301}, {"HTTP/1.1 500 Internal Server Error\r\n", 500}, } for _, tc := range cases { resp := ParseHTTP1Response([]byte(tc.raw)) if resp == nil { t.Errorf("attendu non-nil pour %q", tc.raw) continue } if resp.StatusCode != tc.code { t.Errorf("code attendu %d, obtenu %d pour %q", tc.code, resp.StatusCode, tc.raw) } } } func TestParseHTTP1ResponseInvalid(t *testing.T) { cases := []string{ "GET / HTTP/1.1", "HTTP/1.1 99 Continue", // hors plage 100-599 "", } for _, tc := range cases { resp := ParseHTTP1Response([]byte(tc)) if resp != nil && (resp.StatusCode < 100 || resp.StatusCode > 599) { t.Errorf("code invalide %d pour %q", resp.StatusCode, tc) } } } // min retourne le minimum de deux entiers (helper pour les tests). func min(a, b int) int { if a < b { return a } return b } func TestHTTP1HeaderOrderSignature(t *testing.T) { raw := "GET / HTTP/1.1\r\n" + "Accept: text/html\r\n" + "Accept-Encoding: gzip\r\n" + "Connection: keep-alive\r\n" + "Host: example.com\r\n" + "\r\n" req := ParseHTTP1Request([]byte(raw)) if req == nil { t.Fatal("attendu non-nil") } parts := strings.Split(req.HeaderSig, ";") if len(parts) != 4 { t.Errorf("attendu 4 headers dans la signature, obtenu %d: %q", len(parts), req.HeaderSig) } if parts[0] != "Accept" { t.Errorf("premier header sig: attendu Accept, obtenu %q", parts[0]) } }