Emanuele Micheletti RSS

Proxelar 0.4.0: Intercept & Modify Traffic

2026-04-04

I'm happy to release Proxelar 0.4.0, which delivers the feature I teased at the end of the 0.3.0 post: intercept mode. You can now pause any HTTP or HTTPS request mid-flight, inspect it, edit whatever you want — method, URI, headers, body — and then choose to forward it or drop it entirely.

Until now, Proxelar could capture and display traffic, and with scripting it could modify traffic programmatically. But there was no way to reach in and change a specific request by hand, on the fly, without writing a script first. Intercept mode fills that gap. You see the request frozen in front of you, exactly as the client sent it, and you decide: forward it as-is, modify it first, or drop it entirely.

How Intercept Mode Works

When intercept is off, traffic flows through normally — captured, displayed, forwarded. When intercept is on, every request is held. Nothing reaches the upstream server until you act on it. The proxy is paused, waiting for your decision.

TUI

Toggling Intercept

Press i to enable intercept. The status bar shows a red INTERCEPT badge so you always know whether you're in capture-only mode or actively intercepting.

Press i again to turn it off. Any requests that were pending at that moment are forwarded immediately — clients never hang waiting for a response.

TUI with intercept active — red INTERCEPT badge in the status bar, pending rows in the request list

Acting on a Request

When a request arrives while intercept is on, it appears in the request list as a row instead of the usual status code. Navigate to it with j/k and choose what to do:

KeyAction
fForward the request to the upstream server
dDrop — returns a 504 Gateway Timeout to the client
eOpen the inline editor

The Inline Editor

Press e and the full raw HTTP request appears in an editor panel. Every part of the request is editable — the request line, headers, blank separator, and body, exactly as they would be written on the wire:

POST /api/login HTTP/1.1
host: example.com
content-type: application/json
authorization: Bearer old-token

{"user":"alice","pass":"secret"}

Change anything. Replace the URL, swap the method, add or delete a header, rewrite the body. The editor supports full cursor navigation:

KeyAction
Arrow keys / Home / EndMove the cursor
EnterInsert a new line
Backspace / DeleteDelete characters
EscFinish editing — request stays held, ready to forward
fForward with your edits applied
dDrop
Esc (again, when not typing)Discard your edits

TUI inline editor — full raw HTTP request, editable in place

The design is a two-step flow: edit freely, then Esc to stage your changes, then f to forward. This lets you review your edits before committing. If you change your mind and want to discard everything, press Esc again from the idle-in-editor state.

If the request line you wrote is malformed — wrong format, missing HTTP version, unrecognized method — the editor stays open and the border turns red. Fix the line and try forwarding again. The proxy never sends a request it can't parse.

TUI editor parse error — red border and error message when the request line is malformed

Binary bodies — if the original request body is not valid UTF-8, the editor shows a ⚠ warning. The content is displayed lossily; edits may corrupt binary data, so forward binary-bodied requests without edits or drop them. A future patch will preserve the original bytes when only the method, URI, or headers are changed.

Here is a complete session: a login request caught mid-flight, the token replaced, forwarded to the server:

# Original:
POST /api/login HTTP/1.1
host: api.example.com
content-type: application/json

{"user":"alice","pass":"wrong-password"}

# Edited (in the TUI inline editor):
POST /api/login HTTP/1.1
host: api.example.com
content-type: application/json

{"user":"alice","pass":"correct-password"}

# After pressing f:
→ server receives the corrected request
→ client receives the real response
→ TUI shows the completed exchange as a normal row

No script, no configuration, no restart. You caught it, changed it, forwarded it.

Web GUI

The web GUI gets the same capabilities with a point-and-click interface.

Toggling Intercept

Click the ⏸ Intercept: OFF button in the toolbar to enable intercept. It turns red and starts displaying a count of pending requests — ⏸ Intercept: ON (2) — so you can tell at a glance how many clients are waiting.

Click it again to turn intercept off. All pending requests are forwarded immediately.

Web GUI intercept button active — red, showing pending request count

Acting on a Request

Pending requests appear in the table with an amber left border to distinguish them from completed exchanges. Click a row to open the editor panel.

The panel shows four editable fields:

Edit whatever you need, then:

Web GUI editor panel — method, URI, headers, body fields with Forward and Drop buttons

Here's a typical flow in the web GUI: you're testing an API that reads a user ID from the URL. You intercept a GET /api/users/1 request, change the ID to 99, and forward it to see what the server returns for a user you don't have credentials for. Two clicks, no tooling.

Practical Scenarios

Testing Authorization Logic

You want to verify that your API correctly rejects requests with an expired token. With intercept on, catch a normal request, replace the Authorization header with an expired JWT, and forward:

GET /api/profile HTTP/1.1
host: api.example.com
authorization: Bearer eyJ... (expired token)

The server returns 401. You've confirmed the token validation is working — without touching any client code or adding test infrastructure.

Overriding Request Parameters

Your frontend sends a request with a hardcoded value you can't easily change without recompiling. Intercept it, replace the value in the body, forward it:

# Original body:
{"plan": "free", "user_id": 42}

# Edited:
{"plan": "enterprise", "user_id": 42}

You just tested the premium code path from your existing client session.

Catching and Blocking Specific Requests

Sometimes you want to know what happens when a request doesn't go through. Drop a specific request mid-session — the client gets a 504, and you observe how it handles the failure without shutting anything down.

Replaying a Request with Modifications

Intercept is complementary to Lua scripting. A script is the right tool when you want a rule that applies to every request matching a pattern. Intercept is the right tool when you want to make a one-off decision for a specific request, inspect the result, and move on.

Under the Hood

Intercept mode is built around two new types exported from proxyapi:

pub struct InterceptConfig {
    pub enabled: bool,
}

pub enum InterceptDecision {
    Forward(ProxiedRequest),
    Drop,
}

When intercept is enabled, the CapturingHandler emits a RequestIntercepted event with the request and a oneshot channel instead of forwarding immediately. The interface layer — TUI or web GUI — receives the event, holds the request in a pending list, and waits for the user's decision. When the user acts, an InterceptDecision is sent back through the channel and the proxy forwards or drops accordingly.

The RequestIntercepted event carries the same stable ID that the eventual RequestComplete event will use, so the interface can correlate the pending row with the completed exchange after the request goes through.

Turning intercept off drains the pending queue by sending InterceptDecision::Forward for each waiting request. This is why clients don't hang: the proxy never leaves a oneshot receiver without a sender.

One edge case worth knowing: if a client times out while its request is pending, it drops the TCP connection. The row stays in the UI — the proxy has no way to know the client gave up. If you then forward, the upstream response has nowhere to go and the write fails silently. The proxy handles this gracefully, but the pending row will linger until you act on it or toggle intercept off.

The parse-error path in the TUI editor validates the edited request before forwarding. If the request line doesn't parse — wrong number of parts, unrecognized method, bad HTTP version — the editor returns an error and the border turns red. The forward is not attempted until the input is valid.

Two bugs were fixed in this release along the way:

Getting Started

Update Proxelar:

cargo install proxelar

Run the proxy:

proxelar          # TUI (default)
proxelar -i gui   # Web GUI at localhost:8081

In the TUI, press i to toggle intercept. In the web GUI, click the intercept button in the toolbar. Browse normally — or point curl at the proxy with --proxy http://127.0.0.1:8080 — and watch requests arrive as rows.

The full documentation for intercept mode is at proxelar.micheletti.io/intercept.html. The complete changelog is on GitHub.

What's Next

Intercept mode closes the gap between passively watching traffic and actively controlling it. The remaining items from the 0.3.0 roadmap are still the priority: