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
+17 -14
View File
@@ -2,12 +2,12 @@ package pcap
//go:generate stringer -type=FieldClass -linecomment -output stringers.go .
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"log/slog"
"math"
"strings"
"unsafe"
"github.com/soypat/lneto"
"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.
func httpBodyClass(contentType, body []byte) FieldClass {
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.
mediaType := contentType
if i := bytes.IndexByte(contentType, ';'); i >= 0 {
mediaType = contentType[:i]
if i := strings.IndexByte(ct, ';'); i >= 0 {
ct = strings.TrimSpace(ct[:i])
}
mediaType = bytes.TrimSpace(mediaType)
switch {
case bytes.HasPrefix(mediaType, []byte("text/")):
case strings.HasPrefix(ct, "text/"):
return FieldClassText
case internal.BytesEqual(mediaType, []byte("application/json")),
internal.BytesEqual(mediaType, []byte("application/javascript")),
internal.BytesEqual(mediaType, []byte("application/xml")):
case ct == "application/json",
ct == "application/javascript",
ct == "application/xml":
return FieldClassText
case bytes.HasSuffix(mediaType, []byte("+json")),
bytes.HasSuffix(mediaType, []byte("+xml")):
case strings.HasSuffix(ct, "+json"),
strings.HasSuffix(ct, "+xml"):
return FieldClassText
}
return FieldClassPayload
@@ -603,8 +603,11 @@ func (pc *PacketBreakdown) CaptureHTTP(dst []Frame, pkt []byte, bitOffset int) (
debuglog("pcap:http:parsed")
hdrLen := pc.hdr.BufferParsed()
body, _ := pc.hdr.Body()
debuglog("pcap:http:body")
bodyClass := httpBodyClass(pc.hdr.Get("Content-Type"), body)
debuglog("pcap:http:bodyclass")
finfo := reclaimFrame(&dst, httpProtocol, bitOffset, nil)
debuglog("pcap:http:reclaim")
finfo.Fields = append(finfo.Fields,
FrameField{
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) {
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 {
debugLog("ip:demux")
sb.handlers.info("StackIP.Demux:start")
frame := carrierData[offset:] // we don't care about carrier data in IP.
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...)
}
const enableAllocLog = false
const enableAllocLog = internal.HeapAllocDebugging
func debugLog(msg string) {
if enableAllocLog {
+8 -8
View File
@@ -411,10 +411,10 @@ func TestListener_RSTOnStalePacket(t *testing.T) {
copy(rawBuf[12:16], clientIP[:])
copy(rawBuf[16:20], serverIP[:])
// 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.PutUint32(rawBuf[24:], 500) // SEQ
binary.BigEndian.PutUint32(rawBuf[28:], 200) // ACK
binary.BigEndian.PutUint32(rawBuf[24:], 500) // SEQ
binary.BigEndian.PutUint32(rawBuf[28:], 200) // ACK
rawBuf[32] = 0x50 // offset=5
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.PutUint32(rawBuf[24:], 700) // SEQ = 700
binary.BigEndian.PutUint32(rawBuf[28:], 0) // ACK = 0
rawBuf[32] = 0x50 // offset=5
rawBuf[33] = 0x02 // flags = SYN
rawBuf[32] = 0x50 // offset=5
rawBuf[33] = 0x02 // flags = SYN
err := sp.Demux(rawBuf[:40], 20)
if err == nil {
@@ -546,9 +546,9 @@ func TestListener_ECN_SYN(t *testing.T) {
// TCP header at offset 20.
binary.BigEndian.PutUint16(rawBuf[20:], 5000) // src port
binary.BigEndian.PutUint16(rawBuf[22:], serverPort)
binary.BigEndian.PutUint32(rawBuf[24:], 300) // SEQ
binary.BigEndian.PutUint32(rawBuf[28:], 0) // ACK
rawBuf[32] = 0x50 // offset=5
binary.BigEndian.PutUint32(rawBuf[24:], 300) // SEQ
binary.BigEndian.PutUint32(rawBuf[28:], 0) // ACK
rawBuf[32] = 0x50 // offset=5
rawBuf[33] = byte(tcp.FlagSYN | tcp.FlagECE | tcp.FlagCWR) // SYN+ECE+CWR
// Should be accepted (create connection), not dropped.