From 6a9935ec27db733611696da2b68429f7d467ab39 Mon Sep 17 00:00:00 2001 From: Hadi <112569860+anotherhadi@users.noreply.github.com> Date: Tue, 19 May 2026 13:38:50 +0200 Subject: [PATCH] =?UTF-8?q?=1B[37mfeat:=20add=20HTTPie=20export=20format?= =?UTF-8?q?=20in=20copy-as=1B[0m?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New toHTTPie() function builds an httpie command from raw request - Added "httpie" case in formatAs() switch - Uses util.ParseRawRequest; model lists httpie as a selectable format Co-Authored-By: Claude Sonnet 4.6  --- internal/ui/components/copyas/formats.go | 65 +++++++++++------------- internal/ui/components/copyas/model.go | 1 + 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/internal/ui/components/copyas/formats.go b/internal/ui/components/copyas/formats.go index fa85f01..15331fe 100644 --- a/internal/ui/components/copyas/formats.go +++ b/internal/ui/components/copyas/formats.go @@ -5,6 +5,8 @@ import ( "fmt" "net/url" "strings" + + "github.com/anotherhadi/spilltea/internal/util" ) type header struct{ key, value string } @@ -14,46 +16,22 @@ type parsedRequest struct { path string host string scheme string - headers []header + headers []header // garder header{key, value} pour compat locale body string } func parseRaw(raw, scheme string) parsedRequest { - lines := strings.Split(strings.ReplaceAll(raw, "\r\n", "\n"), "\n") - pr := parsedRequest{scheme: scheme} - if len(lines) == 0 { - return pr + r := util.ParseRawRequest(raw) + pr := parsedRequest{ + method: r.Method, + path: r.Path, + host: r.Host, + scheme: scheme, } - - parts := strings.SplitN(lines[0], " ", 3) - if len(parts) >= 1 { - pr.method = strings.TrimSpace(parts[0]) - } - if len(parts) >= 2 { - pr.path = strings.TrimSpace(parts[1]) - } - - i := 1 - for i < len(lines) { - line := strings.TrimRight(lines[i], "\r") - if line == "" { - i++ - break - } - if kv := strings.SplitN(line, ": ", 2); len(kv) == 2 { - k := strings.TrimSpace(kv[0]) - v := strings.TrimSpace(kv[1]) - pr.headers = append(pr.headers, header{k, v}) - if strings.EqualFold(k, "host") { - pr.host = v - } - } - i++ - } - - if i < len(lines) { - pr.body = strings.TrimRight(strings.Join(lines[i:], "\n"), "\n") + for _, h := range r.Headers { + pr.headers = append(pr.headers, header{h.Key, h.Value}) } + pr.body = r.Body return pr } @@ -82,10 +60,29 @@ func formatAs(id, raw, scheme string) string { return toMarkdown(pr) case "har": return toHAR(pr) + case "httpie": + return toHTTPie(pr) } return raw } +func toHTTPie(pr parsedRequest) string { + var sb strings.Builder + method := strings.ToUpper(pr.method) + fmt.Fprintf(&sb, "http %s '%s'", method, pr.fullURL()) + for _, h := range pr.headers { + if strings.EqualFold(h.key, "content-length") { + continue + } + fmt.Fprintf(&sb, " \\\n '%s:%s'", h.key, h.value) + } + if pr.body != "" { + // Pass body via stdin hint + fmt.Fprintf(&sb, " \\\n <<< %q", pr.body) + } + return sb.String() +} + func toMarkdown(pr parsedRequest) string { var sb strings.Builder fmt.Fprintf(&sb, "### %s %s\n\n", pr.method, pr.fullURL()) diff --git a/internal/ui/components/copyas/model.go b/internal/ui/components/copyas/model.go index 526fcb2..5cd449b 100644 --- a/internal/ui/components/copyas/model.go +++ b/internal/ui/components/copyas/model.go @@ -46,6 +46,7 @@ var allFormats = []list.Item{ formatItem{"ffuf", "FFUF", "web fuzzer: FUZZ in query string"}, formatItem{"markdown", "Markdown", "formatted for documentation"}, formatItem{"har", "HAR", "HTTP Archive (JSON)"}, + formatItem{"httpie", "HTTPie", "HTTPie command line client"}, } type Model struct {