You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
jsonrpc: replace jhttp.Bridge with an in-tree bridge - #1037
Serves JSON-RPC over HTTP with an in-tree bridge (jsonrpc/bridge.go) instead of jrpc2's jhttp.Bridge. The bridge calls handlers directly, encodes each result once, and writes a json.RawMessage result as is, which #1060 needs for its memoized getLatestLedger body. jrpc2 stays at upstream v1.3.3; go.mod is unchanged.
jhttp.Bridge ran each request through an in-memory client and server and re-encoded the result on the way out. One POST over loopback with a 3.1 MB result (median of 8, M4 Pro, Go 1.26):
result
jhttp.Bridge
in-tree bridge
struct
38.1 ms, 28.5 MiB
2.57 ms, 7.4 MiB
json.RawMessage
44.0 ms, 24.3 MiB
0.35 ms, 11 KiB
Changes
Responses are byte-identical to jhttp.Bridge's (TestBridge_ParityWithJHTTP). As in jrpc2.Server, at most NumCPU handlers run at once.
Global duration limit: the bridge runs handlers under context.WithTimeout and answers 504 when they return. MakeHTTPRequestDurationLimiter and bufferedResponseWriter, with their per-request goroutine and response copy, are gone; their counters and log lines moved into the bridge.
Cancellation: handlers run on the request context, so a client disconnect, the global limit or Handler.Close cancels them. sendTransaction ignores that cancellation and is bounded only by its own limit. Calls that fail after their context ends are labeled canceled in the request metrics.
Handler.Close waits for every handler to return, including ones a per-method duration limit stopped waiting for, so none outlives the stores.
Panics in a handler are recovered and logged; the old bridge crashed the process for one outside the per-method limiter.
Logs:json_req is the caller's JSON-RPC ID; the old bridge's client renumbered requests.
Notes
504 timing: sent when the handlers return, not at the deadline. Per-method limits (5–15 s) are under the 25 s global one, so this only shows for a batch that queues past it.
escapeID does not match jhttp.Bridge for statically invalid requests. Upstream's marshalError inserts ParsedRequest.ID directly, while only responses that pass through its client/server are JSON-marshaled and HTML-escaped. Therefore the added html id on invalid request parity case produces "<b>&" from the old bridge but "\u003cb\u003e\u0026" here. Track whether a response is a parser-generated error and preserve its raw ID in that path, while retaining escaping for handler responses.
cjonas9
changed the title
Bypass jrpc2 marshal to enable raw endpoint response passthrough
jsonrpc: replace jhttp.Bridge with an in-tree bridge (#1037)
Oct 12, 2026
cjonas9
changed the title
jsonrpc: replace jhttp.Bridge with an in-tree bridge (#1037)
jsonrpc: replace jhttp.Bridge with an in-tree bridge
Oct 12, 2026
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
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.
Serves JSON-RPC over HTTP with an in-tree bridge (
jsonrpc/bridge.go) instead of jrpc2'sjhttp.Bridge. The bridge calls handlers directly, encodes each result once, and writes ajson.RawMessageresult as is, which #1060 needs for its memoizedgetLatestLedgerbody. jrpc2 stays at upstream v1.3.3;go.modis unchanged.jhttp.Bridgeran each request through an in-memory client and server and re-encoded the result on the way out. One POST over loopback with a 3.1 MB result (median of 8, M4 Pro, Go 1.26):jhttp.Bridgejson.RawMessageChanges
jhttp.Bridge's (TestBridge_ParityWithJHTTP). As injrpc2.Server, at mostNumCPUhandlers run at once.context.WithTimeoutand answers 504 when they return.MakeHTTPRequestDurationLimiterandbufferedResponseWriter, with their per-request goroutine and response copy, are gone; their counters and log lines moved into the bridge.Handler.Closecancels them.sendTransactionignores that cancellation and is bounded only by its own limit. Calls that fail after their context ends are labeledcanceledin the request metrics.Handler.Closewaits for every handler to return, including ones a per-method duration limit stopped waiting for, so none outlives the stores.json_reqis the caller's JSON-RPC ID; the old bridge's client renumbered requests.Notes
json.RawMessageresult is written without validation or HTML escaping. Only methods: memoize latest-ledger reads per ledger sequence #1060 returns one.