bas-http 1.0.0__tar.gz → 1.0.1__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bas-http
3
- Version: 1.0.0
3
+ Version: 1.0.1
4
4
  Summary: Copy-paste your browser's request, bas handles the rest. No impersonation needed.
5
5
  Author: bas
6
6
  License: MIT
@@ -0,0 +1,507 @@
1
+ # bas
2
+
3
+ Copy-paste your browser's request, bas handles the rest.
4
+
5
+ No impersonation needed. No fingerprint chasing. No broken cookies. Just grab your headers + cookies from DevTools and go.
6
+
7
+ ## Why bas?
8
+
9
+ | Problem | curlcffi | bas |
10
+ |---------|----------|-----|
11
+ | Cookies lost during redirects | **BUG** | **Fixed** |
12
+ | Cookies not accumulating across requests | **BUG** | **Fixed** |
13
+ | Manual Cookie header construction | Yes | **Auto-injected** |
14
+ | Requires curl-impersonate | Yes | **No — pure Python** |
15
+ | Browser fingerprint updates | Constant chase | **None — bring your own headers** |
16
+ | External dependencies | Yes | **Zero** |
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install bas-http
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ### Method 1: Paste a curl command from DevTools (Recommended)
27
+
28
+ This is the fastest way. Copy a curl command from your browser and bas does the rest.
29
+
30
+ ```
31
+ 1. Open browser DevTools (F12) → Network tab
32
+ 2. Make a request on the website
33
+ 3. Right-click the request → "Copy as cURL"
34
+ 4. Paste into Python
35
+ ```
36
+
37
+ ```python
38
+ import bas
39
+
40
+ # Paste your curl command (use r'' raw string to preserve backslashes)
41
+ s = bas.from_curl(r'''curl "https://example.com/page" ^
42
+ -H "accept: text/html,application/xhtml+xml" ^
43
+ -H "accept-language: en-US,en;q=0.9" ^
44
+ -H "user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" ^
45
+ -b "cf_clearance=abc123; session_id=xyz; token=def456"''')
46
+
47
+ # Now make requests — all headers and cookies are auto-injected
48
+ r = s.get("https://example.com/page")
49
+ print(r.status_code)
50
+ print(r.text)
51
+
52
+ # Follow-up requests keep the same headers and cookies
53
+ r2 = s.get("https://example.com/dashboard")
54
+ print(r2.status_code)
55
+
56
+ # Add more cookies manually if needed
57
+ s.set_cookie("new_cookie", "value", domain="example.com")
58
+ r3 = s.get("https://example.com/api/data")
59
+ ```
60
+
61
+ ### Method 2: Build headers manually
62
+
63
+ If you have headers copied from DevTools (not as a curl command):
64
+
65
+ ```python
66
+ import bas
67
+
68
+ s = bas.Session()
69
+
70
+ # Paste your headers from DevTools → Network → Headers tab
71
+ s.headers = {
72
+ "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
73
+ "accept-language": "en-US,en;q=0.9",
74
+ "cache-control": "max-age=0",
75
+ "sec-ch-ua": '"Chromium";v="137", "Not/A)Brand";v="24"',
76
+ "sec-ch-ua-mobile": "?0",
77
+ "sec-ch-ua-platform": '"Windows"',
78
+ "sec-fetch-dest": "document",
79
+ "sec-fetch-mode": "navigate",
80
+ "sec-fetch-site": "none",
81
+ "sec-fetch-user": "?1",
82
+ "upgrade-insecure-requests": "1",
83
+ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
84
+ }
85
+
86
+ # Add your cookies from DevTools → Application → Cookies
87
+ s.set_cookie("cf_clearance", "abc123", domain="example.com")
88
+ s.set_cookie("session_id", "xyz", domain="example.com")
89
+ s.set_cookie("csrf_token", "def456", domain="example.com")
90
+
91
+ # Go!
92
+ r = s.get("https://example.com/page")
93
+ print(r.status_code, len(r.text))
94
+ ```
95
+
96
+ ### Method 3: Headers + cookies in one call
97
+
98
+ ```python
99
+ import bas
100
+
101
+ s = bas.from_headers(
102
+ url="https://example.com",
103
+ headers={
104
+ "user-agent": "Mozilla/5.0 ...",
105
+ "accept": "text/html,...",
106
+ },
107
+ cookies={
108
+ "cf_clearance": "abc123",
109
+ "session": "xyz",
110
+ },
111
+ )
112
+
113
+ r = s.get("https://example.com/page")
114
+ ```
115
+
116
+ ## HTTP Methods
117
+
118
+ ```python
119
+ import bas
120
+
121
+ s = bas.from_curl(r'''curl "https://example.com" -b "session=abc"''')
122
+
123
+ # GET
124
+ r = s.get("https://example.com/page")
125
+
126
+ # POST with form data
127
+ r = s.post("https://example.com/login", data={"username": "user", "password": "pass"})
128
+
129
+ # POST with JSON
130
+ r = s.post("https://example.com/api", json={"key": "value"})
131
+
132
+ # PUT
133
+ r = s.put("https://example.com/api/123", json={"name": "updated"})
134
+
135
+ # DELETE
136
+ r = s.delete("https://example.com/api/123")
137
+
138
+ # PATCH
139
+ r = s.patch("https://example.com/api/123", json={"name": "patched"})
140
+
141
+ # HEAD
142
+ r = s.head("https://example.com/page")
143
+ ```
144
+
145
+ ## Response Object
146
+
147
+ ```python
148
+ r = s.get("https://example.com/page")
149
+
150
+ # Status code
151
+ print(r.status_code) # 200
152
+ print(r.ok) # True (status < 400)
153
+ print(r.reason_phrase) # "OK"
154
+
155
+ # Content
156
+ print(r.text) # Decoded text
157
+ print(r.body) # Raw bytes
158
+ print(r.json) # Parsed JSON
159
+ print(r.content_type) # "text/html; charset=utf-8"
160
+
161
+ # Headers
162
+ print(r.headers) # Case-insensitive headers dict
163
+ print(r.headers["content-type"])
164
+
165
+ # URL info
166
+ print(r.url) # Final URL (after redirects)
167
+ print(r.ip) # Server IP
168
+ print(r.http_version) # "1.1" or "2.0"
169
+ print(r.elapsed) # Response time in seconds
170
+
171
+ # Redirect history
172
+ for resp in r.history:
173
+ print(resp.status_code, resp.url)
174
+
175
+ # Raise exception on error
176
+ r.raise_for_status() # Raises HTTPError if status >= 400
177
+
178
+ # Iterate over content
179
+ for chunk in r.iter_content(chunk_size=8192):
180
+ process(chunk)
181
+
182
+ for line in r.iter_lines():
183
+ print(line)
184
+ ```
185
+
186
+ ## Cookie Management
187
+
188
+ ### Auto-injection
189
+
190
+ bas automatically injects cookies into every request. No manual header construction needed.
191
+
192
+ ```python
193
+ import bas
194
+
195
+ s = bas.from_curl(r'''curl "https://example.com" -b "session=abc123; token=xyz"''')
196
+
197
+ # This request automatically has Cookie: session=abc123; token=xyz
198
+ r = s.get("https://example.com/page")
199
+
200
+ # See what cookies were sent
201
+ print(r.request.headers.get("Cookie"))
202
+ # "session=abc123; token=xyz"
203
+ ```
204
+
205
+ ### Set cookies manually
206
+
207
+ ```python
208
+ s = bas.Session()
209
+ s.set_cookie("name", "value", domain="example.com", path="/")
210
+ ```
211
+
212
+ ### Get cookies for a URL
213
+
214
+ ```python
215
+ cookies = s.get_cookies("https://example.com/page")
216
+ print(cookies) # {"session": "abc123", "token": "xyz"}
217
+ ```
218
+
219
+ ### Clear all cookies
220
+
221
+ ```python
222
+ s.clear_cookies()
223
+ ```
224
+
225
+ ### Save cookies to file
226
+
227
+ ```python
228
+ # JSON format
229
+ s.save_cookies("cookies.json")
230
+
231
+ # Netscape format (compatible with curl/wget)
232
+ s.save_cookies("cookies.txt", format="netscape")
233
+ ```
234
+
235
+ ### Load cookies from file
236
+
237
+ ```python
238
+ s.load_cookies("cookies.json")
239
+ s.load_cookies("cookies.txt", format="netscape")
240
+ ```
241
+
242
+ ### Cookie accumulation across requests
243
+
244
+ When the server sends Set-Cookie headers, bas automatically stores them:
245
+
246
+ ```python
247
+ s = bas.Session()
248
+
249
+ # Server sets cookies in this response
250
+ r1 = s.get("https://example.com/login")
251
+ # Set-Cookie: session_id=abc123; Path=/
252
+ # Set-Cookie: user=john; Path=/
253
+
254
+ # These cookies are automatically sent with the next request
255
+ r2 = s.get("https://example.com/dashboard")
256
+ # Cookie: session_id=abc123; user=john
257
+ ```
258
+
259
+ ### Cookies survive redirects
260
+
261
+ ```python
262
+ # Server redirects and sets more cookies
263
+ r = s.get("https://example.com/page")
264
+ # 302 → https://example.com/dashboard
265
+ # Set-Cookie: tracking=xyz; Path=/
266
+
267
+ # ALL cookies are preserved through redirects
268
+ # No cookies lost (unlike curlcffi!)
269
+ ```
270
+
271
+ ## Session Persistence
272
+
273
+ Keep a session alive across multiple script runs:
274
+
275
+ ```python
276
+ import bas
277
+
278
+ s = bas.Session()
279
+
280
+ # Try to load previous session
281
+ try:
282
+ s.load_cookies("my_session.json")
283
+ except FileNotFoundError:
284
+ pass
285
+
286
+ # Make requests
287
+ r = s.get("https://example.com/page")
288
+
289
+ # Save session for next run
290
+ s.save_cookies("my_session.json")
291
+ ```
292
+
293
+ ## Parse curl commands
294
+
295
+ ```python
296
+ from bas.curl_parser import parse_curl, print_curl_summary
297
+
298
+ # See what's in a curl command
299
+ print_curl_summary(r'''curl "https://example.com" -H "User-Agent: ..." -b "cookie=value"''')
300
+
301
+ # Or get it as a dict
302
+ parsed = parse_curl(r'''curl "https://example.com" -H "User-Agent: ..." -b "cookie=value"''')
303
+ print(parsed["method"]) # "GET"
304
+ print(parsed["url"]) # "https://example.com"
305
+ print(parsed["headers"]) # {"User-Agent": "..."}
306
+ print(parsed["cookies"]) # {"cookie": "value"}
307
+ print(parsed["user_agent"]) # "Mozilla/5.0 ..."
308
+ print(parsed["referer"]) # "..."
309
+ ```
310
+
311
+ ## SSL Verification
312
+
313
+ ```python
314
+ # Disable SSL verification (default is enabled)
315
+ s = bas.Session(verify=False)
316
+
317
+ # Or per-request
318
+ r = s.get("https://self-signed.example.com", verify=False)
319
+ ```
320
+
321
+ ## Timeouts
322
+
323
+ ```python
324
+ # Set default timeout (seconds)
325
+ s = bas.Session(timeout=60)
326
+
327
+ # Or per-request
328
+ r = s.get("https://slow.example.com", timeout=120)
329
+ ```
330
+
331
+ ## Redirects
332
+
333
+ ```python
334
+ # Follow redirects (default: True)
335
+ r = s.get("https://example.com/page")
336
+
337
+ # Don't follow redirects
338
+ r = s.get("https://example.com/page", allow_redirects=False)
339
+ print(r.status_code) # 302
340
+ print(r.location) # "https://example.com/dashboard"
341
+
342
+ # Set max redirects
343
+ s = bas.Session(max_redirects=5)
344
+ ```
345
+
346
+ ## Proxy Support
347
+
348
+ ```python
349
+ # TODO: Proxy support coming in v1.1
350
+ ```
351
+
352
+ ## Real-World Example: Web Scraping
353
+
354
+ ```python
355
+ import bas
356
+
357
+ # Step 1: Copy curl from DevTools
358
+ s = bas.from_curl(r'''curl "https://spaceshooter.net/faucet/ltc" ^
359
+ -H "accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" ^
360
+ -H "accept-language: en-US,en;q=0.9" ^
361
+ -H "sec-ch-ua: \"Chromium\";v=\"137\", \"Not/A)Brand\";v=\"24\"" ^
362
+ -H "sec-ch-ua-mobile: ?0" ^
363
+ -H "sec-ch-ua-platform: \"Windows\"" ^
364
+ -H "sec-fetch-dest: document" ^
365
+ -H "sec-fetch-mode: navigate" ^
366
+ -H "sec-fetch-site: none" ^
367
+ -H "upgrade-insecure-requests: 1" ^
368
+ -H "user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" ^
369
+ -b "captcha=rscaptcha; cf_clearance=abc123; ci_session=xyz123; uf=def456"''')
370
+
371
+ # Step 2: Make the request
372
+ r = s.get("https://spaceshooter.net/faucet/ltc")
373
+
374
+ # Step 3: Parse the response
375
+ if r.ok:
376
+ print("Success!")
377
+ print(f"Status: {r.status_code}")
378
+ print(f"Content length: {len(r.text)}")
379
+ print(f"Cookies after request: {s.get_cookies('https://spaceshooter.net')}")
380
+ else:
381
+ print(f"Failed: {r.status_code}")
382
+ ```
383
+
384
+ ## Real-World Example: Form Submission
385
+
386
+ ```python
387
+ import bas
388
+
389
+ # Copy the POST request curl from DevTools
390
+ s = bas.from_curl(r'''curl "https://example.com/login" ^
391
+ -H "content-type: application/x-www-form-urlencoded" ^
392
+ -H "user-agent: Mozilla/5.0 ..." ^
393
+ -H "referer: https://example.com/login" ^
394
+ -b "csrf_token=abc123" ^
395
+ --data-raw "username=myuser&password=mypass"''')
396
+
397
+ r = s.post("https://example.com/login", data={
398
+ "username": "myuser",
399
+ "password": "mypass",
400
+ })
401
+
402
+ print(r.status_code)
403
+ ```
404
+
405
+ ## Comparison with curlcffi
406
+
407
+ ### curlcffi (BROKEN)
408
+
409
+ ```python
410
+ from curl_cffi.requests import Session
411
+
412
+ s = Session(impersonate="chrome131")
413
+
414
+ # Cookies lost during redirects!
415
+ r1 = s.get("https://example.com/page") # 302 redirect
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!
421
+ ```
422
+
423
+ ### bas (FIXED)
424
+
425
+ ```python
426
+ import bas
427
+
428
+ s = bas.from_curl(r'''curl "https://example.com" -b "session=abc"''')
429
+
430
+ # Cookies survive redirects!
431
+ r1 = s.get("https://example.com/page") # 302 redirect
432
+ # ALL cookies preserved through redirect
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
440
+ ```
441
+
442
+ ## API Reference
443
+
444
+ ### `bas.from_curl(curl_cmd, **kwargs)` → Session
445
+
446
+ Create a Session from a curl command. Main entry point.
447
+
448
+ ### `bas.from_headers(url, headers, cookies, **kwargs)` → Session
449
+
450
+ Create a Session from raw headers and cookies.
451
+
452
+ ### `bas.Session(headers, cookies, verify, timeout, allow_redirects, max_redirects)`
453
+
454
+ Pure Python HTTP session. Zero external dependencies.
455
+
456
+ **Methods:**
457
+ - `get(url, **kwargs)` → Response
458
+ - `post(url, **kwargs)` → Response
459
+ - `put(url, **kwargs)` → Response
460
+ - `delete(url, **kwargs)` → Response
461
+ - `patch(url, **kwargs)` → Response
462
+ - `head(url, **kwargs)` → Response
463
+ - `set_cookie(name, value, domain, path)` → None
464
+ - `get_cookies(url)` → dict
465
+ - `clear_cookies()` → None
466
+ - `save_cookies(filepath, format)` → None
467
+ - `load_cookies(filepath, format)` → None
468
+
469
+ ### `bas.Cookie(name, value, domain, path, expires, max_age, secure, http_only, same_site)`
470
+
471
+ Individual cookie object with RFC 6265 compliance.
472
+
473
+ ### `bas.CookieJar`
474
+
475
+ Thread-safe cookie container. Full RFC 6265 domain/path matching.
476
+
477
+ **Methods:**
478
+ - `add(cookie)` → None
479
+ - `remove(cookie)` → None
480
+ - `get(name, domain, path)` → Cookie | None
481
+ - `match(url)` → list[Cookie]
482
+ - `to_header(url)` → str
483
+ - `parse_set_cookie(header, url)` → Cookie
484
+ - `save_json(filepath)` → None
485
+ - `load_json(filepath)` → None
486
+ - `save_netscape(filepath)` → None
487
+ - `load_netscape(filepath)` → None
488
+
489
+ ### `bas.Response`
490
+
491
+ HTTP response object.
492
+
493
+ **Properties:**
494
+ - `status_code` (int): HTTP status code
495
+ - `ok` (bool): True if status < 400
496
+ - `text` (str): Decoded text content
497
+ - `body` (bytes): Raw bytes
498
+ - `json` (Any): Parsed JSON
499
+ - `headers` (Headers): Response headers
500
+ - `url` (str): Final URL
501
+ - `elapsed` (float): Response time
502
+ - `history` (list): Redirect history
503
+ - `cookies` (CookieJar): Cookie jar
504
+
505
+ ## License
506
+
507
+ MIT
@@ -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.0"
31
+ __version__ = "1.0.1"
32
32
  __author__ = "bas"
33
33
 
34
34
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bas-http
3
- Version: 1.0.0
3
+ Version: 1.0.1
4
4
  Summary: Copy-paste your browser's request, bas handles the rest. No impersonation needed.
5
5
  Author: bas
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "bas-http"
7
- version = "1.0.0"
7
+ version = "1.0.1"
8
8
  description = "Copy-paste your browser's request, bas handles the rest. No impersonation needed."
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -1,244 +0,0 @@
1
- # bas
2
-
3
- Copy-paste your browser's request, bas handles the rest.
4
-
5
- No impersonation. No fingerprint chasing. No broken cookies.
6
-
7
- ## Why bas?
8
-
9
- | Issue | curlcffi | bas |
10
- |-------|----------|----------|
11
- | Cookies lost during redirects | **BUG** | **Fixed** |
12
- | Cookies not accumulating across requests | **BUG** | **Fixed** |
13
- | Manual Cookie header construction needed | Yes | **Auto-injected** |
14
- | Requires curl-impersonate | Yes | **No — pure Python** |
15
- | Browser fingerprint updates needed | Yes | **None — you bring your own headers** |
16
-
17
- ## Installation
18
-
19
- ```bash
20
- pip install bas
21
- ```
22
-
23
- Zero external dependencies. Works with Python's built-in `urllib`.
24
-
25
- ## Usage
26
-
27
- ### Method 1: Paste a curl command from DevTools
28
-
29
- ```
30
- 1. Open browser DevTools → Network tab
31
- 2. Right-click any request → "Copy as cURL"
32
- 3. Paste into bas
33
- ```
34
-
35
- ```python
36
- import bas
37
-
38
- # Paste your curl command (use raw string r'' to preserve backslashes)
39
- s = bas.from_curl(r'''curl "https://spaceshooter.net/faucet/ltc" ^
40
- -H "accept: text/html" ^
41
- -H "user-agent: Mozilla/5.0 ..." ^
42
- -b "cf_clearance=abc123; session=xyz"''')
43
-
44
- # Now make requests — cookies and headers auto-injected
45
- r = s.get("https://spaceshooter.net/faucet/ltc")
46
- print(r.status_code, r.text)
47
-
48
- # Add more cookies manually if needed
49
- s.set_cookie("new_cookie", "value", domain="spaceshooter.net")
50
- r = s.get("https://spaceshooter.net/dashboard")
51
- ```
52
-
53
- ### Method 2: Build headers manually
54
-
55
- ```python
56
- import bas
57
-
58
- s = bas.Session()
59
-
60
- # Paste your headers from DevTools
61
- s.headers = {
62
- "accept": "text/html,application/xhtml+xml,...",
63
- "accept-language": "en-US,en;q=0.9",
64
- "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...",
65
- "sec-ch-ua": '"Chromium";v="137", "Not/A)Brand";v="24"',
66
- "sec-ch-ua-mobile": "?0",
67
- "sec-ch-ua-platform": '"Windows"',
68
- "sec-fetch-dest": "document",
69
- "sec-fetch-mode": "navigate",
70
- }
71
-
72
- # Add your cookies
73
- s.set_cookie("cf_clearance", "abc123", domain="spaceshooter.net")
74
- s.set_cookie("session", "xyz", domain="spaceshooter.net")
75
-
76
- # Go!
77
- r = s.get("https://spaceshooter.net/faucet/ltc")
78
- ```
79
-
80
- ### Method 3: Build from headers + cookies dict
81
-
82
- ```python
83
- import bas
84
-
85
- s = bas.from_headers(
86
- url="https://spaceshooter.net/faucet/ltc",
87
- headers={
88
- "user-agent": "Mozilla/5.0 ...",
89
- "accept": "text/html,...",
90
- },
91
- cookies={
92
- "cf_clearance": "abc123",
93
- "session": "xyz",
94
- },
95
- )
96
-
97
- r = s.get("https://spaceshooter.net/faucet/ltc")
98
- ```
99
-
100
- ### Parse a curl command without making a request
101
-
102
- ```python
103
- from bas.curl_parser import parse_curl, print_curl_summary
104
-
105
- # See what's in a curl command
106
- print_curl_summary(r'''curl "https://example.com" -H "User-Agent: ..." -b "cookie=value"''')
107
-
108
- # Or get it as a dict
109
- parsed = parse_curl(r'''curl "https://example.com" -H "User-Agent: ..." -b "cookie=value"''')
110
- print(parsed["method"]) # "GET"
111
- print(parsed["url"]) # "https://example.com"
112
- print(parsed["headers"]) # {"User-Agent": "..."}
113
- print(parsed["cookies"]) # {"cookie": "value"}
114
- ```
115
-
116
- ### Cookie Management
117
-
118
- ```python
119
- import bas
120
-
121
- with bas.Session() as s:
122
- # Pre-load cookies
123
- s.set_cookie("session", "abc123", domain="example.com")
124
-
125
- # Cookies are auto-injected into every request
126
- r = s.get("https://example.com")
127
- print("Cookie header:", r.request.headers.get("Cookie"))
128
-
129
- # Save cookies to file
130
- s.save_cookies("cookies.json")
131
-
132
- # Load cookies from file
133
- s.load_cookies("cookies.json")
134
-
135
- # Check what cookies we have for a URL
136
- print(s.get_cookies("https://example.com"))
137
- ```
138
-
139
- ### Cookie Jar (direct access)
140
-
141
- ```python
142
- from bas.cookies import Cookie, CookieJar
143
-
144
- jar = CookieJar()
145
-
146
- # Parse Set-Cookie headers from responses
147
- jar.parse_set_cookie(
148
- "session=abc123; Domain=.example.com; Path=/; Secure; HttpOnly",
149
- "https://www.example.com/"
150
- )
151
-
152
- # Get cookies for a URL (RFC 6265 compliant)
153
- cookies = jar.match("https://www.example.com/page")
154
-
155
- # Build Cookie header automatically
156
- header = jar.to_header("https://www.example.com/")
157
- print(header) # "session=abc123"
158
-
159
- # Save/load
160
- jar.save_json("cookies.json")
161
- jar.load_json("cookies.json")
162
- ```
163
-
164
- ## How bas Fixes curlcffi's Cookie Bugs
165
-
166
- ### Fix #1: Cookies Accumulate
167
-
168
- ```python
169
- # curlcffi (BROKEN):
170
- r1 = s.get(url)
171
- r2 = s.get(url) # LOST cookies from r1!
172
-
173
- # bas (FIXED):
174
- r1 = s.get(url)
175
- r2 = s.get(url) # Has ALL cookies from r1 + new ones
176
- ```
177
-
178
- ### Fix #2: Redirect Cookie Inheritance
179
-
180
- ```python
181
- # curlcffi (BROKEN):
182
- r = s.get("https://example.com/page") # 302 redirect
183
- # Cookies LOST during redirect!
184
-
185
- # bas (FIXED):
186
- r = s.get("https://example.com/page") # 302 redirect
187
- # Cookies properly inherited + new Set-Cookie headers captured
188
- ```
189
-
190
- ### Fix #3: Auto Cookie Injection
191
-
192
- ```python
193
- # curlcffi (manual):
194
- r = s.get(url, headers={"Cookie": "session=abc123; token=xyz"})
195
-
196
- # bas (automatic):
197
- s.set_cookie("session", "abc123")
198
- s.set_cookie("token", "xyz")
199
- r = s.get(url) # Cookie header auto-generated!
200
- ```
201
-
202
- ## API Reference
203
-
204
- ### `from_curl(curl_cmd, **kwargs)` → Session
205
-
206
- Create a Session from a curl command. The main entry point.
207
-
208
- ### `from_headers(url, headers, cookies, **kwargs)` → Session
209
-
210
- Create a Session from raw headers and cookies.
211
-
212
- ### `Session(headers=None, cookies=None, ...)`
213
-
214
- Simple HTTP session. Pure Python, no curl needed.
215
-
216
- **Parameters:**
217
- - `headers` (dict): Default headers
218
- - `cookies` (dict): Pre-set cookies
219
- - `verify` (bool): SSL verification (default: True)
220
- - `timeout` (float): Request timeout (default: 30)
221
- - `allow_redirects` (bool): Follow redirects (default: True)
222
- - `max_redirects` (int): Max redirects (default: 20)
223
-
224
- **Methods:**
225
- - `get(url, **kwargs)` → Response
226
- - `post(url, **kwargs)` → Response
227
- - `put(url, **kwargs)` → Response
228
- - `delete(url, **kwargs)` → Response
229
- - `set_cookie(name, value, domain, path)` → None
230
- - `get_cookies(url)` → dict
231
- - `save_cookies(filepath, format)` → None
232
- - `load_cookies(filepath, format)` → None
233
-
234
- ### `Cookie(name, value, domain, path, ...)`
235
-
236
- Individual cookie with RFC 6265 compliance.
237
-
238
- ### `CookieJar`
239
-
240
- Thread-safe cookie container. Full RFC 6265 domain/path matching.
241
-
242
- ## License
243
-
244
- 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