import asyncio
import typing
+from http.cookiejar import CookieJar
from types import TracebackType
from .auth import HTTPBasicAuth
*,
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = True,
url,
query_params=query_params,
headers=headers,
+ cookies=cookies,
stream=stream,
auth=auth,
allow_redirects=allow_redirects,
*,
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = True,
url,
query_params=query_params,
headers=headers,
+ cookies=cookies,
stream=stream,
auth=auth,
allow_redirects=allow_redirects,
*,
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = False, # Note: Differs to usual default.
url,
query_params=query_params,
headers=headers,
+ cookies=cookies,
stream=stream,
auth=auth,
allow_redirects=allow_redirects,
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = True,
data=data,
query_params=query_params,
headers=headers,
+ cookies=cookies,
stream=stream,
auth=auth,
allow_redirects=allow_redirects,
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = True,
data=data,
query_params=query_params,
headers=headers,
+ cookies=cookies,
stream=stream,
auth=auth,
allow_redirects=allow_redirects,
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = True,
data=data,
query_params=query_params,
headers=headers,
+ cookies=cookies,
stream=stream,
auth=auth,
allow_redirects=allow_redirects,
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = True,
data=data,
query_params=query_params,
headers=headers,
+ cookies=cookies,
stream=stream,
auth=auth,
allow_redirects=allow_redirects,
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = True,
timeout: TimeoutConfig = None,
) -> Response:
request = Request(
- method, url, data=data, query_params=query_params, headers=headers
+ method,
+ url,
+ data=data,
+ query_params=query_params,
+ headers=headers,
+ cookies=cookies,
)
self.prepare_request(request)
response = await self.send(
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = True,
timeout: TimeoutConfig = None,
) -> SyncResponse:
request = Request(
- method, url, data=data, query_params=query_params, headers=headers
+ method,
+ url,
+ data=data,
+ query_params=query_params,
+ headers=headers,
+ cookies=cookies,
)
self.prepare_request(request)
response = self.send(
*,
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = True,
"GET",
url,
headers=headers,
+ cookies=cookies,
stream=stream,
auth=auth,
allow_redirects=allow_redirects,
*,
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = True,
"OPTIONS",
url,
headers=headers,
+ cookies=cookies,
stream=stream,
auth=auth,
allow_redirects=allow_redirects,
*,
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = False, # Note: Differs to usual default.
"HEAD",
url,
headers=headers,
+ cookies=cookies,
stream=stream,
auth=auth,
allow_redirects=allow_redirects,
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = True,
url,
data=data,
headers=headers,
+ cookies=cookies,
stream=stream,
auth=auth,
allow_redirects=allow_redirects,
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = True,
url,
data=data,
headers=headers,
+ cookies=cookies,
stream=stream,
auth=auth,
allow_redirects=allow_redirects,
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = True,
url,
data=data,
headers=headers,
+ cookies=cookies,
stream=stream,
auth=auth,
allow_redirects=allow_redirects,
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
stream: bool = False,
auth: AuthTypes = None,
allow_redirects: bool = True,
url,
data=data,
headers=headers,
+ cookies=cookies,
stream=stream,
auth=auth,
allow_redirects=allow_redirects,
import asyncio
import cgi
+import email.message
+import http.client
import typing
+import urllib.request
+from http.cookiejar import CookieJar
from urllib.parse import parse_qsl, urlencode
import chardet
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
+ cookies: CookieJar = None,
):
self.method = method.upper()
self.url = URL(url, query_params=query_params)
self.headers = Headers(headers)
+ if cookies:
+ cookies.add_cookie_header(self.cookie_compat)
if isinstance(data, bytes):
self.is_streaming = False
for item in reversed(auto_headers):
self.headers.raw.insert(0, item)
+ @property
+ def cookie_compat(self) -> "CookieCompatRequest":
+ return CookieCompatRequest(self)
+
def __repr__(self) -> str:
class_name = self.__class__.__name__
url = str(self.url)
if message:
raise HttpError(message)
+ @property
+ def cookies(self) -> CookieJar:
+ if not hasattr(self, "_cookies"):
+ assert self.request is not None
+ self._cookies = CookieJar()
+ self._cookies.extract_cookies(
+ self.cookie_compat, self.request.cookie_compat
+ )
+ return self._cookies
+
+ @property
+ def cookie_compat(self) -> "CookieCompatResponse":
+ return CookieCompatResponse(self)
+
def __repr__(self) -> str:
return f"<Response({self.status_code}, {self.reason_phrase!r})>"
def close(self) -> None:
return self._loop.run_until_complete(self._response.close())
+ @property
+ def cookies(self) -> CookieJar:
+ return self._response.cookies
+
def __repr__(self) -> str:
return f"<Response({self.status_code}, {self.reason_phrase!r})>"
+
+
+class CookieCompatRequest(urllib.request.Request):
+ def __init__(self, request: Request) -> None:
+ super().__init__(
+ url=str(request.url), headers=dict(request.headers), method=request.method
+ )
+ self.request = request
+
+ def add_unredirected_header(self, key: str, value: str) -> None:
+ super().add_unredirected_header(key, value)
+ self.request.headers[key] = value
+
+
+class CookieCompatResponse(http.client.HTTPResponse):
+ def __init__(self, response: Response):
+ self.response = response
+
+ def info(self) -> email.message.Message:
+ info = email.message.Message()
+ for key, value in self.response.headers.items():
+ info[key] = value
+ return info
--- /dev/null
+import json
+from http.cookiejar import Cookie, CookieJar
+
+import pytest
+
+from httpcore import (
+ URL,
+ Client,
+ Dispatcher,
+ Request,
+ Response,
+ SSLConfig,
+ TimeoutConfig,
+)
+
+
+class MockDispatch(Dispatcher):
+ async def send(
+ self,
+ request: Request,
+ stream: bool = False,
+ ssl: SSLConfig = None,
+ timeout: TimeoutConfig = None,
+ ) -> Response:
+ if request.url.path.startswith('/echo_cookies'):
+ body = json.dumps({"cookies": request.headers.get("Cookie")}).encode()
+ return Response(200, content=body, request=request)
+ elif request.url.path.startswith('/set_cookie'):
+ headers = {"set-cookie": "example-name=example-value"}
+ return Response(200, headers=headers, request=request)
+
+
+def create_cookie(name, value, **kwargs):
+ result = {
+ "version": 0,
+ "name": name,
+ "value": value,
+ "port": None,
+ "domain": "",
+ "path": "/",
+ "secure": False,
+ "expires": None,
+ "discard": True,
+ "comment": None,
+ "comment_url": None,
+ "rest": {"HttpOnly": None},
+ "rfc2109": False,
+ }
+
+ result.update(kwargs)
+ result["port_specified"] = bool(result["port"])
+ result["domain_specified"] = bool(result["domain"])
+ result["domain_initial_dot"] = result["domain"].startswith(".")
+ result["path_specified"] = bool(result["path"])
+
+ return Cookie(**result)
+
+
+def test_set_cookie():
+ url = "http://example.org/echo_cookies"
+ cookie = create_cookie("example-name", "example-value")
+ cookies = CookieJar()
+ cookies.set_cookie(cookie)
+
+ with Client(dispatch=MockDispatch()) as client:
+ response = client.get(url, cookies=cookies)
+
+ assert response.status_code == 200
+ assert json.loads(response.text) == {"cookies": "example-name=example-value"}
+
+
+def test_get_cookie():
+ url = "http://example.org/set_cookie"
+
+ with Client(dispatch=MockDispatch()) as client:
+ response = client.get(url)
+
+ assert response.status_code == 200
+ cookies = list(response.cookies)
+ assert len(cookies) == 1
+ cookie = cookies[0]
+ assert cookie.name == "example-name"
+ assert cookie.value == "example-value"