creachadair/jrpc2

How to add custom header in NewBridge options

Closed this issue · 4 comments

How to add custom header http request to context json rpc by using NewBridge options?

jhttp.NewBridge(hd, &jhttp.BridgeOptions{})

Example request:

curl -X POST -H 'Content-Type: application/json' \
     -d '{"jsonrpc":"2.0","id":"1111","method":"proto.echo_service.echo", "params":{"name":"javad"}}' \
     http://localhost:8081

Can you say more about what you're trying to accomplish?

If you mean that you'd like to get data from the HTTP headers and add it to the request, you can do that in a ParseRequest handler. You'd need to rewrite the request values to stick in the extra data somewhere that the server will know how to find it.

Can you say more about what you're trying to accomplish?

If you mean that you'd like to get data from the HTTP headers and add it to the request, you can do that in a ParseRequest handler. You'd need to rewrite the request values to stick in the extra data somewhere that the server will know how to find it.

I want to receive an extra header from the client on request on the bridge.

X-Custom-Header: foobar

I want to receive an extra header from the client on request on the bridge.

X-Custom-Header: foobar

Since the JSON-RPC server doesn't have a concept that corresponds to HTTP headers, you'll have to decide how you want that information to be passed through. The Bridge type can't do it automatically.

Probably the most direct solution will be to write a custom ParseRequests method that parses the incoming requests, and injects the headers of interest into the parameters. Something like:

// Warning: untested

type paramsAndHeaders struct {
	Headers    map[string]string `json:"headers,omitempty"`
	UserParams json.RawMessage   `json:"userParams"`
}

func parseAndDecorateRequests(req *http.Request) ([]*jrpc2.ParsedRequest, error) {
	body, err := io.ReadAll(req.Body)
	if err != nil {
		return nil, err
	}
	prs, err := jrpc2.ParseRequests(body)
	if err != nil {
		return nil, err
	}

	// Extract any interesting data from the HTTP heqders.
	h := map[string]string{"X-Custom-Header": req.Header.Get("X-Custom-Header")}

	// Decorate the incoming request parameters with the headers.
	for _, pr := range prs {
		w, err := json.Marshal(paramsAndHeaders{
			Headers:    h,
			UserParams: pr.Params,
		})
		if err != nil {
			return nil, err
		}
		pr.Params = w
	}
	return prs, nil
}

The handlers on the server side would need to be taught to either recognize this wrapper directly, or wrapped in a helper to unpack them. The first is probably easier.

Having said all that: The point of the Bridge type is to opaquely bridge JSON-RPC requests through an HTTP connection. But if you really want HTTP semantics (including headers, auth, etc.) you might as well just use HTTP directly and save the extra encoding step.

type paramsAndHeaders struct {
	Headers    map[string]string `json:"headers,omitempty"`
	UserParams json.RawMessage   `json:"userParams"`
}

Thank you worked on protoc plugin.

https://github.com/PacViewer/jrpc-gateway