Hijackify to be used in conjunction with HijackAcceptor. Tells the server to perform hijack operation on the connection which means the server will retrieve the underlying tcp connection and hand it over / no longer serves requests to it. -> we can use it as a long-running server-client connection a
(conn net.Conn, timeout time.Duration)
| 37 | // will retrieve the underlying tcp connection and hand it over / no longer serves requests to it. |
| 38 | // -> we can use it as a long-running server-client connection and re-purpose it to run our IPC/yamux stack on top. |
| 39 | func Hijackify(conn net.Conn, timeout time.Duration) (net.Conn, error) { |
| 40 | ctx, cancel := context.WithTimeout(context.Background(), timeout) |
| 41 | defer cancel() |
| 42 | req, err := http.NewRequestWithContext(ctx, "GET", "http://secrets-engine.localhost"+hijackPath, nil) |
| 43 | if err != nil { |
| 44 | return nil, err |
| 45 | } |
| 46 | req.Header.Set("Connection", "upgrade") |
| 47 | req.Header.Set("Upgrade", "tcp") |
| 48 | |
| 49 | if err := req.Write(conn); err != nil { |
| 50 | return nil, fmt.Errorf("making hijack request: %s", err) |
| 51 | } |
| 52 | |
| 53 | if err := conn.SetDeadline(time.Now().Add(timeout)); err != nil { |
| 54 | return nil, fmt.Errorf("clearing deadline: %w", err) |
| 55 | } |
| 56 | defer func() { _ = conn.SetDeadline(time.Time{}) }() |
| 57 | br := bufio.NewReader(conn) |
| 58 | resp, err := http.ReadResponse(br, req) |
| 59 | if err != nil { |
| 60 | return nil, err |
| 61 | } |
| 62 | if resp.StatusCode != http.StatusSwitchingProtocols { |
| 63 | var respBody []byte |
| 64 | respBody, _ = io.ReadAll(resp.Body) |
| 65 | return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(respBody)) |
| 66 | } |
| 67 | return &hijackedConn{conn, br}, nil |
| 68 | } |
| 69 | |
| 70 | var _ CloseWriter = &hijackedConn{} |
| 71 |