Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y cmake ninja-build libssl-dev pkg-config autoconf automake libtool libnghttp2-dev
sudo apt-get install -y cmake ninja-build libssl-dev pkg-config autoconf automake libtool libnghttp2-dev libbrotli-dev

- name: Cache Homebrew packages (macOS)
if: runner.os == 'macOS'
Expand Down Expand Up @@ -131,9 +131,9 @@ jobs:
path: |
C:/vcpkg/installed
C:/vcpkg/packages
key: vcpkg-nghttp2-zlib-${{ runner.os }}-v3
key: vcpkg-nghttp2-zlib-brotli-${{ runner.os }}-v4
restore-keys: |
vcpkg-nghttp2-zlib-${{ runner.os }}-
vcpkg-nghttp2-zlib-brotli-${{ runner.os }}-

- name: Setup vcpkg (Windows)
if: runner.os == 'Windows' && steps.cache-vcpkg-restore.outputs.cache-hit != 'true'
Expand All @@ -158,7 +158,7 @@ jobs:
run: |
export VCPKG_ROOT="C:/vcpkg"
export PATH="$VCPKG_ROOT:$PATH"
vcpkg install nghttp2:x64-windows zlib:x64-windows --clean-after-build
vcpkg install nghttp2:x64-windows zlib:x64-windows brotli:x64-windows --clean-after-build
shell: bash

- name: Set vcpkg environment (Windows)
Expand Down Expand Up @@ -254,7 +254,7 @@ jobs:
path: |
C:/vcpkg/installed
C:/vcpkg/packages
key: vcpkg-nghttp2-zlib-${{ runner.os }}-v3
key: vcpkg-nghttp2-zlib-brotli-${{ runner.os }}-v4

- name: Save vendor cache
if: always() && steps.cache-vendor.outputs.cache-hit != 'true'
Expand Down
67 changes: 33 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ A Python HTTP client focused on mimicking browser fingerprints.
- **Requests-compatible API** - Drop-in replacement for most Python `requests` use cases
- **High Performance** - Native C implementation with BoringSSL for HTTP/HTTPS
- **HTTP/2 Support** - Full HTTP/2 with ALPN negotiation via nghttp2 (httpx-like API)
- **Chrome 142 Fingerprint** - Perfect JA3N, JA4, and JA4_R matching
- **Browser Fingerprinting** - Realistic Chrome 142 browser profile
- **TLS Fingerprinting** - JA3/JA3N/JA4 fingerprint generation with post-quantum crypto
- **Chrome 127-143 Fingerprints** - Perfect JA4 fingerprint matching
- **Browser Fingerprinting** - Realistic Chrome browser profiles (127-143)
- **TLS Fingerprinting** - JA3N/JA4/JA4_R fingerprint generation with post-quantum crypto
- **HTTP/2 Fingerprinting** - Perfect Akamai HTTP/2 fingerprint matching
- **Connection Pooling** - Automatic connection reuse for better performance
- **Session Management** - Persistent cookies and headers across requests

Expand Down Expand Up @@ -74,14 +75,14 @@ print(response.http_version) # '2.0'
Mimic real browser behavior with pre-configured profiles:

```python
# Use Chrome fingerprint (defaults to Chrome 142)
# Use Chrome fingerprint (defaults to Chrome 143)
response = httpmorph.get('https://example.com', browser='chrome')

# Use specific Chrome version
session = httpmorph.Session(browser='chrome142')
# Use specific Chrome version (127-143 supported)
session = httpmorph.Session(browser='chrome143')
response = session.get('https://example.com')

# Available browsers: chrome, chrome142
# Available browsers: chrome, chrome127-chrome143
```

### OS-Specific User Agents
Expand Down Expand Up @@ -111,35 +112,34 @@ session = httpmorph.Session(browser='chrome', os='linux')

The OS parameter only affects the User-Agent string, while all other fingerprinting characteristics (TLS, HTTP/2, JA3/JA4) remain consistent to match the specified browser profile.

### Chrome 142 Fingerprint Matching
### Chrome Fingerprint Matching

httpmorph accurately mimics **Chrome 142** TLS fingerprints with:
httpmorph accurately mimics **Chrome 127-143** TLS and HTTP/2 fingerprints with:

- **JA3N** ✅ Perfect match
- **JA4** ✅ Perfect match
- **JA4** ✅ Perfect match (`t13d1516h2_8daaf6152771_d8a2da3f94cd`)
- **JA4_R** ✅ Perfect match
- **User-Agent**: `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36`
- **JA3N** ✅ Perfect match (normalized JA3: `dcefaf3f0e71d260d19dc1d0749c9278`)
- **HTTP/2 Akamai** ✅ Perfect match (`1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p`)
- **User-Agent**: Version-specific Chrome user agents
- **TLS 1.3** with correct cipher suites and extensions
- **HTTP/2** with Chrome-specific SETTINGS frame
- **HTTP/2** with Chrome-specific SETTINGS frame and pseudo-header order
- **Post-quantum cryptography** (X25519MLKEM768)
- **Certificate compression** (Brotli, Zlib)
- **Certificate compression** (Brotli)

**Verify your fingerprint:**

```python
import httpmorph

# Make a request to fingerprint checker
response = httpmorph.get('https://suip.biz/?act=ja4', browser='chrome142')
print(response.text)
response = httpmorph.get('https://tls.peet.ws/api/all', browser='chrome143')
data = response.json()
print(f"JA4: {data['tls']['ja4']}")

# You should see perfect matches for:
# - JA4 fingerprint ✅
# - JA3N fingerprint ✅
# - User-Agent: Chrome/142.0.0.0 ✅
# Expected: t13d1516h2_8daaf6152771_d8a2da3f94cd ✅
```

httpmorph achieves **perfect matches** for all modern fingerprints including JA3N, JA4, and JA4_R when tested against real Chrome 142 browsers.
All Chrome 127-143 profiles produce **exact JA4 matches** with real Chrome browsers.

## Advanced Usage

Expand All @@ -148,19 +148,18 @@ httpmorph achieves **perfect matches** for all modern fingerprints including JA3
httpmorph supports HTTP/2 with an httpx-like API:

```python
# Enable HTTP/2 for a client (default is False)
client = httpmorph.Client(http2=True)
# Both Client and Session default to HTTP/2 (http2=True) like Chrome
client = httpmorph.Client()
response = client.get('https://www.google.com')
print(response.http_version) # '2.0'

# Enable HTTP/2 for a session
session = httpmorph.Session(browser='chrome', http2=True)
session = httpmorph.Session(browser='chrome')
response = session.get('https://www.google.com')
print(response.http_version) # '2.0'

# Per-request HTTP/2 override
client = httpmorph.Client(http2=False) # Default disabled
response = client.get('https://www.google.com', http2=True) # Enable for this request
# Per-request HTTP/2 override (disable for specific request)
client = httpmorph.Client() # Defaults to HTTP/2
response = client.get('https://example.com', http2=False) # Disable for this request
```

### Custom Headers
Expand Down Expand Up @@ -417,7 +416,7 @@ Please open an issue or pull request on GitHub.
httpmorph has a comprehensive test suite with 350+ tests covering:

- All HTTP methods and parameters
- Chrome 142 fingerprint validation (JA3N, JA4, JA4_R)
- Chrome 127-143 fingerprint validation (JA4, JA4_R)
- TLS 1.2/1.3 with post-quantum cryptography
- Certificate compression (Brotli, Zlib)
- Redirect handling and history
Expand All @@ -439,16 +438,16 @@ pytest tests/ -v
- Built on BoringSSL (Google) with post-quantum cryptography support
- HTTP/2 support via nghttp2
- Inspired by Python's requests and httpx libraries
- Chrome 142 fingerprint matching with perfect JA3N, JA4, and JA4_R matches
- Certificate compression support for Cloudflare-protected sites
- Chrome 127-143 fingerprint matching with perfect JA4, JA3N, and HTTP/2 Akamai fingerprints
- Certificate compression (Brotli) for Cloudflare-protected sites

## FAQ

**Q: Why another HTTP client?**
A: httpmorph combines the performance of native C with browser fingerprinting capabilities, making it ideal for applications that need both speed and realistic browser behavior.

**Q: How accurate is the Chrome 142 fingerprint?**
A: httpmorph achieves perfect matches for modern fingerprints including JA3N, JA4, and JA4_R. This is verified against real Chrome 142 browsers. Test your fingerprint at https://suip.biz/?act=ja4
**Q: How accurate are the Chrome fingerprints?**
A: httpmorph achieves perfect JA4 matches for Chrome 127-143. Test your fingerprint at https://tls.peet.ws/api/all

**Q: Is it production-ready?**
A: No, httpmorph is still in active development and not yet recommended for production use.
Expand All @@ -457,7 +456,7 @@ A: No, httpmorph is still in active development and not yet recommended for prod
A: For most common use cases, yes! We've implemented the most widely-used requests API. Some advanced features may have slight differences.

**Q: Does it work with Cloudflare-protected sites?**
A: Yes! httpmorph supports certificate compression (Brotli, Zlib) which is required for many Cloudflare-protected sites. We successfully tested with icanhazip.com and postman-echo.com.
A: Yes! httpmorph supports certificate compression (Brotli) which is required for many Cloudflare-protected sites. We successfully tested with icanhazip.com and postman-echo.com.

**Q: How do I report a bug?**
A: Please open an issue on GitHub with a minimal reproduction example and your environment details (OS, Python version, httpmorph version).
Expand Down
8 changes: 4 additions & 4 deletions docs/source/advanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ TLS Fingerprinting
Browser-Specific Fingerprints
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

httpmorph generates accurate Chrome 142 TLS fingerprints with perfect JA3N, JA4, and JA4_R matching:
httpmorph generates accurate Chrome 143 TLS fingerprints with perfect JA3N, JA4, JA4_R, and Akamai matching:

.. code-block:: python

# Chrome 142 profile (default)
# Chrome 143 profile (default)
session = httpmorph.Session(browser='chrome')
response = session.get('https://example.com')

Expand All @@ -23,7 +23,7 @@ httpmorph generates accurate Chrome 142 TLS fingerprints with perfect JA3N, JA4,
print('HTTP:', response.http_version)

# Output example:
# JA3: 8e19337e7524d2573be54efb2b0784c9 (Chrome 142 normalized)
# JA3: dcefaf3f0e71d260d19dc1d0749c9278 (Chrome 143 normalized)
# TLS: TLSv1.3
# Cipher: TLS_AES_128_GCM_SHA256
# HTTP: 2.0
Expand Down Expand Up @@ -53,7 +53,7 @@ Customize the User-Agent for different operating systems:
GREASE Values
~~~~~~~~~~~~~

Chrome 142 uses GREASE (Generate Random Extensions And Sustain Extensibility) values that are randomized per request to maintain TLS ecosystem extensibility:
Chrome 143 uses GREASE (Generate Random Extensions And Sustain Extensibility) values that are randomized per request to maintain TLS ecosystem extensibility:

.. code-block:: python

Expand Down
57 changes: 35 additions & 22 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,13 @@ Client Class

.. code-block:: python

client = httpmorph.Client(http2=False)
client = httpmorph.Client(http2=True)

HTTP client for making requests.
HTTP client for making requests. Defaults to HTTP/2 to match Chrome behavior.

**Constructor Parameters:**

* ``http2`` (bool) - Enable HTTP/2. Default: ``False``
* ``http2`` (bool) - Enable HTTP/2. Default: ``True``

**Methods:**

Expand Down Expand Up @@ -127,15 +127,15 @@ Session Class

.. code-block:: python

session = httpmorph.Session(browser='chrome', os='macos', http2=False)
session = httpmorph.Session(browser='chrome', os='macos', http2=True)

HTTP session with persistent cookies and headers.
HTTP session with persistent cookies and headers. Sessions default to HTTP/2 to match Chrome browser behavior.

**Constructor Parameters:**

* ``browser`` (str) - Browser profile to mimic. Options: ``'chrome'``, ``'chrome142'``, ``'random'``. Default: ``'chrome'``
* ``browser`` (str) - Browser profile to mimic. Options: ``'chrome'``, ``'chrome127'``-``'chrome143'``, ``'random'``. Default: ``'chrome'`` (Chrome 143)
* ``os`` (str) - Operating system for User-Agent. Options: ``'macos'``, ``'windows'``, ``'linux'``. Default: ``'macos'``
* ``http2`` (bool) - Enable HTTP/2. Default: ``False``
* ``http2`` (bool) - Enable HTTP/2. Default: ``True`` (matches Chrome behavior)

**Attributes:**

Expand Down Expand Up @@ -423,42 +423,55 @@ Browser Profiles

Available browser profiles for ``Session(browser=...)``:

Chrome 142
~~~~~~~~~~
Chrome 143 (Default)
~~~~~~~~~~~~~~~~~~~~

The default and most accurate browser profile, mimicking Chrome 142:
The default and most accurate browser profile, mimicking Chrome 143:

**Fingerprint Characteristics:**

* **JA3N**: ``8e19337e7524d2573be54efb2b0784c9`` (perfect match)
* **JA4**: ``t13d1516h2_8daaf6152771_d8a2da3f94cd`` (perfect match)
* **JA4_R**: ``t13d1516h2_002f,0035,009c,...`` (perfect match)
* **JA4**: ``t13d1516h2_8daaf6152771_e5627efa2ab1`` (perfect match)
* **JA3N**: ``dcefaf3f0e71d260d19dc1d0749c9278`` (perfect match)
* **Peetprint**: ``1d4ffe9b0e34acac0bd883fa7f79d7b5`` (perfect match)
* **Akamai HTTP/2**: ``1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p`` (perfect match)
* **TLS 1.3** with 15 cipher suites
* **Post-quantum cryptography**: X25519MLKEM768 (curve 4588)
* **Certificate compression**: Brotli, Zlib
* **Certificate compression**: Brotli (zlib fallback for compatibility)
* **GREASE**: Randomized per request
* **HTTP/2**: Chrome-specific SETTINGS frame
* **HTTP/2**: Chrome-specific SETTINGS frame, priority (weight=256, exclusive=1)
* **Default headers**: sec-ch-ua, sec-fetch-*, accept-language, priority

**User-Agent Variants:**

* **macOS**: ``Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36``
* **Windows**: ``Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36``
* **Linux**: ``Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36``
* **macOS**: ``Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36``
* **Windows**: ``Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36``
* **Linux**: ``Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36``

**Usage:**

.. code-block:: python

# Use Chrome 142 profile (default)
# Use Chrome 143 profile (default)
session = httpmorph.Session(browser='chrome')

# Explicitly use Chrome 142
session = httpmorph.Session(browser='chrome142')
# Explicitly use Chrome 143
session = httpmorph.Session(browser='chrome143')

# With specific OS
session = httpmorph.Session(browser='chrome', os='windows')

Chrome 127-142
~~~~~~~~~~~~~~

Older Chrome profiles are also available for compatibility testing:

.. code-block:: python

session = httpmorph.Session(browser='chrome127')
session = httpmorph.Session(browser='chrome135')
# etc.

Random
~~~~~~

Randomly selects a browser profile for each session. Currently only Chrome 142 is available.
Randomly selects a browser profile for each session from available Chrome profiles.
30 changes: 16 additions & 14 deletions docs/source/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,12 @@ Mimic Chrome browser with realistic fingerprints:

.. code-block:: python

# Chrome browser profile (defaults to Chrome 142)
# Chrome browser profile (defaults to Chrome 143)
session = httpmorph.Session(browser='chrome')
response = session.get('https://example.com')

# Use specific Chrome version
session = httpmorph.Session(browser='chrome142')
# Use specific Chrome version (127-143 supported)
session = httpmorph.Session(browser='chrome143')
response = session.get('https://example.com')

# Random browser selection
Expand All @@ -118,9 +118,10 @@ The Chrome browser profile includes:
* Chrome-specific User-Agent
* Chrome-specific TLS cipher suites and extensions
* Post-quantum cryptography (X25519MLKEM768)
* Certificate compression (Brotli, Zlib)
* Chrome-specific HTTP/2 settings
* Perfect JA3N, JA4, and JA4_R fingerprint matching
* Certificate compression (Brotli, with zlib fallback)
* Chrome-specific HTTP/2 settings and priority
* Perfect JA3N, JA4, JA4_R, and Akamai fingerprint matching
* Chrome-like default headers (sec-ch-ua, sec-fetch-*, etc.)

OS-Specific User Agents
~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -344,21 +345,22 @@ Upload files:
HTTP/2
------

Enable HTTP/2 support:
Both Client and Session default to HTTP/2 to match Chrome behavior:

.. code-block:: python

# For all requests in a client
client = httpmorph.Client(http2=True)
# Both Client and Session default to HTTP/2 (http2=True)
client = httpmorph.Client()
response = client.get('https://www.google.com')
print(response.http_version) # '2.0'

# For all requests in a session
session = httpmorph.Session(browser='chrome', http2=True)
session = httpmorph.Session(browser='chrome')
response = session.get('https://www.google.com')
print(response.http_version) # '2.0'

# Per-request override
client = httpmorph.Client(http2=False)
response = client.get('https://www.google.com', http2=True)
# Per-request override (disable HTTP/2 for specific request)
client = httpmorph.Client() # Defaults to HTTP/2
response = client.get('https://example.com', http2=False)

Check HTTP version:

Expand Down
Loading
Loading