bas-http 1.0.2__tar.gz → 1.0.4__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.
- {bas_http-1.0.2 → bas_http-1.0.4}/PKG-INFO +61 -31
- {bas_http-1.0.2 → bas_http-1.0.4}/bas/README.md +60 -30
- {bas_http-1.0.2 → bas_http-1.0.4}/bas/__init__.py +1 -1
- {bas_http-1.0.2 → bas_http-1.0.4}/bas/_curl.py +1 -1
- {bas_http-1.0.2 → bas_http-1.0.4}/bas/cookies.py +2 -2
- {bas_http-1.0.2 → bas_http-1.0.4}/bas/impersonate.py +3 -3
- {bas_http-1.0.2 → bas_http-1.0.4}/bas/session.py +5 -5
- {bas_http-1.0.2 → bas_http-1.0.4}/bas/tests/test_cookies.py +6 -6
- {bas_http-1.0.2 → bas_http-1.0.4}/bas/tests/test_real_request.py +3 -3
- {bas_http-1.0.2 → bas_http-1.0.4}/bas_http.egg-info/PKG-INFO +61 -31
- {bas_http-1.0.2 → bas_http-1.0.4}/pyproject.toml +1 -1
- {bas_http-1.0.2 → bas_http-1.0.4}/bas/async_session.py +0 -0
- {bas_http-1.0.2 → bas_http-1.0.4}/bas/curl_parser.py +0 -0
- {bas_http-1.0.2 → bas_http-1.0.4}/bas/models.py +0 -0
- {bas_http-1.0.2 → bas_http-1.0.4}/bas/simple_session.py +0 -0
- {bas_http-1.0.2 → bas_http-1.0.4}/bas/tests/__init__.py +0 -0
- {bas_http-1.0.2 → bas_http-1.0.4}/bas/tests/test_curl_parser.py +0 -0
- {bas_http-1.0.2 → bas_http-1.0.4}/bas/tests/test_spaceshooter.py +0 -0
- {bas_http-1.0.2 → bas_http-1.0.4}/bas_http.egg-info/SOURCES.txt +0 -0
- {bas_http-1.0.2 → bas_http-1.0.4}/bas_http.egg-info/dependency_links.txt +0 -0
- {bas_http-1.0.2 → bas_http-1.0.4}/bas_http.egg-info/top_level.txt +0 -0
- {bas_http-1.0.2 → bas_http-1.0.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bas-http
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Copy-paste your browser's request, bas handles the rest. No impersonation needed. Zero dependencies.
|
|
5
5
|
Author: bas
|
|
6
6
|
License-Expression: MIT
|
|
@@ -27,18 +27,22 @@ Description-Content-Type: text/markdown
|
|
|
27
27
|
|
|
28
28
|
Copy-paste your browser's request, bas handles the rest.
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Zero dependencies. Pure Python. Just grab your headers + cookies from DevTools and go.
|
|
31
31
|
|
|
32
32
|
## Why bas?
|
|
33
33
|
|
|
34
|
-
|
|
|
35
|
-
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
|
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
|
|
|
34
|
+
| Feature | bas | requests | pycurl | curl_cffi |
|
|
35
|
+
|---------|-----|----------|--------|----------|
|
|
36
|
+
| Zero dependencies | ✅ | ❌ (urllib3) | ❌ (libcurl) | ❌ (curl-impersonate) |
|
|
37
|
+
| Paste curl from DevTools | ✅ | ❌ | ❌ | ❌ |
|
|
38
|
+
| Auto Cookie injection | ✅ | ✅ | ❌ | ⚠️ |
|
|
39
|
+
| Cookie jar (RFC 6265) | ✅ | ✅ | ❌ | ⚠️ |
|
|
40
|
+
| No compilation needed | ✅ | ✅ | ❌ | ❌ |
|
|
41
|
+
| Bring your own headers | ✅ | ❌ (generates) | ❌ | ❌ (impersonation) |
|
|
42
|
+
| Works on all platforms | ✅ | ✅ | ⚠️ | ⚠️ |
|
|
43
|
+
| Session persistence | ✅ | ✅ | ❌ | ✅ |
|
|
44
|
+
| Follow redirects | ✅ | ✅ | Manual | ✅ |
|
|
45
|
+
| JSON support | ✅ | ✅ | ❌ | ✅ |
|
|
42
46
|
|
|
43
47
|
## Installation
|
|
44
48
|
|
|
@@ -290,7 +294,7 @@ r = s.get("https://example.com/page")
|
|
|
290
294
|
# Set-Cookie: tracking=xyz; Path=/
|
|
291
295
|
|
|
292
296
|
# ALL cookies are preserved through redirects
|
|
293
|
-
# No cookies lost (unlike
|
|
297
|
+
# No cookies lost (unlike bas!)
|
|
294
298
|
```
|
|
295
299
|
|
|
296
300
|
## Session Persistence
|
|
@@ -427,41 +431,67 @@ r = s.post("https://example.com/login", data={
|
|
|
427
431
|
print(r.status_code)
|
|
428
432
|
```
|
|
429
433
|
|
|
430
|
-
## Comparison with
|
|
434
|
+
## Comparison with Other Libraries
|
|
431
435
|
|
|
432
|
-
###
|
|
436
|
+
### requests
|
|
437
|
+
|
|
438
|
+
```python
|
|
439
|
+
import requests
|
|
440
|
+
|
|
441
|
+
# Manual header/cookie setup
|
|
442
|
+
s = requests.Session()
|
|
443
|
+
s.headers["User-Agent"] = "Mozilla/5.0 ..."
|
|
444
|
+
s.cookies.set("session", "abc", domain="example.com")
|
|
445
|
+
|
|
446
|
+
r = s.get("https://example.com")
|
|
447
|
+
# Works, but no curl copy-paste support
|
|
448
|
+
# Generates its own fingerprint (detectable)
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
### pycurl
|
|
452
|
+
|
|
453
|
+
```python
|
|
454
|
+
import pycurl
|
|
455
|
+
from io import BytesIO
|
|
456
|
+
|
|
457
|
+
# Low-level, verbose setup
|
|
458
|
+
c = pycurl.Curl()
|
|
459
|
+
c.setopt(c.URL, "https://example.com")
|
|
460
|
+
c.setopt(c.HTTPHEADER, ["User-Agent: Mozilla/5.0 ...", "Cookie: session=abc"])
|
|
461
|
+
buffer = BytesIO()
|
|
462
|
+
c.setopt(c.WRITEDATA, buffer)
|
|
463
|
+
c.perform()
|
|
464
|
+
c.close()
|
|
465
|
+
|
|
466
|
+
# No built-in cookie jar, no redirect handling
|
|
467
|
+
# Requires libcurl installed on the system
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### curl_cffi
|
|
433
471
|
|
|
434
472
|
```python
|
|
435
473
|
from curl_cffi.requests import Session
|
|
436
474
|
|
|
475
|
+
# Requires curl-impersonate installed
|
|
437
476
|
s = Session(impersonate="chrome131")
|
|
477
|
+
r = s.get("https://example.com")
|
|
438
478
|
|
|
439
|
-
#
|
|
440
|
-
|
|
441
|
-
# r1 is missing cookies from Set-Cookie headers!
|
|
442
|
-
|
|
443
|
-
# Cookies not accumulating!
|
|
444
|
-
r2 = s.get("https://example.com/page")
|
|
445
|
-
# r2 has LOST cookies from r1!
|
|
479
|
+
# Impersonation fingerprint can become outdated
|
|
480
|
+
# Cookie handling has known issues
|
|
446
481
|
```
|
|
447
482
|
|
|
448
|
-
### bas
|
|
483
|
+
### bas
|
|
449
484
|
|
|
450
485
|
```python
|
|
451
486
|
import bas
|
|
452
487
|
|
|
488
|
+
# Paste curl from DevTools — done
|
|
453
489
|
s = bas.from_curl(r'''curl "https://example.com" -b "session=abc"''')
|
|
454
490
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
#
|
|
458
|
-
|
|
459
|
-
# Cookies accumulate!
|
|
460
|
-
r2 = s.get("https://example.com/dashboard")
|
|
461
|
-
# r2 has ALL cookies from r1 + new ones
|
|
462
|
-
|
|
463
|
-
# No manual Cookie header needed!
|
|
464
|
-
# bas auto-injects cookies from the jar
|
|
491
|
+
r = s.get("https://example.com")
|
|
492
|
+
# All headers auto-applied
|
|
493
|
+
# Cookies auto-injected
|
|
494
|
+
# Zero setup, zero dependencies
|
|
465
495
|
```
|
|
466
496
|
|
|
467
497
|
## API Reference
|
|
@@ -2,18 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
Copy-paste your browser's request, bas handles the rest.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Zero dependencies. Pure Python. Just grab your headers + cookies from DevTools and go.
|
|
6
6
|
|
|
7
7
|
## Why bas?
|
|
8
8
|
|
|
9
|
-
|
|
|
10
|
-
|
|
11
|
-
|
|
|
12
|
-
|
|
|
13
|
-
|
|
|
14
|
-
|
|
|
15
|
-
|
|
|
16
|
-
|
|
|
9
|
+
| Feature | bas | requests | pycurl | curl_cffi |
|
|
10
|
+
|---------|-----|----------|--------|----------|
|
|
11
|
+
| Zero dependencies | ✅ | ❌ (urllib3) | ❌ (libcurl) | ❌ (curl-impersonate) |
|
|
12
|
+
| Paste curl from DevTools | ✅ | ❌ | ❌ | ❌ |
|
|
13
|
+
| Auto Cookie injection | ✅ | ✅ | ❌ | ⚠️ |
|
|
14
|
+
| Cookie jar (RFC 6265) | ✅ | ✅ | ❌ | ⚠️ |
|
|
15
|
+
| No compilation needed | ✅ | ✅ | ❌ | ❌ |
|
|
16
|
+
| Bring your own headers | ✅ | ❌ (generates) | ❌ | ❌ (impersonation) |
|
|
17
|
+
| Works on all platforms | ✅ | ✅ | ⚠️ | ⚠️ |
|
|
18
|
+
| Session persistence | ✅ | ✅ | ❌ | ✅ |
|
|
19
|
+
| Follow redirects | ✅ | ✅ | Manual | ✅ |
|
|
20
|
+
| JSON support | ✅ | ✅ | ❌ | ✅ |
|
|
17
21
|
|
|
18
22
|
## Installation
|
|
19
23
|
|
|
@@ -265,7 +269,7 @@ r = s.get("https://example.com/page")
|
|
|
265
269
|
# Set-Cookie: tracking=xyz; Path=/
|
|
266
270
|
|
|
267
271
|
# ALL cookies are preserved through redirects
|
|
268
|
-
# No cookies lost (unlike
|
|
272
|
+
# No cookies lost (unlike bas!)
|
|
269
273
|
```
|
|
270
274
|
|
|
271
275
|
## Session Persistence
|
|
@@ -402,41 +406,67 @@ r = s.post("https://example.com/login", data={
|
|
|
402
406
|
print(r.status_code)
|
|
403
407
|
```
|
|
404
408
|
|
|
405
|
-
## Comparison with
|
|
409
|
+
## Comparison with Other Libraries
|
|
406
410
|
|
|
407
|
-
###
|
|
411
|
+
### requests
|
|
412
|
+
|
|
413
|
+
```python
|
|
414
|
+
import requests
|
|
415
|
+
|
|
416
|
+
# Manual header/cookie setup
|
|
417
|
+
s = requests.Session()
|
|
418
|
+
s.headers["User-Agent"] = "Mozilla/5.0 ..."
|
|
419
|
+
s.cookies.set("session", "abc", domain="example.com")
|
|
420
|
+
|
|
421
|
+
r = s.get("https://example.com")
|
|
422
|
+
# Works, but no curl copy-paste support
|
|
423
|
+
# Generates its own fingerprint (detectable)
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### pycurl
|
|
427
|
+
|
|
428
|
+
```python
|
|
429
|
+
import pycurl
|
|
430
|
+
from io import BytesIO
|
|
431
|
+
|
|
432
|
+
# Low-level, verbose setup
|
|
433
|
+
c = pycurl.Curl()
|
|
434
|
+
c.setopt(c.URL, "https://example.com")
|
|
435
|
+
c.setopt(c.HTTPHEADER, ["User-Agent: Mozilla/5.0 ...", "Cookie: session=abc"])
|
|
436
|
+
buffer = BytesIO()
|
|
437
|
+
c.setopt(c.WRITEDATA, buffer)
|
|
438
|
+
c.perform()
|
|
439
|
+
c.close()
|
|
440
|
+
|
|
441
|
+
# No built-in cookie jar, no redirect handling
|
|
442
|
+
# Requires libcurl installed on the system
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### curl_cffi
|
|
408
446
|
|
|
409
447
|
```python
|
|
410
448
|
from curl_cffi.requests import Session
|
|
411
449
|
|
|
450
|
+
# Requires curl-impersonate installed
|
|
412
451
|
s = Session(impersonate="chrome131")
|
|
452
|
+
r = s.get("https://example.com")
|
|
413
453
|
|
|
414
|
-
#
|
|
415
|
-
|
|
416
|
-
# r1 is missing cookies from Set-Cookie headers!
|
|
417
|
-
|
|
418
|
-
# Cookies not accumulating!
|
|
419
|
-
r2 = s.get("https://example.com/page")
|
|
420
|
-
# r2 has LOST cookies from r1!
|
|
454
|
+
# Impersonation fingerprint can become outdated
|
|
455
|
+
# Cookie handling has known issues
|
|
421
456
|
```
|
|
422
457
|
|
|
423
|
-
### bas
|
|
458
|
+
### bas
|
|
424
459
|
|
|
425
460
|
```python
|
|
426
461
|
import bas
|
|
427
462
|
|
|
463
|
+
# Paste curl from DevTools — done
|
|
428
464
|
s = bas.from_curl(r'''curl "https://example.com" -b "session=abc"''')
|
|
429
465
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
#
|
|
433
|
-
|
|
434
|
-
# Cookies accumulate!
|
|
435
|
-
r2 = s.get("https://example.com/dashboard")
|
|
436
|
-
# r2 has ALL cookies from r1 + new ones
|
|
437
|
-
|
|
438
|
-
# No manual Cookie header needed!
|
|
439
|
-
# bas auto-injects cookies from the jar
|
|
466
|
+
r = s.get("https://example.com")
|
|
467
|
+
# All headers auto-applied
|
|
468
|
+
# Cookies auto-injected
|
|
469
|
+
# Zero setup, zero dependencies
|
|
440
470
|
```
|
|
441
471
|
|
|
442
472
|
## API Reference
|
|
@@ -28,7 +28,7 @@ from .curl_parser import parse_curl, curl_to_session, print_curl_summary
|
|
|
28
28
|
from .cookies import Cookie, CookieJar
|
|
29
29
|
from .models import Headers, PreparedRequest, Response, HTTPError
|
|
30
30
|
|
|
31
|
-
__version__ = "1.0.
|
|
31
|
+
__version__ = "1.0.4"
|
|
32
32
|
__author__ = "bas"
|
|
33
33
|
|
|
34
34
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Low-level ctypes bindings for libcurl with curl-impersonate support.
|
|
3
3
|
|
|
4
4
|
This module provides Python bindings to libcurl (or curl-impersonate if available)
|
|
5
|
-
using ctypes. It avoids cffi compilation issues that plague
|
|
5
|
+
using ctypes. It avoids cffi compilation issues that plague bas.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import ctypes
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
RFC 6265 compliant CookieJar.
|
|
3
3
|
|
|
4
|
-
This module fixes the major cookie issues in
|
|
4
|
+
This module fixes the major cookie issues in bas:
|
|
5
5
|
1. Cookies lost during redirects (#55)
|
|
6
6
|
2. Cookies not accumulating across session requests (#582)
|
|
7
7
|
3. Need for manual cookie header management
|
|
@@ -226,7 +226,7 @@ class CookieJar:
|
|
|
226
226
|
"""
|
|
227
227
|
Thread-safe, RFC 6265 compliant cookie jar.
|
|
228
228
|
|
|
229
|
-
This is the heart of bas's cookie handling. Unlike
|
|
229
|
+
This is the heart of bas's cookie handling. Unlike bas's
|
|
230
230
|
approach (which relies on libcurl's internal cookie engine and loses
|
|
231
231
|
cookies during redirects), bas manages cookies entirely in Python.
|
|
232
232
|
|
|
@@ -5,7 +5,7 @@ This module provides browser fingerprint profiles that override HTTP/2
|
|
|
5
5
|
settings and headers to mimic real browsers. When curl-impersonate is
|
|
6
6
|
available, it also enables TLS fingerprint mimicry.
|
|
7
7
|
|
|
8
|
-
Unlike
|
|
8
|
+
Unlike bas which bundles impersonation in a single enum, bas
|
|
9
9
|
separates the concerns:
|
|
10
10
|
- TLS impersonation (requires curl-impersonate library)
|
|
11
11
|
- HTTP/2 fingerprinting (works with standard libcurl)
|
|
@@ -348,7 +348,7 @@ PROFILES: dict[str, BrowserProfile] = {
|
|
|
348
348
|
"edge131": EDGE131,
|
|
349
349
|
}
|
|
350
350
|
|
|
351
|
-
# Aliases for
|
|
351
|
+
# Aliases for bas compatibility
|
|
352
352
|
CHROME_ALIASES = {
|
|
353
353
|
"chrome": CHROME131,
|
|
354
354
|
"chrome99": CHROME131, # closest available
|
|
@@ -385,7 +385,7 @@ def get_profile(name: str) -> BrowserProfile:
|
|
|
385
385
|
"""
|
|
386
386
|
Get a browser profile by name.
|
|
387
387
|
|
|
388
|
-
Supports both exact names and
|
|
388
|
+
Supports both exact names and bas-compatible aliases.
|
|
389
389
|
|
|
390
390
|
Args:
|
|
391
391
|
name: Profile name (e.g., "chrome131", "firefox120", "chrome")
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Session-based HTTP client with proper cookie management.
|
|
3
3
|
|
|
4
4
|
This is the main public API of bas. It provides a requests-like
|
|
5
|
-
interface while fixing ALL of
|
|
5
|
+
interface while fixing ALL of bas's cookie bugs:
|
|
6
6
|
|
|
7
7
|
Fix #1: Cookies accumulate correctly across requests in a session
|
|
8
8
|
Fix #2: Cookies are inherited during redirects (even cross-domain)
|
|
@@ -92,7 +92,7 @@ class Session:
|
|
|
92
92
|
"""
|
|
93
93
|
A persistent HTTP session with automatic cookie management.
|
|
94
94
|
|
|
95
|
-
Key improvements over
|
|
95
|
+
Key improvements over bas.Session:
|
|
96
96
|
- Cookies ALWAYS accumulate across requests (fixes #582)
|
|
97
97
|
- Cookies are inherited during redirects (fixes #55)
|
|
98
98
|
- Automatic Cookie header injection (no manual construction)
|
|
@@ -358,7 +358,7 @@ class Session:
|
|
|
358
358
|
)
|
|
359
359
|
|
|
360
360
|
# ── CRITICAL: Parse Set-Cookie and update our jar ──
|
|
361
|
-
# This is what
|
|
361
|
+
# This is what bas gets wrong — it relies on curl's internal
|
|
362
362
|
# cookie engine which loses cookies during redirects.
|
|
363
363
|
self._cookie_jar.parse_set_cookie_headers(
|
|
364
364
|
response_headers,
|
|
@@ -485,7 +485,7 @@ class Session:
|
|
|
485
485
|
3. Re-apply cookies for the next request via our jar
|
|
486
486
|
4. Never lose a single cookie
|
|
487
487
|
|
|
488
|
-
This fixes
|
|
488
|
+
This fixes bas issue #55 where cookies were lost during redirects.
|
|
489
489
|
"""
|
|
490
490
|
if history is None:
|
|
491
491
|
history = []
|
|
@@ -508,7 +508,7 @@ class Session:
|
|
|
508
508
|
redirect_url = urljoin(response.url, location)
|
|
509
509
|
|
|
510
510
|
# ── COOKIE FIX: Parse Set-Cookie before redirect ──
|
|
511
|
-
#
|
|
511
|
+
# bas loses cookies here because it switches to curl's
|
|
512
512
|
# internal cookie engine for the redirect. We don't.
|
|
513
513
|
# (Already done in _curl_perform above)
|
|
514
514
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Comprehensive tests for bas's cookie handling.
|
|
3
3
|
|
|
4
|
-
These tests verify that bas fixes all the cookie bugs in
|
|
4
|
+
These tests verify that bas fixes all the cookie bugs in bas:
|
|
5
5
|
1. Cookies accumulate across session requests
|
|
6
6
|
2. Cookies survive redirects
|
|
7
7
|
3. Proper domain matching (RFC 6265)
|
|
@@ -599,16 +599,16 @@ class TestCookieTimeParsing:
|
|
|
599
599
|
assert t is None
|
|
600
600
|
|
|
601
601
|
|
|
602
|
-
# ──
|
|
602
|
+
# ── bas Bug Regression Tests ───────────────────────────────────────────
|
|
603
603
|
|
|
604
604
|
class TestCurlCffiRegressions:
|
|
605
605
|
"""
|
|
606
|
-
Tests specifically targeting the bugs reported in
|
|
606
|
+
Tests specifically targeting the bugs reported in bas.
|
|
607
607
|
"""
|
|
608
608
|
|
|
609
609
|
def test_cookie_accumulation_across_requests(self):
|
|
610
610
|
"""
|
|
611
|
-
Regression:
|
|
611
|
+
Regression: bas issue #582
|
|
612
612
|
Cookies from previous requests were not available in the session.
|
|
613
613
|
|
|
614
614
|
In bas, cookies accumulate in our Python CookieJar,
|
|
@@ -656,7 +656,7 @@ class TestCurlCffiRegressions:
|
|
|
656
656
|
|
|
657
657
|
def test_redirect_cookie_inheritance(self):
|
|
658
658
|
"""
|
|
659
|
-
Regression:
|
|
659
|
+
Regression: bas issue #55
|
|
660
660
|
Cookies were lost during 302 redirects.
|
|
661
661
|
|
|
662
662
|
In bas, the cookie jar persists across redirects.
|
|
@@ -712,7 +712,7 @@ class TestCurlCffiRegressions:
|
|
|
712
712
|
|
|
713
713
|
def test_no_manual_cookie_header_needed(self):
|
|
714
714
|
"""
|
|
715
|
-
One of
|
|
715
|
+
One of bas's annoyances: users had to manually build
|
|
716
716
|
Cookie headers. bas handles this automatically.
|
|
717
717
|
"""
|
|
718
718
|
jar = CookieJar()
|
|
@@ -105,13 +105,13 @@ def test_full_request_simulation():
|
|
|
105
105
|
|
|
106
106
|
def test_cookie_accumulation_across_redirects():
|
|
107
107
|
"""
|
|
108
|
-
Simulates the
|
|
108
|
+
Simulates the bas #55 bug scenario:
|
|
109
109
|
A request to page A, 302 to B, cookies should carry over.
|
|
110
110
|
"""
|
|
111
111
|
jar = CookieJar()
|
|
112
112
|
|
|
113
113
|
# Step 1: Request to origin - server sets initial cookie
|
|
114
|
-
print("\nRedirect scenario (
|
|
114
|
+
print("\nRedirect scenario (bas #55 fix):")
|
|
115
115
|
jar.parse_set_cookie("cf_clearance=abc123; Path=/; Secure", "https://earnow.online/OW3usd7cl93")
|
|
116
116
|
header1 = jar.to_header("https://earnow.online/OW3usd7cl93")
|
|
117
117
|
assert "cf_clearance=abc123" in header1
|
|
@@ -132,7 +132,7 @@ def test_cookie_accumulation_across_redirects():
|
|
|
132
132
|
assert "tracking=999" in header3
|
|
133
133
|
print(f" Step 3 - After 2nd redirect: ALL 3 cookies present (len={len(header3)})")
|
|
134
134
|
|
|
135
|
-
print("PASS: Cookies accumulate across redirects (
|
|
135
|
+
print("PASS: Cookies accumulate across redirects (bas #55 fixed)")
|
|
136
136
|
|
|
137
137
|
|
|
138
138
|
if __name__ == "__main__":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bas-http
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Copy-paste your browser's request, bas handles the rest. No impersonation needed. Zero dependencies.
|
|
5
5
|
Author: bas
|
|
6
6
|
License-Expression: MIT
|
|
@@ -27,18 +27,22 @@ Description-Content-Type: text/markdown
|
|
|
27
27
|
|
|
28
28
|
Copy-paste your browser's request, bas handles the rest.
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Zero dependencies. Pure Python. Just grab your headers + cookies from DevTools and go.
|
|
31
31
|
|
|
32
32
|
## Why bas?
|
|
33
33
|
|
|
34
|
-
|
|
|
35
|
-
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
|
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
|
|
|
34
|
+
| Feature | bas | requests | pycurl | curl_cffi |
|
|
35
|
+
|---------|-----|----------|--------|----------|
|
|
36
|
+
| Zero dependencies | ✅ | ❌ (urllib3) | ❌ (libcurl) | ❌ (curl-impersonate) |
|
|
37
|
+
| Paste curl from DevTools | ✅ | ❌ | ❌ | ❌ |
|
|
38
|
+
| Auto Cookie injection | ✅ | ✅ | ❌ | ⚠️ |
|
|
39
|
+
| Cookie jar (RFC 6265) | ✅ | ✅ | ❌ | ⚠️ |
|
|
40
|
+
| No compilation needed | ✅ | ✅ | ❌ | ❌ |
|
|
41
|
+
| Bring your own headers | ✅ | ❌ (generates) | ❌ | ❌ (impersonation) |
|
|
42
|
+
| Works on all platforms | ✅ | ✅ | ⚠️ | ⚠️ |
|
|
43
|
+
| Session persistence | ✅ | ✅ | ❌ | ✅ |
|
|
44
|
+
| Follow redirects | ✅ | ✅ | Manual | ✅ |
|
|
45
|
+
| JSON support | ✅ | ✅ | ❌ | ✅ |
|
|
42
46
|
|
|
43
47
|
## Installation
|
|
44
48
|
|
|
@@ -290,7 +294,7 @@ r = s.get("https://example.com/page")
|
|
|
290
294
|
# Set-Cookie: tracking=xyz; Path=/
|
|
291
295
|
|
|
292
296
|
# ALL cookies are preserved through redirects
|
|
293
|
-
# No cookies lost (unlike
|
|
297
|
+
# No cookies lost (unlike bas!)
|
|
294
298
|
```
|
|
295
299
|
|
|
296
300
|
## Session Persistence
|
|
@@ -427,41 +431,67 @@ r = s.post("https://example.com/login", data={
|
|
|
427
431
|
print(r.status_code)
|
|
428
432
|
```
|
|
429
433
|
|
|
430
|
-
## Comparison with
|
|
434
|
+
## Comparison with Other Libraries
|
|
431
435
|
|
|
432
|
-
###
|
|
436
|
+
### requests
|
|
437
|
+
|
|
438
|
+
```python
|
|
439
|
+
import requests
|
|
440
|
+
|
|
441
|
+
# Manual header/cookie setup
|
|
442
|
+
s = requests.Session()
|
|
443
|
+
s.headers["User-Agent"] = "Mozilla/5.0 ..."
|
|
444
|
+
s.cookies.set("session", "abc", domain="example.com")
|
|
445
|
+
|
|
446
|
+
r = s.get("https://example.com")
|
|
447
|
+
# Works, but no curl copy-paste support
|
|
448
|
+
# Generates its own fingerprint (detectable)
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
### pycurl
|
|
452
|
+
|
|
453
|
+
```python
|
|
454
|
+
import pycurl
|
|
455
|
+
from io import BytesIO
|
|
456
|
+
|
|
457
|
+
# Low-level, verbose setup
|
|
458
|
+
c = pycurl.Curl()
|
|
459
|
+
c.setopt(c.URL, "https://example.com")
|
|
460
|
+
c.setopt(c.HTTPHEADER, ["User-Agent: Mozilla/5.0 ...", "Cookie: session=abc"])
|
|
461
|
+
buffer = BytesIO()
|
|
462
|
+
c.setopt(c.WRITEDATA, buffer)
|
|
463
|
+
c.perform()
|
|
464
|
+
c.close()
|
|
465
|
+
|
|
466
|
+
# No built-in cookie jar, no redirect handling
|
|
467
|
+
# Requires libcurl installed on the system
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### curl_cffi
|
|
433
471
|
|
|
434
472
|
```python
|
|
435
473
|
from curl_cffi.requests import Session
|
|
436
474
|
|
|
475
|
+
# Requires curl-impersonate installed
|
|
437
476
|
s = Session(impersonate="chrome131")
|
|
477
|
+
r = s.get("https://example.com")
|
|
438
478
|
|
|
439
|
-
#
|
|
440
|
-
|
|
441
|
-
# r1 is missing cookies from Set-Cookie headers!
|
|
442
|
-
|
|
443
|
-
# Cookies not accumulating!
|
|
444
|
-
r2 = s.get("https://example.com/page")
|
|
445
|
-
# r2 has LOST cookies from r1!
|
|
479
|
+
# Impersonation fingerprint can become outdated
|
|
480
|
+
# Cookie handling has known issues
|
|
446
481
|
```
|
|
447
482
|
|
|
448
|
-
### bas
|
|
483
|
+
### bas
|
|
449
484
|
|
|
450
485
|
```python
|
|
451
486
|
import bas
|
|
452
487
|
|
|
488
|
+
# Paste curl from DevTools — done
|
|
453
489
|
s = bas.from_curl(r'''curl "https://example.com" -b "session=abc"''')
|
|
454
490
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
#
|
|
458
|
-
|
|
459
|
-
# Cookies accumulate!
|
|
460
|
-
r2 = s.get("https://example.com/dashboard")
|
|
461
|
-
# r2 has ALL cookies from r1 + new ones
|
|
462
|
-
|
|
463
|
-
# No manual Cookie header needed!
|
|
464
|
-
# bas auto-injects cookies from the jar
|
|
491
|
+
r = s.get("https://example.com")
|
|
492
|
+
# All headers auto-applied
|
|
493
|
+
# Cookies auto-injected
|
|
494
|
+
# Zero setup, zero dependencies
|
|
465
495
|
```
|
|
466
496
|
|
|
467
497
|
## API Reference
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "bas-http"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.4"
|
|
8
8
|
description = "Copy-paste your browser's request, bas handles the rest. No impersonation needed. Zero dependencies."
|
|
9
9
|
readme = "bas/README.md"
|
|
10
10
|
license = "MIT"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|