// Package raw dumps the exact bytes we decoded back to an io.Writer. It
// is useful for piping through external tools like mitmdump or for
// reproducing captures on replay.
//
// mercemay.top/src/httptap/
package raw
import (
"fmt"
"io"
"strings"
"mercemay.top/httptap/internal/parser"
)
// WriteMessage writes a single message as HTTP/1.x wire bytes. For HTTP/2
// messages it synthesises the HTTP/1.1 equivalent so the output is
// plain-text and diffable.
func WriteMessage(w io.Writer, msg parser.Message) error {
if _, err := io.WriteString(w, msg.StartLine); err != nil {
return err
}
if _, err := io.WriteString(w, "\r\n"); err != nil {
return err
}
for _, kv := range msg.Headers {
if _, err := fmt.Fprintf(w, "%s: %s\r\n", kv[0], kv[1]); err != nil {
return err
}
}
if _, err := io.WriteString(w, "\r\n"); err != nil {
return err
}
if len(msg.Body) > 0 {
if _, err := w.Write(msg.Body); err != nil {
return err
}
}
return nil
}
// WritePair writes req followed by a separator and resp. The separator
// line is a comment-style marker that survives round-tripping through
// most text viewers.
func WritePair(w io.Writer, req, resp parser.Message) error {
if err := WriteMessage(w, req); err != nil {
return err
}
if _, err := io.WriteString(w, "\n# ----- response -----\n"); err != nil {
return err
}
return WriteMessage(w, resp)
}
// String is a convenience that builds a raw dump into a string. It is
// mainly for tests and for the clipboard-copy command.
func String(msg parser.Message) string {
var b strings.Builder
_ = WriteMessage(&b, msg)
return b.String()
}
// Banner is the human-readable header placed at the top of multi-entry
// raw dumps produced by cmd/httptap/cmd/export.
func Banner(source string) string {
return fmt.Sprintf("# httptap raw dump\n# source: %s\n\n", source)
}
// WriteAll writes many message pairs separated by a blank line each.
func WriteAll(w io.Writer, pairs [][2]parser.Message) error {
for i, pair := range pairs {
if i > 0 {
if _, err := io.WriteString(w, "\n"); err != nil {
return err
}
}
if err := WritePair(w, pair[0], pair[1]); err != nil {
return err
}
}
return nil
}