Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,9 @@ jobs:
h2_trailer \
grpc \
grpc_proxy \
grpc_obs ; do
grpc_obs \
grpc_web \
grpc_web_edge ; do
echo "::group::test_runner $suite"
./test_runner "$suite"
echo "::endgroup::"
Expand Down Expand Up @@ -316,6 +318,20 @@ jobs:
# bound; retry timing and trailer-frame delivery are sensitive to
# kqueue vs epoll EOF coalescing and scheduler ordering.
run: ./test_runner grpc_obs
- name: Test - grpc_web (gRPC-Web bridge)
# Boots a real HttpServer; the gRPC-Web integration test (GW1)
# exercises the H2 async-handler complete callback, the wrap
# rollout, and the in-stream trailer-frame wire shape via live
# HPACK / nghttp2 framing. Socket-bound — admission classifier
# and rewriter interact with the H2 dispatch state machine.
run: ./test_runner grpc_web
- name: Test - grpc_web_edge (gRPC-Web edge/race/memory/perf)
# Boots real HttpServer instances for integration edge cases (GWE11-GWE18).
# Tests binary/text Trailers-Only rewrite, +proto suffix propagation,
# 64 KB pass-through, concurrent requests (4×10, 4×8), server stop
# with in-flight gRPC-Web handler, and sequential residue-bleed check.
# kqueue vs epoll EOF coalescing affects the H2 teardown path in GWE16.
run: ./test_runner grpc_web_edge
- name: Test - obs_e2e (real-socket observability end-to-end)
# Boots a real HttpServer and verifies SERVER spans / finalize
# counters / 404 finalize. Socket-bound; the rest of the obs_*
Expand Down
9 changes: 8 additions & 1 deletion .github/workflows/weekly-valgrind.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ jobs:
CFLAGS_EXTRA="-O1 -g -fno-omit-frame-pointer" \
NGHTTP2_CFLAGS_EXTRA="-O1 -g -fno-omit-frame-pointer"
- name: Valgrind sweep (memory-safety subset)
env:
# Signal the test binary to skip wall-clock perf assertions
# (GWE22–GWE24) that fail under valgrind's 10-50× slowdown.
# IsSanitizerOrValgrindBuild() in grpc_web_edge_test.h reads this.
VALGRIND_TEST: "1"
run: |
set -e
# Suites chosen for memory-safety signal-per-minute. Excluded:
Expand Down Expand Up @@ -104,7 +109,9 @@ jobs:
h2_trailer \
grpc \
grpc_proxy \
grpc_obs ; do
grpc_obs \
grpc_web \
grpc_web_edge ; do
echo "::group::valgrind test_runner $suite"
valgrind \
--error-exitcode=1 \
Expand Down
18 changes: 14 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ HTTP2_SRCS = $(SERVER_DIR)/http2_session.cc $(SERVER_DIR)/http2_stream.cc $(SERV
TLS_SRCS = $(SERVER_DIR)/tls_context.cc $(SERVER_DIR)/tls_connection.cc $(SERVER_DIR)/tls_client_context.cc

# Upstream connection pool sources
UPSTREAM_SRCS = $(SERVER_DIR)/upstream_connection.cc $(SERVER_DIR)/pool_partition.cc $(SERVER_DIR)/upstream_host_pool.cc $(SERVER_DIR)/upstream_manager.cc $(SERVER_DIR)/header_rewriter.cc $(SERVER_DIR)/retry_policy.cc $(SERVER_DIR)/upstream_http_codec.cc $(SERVER_DIR)/upstream_h2_codec.cc $(SERVER_DIR)/upstream_h2_connection.cc $(SERVER_DIR)/h2_connection_table.cc $(SERVER_DIR)/http_request_serializer.cc $(SERVER_DIR)/proxy_transaction.cc $(SERVER_DIR)/proxy_handler.cc
UPSTREAM_SRCS = $(SERVER_DIR)/upstream_connection.cc $(SERVER_DIR)/pool_partition.cc $(SERVER_DIR)/upstream_host_pool.cc $(SERVER_DIR)/upstream_manager.cc $(SERVER_DIR)/header_rewriter.cc $(SERVER_DIR)/retry_policy.cc $(SERVER_DIR)/upstream_http_codec.cc $(SERVER_DIR)/upstream_h2_codec.cc $(SERVER_DIR)/upstream_h2_connection.cc $(SERVER_DIR)/h2_connection_table.cc $(SERVER_DIR)/http_request_serializer.cc $(SERVER_DIR)/proxy_transaction.cc $(SERVER_DIR)/proxy_handler.cc $(SERVER_DIR)/grpc_web_inbound_body_stream.cc

# Rate limit layer sources
RATE_LIMIT_SRCS = $(SERVER_DIR)/token_bucket.cc $(SERVER_DIR)/rate_limit_zone.cc $(SERVER_DIR)/rate_limiter.cc
Expand Down Expand Up @@ -133,7 +133,8 @@ UTIL_SRCS = $(UTIL_DIR)/timestamp.cc $(UTIL_DIR)/base64.cc
# Trailers-Only response synthesis.
GRPC_SRCS = $(SERVER_DIR)/grpc_status.cc \
$(SERVER_DIR)/grpc_timeout.cc \
$(SERVER_DIR)/grpc_synthesis.cc
$(SERVER_DIR)/grpc_synthesis.cc \
$(SERVER_DIR)/grpc_web_bridge.cc

# llhttp C sources
LLHTTP_SRC = $(THIRD_PARTY_DIR)/llhttp/llhttp.c $(THIRD_PARTY_DIR)/llhttp/api.c $(THIRD_PARTY_DIR)/llhttp/http.c
Expand Down Expand Up @@ -200,7 +201,8 @@ CLI_HEADERS = $(LIB_DIR)/cli/cli_parser.h $(LIB_DIR)/cli/signal_handler.h $(LIB_
GRPC_HEADERS = $(LIB_DIR)/grpc/grpc_reject_kind.h $(LIB_DIR)/grpc/grpc_status.h $(LIB_DIR)/grpc/grpc_timeout.h $(LIB_DIR)/grpc/grpc_synthesis.h
TEST_HEADERS = $(TEST_DIR)/test_framework.h $(TEST_DIR)/http_test_client.h $(TEST_DIR)/basic_test.h $(TEST_DIR)/stress_test.h $(TEST_DIR)/race_condition_test.h $(TEST_DIR)/timeout_test.h $(TEST_DIR)/config_test.h $(TEST_DIR)/http_test.h $(TEST_DIR)/websocket_test.h $(TEST_DIR)/tls_test.h $(TEST_DIR)/cli_test.h $(TEST_DIR)/http2_test.h $(TEST_DIR)/route_test.h $(TEST_DIR)/upstream_pool_test.h $(TEST_DIR)/proxy_test.h $(TEST_DIR)/rate_limit_test.h $(TEST_DIR)/kqueue_test.h $(TEST_DIR)/circuit_breaker_test.h $(TEST_DIR)/circuit_breaker_components_test.h $(TEST_DIR)/circuit_breaker_integration_test.h $(TEST_DIR)/circuit_breaker_retry_budget_test.h $(TEST_DIR)/circuit_breaker_wait_queue_drain_test.h $(TEST_DIR)/circuit_breaker_observability_test.h $(TEST_DIR)/circuit_breaker_reload_test.h $(TEST_DIR)/auth_foundation_test.h $(TEST_DIR)/jwt_verifier_test.h $(TEST_DIR)/jwks_cache_test.h $(TEST_DIR)/oidc_discovery_test.h $(TEST_DIR)/header_rewriter_auth_test.h $(TEST_DIR)/auth_manager_test.h $(TEST_DIR)/auth_integration_test.h $(TEST_DIR)/auth_failure_mode_test.h $(TEST_DIR)/auth_reload_test.h $(TEST_DIR)/auth_multi_issuer_test.h $(TEST_DIR)/auth_websocket_upgrade_test.h $(TEST_DIR)/auth_race_test.h $(TEST_DIR)/dns_resolver_test.h $(TEST_DIR)/dual_stack_test.h $(TEST_DIR)/router_async_middleware_test.h $(TEST_DIR)/introspection_cache_test.h $(TEST_DIR)/introspection_client_test.h $(TEST_DIR)/mock_introspection_server.h $(TEST_DIR)/auth_introspection_integration_test.h $(TEST_DIR)/auth_observability_test.h $(TEST_DIR)/h2_upstream_test.h $(TEST_DIR)/observability_test_helpers.h $(TEST_DIR)/observability_foundation_test.h $(TEST_DIR)/observability_tracer_test.h $(TEST_DIR)/observability_metrics_test.h $(TEST_DIR)/observability_manager_test.h $(TEST_DIR)/observability_propagator_test.h $(TEST_DIR)/observability_export_pipeline_test.h $(TEST_DIR)/observability_prometheus_test.h $(TEST_DIR)/observability_config_test.h $(TEST_DIR)/observability_shutdown_test.h $(TEST_DIR)/observability_link_kill_test.h $(TEST_DIR)/observability_issue_inject_test.h $(TEST_DIR)/observability_stress_test.h $(TEST_DIR)/observability_e2e_test.h $(TEST_DIR)/observability_self_handler_test.h $(TEST_DIR)/observability_proxy_client_test.h $(TEST_DIR)/observability_auth_trace_test.h $(TEST_DIR)/observability_catalog_test.h $(TEST_DIR)/observability_kill_marshal_test.h $(TEST_DIR)/observability_pool_gauges_test.h $(TEST_DIR)/observability_middleware_metrics_test.h $(TEST_DIR)/observability_self_metrics_test.h $(TEST_DIR)/observability_connection_metrics_test.h $(TEST_DIR)/observability_jaeger_propagator_test.h $(TEST_DIR)/observability_ws_messages_test.h $(TEST_DIR)/sharded_lru_cache_test.h \
$(TEST_DIR)/streaming_request_test.h $(TEST_DIR)/h2_trailer_test.h \
$(TEST_DIR)/grpc_test.h $(TEST_DIR)/grpc_proxy_test.h $(TEST_DIR)/grpc_obs_test.h
$(TEST_DIR)/grpc_test.h $(TEST_DIR)/grpc_proxy_test.h $(TEST_DIR)/grpc_obs_test.h \
$(TEST_DIR)/grpc_web_test.h $(TEST_DIR)/grpc_web_edge_test.h

# All headers combined
HEADERS = $(CORE_HEADERS) $(CALLBACK_HEADERS) $(REACTOR_HEADERS) $(NETWORK_HEADERS) $(DNS_HEADERS) $(SERVER_HEADERS) $(THREAD_POOL_HEADERS) $(UTIL_HEADERS) $(FOUNDATION_HEADERS) $(HTTP_HEADERS) $(HTTP2_HEADERS) $(WS_HEADERS) $(TLS_HEADERS) $(UPSTREAM_HEADERS) $(RATE_LIMIT_HEADERS) $(CIRCUIT_BREAKER_HEADERS) $(AUTH_HEADERS) $(CLI_HEADERS) $(GRPC_HEADERS) $(OBSERVABILITY_HEADERS) $(TEST_HEADERS)
Expand Down Expand Up @@ -539,6 +541,14 @@ test_grpc_obs: $(TARGET)
@echo "Running gRPC observability + trailer-status retry tests..."
./$(TARGET) grpc_obs

test_grpc_web: $(TARGET)
@echo "Running gRPC-Web bridge tests..."
./$(TARGET) grpc_web

test_grpc_web_edge: $(TARGET)
@echo "Running gRPC-Web edge/race/memory/perf tests..."
./$(TARGET) grpc_web_edge

# Thread-Sanitizer build for dual-stack stop/reload/destruction race tests.
# Builds a separate binary (test_runner_tsan) with -fsanitize=thread and
# runs the dual_stack TSAN subset (stop-vs-reload, teardown barrier,
Expand Down Expand Up @@ -641,4 +651,4 @@ help:
# Build only the production server binary
server: $(SERVER_TARGET)

.PHONY: all clean test server test_basic test_stress test_race test_config test_http test_ws test_tls test_cli test_http2 test_upstream test_proxy test_rate_limit test_circuit_breaker test_auth test_auth_foundation test_jwt test_jwks test_oidc test_hrauth test_auth_mgr test_auth2 test_auth_fail test_auth_reload test_auth_multi test_auth_ws test_auth_race test_router_async test_introspection_cache test_intro_client test_auth_intro test_lru_cache test_dns test_dual_stack test_dual_stack_tsan test_dns_resolver test_auth_observability test_h2_upstream test_obs test_obs_foundation test_obs_tracer test_obs_metrics test_obs_mgr test_obs_propagator test_obs_jaeger_propagator test_obs_export test_obs_prom test_obs_config test_obs_shutdown test_obs_linkkill test_obs_issue test_obs_stress test_obs_e2e test_obs_self_handler test_obs_proxy_client test_obs_auth_trace test_obs_catalog test_obs_kill_marshal test_obs_ws_messages test_obs_self_metrics test_obs_connection_metrics test_obs_pool_gauges test_obs_middleware_metrics test_streaming_request test_h2_trailer test_grpc test_grpc_proxy test_grpc_obs help
.PHONY: all clean test server test_basic test_stress test_race test_config test_http test_ws test_tls test_cli test_http2 test_upstream test_proxy test_rate_limit test_circuit_breaker test_auth test_auth_foundation test_jwt test_jwks test_oidc test_hrauth test_auth_mgr test_auth2 test_auth_fail test_auth_reload test_auth_multi test_auth_ws test_auth_race test_router_async test_introspection_cache test_intro_client test_auth_intro test_lru_cache test_dns test_dual_stack test_dual_stack_tsan test_dns_resolver test_auth_observability test_h2_upstream test_obs test_obs_foundation test_obs_tracer test_obs_metrics test_obs_mgr test_obs_propagator test_obs_jaeger_propagator test_obs_export test_obs_prom test_obs_config test_obs_shutdown test_obs_linkkill test_obs_issue test_obs_stress test_obs_e2e test_obs_self_handler test_obs_proxy_client test_obs_auth_trace test_obs_catalog test_obs_kill_marshal test_obs_ws_messages test_obs_self_metrics test_obs_connection_metrics test_obs_pool_gauges test_obs_middleware_metrics test_streaming_request test_h2_trailer test_grpc test_grpc_proxy test_grpc_obs test_grpc_web test_grpc_web_edge help
4 changes: 2 additions & 2 deletions docs/callback_architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The server uses a 3-layer callback chain for separation of concerns. All callbac
- **`include/upstream/upstream_callbacks.h`** — Upstream pool callbacks (`UPSTREAM_CALLBACKS_NAMESPACE`)
- `ReadyCallback` — Delivers a valid UpstreamLease on successful checkout
- `ErrorCallback` — Delivers a PoolPartition error code on checkout failure
- `H2StreamingAbortCallback` — Per-H2-stream keepalive + deferred terminal-error callable; used by `UpstreamH2Stream::streaming_abort_callback` and `UpstreamResponseSink::MakeDeferredErrorCallback()`
- `H2StreamingAbortCallback` — Per-H2-stream keepalive + deferred terminal-error callable `void(int code, string msg, bool breaker_neutral)`; used by `UpstreamH2Stream::streaming_abort_callback` and `UpstreamResponseSink::MakeDeferredErrorCallback()`

**Re-export pattern.** Callback aliases live in their layer's `*_callbacks.h`. Class headers (`ConnectionHandler`, `HttpConnectionHandler`, `Http2ConnectionHandler`, `BodyStream`, `HttpParser`) re-export the short class-scope name via `using LocalAlias = NAMESPACE::CanonicalAlias;` so caller source stays stable.

Expand Down Expand Up @@ -142,7 +142,7 @@ All callbacks must handle partial reads/writes (EAGAIN/EWOULDBLOCK). Read loops
|------|-----------|---------|
| `ReadyCallback` | `void(UpstreamLease)` | Successful checkout — delivers RAII lease |
| `ErrorCallback` | `void(int error_code)` | Failed checkout — delivers error code |
| `H2StreamingAbortCallback` | `void(int code, string msg)` | Per-H2-stream txn keepalive + deferred terminal-error callable; used by `UpstreamH2Stream::streaming_abort_callback` |
| `H2StreamingAbortCallback` | `void(int code, string msg, bool breaker_neutral)` | Per-H2-stream txn keepalive + deferred terminal-error callable; used by `UpstreamH2Stream::streaming_abort_callback`. The third arg lets the ABORTED branch release the breaker admission as neutral (client-shape failure, not upstream health). |

**Checkout error codes** (defined on `PoolPartition`):

Expand Down
Loading
Loading