This plugin demonstrates response status code manipulation by remapping server errors (5xx status codes) to a different status code. It intercepts all 5xx responses (500, 502, 503, etc.) and changes them to 404 Not Found. Use this plugin when you need to hide internal server errors from clients, normalize error responses, or implement custom error mapping strategies for security or UX reasons. It operates during the response headers processing phase.
-
The proxy receives an HTTP response from the upstream server and invokes the plugin's
on_http_response_headerscallback. -
Status code extraction: The plugin reads the
:statuspseudo-header and parses it as an integer. -
5xx detection: The plugin checks if the status code is in the 5xx range by dividing by 100:
response_code / 100 == 5matches 500-599
-
Status code remapping: If a 5xx status is detected:
- The plugin calls
mapResponseCode()(C++/Go) or directly sets"404"(Rust) - The remapping function returns 404 for all 5xx codes
- The plugin replaces the
:statusheader with the new value
- The plugin calls
-
Non-5xx responses: For all other status codes (2xx, 3xx, 4xx), the response passes through unchanged.
-
The plugin returns
Continue/ActionContinue, forwarding the (potentially modified) response to the client.
- Status code parsing: Safely extracts and parses the
:statuspseudo-header into a workable integer representation. - Range detecting logic: Uses integer division (
code / 100 == 5) to efficiently classify all 5xx errors rather than comparing against bounds. - Status overriding: Modifies the
:statusheader to 404 whenever the aforementioned 5xx range test evaluates to true.
No configuration required. The remapping logic (5xx → 404) is hardcoded in the plugin source.
Customization examples:
-
Remap to different codes:
static int mapResponseCode(int response_code) { switch (response_code) { case 500: return 503; // Internal Error → Service Unavailable case 502: return 503; // Bad Gateway → Service Unavailable case 503: return 503; // Keep Service Unavailable default: return response_code; } }
-
Preserve specific 5xx codes:
static int mapResponseCode(int response_code) { if (response_code == 503) { return 503; // Keep 503 unchanged } return (response_code / 100 == 5) ? 404 : response_code; }
-
Remap to 200 (hide all errors):
static int mapResponseCode(int response_code) { return (response_code / 100 == 5) ? 200 : response_code; }
Build the plugin for any supported language from the plugins/ directory:
# Rust
bazelisk build //samples/overwrite_errcode:plugin_rust.wasm
# C++
bazelisk build //samples/overwrite_errcode:plugin_cpp.wasm
# Go
bazelisk build //samples/overwrite_errcode:plugin_go.wasmRun the unit tests defined in tests.textpb:
# Using Docker (recommended)
docker run -it -v $(pwd):/mnt \
us-docker.pkg.dev/service-extensions-samples/plugins/wasm-tester:main \
--proto /mnt/samples/overwrite_errcode/tests.textpb \
--plugin /mnt/bazel-bin/samples/overwrite_errcode/plugin_rust.wasm
# Using Bazel (all languages)
bazelisk test --test_output=all //samples/overwrite_errcode:testsDerived from tests.textpb:
| Scenario | Description |
|---|---|
| With500StatusCodeChangeTo404 | Modifies a 500 error code to 404 Not Found before responding to the client. |
| With502StatusCodeChangeTo404 | Modifies a 502 error code to 404 Not Found before responding to the client. |
| With200StatusCodeNothingChanges | Permits successful 200 OK responses to pass unmodified. |
Important: Remapping 5xx errors to 4xx codes can hide important operational issues:
- Monitoring impact: Error rates in monitoring systems may be misreported
- Debugging difficulty: Makes troubleshooting harder since the original error is lost
- Client confusion: Clients may misinterpret 404 when the actual problem is server-side
Note: When using this pattern, logging the original status code before remapping, using it selectively, preserving original codes in internal headers, and monitoring backend errors separately can help mitigate these issues.