Skip to content

Commit

Permalink
http3: add remote address to request context (#4208)
Browse files Browse the repository at this point in the history
* http3: add remote address to request context

Add the remote address of the underlying packet connection to the
HTTP request context. This is useful for applications that need access
to the actual remote address (wrapped in a net.Addr) rather than just
its string representation.

Fixes #4198

* add an integration test to the self test suite.

I was not sure how deep we want to go to assure the right value is set.
For now, it asserts that a net.Addr is present in the context.

Due to the dynamic nature of the requests, it is a bit harder to know
exactly how the remote address will look like. IPv4 vs IPv6, random high
port. I think it is fine to only assert that the value is present.
  • Loading branch information
oncilla committed Dec 16, 2023
1 parent 6ffb905 commit 06c6a84
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 0 deletions.
11 changes: 11 additions & 0 deletions http3/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,16 @@ func (k *contextKey) String() string { return "quic-go/http3 context value " + k
// type *http3.Server.
var ServerContextKey = &contextKey{"http3-server"}

// RemoteAddrContextKey is a context key. It can be used in
// HTTP handlers with Context.Value to access the remote
// address of the connection. The associated value will be of
// type net.Addr.
//
// Use this value instead of [http.Request.RemoteAddr] if you
// require access to the remote address of the connection rather
// than its string representation.
var RemoteAddrContextKey = &contextKey{"remote-addr"}

type requestError struct {
err error
streamErr ErrCode
Expand Down Expand Up @@ -597,6 +607,7 @@ func (s *Server) handleRequest(conn quic.Connection, str quic.Stream, decoder *q
ctx := str.Context()
ctx = context.WithValue(ctx, ServerContextKey, s)
ctx = context.WithValue(ctx, http.LocalAddrContextKey, conn.LocalAddr())
ctx = context.WithValue(ctx, RemoteAddrContextKey, conn.RemoteAddr())
req = req.WithContext(ctx)
r := newResponseWriter(str, conn, s.logger)
if req.Method == http.MethodHead {
Expand Down
12 changes: 12 additions & 0 deletions integrationtests/self/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -481,4 +481,16 @@ var _ = Describe("HTTP tests", func() {
Expect(time.Now().After(expectedEnd)).To(BeTrue())
Expect(string(body)).To(ContainSubstring("aa"))
})

It("sets remote address", func() {
mux.HandleFunc("/remote-addr", func(w http.ResponseWriter, r *http.Request) {
defer GinkgoRecover()
_, ok := r.Context().Value(http3.RemoteAddrContextKey).(net.Addr)
Expect(ok).To(BeTrue())
})

resp, err := client.Get(fmt.Sprintf("https://localhost:%d/remote-addr", port))
Expect(err).ToNot(HaveOccurred())
Expect(resp.StatusCode).To(Equal(200))
})
})

0 comments on commit 06c6a84

Please sign in to comment.