Add comprehensive integration tests for proxy forwarding#46
Merged
Conversation
Add integration tests covering the full proxy TCP lifecycle: - HTTP GET/POST forwarding with body and headers - Response header forwarding from upstream - Hop-by-hop header stripping (Proxy-Authorization not leaked) - Health check interception vs absolute URL forwarding - SSRF blocking for HTTP, CONNECT, and localhost - 502 Bad Gateway on unreachable upstream - CONNECT tunnel SSRF protection - Multiple sequential requests through one proxy Split tests into two files: - proxy_integration.rs: always runs (SSRF, health check, error handling) - proxy_forwarding.rs: gated behind _test-support feature (forwarding) Add _test-support feature flag with SSRF bypass mechanism so integration tests can use localhost upstreams. The bypass is behind cfg(feature) and defaults to off — never active in production. Also fixes pre-existing cargo fmt issues in http.rs and https.rs.
- Extract start_proxy, start_upstream, send_raw into tests/common/mod.rs - Use std::sync::Once for one-time SSRF bypass setup in forwarding tests - Add CONNECT tunnel bidirectional data test - Replace DNS-dependent 502 tests with deterministic bind+drop pattern - Improve hop-by-hop test to verify both stripping and forwarding - Remove non-deterministic unreachable host test
- Move connection handling logic from main.rs to lib.rs as public generic function, eliminating duplicated code in test helpers - main.rs becomes a thin wrapper (stream split + delegation) - tests/common/mod.rs calls rhoxy::handle_connection directly - tests/malformed_request.rs uses shared helpers instead of own copies - Add SSRF bypass verification test in proxy_forwarding - Fix magic number in POST body assertion
Add 6 new integration tests covering previously untested areas: - Concurrent requests (10 simultaneous via tokio::spawn) - Connection timeout (partial request triggers EOF after timeout) - Connection limit rejection (excess connections get EOF) - Connection limit recovery (permits released after completion) - Large body forwarding (128 KiB POST) - Chunked transfer encoding end-to-end reassembly Add 3 helpers to tests/common: start_proxy_with_timeout, start_proxy_with_limit, start_looping_upstream. 91 tests passing, zero warnings.
…SRF guard - Extract duplicated header+body reading logic into common::read_upstream_body with case-insensitive Content-Length matching - Standardize all status assertions to "200 OK" (not bare "200") - Replace redundant body assertion in health check with ends_with check - Add negative SSRF bypass test to proxy_integration.rs to catch accidental feature flag leakage - Remove unused AsyncBufReadExt import from proxy_forwarding.rs 92 tests passing, zero warnings.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
proxy_integration.rs(SSRF protection, health check) andproxy_forwarding.rs(HTTP/HTTPS forwarding, requires_test-supportfeature)proxy_server.rsfor production server behaviors (timeout, connection limiting)_test-supportcargo feature with SSRF bypass mechanism so forwarding tests can use localhost upstreamshandle_connectiontolib.rsas a single source of truth —main.rsand all test helpers call the same code pathread_upstream_bodyhelper for DRY test upstream serversmalformed_request.rsto use shared test helpersCloses
Closes #36
Closes #37
Closes #38
Closes #39
Test coverage added
test_ssrf_bypass_activetest_ssrf_bypass_not_active_in_integration_teststest_http_get_forwardingtest_http_post_with_bodytest_http_response_headers_forwardedtest_http_hop_by_hop_headers_stripped_and_others_forwardedtest_health_check_returns_200test_health_check_not_intercepted_for_absolute_urltest_http_ssrf_block_private_addresstest_connect_ssrf_block_private_addresstest_http_ssrf_block_localhosttest_connect_handler_ssrf_blocks_privatetest_http_502_on_closed_porttest_connect_502_on_closed_porttest_connect_tunnel_bidirectionaltest_proxy_handles_multiple_sequential_requeststest_proxy_handles_concurrent_requeststest_http_post_large_bodytest_http_post_chunked_transfer_encodingtest_connection_timeout_closes_idle_connectiontest_connection_limit_rejects_excesstest_connection_limit_recovers_after_completionArchitecture
How to run
Test plan
cargo test --features _test-supportpasses (92 tests)cargo fmt -- --checkcleancargo clippy --features _test-support -- -D warningsclean🤖 Generated with Claude Code