Skip to content

Commit 12678c0

Browse files
vigoclaude
andauthored
feat: add form data and file upload support (#21)
* feat: add form urlencoded support and fix SSE/race issues - Add application/x-www-form-urlencoded content type support - Parse and display form data in table format (CLI and WebUI) - Multiple values for same key shown comma-separated - URL-encoded characters automatically decoded - Fix data race in run.go (stopErr variable) - Fix SSE connection initialization (send connected comment) - Fix SSE event ordering in WebUI (load after connect) - Update header padding alignment in WebUI - Update tests for SSE changes (io.Pipe unbuffered reads) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: update linter config and pre-commit hooks - Switch pre-commit-golang repo to TekWizely/pre-commit-golang - Use golangci-lint-mod for full module linting - Update golangci.yml errcheck exclusions for fmt.Fprint Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add multipart/form-data support with image preview - add multipart/form-data content type support for file uploads - display file metadata (filename, size, content-type) in terminal - show content for small text files (under 1KB) - sanitize binary content in raw HTTP output ([binary data: X KB]) - add image preview in web dashboard for uploaded images - store file attachments with base64-encoded data for WebUI - add comprehensive tests for multipart handling Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: add more multipart tests for better coverage - add tests for PNG, JPEG, GIF image uploads - add test for mixed files and fields with binary detection - improve coverage for image content type detection - improve coverage for binary data sanitization Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address codex review suggestions - Load initial requests on page load instead of only on SSE open - Add fallback to load requests on SSE error - Cap image preview base64 encoding to 5MB max to prevent memory issues Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: clarify that URL path doesn't matter Add a note explaining that the server captures all incoming requests regardless of the URL path. The paths in examples are for illustration only. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * ci: add workflow_dispatch trigger for manual runs Allows manually triggering the test workflow from GitHub Actions UI or via gh CLI. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * perf: stream multipart parts instead of reading all into memory - Only buffer what's needed for preview (1KB for text, 5MB for images) - Discard remaining bytes while counting total size - Prevents OOM on large file uploads Addresses Codex review feedback. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: prevent race condition between initial load and SSE - Load initial requests BEFORE connecting SSE - Remove redundant load from onopen to avoid overwriting SSE data - Track initialLoadDone to only fallback-load once on SSE failure Prevents requests arriving via SSE from being silently dropped when loadInitialRequests() overwrites the array. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * security: sanitize image content-type to prevent XSS Add whitelist of safe image MIME types (png, jpeg, gif, webp, bmp, x-icon). Content-Type header is attacker-controlled and was interpolated directly into data URL, allowing XSS via headers like: Content-Type: image/png" onerror="alert(1) Now only whitelisted types are used; others fall back to application/octet-stream. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: preserve raw body when saving raw HTTP requests Terminal output gets sanitized body (no binary garbage). Raw file gets unsanitized body for faithful capture and replay with nc. Previously both outputs received sanitized body, corrupting saved files and breaking the documented `nc localhost 9002 < file.raw` workflow. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 90ad0ce commit 12678c0

11 files changed

Lines changed: 1361 additions & 43 deletions

File tree

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
name: Test go code
22

33
on:
4+
workflow_dispatch:
45
pull_request:
56
paths:
67
- '**.go'

.golangci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ linters:
3636
exclude-functions:
3737
- fmt.Fprintln
3838
- fmt.Fprintf
39+
- fmt.Fprint
3940
wrapcheck:
4041
ignore-package-globs:
4142
- encoding/*

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
2-
- repo: https://github.com/dnephin/pre-commit-golang
3-
rev: v0.5.1
2+
- repo: https://github.com/TekWizely/pre-commit-golang
3+
rev: v1.0.0-rc.1
44
hooks:
5-
- id: golangci-lint
5+
- id: golangci-lint-mod
66
- id: go-mod-tidy

README.md

Lines changed: 149 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ Start the server;
6060
basichttpdebugger # listens at :9002
6161
```
6262

63+
> **Note:** The URL path doesn't matter. The server captures **all** incoming
64+
> requests regardless of the path. `http://localhost:9002/`,
65+
> `http://localhost:9002/webhook`, `http://localhost:9002/api/v1/users` - they
66+
> all work the same way. The paths used in examples below (`/login`, `/upload`,
67+
> etc.) are just for illustration purposes.
68+
6369
Listen different port:
6470

6571
```bash
@@ -368,8 +374,8 @@ Here is how it looks, a GitHub webhook (trimmed, masked due to it’s huge/priva
368374
{"action":"created","issue":{"url": ...} ... }
369375
----------------------------------------------------------------------------------------------------
370376

371-
If you are checking secret token/secret token header (`test`, `X-Gitlab-Token`),
372-
youll see something like this in Payload section:
377+
If you are checking secret token/secret token header (`test`, `X-Gitlab-Token`),
378+
you'll see something like this in Payload section:
373379

374380
+-----------------------------------+-----------------------------+
375381
| Payload | |
@@ -381,6 +387,133 @@ you’ll see something like this in Payload section:
381387

382388
---
383389

390+
## Form Data Support
391+
392+
The debugger supports `application/x-www-form-urlencoded` content type. Form
393+
data is parsed and displayed in a table format:
394+
395+
```bash
396+
curl -X POST http://localhost:9002/login \
397+
-H "Content-Type: application/x-www-form-urlencoded" \
398+
-d "username=john&password=secret123&remember=true"
399+
```
400+
401+
Output:
402+
403+
+-----------------------------------------------------+
404+
| Payload |
405+
+--------------+--------------------------------------+
406+
| Incoming | application/x-www-form-urlencoded |
407+
+--------------+--------------------------------------+
408+
| Form Data |
409+
+--------------+--------------------------------------+
410+
| password | secret123 |
411+
| remember | true |
412+
| username | john |
413+
+--------------+--------------------------------------+
414+
415+
Form fields are sorted alphabetically. Multiple values for the same key are
416+
displayed comma-separated:
417+
418+
```bash
419+
curl -X POST http://localhost:9002/colors \
420+
-H "Content-Type: application/x-www-form-urlencoded" \
421+
-d "color=red&color=green&color=blue"
422+
```
423+
424+
Output:
425+
426+
+--------------+--------------------------------------+
427+
| Form Data |
428+
+--------------+--------------------------------------+
429+
| color | red, green, blue |
430+
+--------------+--------------------------------------+
431+
432+
URL-encoded special characters are automatically decoded:
433+
434+
```bash
435+
curl -X POST http://localhost:9002/search \
436+
-H "Content-Type: application/x-www-form-urlencoded" \
437+
-d "email=user%40example.com&query=hello+world"
438+
```
439+
440+
Output:
441+
442+
+--------------+--------------------------------------+
443+
| Form Data |
444+
+--------------+--------------------------------------+
445+
| email | user@example.com |
446+
| query | hello world |
447+
+--------------+--------------------------------------+
448+
449+
---
450+
451+
## File Upload Support
452+
453+
The debugger supports `multipart/form-data` content type for file uploads.
454+
Both form fields and files are parsed and displayed:
455+
456+
```bash
457+
curl -X POST http://localhost:9002/upload \
458+
-F "username=vigo" \
459+
-F "description=Test upload" \
460+
-F "config=@config.json"
461+
```
462+
463+
Output:
464+
465+
+-----------------------------------------------------+
466+
| Payload |
467+
+--------------+--------------------------------------+
468+
| Incoming | multipart/form-data; boundary=... |
469+
+--------------+--------------------------------------+
470+
| Form Data |
471+
+--------------+--------------------------------------+
472+
| description | Test upload |
473+
| username | vigo |
474+
+--------------+--------------------------------------+
475+
| Files |
476+
+--------------+--------------------------------------+
477+
| config.json | 18 B | application/json |
478+
| {"theme": "dark"} |
479+
+-----------------------------------------------------+
480+
481+
File metadata is displayed for all uploaded files:
482+
483+
```bash
484+
curl -X POST http://localhost:9002/upload \
485+
-F "avatar=@photo.png"
486+
```
487+
488+
Output:
489+
490+
+-----------------------------------------------------+
491+
| Files |
492+
+-----------------------------------------------------+
493+
| photo.png | 2.5 KB | application/octet-stream |
494+
+-----------------------------------------------------+
495+
496+
For small text files (under 1KB), the content is displayed. For larger files
497+
or binary files, only metadata (filename, size, content-type) is shown.
498+
499+
**Image Preview in Web Dashboard:** When you upload image files (JPEG, PNG, GIF,
500+
etc.), the web dashboard displays a preview of the image alongside the file
501+
metadata.
502+
503+
Multiple files can be uploaded at once:
504+
505+
```bash
506+
curl -X POST http://localhost:9002/upload \
507+
-F "file1=@readme.txt" \
508+
-F "file2=@data.json" \
509+
-F "image=@logo.png"
510+
```
511+
512+
Form fields and files are displayed in separate sections, both in the terminal
513+
and in the web dashboard.
514+
515+
---
516+
384517
## Docker
385518

386519
For local docker usage, default expose port is: `9002` (debug) and `9003` (web dashboard).
@@ -450,6 +583,19 @@ rake test # run test
450583

451584
## Change Log
452585

586+
**2026-01-23**
587+
588+
- add `application/x-www-form-urlencoded` content type support
589+
- add `multipart/form-data` content type support for file uploads
590+
- form data is parsed and displayed in table format
591+
- file uploads show metadata (filename, size, content-type)
592+
- small text files (under 1KB) display content inline
593+
- multiple values for the same key are comma-separated
594+
- URL-encoded characters are automatically decoded
595+
- web dashboard supports form data and file upload display
596+
- web dashboard shows image preview for uploaded images (JPEG, PNG, GIF, etc.)
597+
- binary file content is sanitized in terminal output (`[binary data: X KB]`)
598+
453599
**2025-01-23**
454600

455601
- add web dashboard for real-time request monitoring (similar to ngrok)
@@ -489,8 +635,7 @@ rake test # run test
489635

490636
## TODO
491637

492-
- Add http form requests support
493-
- Add http file upload requests support
638+
- Add brew tap installation support
494639

495640
---
496641

0 commit comments

Comments
 (0)