heap: remove heap alloc in pcap of HTTP content type; more debugging logs

This commit is contained in:
Patricio Whittingslow
2026-02-28 17:46:08 -03:00
parent 4f7635b216
commit f6e7801d8c
5 changed files with 40 additions and 26 deletions
+4 -3
View File
@@ -3,7 +3,6 @@ package httpraw
import ( import (
"bytes" "bytes"
"errors" "errors"
"log/slog"
"slices" "slices"
"unsafe" "unsafe"
@@ -300,11 +299,13 @@ func (h *Header) appendHeader(key, value string) {
if h.flags.hasAny(flagNoBufferGrow) { if h.flags.hasAny(flagNoBufferGrow) {
panic(errSmallBuffer) panic(errSmallBuffer)
} }
debuglog("http:appendhdr:grow-buf")
hb.buf = slices.Grow(buf, len(key)+len(value)) hb.buf = slices.Grow(buf, len(key)+len(value))
} }
h.flags |= flagMangledBuffer h.flags |= flagMangledBuffer
k := hb.mustAppendSlice(key) k := hb.mustAppendSlice(key)
v := hb.mustAppendSlice(value) v := hb.mustAppendSlice(value)
debuglog("http:appendhdr:grow-hdrs")
hb.headers = append(hb.headers, argsKV{ hb.headers = append(hb.headers, argsKV{
key: k, key: k,
value: v, value: v,
@@ -426,10 +427,10 @@ func bytes2tok(buf, value []byte) headerSlice {
} }
} }
const enableDebug = false const enableDebug = internal.HeapAllocDebugging
func debuglog(msg string) { func debuglog(msg string) {
if enableDebug { if enableDebug {
internal.LogAttrs(nil, slog.LevelDebug, msg) internal.LogAllocs(msg)
} }
} }
+17 -14
View File
@@ -2,12 +2,12 @@ package pcap
//go:generate stringer -type=FieldClass -linecomment -output stringers.go . //go:generate stringer -type=FieldClass -linecomment -output stringers.go .
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"log/slog"
"math" "math"
"strings"
"unsafe"
"github.com/soypat/lneto" "github.com/soypat/lneto"
"github.com/soypat/lneto/arp" "github.com/soypat/lneto/arp"
@@ -553,21 +553,21 @@ func (pc *PacketBreakdown) CaptureDHCPv4(dst []Frame, pkt []byte, bitOffset int)
// based on the Content-Type header, falling back to byte inspection when Content-Type is absent. // based on the Content-Type header, falling back to byte inspection when Content-Type is absent.
func httpBodyClass(contentType, body []byte) FieldClass { func httpBodyClass(contentType, body []byte) FieldClass {
if len(contentType) > 0 { if len(contentType) > 0 {
// Use unsafe string conversion to avoid []byte("literal") heap allocations in TinyGo.
ct := unsafe.String(&contentType[0], len(contentType))
// Strip parameters (e.g. "; charset=utf-8") for media type matching. // Strip parameters (e.g. "; charset=utf-8") for media type matching.
mediaType := contentType if i := strings.IndexByte(ct, ';'); i >= 0 {
if i := bytes.IndexByte(contentType, ';'); i >= 0 { ct = strings.TrimSpace(ct[:i])
mediaType = contentType[:i]
} }
mediaType = bytes.TrimSpace(mediaType)
switch { switch {
case bytes.HasPrefix(mediaType, []byte("text/")): case strings.HasPrefix(ct, "text/"):
return FieldClassText return FieldClassText
case internal.BytesEqual(mediaType, []byte("application/json")), case ct == "application/json",
internal.BytesEqual(mediaType, []byte("application/javascript")), ct == "application/javascript",
internal.BytesEqual(mediaType, []byte("application/xml")): ct == "application/xml":
return FieldClassText return FieldClassText
case bytes.HasSuffix(mediaType, []byte("+json")), case strings.HasSuffix(ct, "+json"),
bytes.HasSuffix(mediaType, []byte("+xml")): strings.HasSuffix(ct, "+xml"):
return FieldClassText return FieldClassText
} }
return FieldClassPayload return FieldClassPayload
@@ -603,8 +603,11 @@ func (pc *PacketBreakdown) CaptureHTTP(dst []Frame, pkt []byte, bitOffset int) (
debuglog("pcap:http:parsed") debuglog("pcap:http:parsed")
hdrLen := pc.hdr.BufferParsed() hdrLen := pc.hdr.BufferParsed()
body, _ := pc.hdr.Body() body, _ := pc.hdr.Body()
debuglog("pcap:http:body")
bodyClass := httpBodyClass(pc.hdr.Get("Content-Type"), body) bodyClass := httpBodyClass(pc.hdr.Get("Content-Type"), body)
debuglog("pcap:http:bodyclass")
finfo := reclaimFrame(&dst, httpProtocol, bitOffset, nil) finfo := reclaimFrame(&dst, httpProtocol, bitOffset, nil)
debuglog("pcap:http:reclaim")
finfo.Fields = append(finfo.Fields, finfo.Fields = append(finfo.Fields,
FrameField{ FrameField{
Name: "HTTP Header", Name: "HTTP Header",
@@ -1351,10 +1354,10 @@ func reclaimRemainingFrame(dst *[]Frame, proto string, class FieldClass, pktBitO
}) })
} }
const enableDebug = false const enableDebug = internal.HeapAllocDebugging
func debuglog(msg string) { func debuglog(msg string) {
if enableDebug { if enableDebug {
internal.LogAttrs(nil, slog.LevelDebug, msg) internal.LogAllocs(msg)
} }
} }
+2 -1
View File
@@ -70,6 +70,7 @@ func (sb *StackIP) SetLogger(logger *slog.Logger) {
} }
func (sb *StackIP) Demux(carrierData []byte, offset int) error { func (sb *StackIP) Demux(carrierData []byte, offset int) error {
debugLog("ip:demux")
sb.handlers.info("StackIP.Demux:start") sb.handlers.info("StackIP.Demux:start")
frame := carrierData[offset:] // we don't care about carrier data in IP. frame := carrierData[offset:] // we don't care about carrier data in IP.
ifrm, err := ipv4.NewFrame(frame) ifrm, err := ipv4.NewFrame(frame)
@@ -232,7 +233,7 @@ func (l logger) trace(msg string, attrs ...slog.Attr) {
internal.LogAttrs(l.log, internal.LevelTrace, msg, attrs...) internal.LogAttrs(l.log, internal.LevelTrace, msg, attrs...)
} }
const enableAllocLog = false const enableAllocLog = internal.HeapAllocDebugging
func debugLog(msg string) { func debugLog(msg string) {
if enableAllocLog { if enableAllocLog {
+8 -8
View File
@@ -411,10 +411,10 @@ func TestListener_RSTOnStalePacket(t *testing.T) {
copy(rawBuf[12:16], clientIP[:]) copy(rawBuf[12:16], clientIP[:])
copy(rawBuf[16:20], serverIP[:]) copy(rawBuf[16:20], serverIP[:])
// TCP header at offset 20. // TCP header at offset 20.
binary.BigEndian.PutUint16(rawBuf[20:], 1337) // src port binary.BigEndian.PutUint16(rawBuf[20:], 1337) // src port
binary.BigEndian.PutUint16(rawBuf[22:], serverPort) // dst port binary.BigEndian.PutUint16(rawBuf[22:], serverPort) // dst port
binary.BigEndian.PutUint32(rawBuf[24:], 500) // SEQ binary.BigEndian.PutUint32(rawBuf[24:], 500) // SEQ
binary.BigEndian.PutUint32(rawBuf[28:], 200) // ACK binary.BigEndian.PutUint32(rawBuf[28:], 200) // ACK
rawBuf[32] = 0x50 // offset=5 rawBuf[32] = 0x50 // offset=5
rawBuf[33] = 0x11 // flags = FIN|ACK (0x01|0x10) rawBuf[33] = 0x11 // flags = FIN|ACK (0x01|0x10)
@@ -484,8 +484,8 @@ func TestStackPorts_RSTOnUnknownPort(t *testing.T) {
binary.BigEndian.PutUint16(rawBuf[22:], 443) // dst port (no listener!) binary.BigEndian.PutUint16(rawBuf[22:], 443) // dst port (no listener!)
binary.BigEndian.PutUint32(rawBuf[24:], 700) // SEQ = 700 binary.BigEndian.PutUint32(rawBuf[24:], 700) // SEQ = 700
binary.BigEndian.PutUint32(rawBuf[28:], 0) // ACK = 0 binary.BigEndian.PutUint32(rawBuf[28:], 0) // ACK = 0
rawBuf[32] = 0x50 // offset=5 rawBuf[32] = 0x50 // offset=5
rawBuf[33] = 0x02 // flags = SYN rawBuf[33] = 0x02 // flags = SYN
err := sp.Demux(rawBuf[:40], 20) err := sp.Demux(rawBuf[:40], 20)
if err == nil { if err == nil {
@@ -546,9 +546,9 @@ func TestListener_ECN_SYN(t *testing.T) {
// TCP header at offset 20. // TCP header at offset 20.
binary.BigEndian.PutUint16(rawBuf[20:], 5000) // src port binary.BigEndian.PutUint16(rawBuf[20:], 5000) // src port
binary.BigEndian.PutUint16(rawBuf[22:], serverPort) binary.BigEndian.PutUint16(rawBuf[22:], serverPort)
binary.BigEndian.PutUint32(rawBuf[24:], 300) // SEQ binary.BigEndian.PutUint32(rawBuf[24:], 300) // SEQ
binary.BigEndian.PutUint32(rawBuf[28:], 0) // ACK binary.BigEndian.PutUint32(rawBuf[28:], 0) // ACK
rawBuf[32] = 0x50 // offset=5 rawBuf[32] = 0x50 // offset=5
rawBuf[33] = byte(tcp.FlagSYN | tcp.FlagECE | tcp.FlagCWR) // SYN+ECE+CWR rawBuf[33] = byte(tcp.FlagSYN | tcp.FlagECE | tcp.FlagCWR) // SYN+ECE+CWR
// Should be accepted (create connection), not dropped. // Should be accepted (create connection), not dropped.
+9
View File
@@ -241,6 +241,7 @@ func (listener *Listener) Demux(carrierData []byte, tcpFrameOffset int) error {
listener.logerr("Listener:demux", slog.String("err", err.Error())) listener.logerr("Listener:demux", slog.String("err", err.Error()))
return lneto.ErrPacketDrop return lneto.ErrPacketDrop
} }
debuglog("tcplistener:demux-append")
listener.incoming = append(listener.incoming, handler{ listener.incoming = append(listener.incoming, handler{
conn: conn, conn: conn,
id: *conn.ConnectionID(), id: *conn.ConnectionID(),
@@ -316,3 +317,11 @@ func (listener *Listener) returnIncoming(idx int) {
listener.poolReturn(listener.incoming[idx].conn) listener.poolReturn(listener.incoming[idx].conn)
listener.incoming[idx] = handler{} listener.incoming[idx] = handler{}
} }
const enableDebug = internal.HeapAllocDebugging
func debuglog(msg string) {
if enableDebug {
internal.LogAllocs(msg)
}
}