Skip to content

Commit 40e1d13

Browse files
committed
Migrate cookie handling to shared library and prepare for 2.0.0 release
- Remove upcoming breaking changes section from README - Refactor cookie implementation to use standard http.cookiejar - Update cffi layer with async cookie management methods - Replace requests dependency with nocasedict for header handling - Implement new session class with native cookie delegation - Deprecate direct manipulation of session.cookies - Add comprehensive cookie test suite - Bump version to 2.0.0
1 parent 289c3c4 commit 40e1d13

File tree

14 files changed

+1060
-1078
lines changed

14 files changed

+1060
-1078
lines changed

README.md

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,32 +43,6 @@ The fork was created due to the lack of updates in the original repository, whil
4343
library [tls-client](https://github.com/bogdanfinn/tls-client) continues to evolve actively. This project aims to keep
4444
up with the latest developments in the GoLang library and provide a modern, asynchronous interface for Python users.
4545

46-
## Upcoming Breaking Changes 🚧
47-
48-
The library plans several breaking changes in future major releases to improve maintainability and reduce technical
49-
debt:
50-
51-
### Key Changes Planned:
52-
53-
1. **Syntax Divergence from `requests`**
54-
- The API will evolve to be less similar to `requests` to avoid dependency on its internal implementations.
55-
- This may affect session/request patterns and method signatures.
56-
57-
2. **Direct Import of `CaseInsensitiveDict`**
58-
- The current custom `CaseInsensitiveDict` (copied from `requests.structures`) will be replaced by direct imports
59-
from `requests` or standard library alternatives.
60-
- Users relying on `async_tls_client.structures.CaseInsensitiveDict` should prepare for import path changes.
61-
62-
3. **Standard `http.cookiejar.CookieJar` Implementation**
63-
- The custom `RequestsCookieJar` (borrowed from `requests`) will be replaced with `http.cookiejar.CookieJar` for
64-
cookie management.
65-
- This may impact cookie handling APIs and persistence behavior.
66-
67-
4. **Response Class Refactoring**
68-
- The `Response` class may undergo structural changes to simplify implementation and align with modern Python
69-
practices.
70-
- Potential impacts include changes to attribute access, content handling, or JSON parsing methods.
71-
7246
### Recommendations:
7347

7448
- Monitor changelogs for deprecation warnings in future minor releases

async_tls_client/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
# tls-client: https://github.com/bogdanfinn/tls-client
1313
# requests: https://github.com/psf/requests
1414

15-
from async_tls_client.session.async_session import AsyncSession
15+
from async_tls_client.session.session import AsyncSession

async_tls_client/cffi.py

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
import asyncio
12
import ctypes
3+
import json
24
import os
35
from platform import machine
46
from sys import platform
57

8+
from .exceptions import TLSClientException
9+
610
if platform == 'darwin':
711
file_ext = '-arm64.dylib' if machine() == "arm64" else '-x86.dylib'
812
elif platform in ('win32', 'cygwin'):
@@ -19,15 +23,81 @@
1923
binary_filepath = os.path.join(root_dir, 'dependencies', f'tls-client{file_ext}')
2024
library = ctypes.cdll.LoadLibrary(binary_filepath)
2125

22-
# extract the exposed request function from the shared package
23-
request = library.request
24-
request.argtypes = [ctypes.c_char_p]
25-
request.restype = ctypes.c_char_p
26+
# Extract methods from the shared library
27+
_freeMemory = library.freeMemory
28+
_freeMemory.argtypes = [ctypes.c_char_p]
29+
_freeMemory.restype = ctypes.c_char_p
30+
31+
_request = library.request
32+
_request.argtypes = [ctypes.c_char_p]
33+
_request.restype = ctypes.c_char_p
34+
35+
_destroySession = library.destroySession
36+
_destroySession.argtypes = [ctypes.c_char_p]
37+
_destroySession.restype = ctypes.c_char_p
38+
39+
_getCookiesFromSession = library.getCookiesFromSession
40+
_getCookiesFromSession.argtypes = [ctypes.c_char_p]
41+
_getCookiesFromSession.restype = ctypes.c_char_p
42+
43+
_addCookiesToSession = library.addCookiesToSession
44+
_addCookiesToSession.argtypes = [ctypes.c_char_p]
45+
_addCookiesToSession.restype = ctypes.c_char_p
46+
47+
48+
async def free_memory(response_id: str):
49+
await asyncio.to_thread(_freeMemory, response_id.encode('utf-8'))
50+
51+
52+
async def request(payload: dict) -> dict:
53+
response = await asyncio.to_thread(
54+
_request,
55+
json.dumps(payload).encode('utf-8')
56+
)
57+
response_bytes = ctypes.string_at(response)
58+
response_string = response_bytes.decode('utf-8')
59+
response_object = json.loads(response_string)
60+
61+
await free_memory(response_object["id"])
62+
63+
if response_object["status"] == 0:
64+
raise TLSClientException(response_object["body"])
65+
66+
return response_object
67+
68+
69+
async def destroy_session(session_id: str) -> dict:
70+
destroy_session_response = await asyncio.to_thread(
71+
_destroySession,
72+
json.dumps({"sessionId": session_id}).encode('utf-8')
73+
)
74+
destroy_session_response_bytes = ctypes.string_at(destroy_session_response)
75+
destroy_session_response_string = destroy_session_response_bytes.decode('utf-8')
76+
destroy_session_response_object = json.loads(destroy_session_response_string)
77+
await free_memory(destroy_session_response_object['id'])
78+
return destroy_session_response_object
79+
80+
81+
async def get_cookies_from_session(session_id: str, url: str) -> dict:
82+
cookies_response = await asyncio.to_thread(
83+
_getCookiesFromSession,
84+
json.dumps({"sessionId": session_id, "url": url}).encode('utf-8')
85+
)
86+
# we dereference the pointer to a byte array
87+
cookies_response_bytes = ctypes.string_at(cookies_response)
88+
# convert our byte array to a string (tls client returns json)
89+
cookies_response_string = cookies_response_bytes.decode('utf-8')
90+
# convert response string to json
91+
cookies_response_object = json.loads(cookies_response_string)
92+
return cookies_response_object
2693

27-
freeMemory = library.freeMemory
28-
freeMemory.argtypes = [ctypes.c_char_p]
29-
freeMemory.restype = ctypes.c_char_p
3094

31-
destroySession = library.destroySession
32-
destroySession.argtypes = [ctypes.c_char_p]
33-
destroySession.restype = ctypes.c_char_p
95+
async def add_cookies_to_session(session_id, cookies: list[dict], url: str) -> dict:
96+
add_cookies_to_session_response = await asyncio.to_thread(
97+
_addCookiesToSession,
98+
json.dumps({"cookies": cookies, "sessionId": session_id, "url": url}).encode('utf-8')
99+
)
100+
add_cookies_bytes = ctypes.string_at(add_cookies_to_session_response)
101+
add_cookies_string = add_cookies_bytes.decode('utf-8')
102+
add_cookies_object = json.loads(add_cookies_string)
103+
return add_cookies_object

0 commit comments

Comments
 (0)