You've already forked httpie-cli
mirror of
https://github.com/httpie/cli.git
synced 2025-08-10 22:42:05 +02:00
Add support for sending secure cookies over localhost (#1327)
* Add support for sending secure cookies over localhost * Refactor * Fix the CI Co-authored-by: Jakub Roztocil <jakub@roztocil.co>
This commit is contained in:
@@ -7,6 +7,7 @@ from pytest_httpbin import certs
|
||||
from .utils import ( # noqa
|
||||
HTTPBIN_WITH_CHUNKED_SUPPORT_DOMAIN,
|
||||
HTTPBIN_WITH_CHUNKED_SUPPORT,
|
||||
REMOTE_HTTPBIN_DOMAIN,
|
||||
mock_env
|
||||
)
|
||||
from .utils.plugins_cli import ( # noqa
|
||||
@@ -17,7 +18,7 @@ from .utils.plugins_cli import ( # noqa
|
||||
httpie_plugins_success,
|
||||
interface,
|
||||
)
|
||||
from .utils.http_server import http_server # noqa
|
||||
from .utils.http_server import http_server, localhost_http_server # noqa
|
||||
|
||||
|
||||
@pytest.fixture(scope='function', autouse=True)
|
||||
@@ -58,6 +59,22 @@ def httpbin_with_chunked_support(_httpbin_with_chunked_support_available):
|
||||
pytest.skip(f'{HTTPBIN_WITH_CHUNKED_SUPPORT_DOMAIN} not resolvable')
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def _remote_httpbin_available():
|
||||
try:
|
||||
socket.gethostbyname(REMOTE_HTTPBIN_DOMAIN)
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def remote_httpbin(_remote_httpbin_available):
|
||||
if _remote_httpbin_available:
|
||||
return 'http://' + REMOTE_HTTPBIN_DOMAIN
|
||||
pytest.skip(f'{REMOTE_HTTPBIN_DOMAIN} not resolvable')
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope='session')
|
||||
def pyopenssl_inject():
|
||||
"""
|
||||
|
@@ -2,11 +2,6 @@ import pytest
|
||||
from .utils import http
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def remote_httpbin(httpbin_with_chunked_support):
|
||||
return httpbin_with_chunked_support
|
||||
|
||||
|
||||
def _stringify(fixture):
|
||||
return fixture + ''
|
||||
|
||||
|
@@ -800,3 +800,37 @@ def test_session_multiple_headers_with_same_name(basic_session, httpbin):
|
||||
)
|
||||
assert r.count('Foo: bar') == 2
|
||||
assert 'Foo: baz' in r
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'server, expected_cookies',
|
||||
[
|
||||
(
|
||||
pytest.lazy_fixture('localhost_http_server'),
|
||||
{'secure_cookie': 'foo', 'insecure_cookie': 'bar'}
|
||||
),
|
||||
(
|
||||
pytest.lazy_fixture('remote_httpbin'),
|
||||
{'insecure_cookie': 'bar'}
|
||||
)
|
||||
]
|
||||
)
|
||||
def test_secure_cookies_on_localhost(mock_env, tmp_path, server, expected_cookies):
|
||||
session_path = tmp_path / 'session.json'
|
||||
http(
|
||||
'--session', str(session_path),
|
||||
server + '/cookies/set',
|
||||
'secure_cookie==foo',
|
||||
'insecure_cookie==bar'
|
||||
)
|
||||
|
||||
with open_session(session_path, mock_env) as session:
|
||||
for cookie in session.cookies:
|
||||
if cookie.name == 'secure_cookie':
|
||||
cookie.secure = True
|
||||
|
||||
r = http(
|
||||
'--session', str(session_path),
|
||||
server + '/cookies'
|
||||
)
|
||||
assert r.json == {'cookies': expected_cookies}
|
||||
|
@@ -21,6 +21,8 @@ from httpie.context import Environment
|
||||
from httpie.utils import url_as_host
|
||||
|
||||
|
||||
REMOTE_HTTPBIN_DOMAIN = 'pie.dev'
|
||||
|
||||
# pytest-httpbin currently does not support chunked requests:
|
||||
# <https://github.com/kevin1024/pytest-httpbin/issues/33>
|
||||
# <https://github.com/kevin1024/pytest-httpbin/issues/28>
|
||||
|
@@ -1,9 +1,12 @@
|
||||
import threading
|
||||
import json
|
||||
|
||||
from collections import defaultdict
|
||||
from contextlib import contextmanager
|
||||
from http import HTTPStatus
|
||||
from http.cookies import SimpleCookie
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
from urllib.parse import urlparse
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -85,6 +88,34 @@ def status_custom_msg(handler):
|
||||
handler.end_headers()
|
||||
|
||||
|
||||
@TestHandler.handler('GET', '/cookies')
|
||||
def get_cookies(handler):
|
||||
cookies = {
|
||||
'cookies': {
|
||||
key: cookie.value
|
||||
for key, cookie in SimpleCookie(handler.headers.get('Cookie')).items()
|
||||
}
|
||||
}
|
||||
payload = json.dumps(cookies)
|
||||
|
||||
handler.send_response(200)
|
||||
handler.send_header('Content-Length', len(payload))
|
||||
handler.send_header('Content-Type', 'application/json')
|
||||
handler.end_headers()
|
||||
handler.wfile.write(payload.encode('utf-8'))
|
||||
|
||||
|
||||
@TestHandler.handler('GET', '/cookies/set')
|
||||
def set_cookies(handler):
|
||||
options = parse_qs(urlparse(handler.path).query)
|
||||
|
||||
handler.send_response(200)
|
||||
for cookie, [value] in options.items():
|
||||
handler.send_header('Set-Cookie', f'{cookie}={value}')
|
||||
|
||||
handler.end_headers()
|
||||
|
||||
|
||||
@TestHandler.handler('GET', '/cookies/set-and-redirect')
|
||||
def set_cookie_and_redirect(handler):
|
||||
handler.send_response(302)
|
||||
@@ -98,15 +129,30 @@ def set_cookie_and_redirect(handler):
|
||||
handler.end_headers()
|
||||
|
||||
|
||||
@contextmanager
|
||||
def _http_server():
|
||||
server = HTTPServer(('localhost', 0), TestHandler)
|
||||
thread = threading.Thread(target=server.serve_forever)
|
||||
thread.start()
|
||||
yield server
|
||||
server.shutdown()
|
||||
thread.join()
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def http_server():
|
||||
"""A custom HTTP server implementation for our tests, that is
|
||||
built on top of the http.server module. Handy when we need to
|
||||
deal with details which httpbin can not capture."""
|
||||
|
||||
server = HTTPServer(('localhost', 0), TestHandler)
|
||||
thread = threading.Thread(target=server.serve_forever)
|
||||
thread.start()
|
||||
yield '{}:{}'.format(*server.socket.getsockname())
|
||||
server.shutdown()
|
||||
thread.join(timeout=0.5)
|
||||
with _http_server() as server:
|
||||
yield '{0}:{1}'.format(*server.socket.getsockname())
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def localhost_http_server():
|
||||
"""Just like the http_server, but uses the static
|
||||
`localhost` name for the host."""
|
||||
|
||||
with _http_server() as server:
|
||||
yield 'localhost:{1}'.format(*server.socket.getsockname())
|
||||
|
Reference in New Issue
Block a user