| 128 | } |
| 129 | |
| 130 | func proxyRaw(c *echo.Context, t *ProxyTarget, config ProxyConfig) http.Handler { |
| 131 | var dialFunc func(ctx context.Context, network, addr string) (net.Conn, error) |
| 132 | if transport, ok := config.Transport.(*http.Transport); ok { |
| 133 | if transport.TLSClientConfig != nil { |
| 134 | d := tls.Dialer{ |
| 135 | Config: transport.TLSClientConfig, |
| 136 | } |
| 137 | dialFunc = d.DialContext |
| 138 | } |
| 139 | } |
| 140 | if dialFunc == nil { |
| 141 | var d net.Dialer |
| 142 | dialFunc = d.DialContext |
| 143 | } |
| 144 | |
| 145 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 146 | in, _, err := http.NewResponseController(w).Hijack() |
| 147 | if err != nil { |
| 148 | c.Set("_error", fmt.Errorf("proxy raw, hijack error=%w, url=%s", err, t.URL)) |
| 149 | return |
| 150 | } |
| 151 | defer in.Close() |
| 152 | |
| 153 | out, err := dialFunc(c.Request().Context(), "tcp", t.URL.Host) |
| 154 | if err != nil { |
| 155 | c.Set("_error", echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, dial error=%v, url=%s", err, t.URL))) |
| 156 | return |
| 157 | } |
| 158 | defer out.Close() |
| 159 | |
| 160 | // Write header |
| 161 | err = r.Write(out) |
| 162 | if err != nil { |
| 163 | c.Set("_error", echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, request header copy error=%v, url=%s", err, t.URL))) |
| 164 | return |
| 165 | } |
| 166 | |
| 167 | errCh := make(chan error, 2) |
| 168 | cp := func(dst io.Writer, src io.Reader) { |
| 169 | _, copyErr := io.Copy(dst, src) |
| 170 | errCh <- copyErr |
| 171 | } |
| 172 | |
| 173 | go cp(out, in) |
| 174 | go cp(in, out) |
| 175 | |
| 176 | // Wait for BOTH goroutines to complete |
| 177 | err1 := <-errCh |
| 178 | err2 := <-errCh |
| 179 | |
| 180 | if err1 != nil && err1 != io.EOF { |
| 181 | c.Set("_error", fmt.Errorf("proxy raw, copy body error=%w, url=%s", err1, t.URL)) |
| 182 | } else if err2 != nil && err2 != io.EOF { |
| 183 | c.Set("_error", fmt.Errorf("proxy raw, copy body error=%w, url=%s", err2, t.URL)) |
| 184 | } |
| 185 | }) |
| 186 | } |
| 187 | |