http_mimic 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 32ae2902090ddf216e6f33843f1fb53d82d13cda864a3a71fd7318f5f316cdf4
4
+ data.tar.gz: 907aec51da124505902e104ebf3bce70eb2883490ec8b360f3f0571e6efd98c2
5
+ SHA512:
6
+ metadata.gz: e47bf2078c03dc6a37ecb3478ee5f7a42724375161c63175067fd6df5c8c76fae90b04867eb6f4b8fe03ab2ad2d919ef64dcfd1389ab20befdcb9e2ff245d492
7
+ data.tar.gz: 31c4ebd49e1180914bd949dc23bbc4bd7580dea84f898c7a97bc4977a8501120b1d3d5e6301b65ef2bf7cfa9e5c9bbecd8a7f47806f0a8cf42e1e1b4e7b2e45c
data/CHANGELOG.md ADDED
@@ -0,0 +1,60 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.3.0] - 2026-08-24
9
+
10
+ ### Added
11
+ - **Live Fingerprint Test Suite**: Added integration tests (`rake test:live`) verifying real-world JA3, JA4, and Akamai HTTP/2 fingerprints against live endpoints (`tls.browserleaks.com`, `tls.peet.ws`).
12
+ - **Standard MIT License**: Included official `LICENSE.txt` and repository metadata.
13
+ - **Rakefile Integration**: Added standard Rake test tasks for unit tests, live tests, and full test suites.
14
+
15
+ ### Changed
16
+ - **Default Impersonation Target**: Upgraded default impersonation from `chrome116` to modern `chrome131` with Post-Quantum (ML-KEM) and modern Client Hints support.
17
+ - **Internationalization**: Fully translated all code comments, error messages, and documentation into English.
18
+
19
+ ## [0.2.0] - 2026-08-24
20
+
21
+ ### Added
22
+ - **Webdrivers-like Auto Driver Management (`HttpMimic::Downloader`)**:
23
+ - Automatically downloads and unpacks official binaries from [`lexiforest/curl-impersonate`](https://github.com/lexiforest/curl-impersonate) releases to `~/.http_mimic/bin`.
24
+ - Automatic platform detection for macOS (ARM64 / x86_64), Linux (GNU / MUSL, x86_64, aarch64, arm, i386, riscv64, loongarch64), Windows (x86_64, arm64, i686), and FreeBSD.
25
+ - Manual driver management helpers: `HttpMimic.download_driver!`, `HttpMimic.driver_installed?`, `HttpMimic::Downloader.available_binaries`.
26
+ - Configurable auto-download, target release version, install directory, and custom GitHub repo.
27
+ - **Expanded Browser Target Support**:
28
+ - Support for Chrome (`chrome116`, `chrome120`, `chrome123`, `chrome124`, `chrome131`, `chrome133a`, `chrome136`, `chrome142`, `chrome99-110`).
29
+ - Support for Firefox (`firefox133`, `firefox135`, `firefox144`, `firefox117`, `firefox109`, `firefox102`, `firefox98`).
30
+ - Support for Safari (`safari180`, `safari170`, `safari155`, `safari153`).
31
+ - Support for Edge (`edge101`, `edge99`) and Tor (`tor145`).
32
+
33
+ ## [0.1.0] - 2026-08-24
34
+
35
+ ### Added
36
+ - **Initial Release of `HttpMimic`**: A HTTParty-like Ruby client wrapping `curl-impersonate` via `Open3.capture3`.
37
+ - **Core HTTP Verbs**: Support for `get`, `post`, `put`, `patch`, `delete`, `head`, and `options`.
38
+ - **HTTParty-Style API**:
39
+ - Direct module methods: `HttpMimic.get`, `HttpMimic.post`, etc.
40
+ - Class-level DSL mixin via `include HttpMimic` (`base_uri`, `headers`, `default_params`, `default_timeout`, `impersonate`, `proxy`, `cookies`).
41
+ - Reusable instance client: `HttpMimic::Client.new(...)`.
42
+ - **Smart Response & Parser**:
43
+ - Auto-parsing JSON responses and method delegation (`response['key']`, `response.parsed_response`).
44
+ - Case-insensitive header access (`response.headers['content-type']`).
45
+ - Automatic `Set-Cookie` header parsing and cookie jar representation (`response.cookies`).
46
+ - Complete 3xx redirect history tracking (`response.history`).
47
+ - Rich status helpers (`response.success?`, `response.redirect?`, `response.client_error?`, `response.server_error?`, `response.ok?`).
48
+ - **Comprehensive Request Options**:
49
+ - Query parameters (auto URL encoding and nested parameters).
50
+ - Headers, JSON payloads (`json:`), Form URL-encoded data (`body:`), and Multipart (`form:` / `multipart:`).
51
+ - Basic and Digest authentication (`basic_auth:`, `digest_auth:`, `bearer_token:`).
52
+ - Timeouts (`timeout:`, `connect_timeout:`).
53
+ - Proxy and Proxy authentication (`proxy:`, `proxy_auth:`).
54
+ - SSL/TLS settings (`insecure:`, `ssl_ca_file:`, `ssl_cert:`, `ssl_key:`).
55
+ - Raw curl arguments passthrough (`curl_options:`).
56
+ - **Safe CLI Execution**:
57
+ - Uses array arguments in `Open3.capture3` to eliminate shell injection vulnerabilities.
58
+ - Stdin streaming (`stdin_data`) with `-d @-` to bypass OS command line length limits for large payloads.
59
+ - **Unit Test Suite**:
60
+ - Comprehensive tests for header handling, cookie parsing, command generation, response parsing, redirect chains, and platform slug detection.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 anxgang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,263 @@
1
+ # HttpMimic
2
+
3
+ `http_mimic` is a Ruby HTTP Client gem built on top of `Open3.capture3` and `curl-impersonate`.
4
+ It provides an elegant, concise, and intuitive **HTTParty-style** API while leveraging [`lexiforest/curl-impersonate`](https://github.com/lexiforest/curl-impersonate) to simulate authentic Chrome, Firefox, Safari, Edge, and Tor TLS / HTTP2 fingerprints (JA3, JA4, Akamai) and handshakes.
5
+
6
+ It also includes **Webdrivers-like automatic driver management**, automatically downloading and managing `curl-impersonate` binaries across macOS, Linux, and Windows without manual setup.
7
+
8
+ ---
9
+
10
+ ## ๐ŸŒŸ Features
11
+
12
+ - **Webdrivers-Style Driver Management**:
13
+ - Automatically downloads and unpacks official binaries from [`lexiforest/curl-impersonate`](https://github.com/lexiforest/curl-impersonate) to `~/.http_mimic/bin`.
14
+ - **Automatic platform & architecture detection** (macOS ARM/Intel, Linux x86_64/aarch64/musl, Windows x86_64/arm64, FreeBSD).
15
+ - Zero configuration requiredโ€”installs on first request automatically.
16
+ - Manual driver management helpers: `HttpMimic.download_driver!`, `HttpMimic.driver_installed?`, `HttpMimic::Downloader.available_binaries`.
17
+ - **Authentic Browser Handshakes & Fingerprints**:
18
+ - Chrome support: `chrome131` (default), `chrome124`, `chrome120`, `chrome133a`, `chrome136`, `chrome142`, `chrome99-110`.
19
+ - Firefox support: `firefox135`, `firefox133`, `firefox144`, `firefox117`, `firefox109`, `firefox102`, `firefox98`.
20
+ - Safari support: `safari180`, `safari170`, `safari155`, `safari153`.
21
+ - Edge & Tor support: `edge101`, `edge99`, `tor145`.
22
+ - **HTTParty-Style API**:
23
+ - Direct module methods: `HttpMimic.get`, `HttpMimic.post`, etc.
24
+ - Class mixin via `include HttpMimic` (`base_uri`, `headers`, `default_params`, `default_timeout`, `impersonate`, `proxy`, `cookies`).
25
+ - Reusable instance client: `HttpMimic::Client.new(...)`.
26
+ - **Zero Shell Injection Risk**:
27
+ - Executes commands with array arguments via `Open3.capture3(*cmd_array)`.
28
+ - Uses stdin streaming (`-d @-`) to safely handle large payloads without hitting OS command-line limits.
29
+ - **Smart Response Parsing**:
30
+ - HTTP status helpers: `response.code`, `response.success?`, `response.redirect?`, `response.client_error?`, `response.server_error?`.
31
+ - Case-insensitive header access: `response.headers['Content-Type']`.
32
+ - Automatic `Set-Cookie` header parsing: `response.cookies['session_id']`.
33
+ - Auto-parsed JSON with object delegation: `response['key']`, `response.parsed_response`.
34
+ - Complete 3xx redirect history tracking: `response.history`.
35
+ - **Comprehensive Request Options**:
36
+ - Supports `query`, `headers`, `json`, `body` (form data), `cookies`, `timeout`, `connect_timeout`, `proxy`, `basic_auth`, `digest_auth`, `bearer_token`, `insecure`, custom `curl_options`, and more.
37
+ - **Graceful Fallback**:
38
+ - If a specific binary is unavailable and auto-download is disabled, automatically falls back to system standard `curl`.
39
+
40
+ ---
41
+
42
+ ## ๐Ÿ“ฆ Installation
43
+
44
+ Add this line to your application's `Gemfile`:
45
+
46
+ ```ruby
47
+ gem 'http_mimic'
48
+ ```
49
+
50
+ And then execute:
51
+
52
+ ```bash
53
+ bundle install
54
+ ```
55
+
56
+ ---
57
+
58
+ ## ๐Ÿค– Driver Management
59
+
60
+ `HttpMimic` automatically downloads the corresponding platform binary of `curl-impersonate` on the first request and saves it to `~/.http_mimic/bin`.
61
+
62
+ You can also manage drivers manually:
63
+
64
+ ```ruby
65
+ require 'http_mimic'
66
+
67
+ # Check if driver is installed locally
68
+ HttpMimic.driver_installed? # => true / false
69
+
70
+ # Manually trigger download (defaults to latest stable release v2.1.1)
71
+ HttpMimic.download_driver!
72
+
73
+ # Specify a version or force re-download
74
+ HttpMimic.download_driver!(version: 'v2.1.1', force: true)
75
+
76
+ # List all available browser binary names installed locally
77
+ HttpMimic::Downloader.available_binaries
78
+ # => ["curl_chrome131", "curl_chrome120", "curl_firefox135", "curl_safari180", ...]
79
+ ```
80
+
81
+ ---
82
+
83
+ ## ๐Ÿš€ Quick Start
84
+
85
+ ### 1. Direct Module Calls
86
+
87
+ ```ruby
88
+ require 'http_mimic'
89
+
90
+ # Send a GET request (simulates Chrome 131 fingerprint by default)
91
+ response = HttpMimic.get(
92
+ 'https://tls.browserleaks.com/json',
93
+ impersonate: 'chrome131'
94
+ )
95
+
96
+ puts response.code # => 200
97
+ puts response.success? # => true
98
+ puts response['ja3_hash'] # => Authentic Chrome 131 JA3 fingerprint
99
+ puts response.headers['content-type'] # => "application/json"
100
+
101
+ # Send a POST JSON request (simulating Safari 18.0)
102
+ response = HttpMimic.post(
103
+ 'https://httpbin.org/post',
104
+ json: { name: 'Alice', role: 'admin' },
105
+ impersonate: 'safari180'
106
+ )
107
+
108
+ puts response.code # => 200
109
+ puts response['json']['name'] # => "Alice"
110
+ ```
111
+
112
+ ---
113
+
114
+ ### 2. Class Mixin Mode (HTTParty Style)
115
+
116
+ ```ruby
117
+ class BrowserLeaksClient
118
+ include HttpMimic
119
+
120
+ base_uri 'https://tls.browserleaks.com'
121
+ impersonate 'chrome120' # Default to Chrome 120
122
+ default_timeout 30
123
+ headers 'Accept-Language' => 'en-US,en;q=0.9'
124
+
125
+ def test_fingerprint
126
+ get('/json')
127
+ end
128
+ end
129
+
130
+ client = BrowserLeaksClient.new
131
+ res = client.test_fingerprint
132
+
133
+ puts "HTTP Status: #{res.code}"
134
+ puts "JA3 Hash: #{res['ja3_hash']}"
135
+ puts "User-Agent: #{res['user_agent']}"
136
+ ```
137
+
138
+ ---
139
+
140
+ ### 3. Instance Mode
141
+
142
+ ```ruby
143
+ client = HttpMimic::Client.new(
144
+ base_uri: 'https://api.example.com',
145
+ impersonate: 'firefox135',
146
+ timeout: 15,
147
+ headers: {
148
+ 'X-API-KEY' => 'my_api_key'
149
+ }
150
+ )
151
+
152
+ # Execute GET
153
+ response = client.get('/v1/users', query: { limit: 10 })
154
+
155
+ # Execute POST
156
+ response = client.post('/v1/users', json: { username: 'bob' })
157
+ ```
158
+
159
+ ---
160
+
161
+ ## โš™๏ธ Global Configuration
162
+
163
+ Configure global defaults in an initializer (e.g., `config/initializers/http_mimic.rb`):
164
+
165
+ ```ruby
166
+ HttpMimic.configure do |config|
167
+ # Browser simulation & request defaults
168
+ config.default_impersonate = 'chrome131' # Default browser target
169
+ config.default_timeout = 30 # Request timeout (seconds)
170
+ config.default_connect_timeout = 10 # Connection timeout (seconds)
171
+ config.follow_redirects = true # Automatically follow 3xx redirects
172
+ config.max_redirects = 10 # Maximum redirect limit
173
+ config.fallback_to_curl = true # Fall back to system curl if binary is missing
174
+ config.raise_on_error = false # Raise exceptions on HTTP errors / non-zero exits
175
+ config.debug = false # Print debug logs
176
+
177
+ # Webdrivers-like auto-download settings (enabled by default)
178
+ config.auto_download = true # Auto-download missing binary
179
+ config.driver_version = 'v2.1.1' # Target release version
180
+ config.install_dir = File.expand_path('~/.http_mimic/bin') # Directory for binaries
181
+ config.github_repo = 'lexiforest/curl-impersonate' # GitHub source repository
182
+ end
183
+ ```
184
+
185
+ ---
186
+
187
+ ## ๐Ÿ› ๏ธ Supported Request Options
188
+
189
+ | Option | Type | Description |
190
+ | :--- | :--- | :--- |
191
+ | `:impersonate` | String | Target browser to mimic (e.g., `'chrome131'`, `'chrome120'`, `'firefox135'`, `'safari180'`, `'tor145'`) |
192
+ | `:binary` | String | Path to a custom `curl-impersonate` executable |
193
+ | `:query` / `:params` | Hash | URL query parameters (supports nested parameters and encoding) |
194
+ | `:headers` | Hash | Custom HTTP request headers |
195
+ | `:json` | Hash / Array | Serialized to JSON with `Content-Type: application/json` |
196
+ | `:body` | Hash / String | Form payload (Hash) or raw request body string |
197
+ | `:cookies` | Hash / String | Request cookies |
198
+ | `:cookie_jar` | String | Path to save cookies (`-c`) |
199
+ | `:cookie_file` | String | Path to read cookies (`-b`) |
200
+ | `:timeout` | Integer / Float | Maximum execution timeout in seconds (`--max-time`) |
201
+ | `:connect_timeout` | Integer / Float | Connection timeout in seconds (`--connect-timeout`) |
202
+ | `:proxy` | String | Proxy address (e.g., `'http://127.0.0.1:8888'`) |
203
+ | `:basic_auth` | Hash | `{ username: 'admin', password: 'secret' }` |
204
+ | `:bearer_token` | String | Appends `Authorization: Bearer <token>` header |
205
+ | `:insecure` | Boolean | Disable SSL certificate verification (`-k`) |
206
+ | `:curl_options` | Array / String | Additional raw curl arguments (e.g., `['--http2', '--compressed']`) |
207
+
208
+ ---
209
+
210
+ ## ๐Ÿ“„ Response Object
211
+
212
+ The `Response` object wraps the HTTP response with convenient methods:
213
+
214
+ ```ruby
215
+ response = HttpMimic.get('https://httpbin.org/get')
216
+
217
+ # Status information
218
+ response.code # => 200 (Integer)
219
+ response.status # => 200
220
+ response.status_message # => "OK"
221
+ response.http_version # => "2"
222
+ response.success? # => true (2xx)
223
+ response.redirect? # => false (3xx)
224
+ response.client_error? # => false (4xx)
225
+ response.server_error? # => false (5xx)
226
+
227
+ # Response body
228
+ response.body # => Raw Body (String)
229
+ response.parsed_response# => Auto-parsed JSON Hash / Array
230
+ response['key'] # => Direct key access to parsed_response
231
+
232
+ # Headers & Cookies
233
+ response.headers['content-type'] # => Case-insensitive header access
234
+ response.cookies['session_id'] # => Parsed Set-Cookie store
235
+ response.history # => Array of redirect history metadata
236
+
237
+ # Underlying execution details
238
+ response.exit_code # => Process exit status (0 for success)
239
+ response.stderr # => Stderr output from curl
240
+ response.command # => Array of the exact CLI arguments executed
241
+ ```
242
+
243
+ ---
244
+
245
+ ## ๐Ÿงช Testing
246
+
247
+ ```bash
248
+ # Run offline unit tests
249
+ bundle exec rake test
250
+
251
+ # Run live integration tests against external TLS / JA3 / JA4 / Akamai endpoints
252
+ bundle exec rake test:live
253
+
254
+ # Run all tests
255
+ bundle exec rake test:all
256
+ ```
257
+
258
+ ---
259
+
260
+ ## ๐Ÿ“„ License
261
+
262
+ This project is available as open source under the terms of the [MIT License](file:///Users/ivan/work/Tranyi/_gem/http_mimic/LICENSE.txt).
263
+ Source code is hosted on [GitHub](https://github.com/anxgang/http_mimic).
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'http_mimic/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "http_mimic"
9
+ spec.version = HttpMimic::VERSION
10
+ spec.authors = ["anxgang"]
11
+ spec.summary = "A HTTParty-like Ruby client wrapping curl-impersonate via Open3."
12
+ spec.description = "Simplifies making HTTP requests using curl-impersonate to mimic real browser TLS/HTTP2 fingerprints."
13
+ spec.homepage = "https://github.com/anxgang/http_mimic"
14
+ spec.license = "MIT"
15
+
16
+ spec.metadata = {
17
+ "homepage_uri" => "https://github.com/anxgang/http_mimic",
18
+ "source_code_uri" => "https://github.com/anxgang/http_mimic",
19
+ "bug_tracker_uri" => "https://github.com/anxgang/http_mimic/issues",
20
+ "changelog_uri" => "https://github.com/anxgang/http_mimic/blob/main/CHANGELOG.md"
21
+ }
22
+
23
+ spec.required_ruby_version = ">= 2.3.0"
24
+
25
+ spec.files = Dir["lib/**/*.rb", "README.md", "CHANGELOG.md", "LICENSE.txt", "http_mimic.gemspec"]
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.add_development_dependency "bundler", ">= 1.17"
29
+ spec.add_development_dependency "rake"
30
+ spec.add_development_dependency "minitest"
31
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HttpMimic
4
+ class Client
5
+ attr_accessor :default_options, :config
6
+
7
+ def initialize(options = {}, config = nil)
8
+ @default_options = options.dup
9
+ @config = config || HttpMimic.configuration.dup
10
+ end
11
+
12
+ def get(url, options = {})
13
+ request(:get, url, options)
14
+ end
15
+
16
+ def post(url, options = {})
17
+ request(:post, url, options)
18
+ end
19
+
20
+ def put(url, options = {})
21
+ request(:put, url, options)
22
+ end
23
+
24
+ def patch(url, options = {})
25
+ request(:patch, url, options)
26
+ end
27
+
28
+ def delete(url, options = {})
29
+ request(:delete, url, options)
30
+ end
31
+
32
+ def head(url, options = {})
33
+ request(:head, url, options)
34
+ end
35
+
36
+ def options(url, options = {})
37
+ request(:options, url, options)
38
+ end
39
+
40
+ def request(method, url, options = {})
41
+ merged_options = merge_options(@default_options, options)
42
+ Request.new(method, url, merged_options, @config).perform
43
+ end
44
+
45
+ private
46
+
47
+ def merge_options(base, override)
48
+ result = base.merge(override)
49
+
50
+ # Deep merge headers
51
+ if base[:headers] || override[:headers]
52
+ base_headers = base[:headers] || {}
53
+ over_headers = override[:headers] || {}
54
+ result[:headers] = base_headers.merge(over_headers)
55
+ end
56
+
57
+ # Deep merge query / params
58
+ base_query = base[:query] || base[:params] || {}
59
+ over_query = override[:query] || override[:params] || {}
60
+ if !base_query.empty? || !over_query.empty?
61
+ result[:query] = base_query.merge(over_query)
62
+ end
63
+
64
+ # Deep merge cookies
65
+ if base[:cookies].is_a?(Hash) && override[:cookies].is_a?(Hash)
66
+ result[:cookies] = base[:cookies].merge(override[:cookies])
67
+ end
68
+
69
+ result
70
+ end
71
+ end
72
+ end