impit 0.2.1__tar.gz → 0.2.2__tar.gz
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.
- {impit-0.2.1 → impit-0.2.2}/Cargo.lock +34 -46
- {impit-0.2.1 → impit-0.2.2}/PKG-INFO +1 -1
- impit-0.2.2/impit/src/errors.rs +107 -0
- {impit-0.2.1 → impit-0.2.2}/impit/src/http_headers/mod.rs +21 -13
- {impit-0.2.1 → impit-0.2.2}/impit/src/impit.rs +40 -40
- {impit-0.2.1 → impit-0.2.2}/impit/src/lib.rs +3 -0
- {impit-0.2.1 → impit-0.2.2}/impit/src/request.rs +3 -3
- impit-0.2.2/impit-python/python/impit/__init__.py +89 -0
- {impit-0.2.1 → impit-0.2.2}/impit-python/python/impit/impit.pyi +56 -0
- {impit-0.2.1 → impit-0.2.2}/impit-python/src/async_client.rs +10 -18
- {impit-0.2.1 → impit-0.2.2}/impit-python/src/client.rs +22 -23
- impit-0.2.2/impit-python/src/errors.rs +110 -0
- impit-0.2.2/impit-python/src/lib.rs +111 -0
- {impit-0.2.1 → impit-0.2.2}/impit-python/src/response.rs +11 -0
- {impit-0.2.1 → impit-0.2.2}/impit-python/test/async_test.py +2 -2
- {impit-0.2.1 → impit-0.2.2}/impit-python/test/basic_test.py +2 -2
- {impit-0.2.1 → impit-0.2.2}/impit-python/uv.lock +178 -178
- {impit-0.2.1 → impit-0.2.2}/pyproject.toml +1 -1
- impit-0.2.2/python/impit/__init__.py +89 -0
- {impit-0.2.1 → impit-0.2.2}/python/impit/impit.pyi +56 -0
- impit-0.2.1/impit-python/python/impit/__init__.py +0 -33
- impit-0.2.1/impit-python/src/lib.rs +0 -45
- impit-0.2.1/python/impit/__init__.py +0 -33
- {impit-0.2.1 → impit-0.2.2}/Cargo.toml +0 -0
- {impit-0.2.1 → impit-0.2.2}/README.md +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit/Cargo.toml +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit/README.md +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit/docs/index.html +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit/examples/basic.rs +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit/src/http3.rs +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit/src/http_headers/statics.rs +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit/src/response_parsing/mod.rs +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit/src/tls/ffdhe.rs +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit/src/tls/mod.rs +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit/src/tls/statics.rs +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit-python/Cargo.toml +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit-python/README.md +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit-python/clippy.toml +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit-python/python/impit/py.typed +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit-python/src/request.rs +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit-python/test/__init__.py +0 -0
- {impit-0.2.1 → impit-0.2.2}/impit-python/test/httpbin.py +0 -0
- {impit-0.2.1 → impit-0.2.2}/python/impit/py.typed +0 -0
|
@@ -132,14 +132,15 @@ dependencies = [
|
|
|
132
132
|
|
|
133
133
|
[[package]]
|
|
134
134
|
name = "async-executor"
|
|
135
|
-
version = "1.13.
|
|
135
|
+
version = "1.13.2"
|
|
136
136
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
137
|
-
checksum = "
|
|
137
|
+
checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa"
|
|
138
138
|
dependencies = [
|
|
139
139
|
"async-task",
|
|
140
140
|
"concurrent-queue",
|
|
141
141
|
"fastrand",
|
|
142
142
|
"futures-lite",
|
|
143
|
+
"pin-project-lite",
|
|
143
144
|
"slab",
|
|
144
145
|
]
|
|
145
146
|
|
|
@@ -207,17 +208,6 @@ dependencies = [
|
|
|
207
208
|
"tracing",
|
|
208
209
|
]
|
|
209
210
|
|
|
210
|
-
[[package]]
|
|
211
|
-
name = "async-recursion"
|
|
212
|
-
version = "1.1.1"
|
|
213
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
214
|
-
checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
|
215
|
-
dependencies = [
|
|
216
|
-
"proc-macro2",
|
|
217
|
-
"quote",
|
|
218
|
-
"syn",
|
|
219
|
-
]
|
|
220
|
-
|
|
221
211
|
[[package]]
|
|
222
212
|
name = "async-signal"
|
|
223
213
|
version = "0.2.10"
|
|
@@ -294,9 +284,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
|
|
294
284
|
|
|
295
285
|
[[package]]
|
|
296
286
|
name = "aws-lc-fips-sys"
|
|
297
|
-
version = "0.13.
|
|
287
|
+
version = "0.13.6"
|
|
298
288
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
299
|
-
checksum = "
|
|
289
|
+
checksum = "e99d74bb793a19f542ae870a6edafbc5ecf0bc0ba01d4636b7f7e0aba9ee9bd3"
|
|
300
290
|
dependencies = [
|
|
301
291
|
"bindgen",
|
|
302
292
|
"cc",
|
|
@@ -396,9 +386,9 @@ dependencies = [
|
|
|
396
386
|
|
|
397
387
|
[[package]]
|
|
398
388
|
name = "brotli"
|
|
399
|
-
version = "8.0.
|
|
389
|
+
version = "8.0.1"
|
|
400
390
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
401
|
-
checksum = "
|
|
391
|
+
checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d"
|
|
402
392
|
dependencies = [
|
|
403
393
|
"alloc-no-stdlib",
|
|
404
394
|
"alloc-stdlib",
|
|
@@ -435,9 +425,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
|
|
435
425
|
|
|
436
426
|
[[package]]
|
|
437
427
|
name = "cc"
|
|
438
|
-
version = "1.2.
|
|
428
|
+
version = "1.2.21"
|
|
439
429
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
440
|
-
checksum = "
|
|
430
|
+
checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0"
|
|
441
431
|
dependencies = [
|
|
442
432
|
"jobserver",
|
|
443
433
|
"libc",
|
|
@@ -1163,9 +1153,9 @@ dependencies = [
|
|
|
1163
1153
|
|
|
1164
1154
|
[[package]]
|
|
1165
1155
|
name = "hashbrown"
|
|
1166
|
-
version = "0.15.
|
|
1156
|
+
version = "0.15.3"
|
|
1167
1157
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1168
|
-
checksum = "
|
|
1158
|
+
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
|
1169
1159
|
|
|
1170
1160
|
[[package]]
|
|
1171
1161
|
name = "heck"
|
|
@@ -1181,9 +1171,9 @@ checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
|
|
1181
1171
|
|
|
1182
1172
|
[[package]]
|
|
1183
1173
|
name = "hickory-client"
|
|
1184
|
-
version = "0.25.
|
|
1174
|
+
version = "0.25.2"
|
|
1185
1175
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1186
|
-
checksum = "
|
|
1176
|
+
checksum = "c466cd63a4217d5b2b8e32f23f58312741ce96e3c84bf7438677d2baff0fc555"
|
|
1187
1177
|
dependencies = [
|
|
1188
1178
|
"cfg-if",
|
|
1189
1179
|
"data-encoding",
|
|
@@ -1200,14 +1190,12 @@ dependencies = [
|
|
|
1200
1190
|
|
|
1201
1191
|
[[package]]
|
|
1202
1192
|
name = "hickory-proto"
|
|
1203
|
-
version = "0.25.
|
|
1193
|
+
version = "0.25.2"
|
|
1204
1194
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1205
|
-
checksum = "
|
|
1195
|
+
checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502"
|
|
1206
1196
|
dependencies = [
|
|
1207
|
-
"async-recursion",
|
|
1208
1197
|
"async-trait",
|
|
1209
1198
|
"cfg-if",
|
|
1210
|
-
"critical-section",
|
|
1211
1199
|
"data-encoding",
|
|
1212
1200
|
"enum-as-inner",
|
|
1213
1201
|
"futures-channel",
|
|
@@ -1980,9 +1968,9 @@ dependencies = [
|
|
|
1980
1968
|
|
|
1981
1969
|
[[package]]
|
|
1982
1970
|
name = "openssl-sys"
|
|
1983
|
-
version = "0.9.
|
|
1971
|
+
version = "0.9.108"
|
|
1984
1972
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1985
|
-
checksum = "
|
|
1973
|
+
checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847"
|
|
1986
1974
|
dependencies = [
|
|
1987
1975
|
"cc",
|
|
1988
1976
|
"libc",
|
|
@@ -2316,9 +2304,9 @@ dependencies = [
|
|
|
2316
2304
|
|
|
2317
2305
|
[[package]]
|
|
2318
2306
|
name = "quinn-udp"
|
|
2319
|
-
version = "0.5.
|
|
2307
|
+
version = "0.5.12"
|
|
2320
2308
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2321
|
-
checksum = "
|
|
2309
|
+
checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842"
|
|
2322
2310
|
dependencies = [
|
|
2323
2311
|
"cfg_aliases",
|
|
2324
2312
|
"libc",
|
|
@@ -2399,9 +2387,9 @@ dependencies = [
|
|
|
2399
2387
|
|
|
2400
2388
|
[[package]]
|
|
2401
2389
|
name = "redox_syscall"
|
|
2402
|
-
version = "0.5.
|
|
2390
|
+
version = "0.5.12"
|
|
2403
2391
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2404
|
-
checksum = "
|
|
2392
|
+
checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
|
|
2405
2393
|
dependencies = [
|
|
2406
2394
|
"bitflags",
|
|
2407
2395
|
]
|
|
@@ -2540,9 +2528,9 @@ dependencies = [
|
|
|
2540
2528
|
|
|
2541
2529
|
[[package]]
|
|
2542
2530
|
name = "rustix"
|
|
2543
|
-
version = "1.0.
|
|
2531
|
+
version = "1.0.7"
|
|
2544
2532
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2545
|
-
checksum = "
|
|
2533
|
+
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
|
2546
2534
|
dependencies = [
|
|
2547
2535
|
"bitflags",
|
|
2548
2536
|
"errno",
|
|
@@ -2832,9 +2820,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
|
|
2832
2820
|
|
|
2833
2821
|
[[package]]
|
|
2834
2822
|
name = "syn"
|
|
2835
|
-
version = "2.0.
|
|
2823
|
+
version = "2.0.101"
|
|
2836
2824
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2837
|
-
checksum = "
|
|
2825
|
+
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
|
2838
2826
|
dependencies = [
|
|
2839
2827
|
"proc-macro2",
|
|
2840
2828
|
"quote",
|
|
@@ -2852,9 +2840,9 @@ dependencies = [
|
|
|
2852
2840
|
|
|
2853
2841
|
[[package]]
|
|
2854
2842
|
name = "synstructure"
|
|
2855
|
-
version = "0.13.
|
|
2843
|
+
version = "0.13.2"
|
|
2856
2844
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2857
|
-
checksum = "
|
|
2845
|
+
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
|
2858
2846
|
dependencies = [
|
|
2859
2847
|
"proc-macro2",
|
|
2860
2848
|
"quote",
|
|
@@ -2897,7 +2885,7 @@ dependencies = [
|
|
|
2897
2885
|
"fastrand",
|
|
2898
2886
|
"getrandom 0.3.2",
|
|
2899
2887
|
"once_cell",
|
|
2900
|
-
"rustix 1.0.
|
|
2888
|
+
"rustix 1.0.7",
|
|
2901
2889
|
"windows-sys 0.59.0",
|
|
2902
2890
|
]
|
|
2903
2891
|
|
|
@@ -3338,9 +3326,9 @@ dependencies = [
|
|
|
3338
3326
|
|
|
3339
3327
|
[[package]]
|
|
3340
3328
|
name = "webpki-roots"
|
|
3341
|
-
version = "0.26.
|
|
3329
|
+
version = "0.26.10"
|
|
3342
3330
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3343
|
-
checksum = "
|
|
3331
|
+
checksum = "37493cadf42a2a939ed404698ded7fb378bf301b5011f973361779a3a74f8c93"
|
|
3344
3332
|
dependencies = [
|
|
3345
3333
|
"rustls-pki-types",
|
|
3346
3334
|
]
|
|
@@ -3585,18 +3573,18 @@ dependencies = [
|
|
|
3585
3573
|
|
|
3586
3574
|
[[package]]
|
|
3587
3575
|
name = "zerocopy"
|
|
3588
|
-
version = "0.8.
|
|
3576
|
+
version = "0.8.25"
|
|
3589
3577
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3590
|
-
checksum = "
|
|
3578
|
+
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
|
|
3591
3579
|
dependencies = [
|
|
3592
3580
|
"zerocopy-derive",
|
|
3593
3581
|
]
|
|
3594
3582
|
|
|
3595
3583
|
[[package]]
|
|
3596
3584
|
name = "zerocopy-derive"
|
|
3597
|
-
version = "0.8.
|
|
3585
|
+
version = "0.8.25"
|
|
3598
3586
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3599
|
-
checksum = "
|
|
3587
|
+
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
|
|
3600
3588
|
dependencies = [
|
|
3601
3589
|
"proc-macro2",
|
|
3602
3590
|
"quote",
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
use std::time::Duration;
|
|
2
|
+
|
|
3
|
+
use thiserror::Error;
|
|
4
|
+
|
|
5
|
+
pub struct ErrorContext {
|
|
6
|
+
pub timeout: Duration,
|
|
7
|
+
pub max_redirects: usize,
|
|
8
|
+
pub method: String,
|
|
9
|
+
pub protocol: String,
|
|
10
|
+
pub url: String,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/// Error types that can be returned by the [`Impit`] struct.
|
|
14
|
+
///
|
|
15
|
+
/// The `ImpitError` enum is used to represent the different types of errors that can occur when making requests.
|
|
16
|
+
/// The `RequestError` variant is used to wrap the `reqwest::Error` type.
|
|
17
|
+
#[derive(Error, Debug)]
|
|
18
|
+
pub enum ImpitError {
|
|
19
|
+
#[error("HTTP error occurred.")]
|
|
20
|
+
HTTPError,
|
|
21
|
+
#[error("Request error occurred.")]
|
|
22
|
+
RequestError,
|
|
23
|
+
#[error("Transport error occurred.")]
|
|
24
|
+
TransportError,
|
|
25
|
+
#[error("Request timeout ({0}) ms exceeded.")]
|
|
26
|
+
TimeoutException(u128),
|
|
27
|
+
#[error("Connection timed out.")]
|
|
28
|
+
ConnectTimeout,
|
|
29
|
+
#[error("Read operation timed out.")]
|
|
30
|
+
ReadTimeout,
|
|
31
|
+
#[error("Write operation timed out.")]
|
|
32
|
+
WriteTimeout,
|
|
33
|
+
#[error("Connection pool timed out.")]
|
|
34
|
+
PoolTimeout,
|
|
35
|
+
#[error("Network error occurred.")]
|
|
36
|
+
NetworkError,
|
|
37
|
+
#[error("Failed to connect to the server.")]
|
|
38
|
+
ConnectError,
|
|
39
|
+
#[error("Failed to read data from the server.")]
|
|
40
|
+
ReadError,
|
|
41
|
+
#[error("Failed to write data to the server.")]
|
|
42
|
+
WriteError,
|
|
43
|
+
#[error("Failed to close the connection.")]
|
|
44
|
+
CloseError,
|
|
45
|
+
#[error("Protocol error occurred.")]
|
|
46
|
+
ProtocolError,
|
|
47
|
+
#[error("Local protocol error occurred.")]
|
|
48
|
+
LocalProtocolError,
|
|
49
|
+
#[error("Remote protocol error occurred.")]
|
|
50
|
+
RemoteProtocolError,
|
|
51
|
+
#[error("The proxy URL `{0}` is invalid or unreachable.")]
|
|
52
|
+
ProxyError(String),
|
|
53
|
+
#[error("The protocol is unsupported.")]
|
|
54
|
+
UnsupportedProtocol,
|
|
55
|
+
#[error("The response body couldn't be decoded.")]
|
|
56
|
+
DecodingError,
|
|
57
|
+
#[error("Too many redirects occurred. Maximum allowed: {0}")]
|
|
58
|
+
TooManyRedirects(usize),
|
|
59
|
+
#[error("HTTP status error occurred with status code {0}.")]
|
|
60
|
+
HTTPStatusError(u16),
|
|
61
|
+
#[error("The URL is invalid.")]
|
|
62
|
+
InvalidURL,
|
|
63
|
+
#[error("A cookie conflict occurred.")]
|
|
64
|
+
CookieConflict,
|
|
65
|
+
#[error("A stream error occurred.")]
|
|
66
|
+
StreamError,
|
|
67
|
+
#[error("The stream has already been consumed.")]
|
|
68
|
+
StreamConsumed,
|
|
69
|
+
#[error("The response has not been read.")]
|
|
70
|
+
ResponseNotRead,
|
|
71
|
+
#[error("The request has not been read.")]
|
|
72
|
+
RequestNotRead,
|
|
73
|
+
#[error("The stream has been closed.")]
|
|
74
|
+
StreamClosed,
|
|
75
|
+
#[error("The URL couldn't be parsed.")]
|
|
76
|
+
UrlParsingError,
|
|
77
|
+
#[error("The URL ({0}) is missing the hostname.")]
|
|
78
|
+
UrlMissingHostnameError(String),
|
|
79
|
+
#[error("The URL uses an unsupported protocol (`{0}`). Currently, only HTTP and HTTPS are supported.")]
|
|
80
|
+
UrlProtocolError(String),
|
|
81
|
+
#[error("The request was made with http3_prior_knowledge, but HTTP/3 usage wasn't enabled.")]
|
|
82
|
+
Http3Disabled,
|
|
83
|
+
#[error("The request method `{0}` is invalid. Only GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS and TRACE are supported.")]
|
|
84
|
+
InvalidMethod(String),
|
|
85
|
+
#[error("{0}")]
|
|
86
|
+
BindingPassthroughError(String),
|
|
87
|
+
#[error("The header name `{0}` is invalid. Header names must be ASCII and cannot contain control characters or whitespace.")]
|
|
88
|
+
InvalidHeaderName(String),
|
|
89
|
+
#[error("The header value `{0}` is invalid.")]
|
|
90
|
+
InvalidHeaderValue(String),
|
|
91
|
+
#[error("{0:#?}")]
|
|
92
|
+
ReqwestError(reqwest::Error),
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
impl ImpitError {
|
|
96
|
+
pub fn from(error: reqwest::Error, context: ErrorContext) -> Self {
|
|
97
|
+
if error.is_timeout() {
|
|
98
|
+
return ImpitError::TimeoutException(context.timeout.as_millis());
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if error.is_redirect() {
|
|
102
|
+
return ImpitError::TooManyRedirects(context.max_redirects);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
ImpitError::RequestError
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
use crate::emulation::Browser;
|
|
1
|
+
use crate::{emulation::Browser, errors::ImpitError};
|
|
2
2
|
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
|
|
3
|
-
use std::{
|
|
4
|
-
collections::{HashMap, HashSet},
|
|
5
|
-
str::FromStr,
|
|
6
|
-
};
|
|
3
|
+
use std::{collections::HashSet, str::FromStr};
|
|
7
4
|
|
|
8
5
|
mod statics;
|
|
9
6
|
|
|
@@ -23,7 +20,7 @@ impl HttpHeaders {
|
|
|
23
20
|
}
|
|
24
21
|
}
|
|
25
22
|
|
|
26
|
-
impl From<HttpHeaders> for HeaderMap {
|
|
23
|
+
impl From<HttpHeaders> for Result<HeaderMap, ImpitError> {
|
|
27
24
|
fn from(val: HttpHeaders) -> Self {
|
|
28
25
|
let impersonated_headers = match val.context.browser {
|
|
29
26
|
Some(Browser::Chrome) => statics::CHROME_HEADERS,
|
|
@@ -60,13 +57,24 @@ impl From<HttpHeaders> for HeaderMap {
|
|
|
60
57
|
continue;
|
|
61
58
|
}
|
|
62
59
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
)
|
|
60
|
+
let header_name = HeaderName::from_str(name);
|
|
61
|
+
let header_value = HeaderValue::from_str(value);
|
|
62
|
+
|
|
63
|
+
match (header_name, header_value) {
|
|
64
|
+
(Err(_), _) => {
|
|
65
|
+
return Err(ImpitError::InvalidHeaderName(name.to_string()));
|
|
66
|
+
}
|
|
67
|
+
(_, Err(_)) => {
|
|
68
|
+
return Err(ImpitError::InvalidHeaderValue(value.to_string()));
|
|
69
|
+
}
|
|
70
|
+
(Ok(header_name), Ok(header_value)) => {
|
|
71
|
+
headers.append(header_name, header_value);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
67
75
|
used_header_names.insert(name.to_lowercase());
|
|
68
76
|
}
|
|
69
|
-
headers
|
|
77
|
+
Ok(headers)
|
|
70
78
|
}
|
|
71
79
|
}
|
|
72
80
|
|
|
@@ -75,7 +83,7 @@ pub struct HttpHeadersBuilder {
|
|
|
75
83
|
host: String,
|
|
76
84
|
browser: Option<Browser>,
|
|
77
85
|
https: bool,
|
|
78
|
-
custom_headers:
|
|
86
|
+
custom_headers: Vec<(String, String)>,
|
|
79
87
|
}
|
|
80
88
|
|
|
81
89
|
impl HttpHeadersBuilder {
|
|
@@ -95,7 +103,7 @@ impl HttpHeadersBuilder {
|
|
|
95
103
|
self
|
|
96
104
|
}
|
|
97
105
|
|
|
98
|
-
pub fn with_custom_headers(&mut self, custom_headers: &
|
|
106
|
+
pub fn with_custom_headers(&mut self, custom_headers: &Vec<(String, String)>) -> &mut Self {
|
|
99
107
|
self.custom_headers = custom_headers.to_owned();
|
|
100
108
|
self
|
|
101
109
|
}
|
|
@@ -1,33 +1,17 @@
|
|
|
1
1
|
use log::debug;
|
|
2
|
-
use reqwest::{Method, Response, Version};
|
|
2
|
+
use reqwest::{header::HeaderMap, Method, Response, Version};
|
|
3
3
|
use std::{str::FromStr, time::Duration};
|
|
4
|
-
use thiserror::Error;
|
|
5
4
|
use url::Url;
|
|
6
5
|
|
|
7
6
|
use crate::{
|
|
8
|
-
emulation::Browser,
|
|
7
|
+
emulation::Browser,
|
|
8
|
+
errors::{ErrorContext, ImpitError},
|
|
9
|
+
http3::H3Engine,
|
|
10
|
+
http_headers::HttpHeaders,
|
|
11
|
+
request::RequestOptions,
|
|
12
|
+
tls,
|
|
9
13
|
};
|
|
10
14
|
|
|
11
|
-
/// Error types that can be returned by the [`Impit`] struct.
|
|
12
|
-
///
|
|
13
|
-
/// The `ErrorType` enum is used to represent the different types of errors that can occur when making requests.
|
|
14
|
-
/// The `RequestError` variant is used to wrap the `reqwest::Error` type.
|
|
15
|
-
#[derive(Error, Debug)]
|
|
16
|
-
pub enum ErrorType {
|
|
17
|
-
#[error("The URL couldn't be parsed.")]
|
|
18
|
-
UrlParsingError,
|
|
19
|
-
#[error("The URL is missing the hostname.")]
|
|
20
|
-
UrlMissingHostnameError,
|
|
21
|
-
#[error("The URL uses an unsupported protocol (`{0}`). Currently, only HTTP and HTTPS are supported.")]
|
|
22
|
-
UrlProtocolError(String),
|
|
23
|
-
#[error("The request was made with http3_prior_knowledge, but HTTP/3 usage wasn't enabled.")]
|
|
24
|
-
Http3Disabled,
|
|
25
|
-
#[error("The request method `{0}` is invalid. Only GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS and TRACE are supported.")]
|
|
26
|
-
InvalidMethod(String),
|
|
27
|
-
#[error(transparent)]
|
|
28
|
-
RequestError(#[from] reqwest::Error),
|
|
29
|
-
}
|
|
30
|
-
|
|
31
15
|
/// Impit is the main struct used to make (impersonated) requests.
|
|
32
16
|
///
|
|
33
17
|
/// It uses `reqwest::Client` to make requests and holds info about the impersonated browser.
|
|
@@ -250,11 +234,11 @@ impl Impit {
|
|
|
250
234
|
}
|
|
251
235
|
}
|
|
252
236
|
|
|
253
|
-
fn parse_url(&self, url: String) -> Result<Url,
|
|
254
|
-
let url = Url::parse(&url).map_err(|_|
|
|
237
|
+
fn parse_url(&self, url: String) -> Result<Url, ImpitError> {
|
|
238
|
+
let url = Url::parse(&url).map_err(|_| ImpitError::UrlParsingError)?;
|
|
255
239
|
|
|
256
240
|
if url.host_str().is_none() {
|
|
257
|
-
return Err(
|
|
241
|
+
return Err(ImpitError::UrlMissingHostnameError(url.to_string()));
|
|
258
242
|
}
|
|
259
243
|
|
|
260
244
|
let protocol = url.scheme();
|
|
@@ -262,7 +246,7 @@ impl Impit {
|
|
|
262
246
|
match protocol {
|
|
263
247
|
"http" => Ok(url),
|
|
264
248
|
"https" => Ok(url),
|
|
265
|
-
_ => Err(
|
|
249
|
+
_ => Err(ImpitError::UrlProtocolError(protocol.to_string())),
|
|
266
250
|
}
|
|
267
251
|
}
|
|
268
252
|
|
|
@@ -289,11 +273,11 @@ impl Impit {
|
|
|
289
273
|
url: String,
|
|
290
274
|
body: Option<Vec<u8>>,
|
|
291
275
|
options: Option<RequestOptions>,
|
|
292
|
-
) -> Result<Response,
|
|
276
|
+
) -> Result<Response, ImpitError> {
|
|
293
277
|
let options = options.unwrap_or_default();
|
|
294
278
|
|
|
295
279
|
if options.http3_prior_knowledge && self.config.max_http_version < Version::HTTP_3 {
|
|
296
|
-
return Err(
|
|
280
|
+
return Err(ImpitError::Http3Disabled);
|
|
297
281
|
}
|
|
298
282
|
|
|
299
283
|
let parsed_url = self.parse_url(url.clone())?;
|
|
@@ -316,9 +300,11 @@ impl Impit {
|
|
|
316
300
|
&self.base_client
|
|
317
301
|
};
|
|
318
302
|
|
|
303
|
+
let header_map: Result<HeaderMap, ImpitError> = headers.into();
|
|
304
|
+
|
|
319
305
|
let mut request = client
|
|
320
|
-
.request(method.clone(), parsed_url)
|
|
321
|
-
.headers(
|
|
306
|
+
.request(method.clone(), parsed_url.clone())
|
|
307
|
+
.headers(header_map?);
|
|
322
308
|
|
|
323
309
|
if h3 {
|
|
324
310
|
request = request.version(Version::HTTP_3);
|
|
@@ -336,7 +322,21 @@ impl Impit {
|
|
|
336
322
|
let response = request.send().await;
|
|
337
323
|
|
|
338
324
|
if response.is_err() {
|
|
339
|
-
|
|
325
|
+
let max_redirects = match self.config.redirect {
|
|
326
|
+
RedirectBehavior::FollowRedirect(max) => max,
|
|
327
|
+
RedirectBehavior::ManualRedirect => 0,
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
return Err(ImpitError::from(
|
|
331
|
+
response.err().unwrap(),
|
|
332
|
+
ErrorContext {
|
|
333
|
+
timeout: options.timeout.unwrap_or(Duration::from_millis(0)),
|
|
334
|
+
max_redirects,
|
|
335
|
+
method: method.to_string(),
|
|
336
|
+
protocol: parsed_url.scheme().to_string(),
|
|
337
|
+
url: url.clone(),
|
|
338
|
+
},
|
|
339
|
+
));
|
|
340
340
|
}
|
|
341
341
|
|
|
342
342
|
let response = response.unwrap();
|
|
@@ -371,7 +371,7 @@ impl Impit {
|
|
|
371
371
|
&mut self,
|
|
372
372
|
url: String,
|
|
373
373
|
options: Option<RequestOptions>,
|
|
374
|
-
) -> Result<Response,
|
|
374
|
+
) -> Result<Response, ImpitError> {
|
|
375
375
|
self.make_request(Method::GET, url, None, options).await
|
|
376
376
|
}
|
|
377
377
|
|
|
@@ -385,7 +385,7 @@ impl Impit {
|
|
|
385
385
|
&mut self,
|
|
386
386
|
url: String,
|
|
387
387
|
options: Option<RequestOptions>,
|
|
388
|
-
) -> Result<Response,
|
|
388
|
+
) -> Result<Response, ImpitError> {
|
|
389
389
|
self.make_request(Method::HEAD, url, None, options).await
|
|
390
390
|
}
|
|
391
391
|
|
|
@@ -399,7 +399,7 @@ impl Impit {
|
|
|
399
399
|
&mut self,
|
|
400
400
|
url: String,
|
|
401
401
|
options: Option<RequestOptions>,
|
|
402
|
-
) -> Result<Response,
|
|
402
|
+
) -> Result<Response, ImpitError> {
|
|
403
403
|
self.make_request(Method::OPTIONS, url, None, options).await
|
|
404
404
|
}
|
|
405
405
|
|
|
@@ -413,7 +413,7 @@ impl Impit {
|
|
|
413
413
|
&mut self,
|
|
414
414
|
url: String,
|
|
415
415
|
options: Option<RequestOptions>,
|
|
416
|
-
) -> Result<Response,
|
|
416
|
+
) -> Result<Response, ImpitError> {
|
|
417
417
|
self.make_request(Method::TRACE, url, None, options).await
|
|
418
418
|
}
|
|
419
419
|
|
|
@@ -427,7 +427,7 @@ impl Impit {
|
|
|
427
427
|
&mut self,
|
|
428
428
|
url: String,
|
|
429
429
|
options: Option<RequestOptions>,
|
|
430
|
-
) -> Result<Response,
|
|
430
|
+
) -> Result<Response, ImpitError> {
|
|
431
431
|
self.make_request(Method::DELETE, url, None, options).await
|
|
432
432
|
}
|
|
433
433
|
|
|
@@ -442,7 +442,7 @@ impl Impit {
|
|
|
442
442
|
url: String,
|
|
443
443
|
body: Option<Vec<u8>>,
|
|
444
444
|
options: Option<RequestOptions>,
|
|
445
|
-
) -> Result<Response,
|
|
445
|
+
) -> Result<Response, ImpitError> {
|
|
446
446
|
self.make_request(Method::POST, url, body, options).await
|
|
447
447
|
}
|
|
448
448
|
|
|
@@ -457,7 +457,7 @@ impl Impit {
|
|
|
457
457
|
url: String,
|
|
458
458
|
body: Option<Vec<u8>>,
|
|
459
459
|
options: Option<RequestOptions>,
|
|
460
|
-
) -> Result<Response,
|
|
460
|
+
) -> Result<Response, ImpitError> {
|
|
461
461
|
self.make_request(Method::PUT, url, body, options).await
|
|
462
462
|
}
|
|
463
463
|
|
|
@@ -472,7 +472,7 @@ impl Impit {
|
|
|
472
472
|
url: String,
|
|
473
473
|
body: Option<Vec<u8>>,
|
|
474
474
|
options: Option<RequestOptions>,
|
|
475
|
-
) -> Result<Response,
|
|
475
|
+
) -> Result<Response, ImpitError> {
|
|
476
476
|
self.make_request(Method::PATCH, url, body, options).await
|
|
477
477
|
}
|
|
478
478
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
use std::
|
|
1
|
+
use std::time::Duration;
|
|
2
2
|
|
|
3
3
|
/// A struct that holds the request options.
|
|
4
4
|
///
|
|
@@ -7,8 +7,8 @@ use std::{collections::HashMap, time::Duration};
|
|
|
7
7
|
/// Used by the [`Impit`](crate::impit::Impit) struct's methods.
|
|
8
8
|
#[derive(Debug, Clone, Default)]
|
|
9
9
|
pub struct RequestOptions {
|
|
10
|
-
/// A `
|
|
11
|
-
pub headers:
|
|
10
|
+
/// A `Vec` of string pairs that represent custom HTTP request headers. These are added to the default headers.
|
|
11
|
+
pub headers: Vec<(String, String)>,
|
|
12
12
|
/// The timeout for the request. This option overrides the global [`Impit`] timeout.
|
|
13
13
|
pub timeout: Option<Duration>,
|
|
14
14
|
/// Enforce the use of HTTP/3 for this request. This will cause broken responses from servers that don't support HTTP/3.
|