mirror of
https://github.com/buger/goreplay.git
synced 2024-04-21 12:32:02 +00:00
### performance - handling of the very big packet(any size that can be buffered) - speeding up TCP sessions by using message hints: Added **proto.HasFullPayload** that helps to validate the entire HTTP request, it supports `Chunked` encoding too! Added **proto.HasRequestTitle** and **proto.HasResponseTitle** for validating the beginning of HTTP request. Those methods are used `input_raw.go` with `TCP`. - supports Keep-Alive: the above functions helps to support keep-alive ### Packaging - **capture:** engines(capture/doc.go) - **tcp:** tcp message parser (tcp/doc.go) ### benchmarking - **capture.BenchmarkPcapDump:** the benchmarks regarding dumping packets in a pcap file - **capture.BenchmarkPcapFile:** the benchmarks of reading packets from a pcap file - **capture.BenchmarkPcap:** the benchmarks of parsing packets from the loopback interface with pcap handles - **proto.BenchmarkHasFullPayload:**: benchmarking this function which validates the HTTP payload - **tcp.BenchmarkPacketParseAndSort:** benchmarks of parsing and sorting packets - **tcp.BenchmarkMessageParserWithoutHint:** benchmarks of message reasembling by using `SYN` and `FIN` flag - **tcp.BenchmarkMessageParserWithHint:** benchmarks of message reasembling by using `proto.HasRequestTitle` and `proto.HasFullPayload` flag ### issues see linked issues ### tests - fixed input raw and engine tests **Most of the changed of the files, was about using functionalities of** `tcp` **and** `capture` **in existing functionalities**
93 lines
1.9 KiB
Go
93 lines
1.9 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"fmt"
|
|
)
|
|
|
|
// These constants help to indicate the type of payload
|
|
const (
|
|
RequestPayload = '1'
|
|
ResponsePayload = '2'
|
|
ReplayedResponsePayload = '3'
|
|
)
|
|
|
|
func randByte(len int) []byte {
|
|
b := make([]byte, len/2)
|
|
rand.Read(b)
|
|
|
|
h := make([]byte, len)
|
|
hex.Encode(h, b)
|
|
|
|
return h
|
|
}
|
|
|
|
func uuid() []byte {
|
|
return randByte(24)
|
|
}
|
|
|
|
var payloadSeparator = "\n🐵🙈🙉\n"
|
|
|
|
func payloadScanner(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
|
if atEOF && len(data) == 0 {
|
|
return 0, nil, nil
|
|
}
|
|
|
|
if i := bytes.Index(data, []byte(payloadSeparator)); i >= 0 {
|
|
// We have a full newline-terminated line.
|
|
return i + len([]byte(payloadSeparator)), data[0:i], nil
|
|
}
|
|
|
|
if atEOF {
|
|
return len(data), data, nil
|
|
}
|
|
return 0, nil, nil
|
|
}
|
|
|
|
// Timing is request start or round-trip time, depending on payloadType
|
|
func payloadHeader(payloadType byte, uuid []byte, timing int64, latency int64) (header []byte) {
|
|
//Example:
|
|
// 3 f45590522cd1838b4a0d5c5aab80b77929dea3b3 13923489726487326 1231\n
|
|
return []byte(fmt.Sprintf("%c %s %d %d\n", payloadType, uuid, timing, latency))
|
|
}
|
|
|
|
func payloadBody(payload []byte) []byte {
|
|
headerSize := bytes.IndexByte(payload, '\n')
|
|
return payload[headerSize+1:]
|
|
}
|
|
|
|
func payloadMeta(payload []byte) [][]byte {
|
|
headerSize := bytes.IndexByte(payload, '\n')
|
|
if headerSize < 0 {
|
|
return nil
|
|
}
|
|
return bytes.Split(payload[:headerSize], []byte{' '})
|
|
}
|
|
|
|
func payloadID(payload []byte) (id []byte) {
|
|
meta := payloadMeta(payload)
|
|
|
|
if len(meta) < 2 {
|
|
return
|
|
}
|
|
// id is encoded in hex, we need to revert to how it was
|
|
id = make([]byte, 20)
|
|
hex.Decode(id, meta[1])
|
|
return
|
|
}
|
|
|
|
func isOriginPayload(payload []byte) bool {
|
|
switch payload[0] {
|
|
case RequestPayload, ResponsePayload:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func isRequestPayload(payload []byte) bool {
|
|
return payload[0] == RequestPayload
|
|
}
|