Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor WebSocket support into separate sync/async implementations #206

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
Next Next commit
Initial refactor
  • Loading branch information
dolfies committed Jan 4, 2024
commit fc040c45d035e5fbdc00d677090fbb9bf414c88e
2 changes: 1 addition & 1 deletion curl_cffi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from ._wrapper import ffi, lib # type: ignore

from .const import CurlInfo, CurlMOpt, CurlOpt, CurlECode, CurlHttpVersion
from .curl import Curl, CurlError
from .curl import Curl, CurlError, CurlWsFrame
from .aio import AsyncCurl

from .__version__ import __title__, __version__, __description__, __curl_version__
32 changes: 18 additions & 14 deletions curl_cffi/curl.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import re
import warnings
from http.cookies import SimpleCookie
Expand All @@ -8,9 +10,18 @@
from ._wrapper import ffi, lib # type: ignore
from .const import CurlHttpVersion, CurlInfo, CurlOpt, CurlWsFlag


DEFAULT_CACERT = certifi.where()


class CurlWsFrame(ffi.CData):
age: int
flags: int
offset: int
bytesleft: int
len: int


class CurlError(Exception):
"""Base exception for curl_cffi package"""

Expand Down Expand Up @@ -50,11 +61,13 @@ def buffer_callback(ptr, size, nmemb, userdata):
buffer.write(ffi.buffer(ptr, nmemb)[:])
return nmemb * size


def ensure_int(s):
if not s:
return 0
return int(s)


@ffi.def_extern()
def write_callback(ptr, size, nmemb, userdata):
# although similar enough to the function above, kept here for performance reasons
Expand Down Expand Up @@ -85,7 +98,7 @@ class Curl:
Wrapper for `curl_easy_*` functions of libcurl.
"""

def __init__(self, cacert: str = DEFAULT_CACERT, debug: bool = False, handle = None):
def __init__(self, cacert: str = DEFAULT_CACERT, debug: bool = False, handle=None):
"""
Parameters:
cacert: CA cert path to use, by default, curl_cffi uses its own bundled cert.
Expand Down Expand Up @@ -159,15 +172,11 @@ def setopt(self, option: CurlOpt, value: Any):
elif option == CurlOpt.WRITEDATA:
c_value = ffi.new_handle(value)
self._write_handle = c_value
lib._curl_easy_setopt(
self._curl, CurlOpt.WRITEFUNCTION, lib.buffer_callback
)
lib._curl_easy_setopt(self._curl, CurlOpt.WRITEFUNCTION, lib.buffer_callback)
elif option == CurlOpt.HEADERDATA:
c_value = ffi.new_handle(value)
self._header_handle = c_value
lib._curl_easy_setopt(
self._curl, CurlOpt.HEADERFUNCTION, lib.buffer_callback
)
lib._curl_easy_setopt(self._curl, CurlOpt.HEADERFUNCTION, lib.buffer_callback)
elif option == CurlOpt.WRITEFUNCTION:
c_value = ffi.new_handle(value)
self._write_handle = c_value
Expand Down Expand Up @@ -246,9 +255,7 @@ def impersonate(self, target: str, default_headers: bool = True) -> int:
target: browser to impersonate.
default_headers: whether to add default headers, like User-Agent.
"""
return lib.curl_easy_impersonate(
self._curl, target.encode(), int(default_headers)
)
return lib.curl_easy_impersonate(self._curl, target.encode(), int(default_headers))

def _ensure_cacert(self):
if not self._is_cert_set:
Expand Down Expand Up @@ -346,7 +353,7 @@ def close(self):
ffi.release(self._error_buffer)
self._resolve = ffi.NULL

def ws_recv(self, n: int = 1024):
def ws_recv(self, n: int = 1024) -> Tuple[bytes, CurlWsFrame]:
buffer = ffi.new("char[]", n)
n_recv = ffi.new("int *")
p_frame = ffi.new("struct curl_ws_frame **")
Expand All @@ -365,6 +372,3 @@ def ws_send(self, payload: bytes, flags: CurlWsFlag = CurlWsFlag.BINARY) -> int:
ret = lib.curl_ws_send(self._curl, buffer, len(buffer), n_sent, 0, flags)
self._check_error(ret, "WS_SEND")
return n_sent[0]

def ws_close(self):
self.ws_send(b"", CurlWsFlag.CLOSE)
5 changes: 3 additions & 2 deletions curl_cffi/requests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"Headers",
"Request",
"Response",
"AsyncWebSocket",
"WebSocket",
"WebSocketError",
"WsCloseCode",
Expand All @@ -31,7 +32,7 @@
from .errors import RequestsError
from .headers import Headers, HeaderTypes
from .session import AsyncSession, BrowserType, Session
from .websockets import WebSocket, WebSocketError, WsCloseCode
from .websockets import AsyncWebSocket, WebSocket, WebSocketError, WsCloseCode

# ThreadType = Literal["eventlet", "gevent", None]

Expand All @@ -50,7 +51,7 @@ def request(
allow_redirects: bool = True,
max_redirects: int = -1,
proxies: Optional[dict] = None,
verify: Optional[bool] = None,
verify: Optional[Union[bool, str]] = None,
referer: Optional[str] = None,
accept_encoding: Optional[str] = "gzip, deflate, br",
content_callback: Optional[Callable] = None,
Expand Down
Loading