Add a pcap-split tool
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"pcap-web-tools/internal/pcap"
|
||||
)
|
||||
|
||||
func testPcap(t *testing.T, packets int) []byte {
|
||||
t.Helper()
|
||||
var buf bytes.Buffer
|
||||
w, err := pcap.NewWriter(&buf, pcap.LinkTypeEthernet)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := range packets {
|
||||
if err := w.WritePacket(time.Unix(int64(i), 0), make([]byte, 100)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func postSplit(t *testing.T, srv *Server, filename string, file []byte, fields map[string]string) *httptest.ResponseRecorder {
|
||||
t.Helper()
|
||||
var body bytes.Buffer
|
||||
mw := multipart.NewWriter(&body)
|
||||
for k, v := range fields {
|
||||
mw.WriteField(k, v)
|
||||
}
|
||||
if file != nil {
|
||||
fw, err := mw.CreateFormFile("file", filename)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fw.Write(file)
|
||||
}
|
||||
mw.Close()
|
||||
req := httptest.NewRequest("POST", "/split", &body)
|
||||
req.Header.Set("Content-Type", mw.FormDataContentType())
|
||||
rec := httptest.NewRecorder()
|
||||
srv.ServeHTTP(rec, req)
|
||||
return rec
|
||||
}
|
||||
|
||||
func TestSplitHandler(t *testing.T) {
|
||||
srv, err := New(Config{MaxUploadBytes: 1 << 20})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
in := testPcap(t, 25)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fields map[string]string
|
||||
want []int // packets per part
|
||||
}{
|
||||
{"by packets", map[string]string{"mode": "packets", "packets": "10"}, []int{10, 10, 5}},
|
||||
// Each record is 116 bytes: 24 + 8*116 = 952 <= 1000, a ninth does not fit.
|
||||
{"by size", map[string]string{"mode": "size", "size": "1", "unit": "KB"}, []int{8, 8, 8, 1}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
rec := postSplit(t, srv, `C:\caps\my capture.pcap`, in, tt.fields)
|
||||
if rec.Code != http.StatusOK || rec.Header().Get("Content-Type") != "application/zip" {
|
||||
t.Fatalf("status %d %s: %s", rec.Code, rec.Header().Get("Content-Type"), rec.Body)
|
||||
}
|
||||
if cd := rec.Header().Get("Content-Disposition"); cd != `attachment; filename="my_capture_split.zip"` {
|
||||
t.Errorf("Content-Disposition %q", cd)
|
||||
}
|
||||
zr, err := zip.NewReader(bytes.NewReader(rec.Body.Bytes()), int64(rec.Body.Len()))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(zr.File) != len(tt.want) {
|
||||
t.Fatalf("got %d files, want %d", len(zr.File), len(tt.want))
|
||||
}
|
||||
for i, f := range zr.File {
|
||||
if want := "my_capture_00" + string(rune('1'+i)) + ".pcap"; f.Name != want {
|
||||
t.Errorf("file %d named %q, want %q", i, f.Name, want)
|
||||
}
|
||||
if want := int64(24 + tt.want[i]*116); int64(f.UncompressedSize64) != want {
|
||||
t.Errorf("%s: %d bytes, want %d", f.Name, f.UncompressedSize64, want)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitHandlerErrors(t *testing.T) {
|
||||
srv, err := New(Config{MaxUploadBytes: 4000})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func(n int) { maxSplitParts = n }(maxSplitParts)
|
||||
maxSplitParts = 5
|
||||
|
||||
ok := map[string]string{"mode": "packets", "packets": "1"}
|
||||
tests := []struct {
|
||||
name string
|
||||
file []byte
|
||||
fields map[string]string
|
||||
status int
|
||||
want string
|
||||
}{
|
||||
{"no file", nil, ok, http.StatusBadRequest, "choose a pcap file"},
|
||||
{"not pcap", []byte(strings.Repeat("x", 100)), ok, http.StatusBadRequest, "not a pcap file"},
|
||||
{"too large", testPcap(t, 700), ok, http.StatusRequestEntityTooLarge, "file too large"},
|
||||
{"too many parts", testPcap(t, 6), ok, http.StatusBadRequest, "more than 5 files"},
|
||||
{"bad packets", testPcap(t, 1), map[string]string{"mode": "packets", "packets": "0"}, http.StatusBadRequest, "at least 1"},
|
||||
{"bad size", testPcap(t, 1), map[string]string{"mode": "size", "size": "abc", "unit": "MB"}, http.StatusBadRequest, "positive number"},
|
||||
{"bad unit", testPcap(t, 1), map[string]string{"mode": "size", "size": "1", "unit": "XB"}, http.StatusBadRequest, "unknown size unit"},
|
||||
{"no mode", testPcap(t, 1), map[string]string{}, http.StatusBadRequest, "choose whether"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
rec := postSplit(t, srv, "x.pcap", tt.file, tt.fields)
|
||||
if rec.Code != tt.status || !strings.Contains(rec.Body.String(), tt.want) {
|
||||
t.Errorf("%s: status %d, body %.300s", tt.name, rec.Code, rec.Body)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user