Files
phishingclub/backend/vendor/github.com/enetx/surf/adapter.go
T
Ronni Skansing 07c8adaf76 update vendor deps
Signed-off-by: Ronni Skansing <rskansing@gmail.com>
2025-11-06 23:31:08 +01:00

251 lines
7.1 KiB
Go

package surf
import (
_http "net/http"
"net/url"
"github.com/enetx/http"
)
// Std returns a standard net/http.Client that wraps the configured surf client.
// This is useful for integrating with third-party libraries that expect a standard net/http.Client
// while preserving most surf features.
//
// Supported features:
// - JA3/TLS fingerprinting
// - HTTP/2 settings
// - Cookies and sessions
// - Request/Response middleware
// - Headers (User-Agent, custom headers)
// - Proxy configuration
// - Timeout settings
// - Redirect policies
// - Impersonate browser headers
//
// Known limitations:
// - Retry logic is NOT supported (implemented in Request.Do(), not in transport)
// - Response body caching is NOT supported
// - Remote address tracking is NOT supported
// - Request timing information is NOT available
//
// For applications requiring retry logic, consider implementing it at the application level
// or use surf.Client directly for those specific requests.
//
// Example usage:
//
// surfClient := surf.NewClient().
// Builder().
// JA3().Chrome().
// Session().
// Build()
//
// // For libraries expecting net/http.Client
// stdClient := surfClient.Std()
//
// botClient := &BaseBotClient{
// Client: *stdClient,
// }
func (c *Client) Std() *_http.Client {
var jar _http.CookieJar
if c.cli.Jar != nil {
jar = &CookieJarAdapter{jar: c.cli.Jar}
}
return &_http.Client{
Transport: &TransportAdapter{
transport: c.transport,
client: c,
},
Jar: jar,
Timeout: c.cli.Timeout,
CheckRedirect: redirect(c.cli.CheckRedirect),
}
}
// TransportAdapter adapts surf.Client to net/http.RoundTripper
// It uses the full surf pipeline including middleware
type TransportAdapter struct {
transport http.RoundTripper
client *Client
}
func (s *TransportAdapter) CloseIdleConnections() {
if closer, ok := s.transport.(interface{ CloseIdleConnections() }); ok {
closer.CloseIdleConnections()
}
}
// RoundTrip implements net/http.RoundTripper interface using surf's full pipeline
func (s *TransportAdapter) RoundTrip(req *_http.Request) (*_http.Response, error) {
sreq := &Request{
request: request(req),
cli: s.client,
}
if err := s.client.applyReqMW(sreq); err != nil {
return nil, err
}
_resp, err := s.client.cli.Transport.RoundTrip(sreq.request)
if err != nil {
return nil, err
}
resp := &Response{
response: _resp,
Client: s.client,
StatusCode: StatusCode(_resp.StatusCode),
Headers: Headers(_resp.Header),
request: sreq,
}
if err := s.client.applyRespMW(resp); err != nil {
return nil, err
}
return response(resp.response, req), nil
}
// request converts net/http.Request to github.com/enetx/http.Request.
// It preserves all fields including headers, body, and context while
// adapting to the enetx/http package types.
func request(_req *_http.Request) *http.Request {
req := &http.Request{
Method: _req.Method,
URL: _req.URL,
Proto: _req.Proto,
ProtoMajor: _req.ProtoMajor,
ProtoMinor: _req.ProtoMinor,
Header: http.Header(_req.Header),
Body: _req.Body,
ContentLength: _req.ContentLength,
TransferEncoding: _req.TransferEncoding,
Close: _req.Close,
Host: _req.Host,
Form: _req.Form,
PostForm: _req.PostForm,
MultipartForm: _req.MultipartForm,
Trailer: http.Header(_req.Trailer),
RemoteAddr: _req.RemoteAddr,
RequestURI: _req.RequestURI,
TLS: _req.TLS,
Response: nil,
GetBody: _req.GetBody,
Pattern: _req.Pattern,
Cancel: _req.Cancel, // deprecated but kept for compatibility
}
return req.WithContext(_req.Context())
}
// response converts github.com/enetx/http.Response to net/http.Response.
// It preserves all response fields including status, headers, and body
// while adapting back to standard net/http types.
func response(resp *http.Response, _req *_http.Request) *_http.Response {
return &_http.Response{
Status: resp.Status,
StatusCode: resp.StatusCode,
Proto: resp.Proto,
ProtoMajor: resp.ProtoMajor,
ProtoMinor: resp.ProtoMinor,
Header: _http.Header(resp.Header),
Body: resp.Body,
ContentLength: resp.ContentLength,
TransferEncoding: resp.TransferEncoding,
Close: resp.Close,
Uncompressed: resp.Uncompressed,
Trailer: _http.Header(resp.Trailer),
Request: _req,
TLS: resp.TLS,
}
}
// CookieJarAdapter adapts github.com/enetx/http.CookieJar to net/http.CookieJar.
// It provides bidirectional cookie conversion between the two HTTP packages,
// ensuring cookies set through either interface work correctly.
type CookieJarAdapter struct{ jar http.CookieJar }
// SetCookies implements http.CookieJar interface.
// It converts standard net/http cookies to enetx/http format and
// delegates to the underlying surf cookie jar.
func (c *CookieJarAdapter) SetCookies(u *url.URL, _cookies []*_http.Cookie) {
if len(_cookies) == 0 {
c.jar.SetCookies(u, nil)
return
}
cookies := make([]*http.Cookie, 0, len(_cookies))
for _, ck := range _cookies {
cookies = append(cookies, &http.Cookie{
Name: ck.Name,
Value: ck.Value,
Quoted: ck.Quoted,
Path: ck.Path,
Domain: ck.Domain,
Expires: ck.Expires,
RawExpires: ck.RawExpires,
MaxAge: ck.MaxAge,
Secure: ck.Secure,
HttpOnly: ck.HttpOnly,
SameSite: http.SameSite(ck.SameSite),
Partitioned: ck.Partitioned,
Raw: ck.Raw,
Unparsed: ck.Unparsed,
})
}
c.jar.SetCookies(u, cookies)
}
// Cookies implements http.CookieJar interface.
// It retrieves cookies from the underlying surf cookie jar and
// converts them to standard net/http cookie format.
func (c *CookieJarAdapter) Cookies(u *url.URL) []*_http.Cookie {
cookies := c.jar.Cookies(u)
if len(cookies) == 0 {
return nil
}
_cookies := make([]*_http.Cookie, 0, len(cookies))
for _, ck := range cookies {
_cookies = append(_cookies, &_http.Cookie{
Name: ck.Name,
Value: ck.Value,
Quoted: ck.Quoted,
Path: ck.Path,
Domain: ck.Domain,
Expires: ck.Expires,
RawExpires: ck.RawExpires,
MaxAge: ck.MaxAge,
Secure: ck.Secure,
HttpOnly: ck.HttpOnly,
SameSite: _http.SameSite(ck.SameSite),
Partitioned: ck.Partitioned,
Raw: ck.Raw,
Unparsed: ck.Unparsed,
})
}
return _cookies
}
// redirect adapts surf's redirect policy function to work with standard net/http.
// It converts net/http requests to enetx/http format, calls the surf redirect policy,
// and returns the result. This ensures custom redirect policies work correctly
// through the standard http.Client interface.
func redirect(fn func(*http.Request, []*http.Request) error) func(*_http.Request, []*_http.Request) error {
if fn == nil {
return nil
}
return func(req *_http.Request, via []*_http.Request) error {
_req := request(req)
_via := make([]*http.Request, len(via))
for i := range via {
_via[i] = request(via[i])
}
return fn(_req, _via)
}
}