package main import ( "bytes" "encoding/json" "fmt" "io" "log" "net/http" "time" ) const maxBodySample = 4096 // inspect sends the request metadata + body sample to the WAF for inspection. // Returns the WAF's HTTP status code or an error if unreachable. func inspect(r *http.Request) (int, error) { cfg := getConfig() // Sample body. var bodySample []byte if r.Body != nil { bodySample = make([]byte, maxBodySample) n, _ := io.ReadFull(r.Body, bodySample) bodySample = bodySample[:n] // Restore body so downstream can read it. r.Body = io.NopCloser(io.MultiReader(bytes.NewReader(bodySample), r.Body)) } // Build inspection payload with the original URI. originalPath := r.Header.Get("X-Zoraxy-Uri") if originalPath == "" { originalPath = r.URL.String() } payload, err := json.Marshal(map[string]interface{}{ "method": r.Method, "url": originalPath, "host": r.Host, "remote_addr": r.RemoteAddr, "content_type": r.Header.Get("Content-Type"), "content_length": r.ContentLength, "headers": r.Header, "body_sample": bodySample, }) if err != nil { return 0, fmt.Errorf("marshal: %w", err) } client := &http.Client{Timeout: time.Duration(cfg.TimeoutMs) * time.Millisecond} resp, err := client.Post(cfg.WAFURL+"/inspect", "application/json", bytes.NewReader(payload)) if err != nil { return 0, fmt.Errorf("unreachable: %w", err) } defer resp.Body.Close() log.Printf("Firewall: %s %s → status %d", r.Method, r.URL.Path, resp.StatusCode) return resp.StatusCode, nil }