mirror of
https://github.com/anotherhadi/spilltea.git
synced 2026-05-20 01:32:33 +02:00
[37mrefactor: centralize raw HTTP parsing and header serialization[0m
[37m- Add internal/util/rawhttp.go with ParseRawRequest and SortedHeaderLines[0m [37m- Refactor intercept/format.go and ui/intercept/helpers.go to use them[0m [37m- Eliminates duplicated bufio.Reader + textproto parsing spread across 3+ files[0m [37mCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>[0m
This commit is contained in:
@@ -3,9 +3,9 @@ package intercept
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/anotherhadi/spilltea/internal/util"
|
||||
"github.com/lqqyt2423/go-mitmproxy/proxy"
|
||||
)
|
||||
|
||||
@@ -14,15 +14,8 @@ func FormatRawRequest(f *proxy.Flow) string {
|
||||
r := f.Request
|
||||
var sb strings.Builder
|
||||
fmt.Fprintf(&sb, "%s %s %s\n", r.Method, r.URL.RequestURI(), r.Proto)
|
||||
keys := make([]string, 0, len(r.Header))
|
||||
for k := range r.Header {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
for _, v := range r.Header[k] {
|
||||
fmt.Fprintf(&sb, "%s: %s\n", k, v)
|
||||
}
|
||||
for _, line := range util.SortedHeaderLines(r.Header) {
|
||||
sb.WriteString(line)
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
if len(r.Body) > 0 {
|
||||
@@ -43,15 +36,8 @@ func FormatRawResponse(f *proxy.Flow) string {
|
||||
proto = "HTTP/1.1"
|
||||
}
|
||||
fmt.Fprintf(&sb, "%s %d %s\n", proto, r.StatusCode, http.StatusText(r.StatusCode))
|
||||
keys := make([]string, 0, len(r.Header))
|
||||
for k := range r.Header {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
for _, v := range r.Header[k] {
|
||||
fmt.Fprintf(&sb, "%s: %s\n", k, v)
|
||||
}
|
||||
for _, line := range util.SortedHeaderLines(r.Header) {
|
||||
sb.WriteString(line)
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
if len(r.Body) > 0 {
|
||||
|
||||
@@ -9,51 +9,32 @@ import (
|
||||
|
||||
"github.com/anotherhadi/spilltea/internal/intercept"
|
||||
"github.com/anotherhadi/spilltea/internal/style"
|
||||
"github.com/anotherhadi/spilltea/internal/util"
|
||||
)
|
||||
|
||||
func parseRawRequest(content string, req *intercept.PendingRequest) {
|
||||
parsed := util.ParseRawRequest(content)
|
||||
r := req.Flow.Request
|
||||
lines := strings.Split(strings.ReplaceAll(content, "\r\n", "\n"), "\n")
|
||||
if len(lines) == 0 {
|
||||
return
|
||||
if parsed.Method != "" {
|
||||
r.Method = parsed.Method
|
||||
}
|
||||
|
||||
parts := strings.SplitN(lines[0], " ", 3)
|
||||
if len(parts) >= 1 {
|
||||
r.Method = strings.TrimSpace(parts[0])
|
||||
}
|
||||
if len(parts) >= 2 {
|
||||
if u, err := url.ParseRequestURI(strings.TrimSpace(parts[1])); err == nil {
|
||||
if parsed.Path != "" {
|
||||
if u, err := url.ParseRequestURI(parsed.Path); err == nil {
|
||||
r.URL.Path = u.Path
|
||||
r.URL.RawQuery = u.RawQuery
|
||||
}
|
||||
}
|
||||
if len(parts) >= 3 {
|
||||
r.Proto = strings.TrimSpace(parts[2])
|
||||
if parsed.Proto != "" {
|
||||
r.Proto = parsed.Proto
|
||||
}
|
||||
|
||||
r.Header = make(http.Header)
|
||||
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 {
|
||||
r.Header.Set(strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1]))
|
||||
}
|
||||
i++
|
||||
for _, h := range parsed.Headers {
|
||||
r.Header.Set(h.Key, h.Value)
|
||||
}
|
||||
|
||||
if i < len(lines) {
|
||||
body := strings.Join(lines[i:], "\n")
|
||||
body = strings.TrimRight(body, "\n")
|
||||
if body != "" {
|
||||
r.Body = []byte(body)
|
||||
} else {
|
||||
r.Body = nil
|
||||
}
|
||||
if parsed.Body != "" {
|
||||
r.Body = []byte(parsed.Body)
|
||||
} else {
|
||||
r.Body = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RawRequest holds a parsed raw HTTP request string.
|
||||
type RawRequest struct {
|
||||
Method string
|
||||
Path string
|
||||
Proto string
|
||||
Host string
|
||||
Headers []RawHeader
|
||||
Body string
|
||||
}
|
||||
|
||||
// RawHeader is a single header key/value pair preserving insertion order.
|
||||
type RawHeader struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
// ParseRawRequest parses a raw HTTP request string (as produced by
|
||||
// FormatRawRequest). The Host header, if present, is extracted into Host
|
||||
// but also kept in Headers.
|
||||
func ParseRawRequest(raw string) RawRequest {
|
||||
lines := strings.Split(strings.ReplaceAll(raw, "\r\n", "\n"), "\n")
|
||||
var r RawRequest
|
||||
if len(lines) == 0 {
|
||||
return r
|
||||
}
|
||||
|
||||
parts := strings.SplitN(lines[0], " ", 3)
|
||||
if len(parts) >= 1 {
|
||||
r.Method = strings.TrimSpace(parts[0])
|
||||
}
|
||||
if len(parts) >= 2 {
|
||||
r.Path = strings.TrimSpace(parts[1])
|
||||
}
|
||||
if len(parts) >= 3 {
|
||||
r.Proto = strings.TrimSpace(parts[2])
|
||||
}
|
||||
|
||||
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])
|
||||
r.Headers = append(r.Headers, RawHeader{k, v})
|
||||
if strings.EqualFold(k, "host") {
|
||||
r.Host = v
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
if i < len(lines) {
|
||||
r.Body = strings.TrimRight(strings.Join(lines[i:], "\n"), "\n")
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// SortedHeaderLines returns header lines sorted by key name, formatted as
|
||||
// "Key: Value\n" strings. Useful for deterministic serialisation.
|
||||
func SortedHeaderLines(h http.Header) []string {
|
||||
keys := make([]string, 0, len(h))
|
||||
for k := range h {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
var out []string
|
||||
for _, k := range keys {
|
||||
for _, v := range h[k] {
|
||||
out = append(out, fmt.Sprintf("%s: %s\n", k, v))
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user