Accessing the Underlying Socket of an HTTP Response
In Go, you may encounter situations where you need to access the underlying socket of an HTTP response. Typically, accessing the socket is required when you want to perform platform-specific operations on it, such as TCP_INFO. While there is no straightforward way to obtain the socket directly from the HTTP response, there are several approaches you can explore:
1. Using the Context Key (Go 1.13 ):
Once Go 1.13 is released, it is anticipated to support storing the net.Conn in the Request Context. This provides a clean and straightforward method:
<code class="go">package main import ( "net/http" "context" "net" "log" ) type contextKey struct { key string } var ConnContextKey = &contextKey{"http-conn"} func SaveConnInContext(ctx context.Context, c net.Conn) (context.Context) { return context.WithValue(ctx, ConnContextKey, c) } func GetConn(r *http.Request) (net.Conn) { return r.Context().Value(ConnContextKey).(net.Conn) } func main() { http.HandleFunc("/", myHandler) server := http.Server{ Addr: ":8080", ConnContext: SaveConnInContext, } server.ListenAndServe() } func myHandler(w http.ResponseWriter, r *http.Request) { conn := GetConn(r) ... }</code>
2. Mapping Connection by Remote Address (TCP):
For servers listening on TCP, each connection has a unique net.Conn.RemoteAddr().String() value. This value can be used as a key to a global map of connections:
<code class="go">package main import ( "net/http" "net" "fmt" "log" ) var conns = make(map[string]net.Conn) func ConnStateEvent(conn net.Conn, event http.ConnState) { if event == http.StateActive { conns[conn.RemoteAddr().String()] = conn } else if event == http.StateHijacked || event == http.StateClosed { delete(conns, conn.RemoteAddr().String()) } } func GetConn(r *http.Request) (net.Conn) { return conns[r.RemoteAddr] } func main() { http.HandleFunc("/", myHandler) server := http.Server{ Addr: ":8080", ConnState: ConnStateEvent, } server.ListenAndServe() } func myHandler(w http.ResponseWriter, r *http.Request) { conn := GetConn(r) ... }</code>
3. Overriding Remote Address for UNIX Sockets:
For UNIX sockets, net.Conn.RemoteAddr().String() always returns "@", making it unsuitable for mapping. To overcome this:
<code class="go">package main import ( "net/http" "net" "os" "golang.org/x/sys/unix" "fmt" "log" ) // ... (code omitted for brevity) func main() { http.HandleFunc("/", myHandler) listenPath := "/var/run/go_server.sock" l, err := NewUnixListener(listenPath) if err != nil { log.Fatal(err) } defer os.Remove(listenPath) server := http.Server{ ConnState: ConnStateEvent, } server.Serve(NewConnSaveListener(l)) } // ... (code omitted for brevity)</code>
The above is the detailed content of How Can I Access the Underlying Socket of an HTTP Response in Go?. For more information, please follow other related articles on the PHP Chinese website!