Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible to retrieve peer info? #357

Closed
eberkund opened this issue Sep 7, 2022 · 7 comments · Fixed by #364
Closed

Possible to retrieve peer info? #357

eberkund opened this issue Sep 7, 2022 · 7 comments · Fixed by #364
Labels
enhancement New feature or request

Comments

@eberkund
Copy link

eberkund commented Sep 7, 2022

With grpc-go I can get peer info like so:

p, ok := peer.FromContext(ctx)
if !ok {
    return nil, errors.New("could not get peer from context")
}
addr := p.Addr.String()

Is it possible to do this with connect-go?

I am trying to get the IP that the request is originating from.

Thanks

@eberkund eberkund added the enhancement New feature or request label Sep 7, 2022
@akshayjshah
Copy link
Member

akshayjshah commented Sep 8, 2022

Currently, it's possible but not super-simple. You'd need to write a small piece of net/http middleware to attach the HTTP Request.RemoteAddr to the context, then pull it off the context and include it in your logs.

I'm open to exposing this in handlers with an easier-to-use API, but I'd like to see what else people expect to do with this information. For example, we don't have any current plans to expose an equivalent to the grpc.Peer call options.

@clly
Copy link

clly commented Sep 9, 2022

Some potential usages I can think of include per IP rate limiting, caching, or naive authorization.

It might be nicer to include it in the request object like the headers are. It makes them more explicit, less magical, and easier to use.

@eberkund
Copy link
Author

eberkund commented Sep 9, 2022

A middleware like @akshayjshah suggested indeed works for anyone who comes across this issue. This is how I implemented it:

type remoteAddrKey struct{}

func addRemoteAddr(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := context.WithValue(r.Context(), remoteAddrKey{}, r.RemoteAddr)
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

Make sure you wrap your handler in the middleware (like any other HTTP middleware in Go):

mux.Handle(path, addRemoteAddr(handler))

And then in your handler:

remoteAddr, ok := ctx.Value(remoteAddrKey{}).(string)

@eberkund
Copy link
Author

eberkund commented Sep 9, 2022

But besides the option above, is there a way to get the remote address without the middleware?

I saw the IP address is already in the context when I was playing around with my debugger but I just didn't get to a point of figuring out how to extract it.

@akshayjshah
Copy link
Member

I saw the IP address is already in the context when I was playing around with my debugger but I just didn't get to a point of figuring out how to extract it.

Nothing in connect-go is putting the IP onto the context, and AFAIK nothing in net/http is either.

akshayjshah added a commit that referenced this issue Sep 22, 2022
On requests and streams, expose the peer's address. For clients, the
address is the host or host:port, parsed from the URL. For servers, the
address is an IP:port pair, provided by `net/http` as
`Request.RemoteAddr`.

In #357, a handful of users asked for this information for logging,
per-IP rate limiting, and a variety of other server-side concerns. It's
also necessary for OpenTelemetry interceptors (#344).

Fixes #357.
akshayjshah added a commit that referenced this issue Sep 22, 2022
On requests and streams, expose the peer's address. For clients, the
address is the host or host:port, parsed from the URL. For servers, the
address is an IP:port pair, provided by `net/http` as
`Request.RemoteAddr`.

In #357, a handful of users asked for this information for logging,
per-IP rate limiting, and a variety of other server-side concerns. It's
also necessary for OpenTelemetry interceptors (#344).

Fixes #357.
@akshayjshah
Copy link
Member

Opened a PR that exposes this info on Request, AnyRequest, StreamingClientConn, StreamingHandlerConn, and the relevant wrappers. @clly, we're definitely not attaching anything to the context!

Usage looks like this:

type PingServer struct {}

func (p *PingServer) Ping(
  ctx context.Context,
  request *connect.Request[pingv1.PingRequest],
) (*connect.Response[pingv1.PingResponse], error) {
  fmt.Println(request.Peer().Addr) // <-- this is new!
  return connect.NewResponse(&pingv1.PingResponse{
    Number: request.Msg.Number,
  }), nil
}

akshayjshah added a commit that referenced this issue Sep 23, 2022
* Add Spec to some user-facing streams

Where the generated code replaces Request with a stream, expose the
Spec.

* Expose peer information to servers and clients

On requests and streams, expose the peer's address. For clients, the
address is the host or host:port, parsed from the URL. For servers, the
address is an IP:port pair, provided by `net/http` as
`Request.RemoteAddr`.

In #357, a handful of users asked for this information for logging,
per-IP rate limiting, and a variety of other server-side concerns. It's
also necessary for OpenTelemetry interceptors (#344).

Fixes #357.
@akshayjshah
Copy link
Member

Released in v0.5.0!

akshayjshah added a commit that referenced this issue Jul 26, 2023
* Add Spec to some user-facing streams

Where the generated code replaces Request with a stream, expose the
Spec.

* Expose peer information to servers and clients

On requests and streams, expose the peer's address. For clients, the
address is the host or host:port, parsed from the URL. For servers, the
address is an IP:port pair, provided by `net/http` as
`Request.RemoteAddr`.

In #357, a handful of users asked for this information for logging,
per-IP rate limiting, and a variety of other server-side concerns. It's
also necessary for OpenTelemetry interceptors (#344).

Fixes #357.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants