Curl-Impersonate

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN

            url     => 'https://example.com/api',
            headers => { 'content-type' => 'application/json' },
            body    => '{"hello":"world"}',
        );

        # which browsers can I be?
        my @targets = Curl::Impersonate->targets;

        # asynchronous (concurrent upstreams)
        my $m = Curl::Impersonate->multi;
        for my $url (@urls) {
            my $h = Curl::Impersonate->new(impersonate => 'chrome131');
            $m->add($h, { url => $url }, sub {
                my ($res, $err) = @_;
                $err ? warn($err) : print $res->{status}, "\n";
            });
        }
        $m->perform_blocking;

DESCRIPTION
    Wraps "libcurl-impersonate" (a patched libcurl built against BoringSSL,
    via Alien::curlimpersonate) so a request carries a chosen real browser's
    TLS (JA3/JA4) and HTTP/2 (Akamai) connection fingerprint. Origin
    certificate verification stays on by default; impersonation changes the
    handshake shape, not whether the peer is verified.

    This is an HTTP client, not a full browser. It reproduces the connection
    fingerprint (TLS + HTTP/2); it does not run JavaScript, and HTTP/3 and
    WebSockets are out of scope in this release.

REQUIREMENTS
    Requires Alien::curlimpersonate 0.02 or newer, which builds
    "libcurl-impersonate" (a patched curl plus BoringSSL) from source at
    install time. That build needs a C/C++ toolchain, cmake, ninja, go and
    patch -- see that module for the details. No system
    "libcurl-impersonate" is used.

METHODS
  new
        my $c = Curl::Impersonate->new(%opt);

    Creates a client (one reusable connection handle). Options:

    impersonate => $target
        A browser profile name (see "targets"), e.g. 'chrome131'. Applies
        that browser's TLS/HTTP2 fingerprint and, unless "default_headers"
        is false, its default header set. An unknown target croaks.

    default_headers => $bool
        Whether to also install the target's default request headers.
        Default true.

    timeout => $seconds
        Whole-request timeout. There is no default: libcurl waits
        indefinitely, so a blackholed address or a server that accepts and
        never answers will hang the caller. Set one for anything talking to
        the open internet.

    verify => $bool
        TLS peer/host verification. Default true. Set false only for testing
        against self-signed endpoints.

    follow_redirects => $bool
        Follow "3xx" redirects. Default false. libcurl bounds the chain
        itself, so a redirect loop ends with "Number of redirects hit
        maximum amount" rather than spinning.

    decode => $bool
        Decompress the response body. libcurl decodes whatever it was built
        with -- here gzip, deflate, br and zstd -- and "$res->{body}" is the
        decoded bytes. Off by default, so the body arrives exactly as the
        origin sent it.

        This does not change the request on the wire. The "Accept-Encoding"
        the impersonate target installs is a custom header, and libcurl lets
        a custom header replace the one it would generate itself, so the
        fingerprint is untouched; only the response side differs.

        "$res->{headers}" still reports the origin's "Content-Encoding" and
        "Content-Length", which now describe the bytes before decoding.
        Anything forwarding this response onward must drop both.

    proxy => $url
        Route requests through a proxy, e.g. 'http://127.0.0.1:8080' or
        'socks5h://host:1080'. Credentials go in the URL. Note that a proxy
        which terminates TLS presents its own fingerprint, not the
        impersonated one; to keep the fingerprint intact the proxy must
        tunnel with "CONNECT".

  get
        my $res = $c->get($url);

    Convenience for a GET "request".

  request
        my $res = $c->request(
            method  => 'GET',      # default GET
            url     => $url,       # required
            headers => \%headers,  # optional; values are strings
            body    => $bytes,     # optional request body
        );

    A header name or value containing CR, LF or NUL croaks: libcurl would
    pass such a line through verbatim and the origin would read it as extra
    headers. An undef value removes a header the impersonation profile would
    otherwise send.

    Performs the request and returns a hashref. On success:

        { status => $int, headers => \%response_headers, body => $bytes,
          url => $effective_url }

    "url" is where the request actually ended up, which differs from the one
    asked for when "follow_redirects" sent it elsewhere.

    Response header names are lower-cased; a header that appears more than
    once (e.g. "set-cookie") is kept as an arrayref of its values. On a
    transport-level failure (DNS, TLS, timeout) it returns instead:

        { error => $string, code => $curl_errno }



( run in 1.330 second using v1.01-cache-2.11-cpan-5c0b1e786e0 )