Skip to content

Conversation

@ammar-agent
Copy link
Contributor

@ammar-agent ammar-agent commented Nov 9, 2025

Fixes #84

Problem

When httpjail runs in server mode and receives a request targeting itself (e.g., curl --proxy http://localhost:8080 http://localhost:8080/test), it creates an infinite loop.

Solution

Implemented nonce-based loop detection:

  • Each httpjail instance generates a random nonce on startup
  • Appends nonce to Httpjail-Loop-Prevention header on outgoing requests
  • Blocks incoming requests with 403 if they contain our nonce

Changes

  • Added ProxyContext struct to bundle shared state (DRY refactoring)
  • Loop detection using HTTP multi-value headers
  • Test completes in ~0.3s (vs 3+ second timeout without fix)

Benefits

  • Robust across network topologies (reverse proxies, Docker, NAT)
  • Supports chaining multiple httpjail instances
  • Standards-compliant (native HTTP multi-value headers)

When httpjail in server mode receives a request targeting itself, it now
detects and blocks the loop using a unique nonce per proxy instance.

Each proxy instance:
- Generates a random nonce on startup
- Appends its nonce to Httpjail-Loop-Prevention header (using HTTP's
  native multi-value header support)
- Checks incoming requests for its own nonce and blocks with 403 if found

This approach:
- Supports chaining multiple httpjail instances
- Works across network topologies (reverse proxies, Docker, etc.)
- Uses HTTP standard multi-value headers instead of CSV parsing

Also refactored code for DRY:
- Created ProxyContext struct to bundle rule_engine, cert_manager, loop_nonce
- Reduced function signature duplication throughout codebase
- Extracted wait_for_server() helper to tests/common for reuse

Test: New test_server_mode_self_request_loop_prevention verifies the fix,
completing in ~0.3s (vs timing out without the fix).
The perform_tls_interception function uses CertificateManager::is_ca_trusted()
on macOS but the import was missing from the main module (only present in tests).
This caused compilation to fail on macOS CI.

Added conditional import with #[cfg(target_os = "macos")] to match usage.
@ammario ammario changed the title Fix #84: Prevent infinite loop in server mode with nonce-based detection fix: prevent infinite proxy loop with nonce-based detection Nov 9, 2025
- Convert wait_for_server() to async using tokio::time and tokio::net::TcpStream
- Update all callers (start_server, start_server_with_bind, and tests) to async
- Clean up self_request_loop test: remove verbose comments and println
- Use tracing::debug for test debugging output
- Simplify test assertions to focus on essential behavior
@ammario ammario merged commit 22f90fd into main Nov 9, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Endless loop with GET request to httpjail in server mode

2 participants