Skip to content

Commit

Permalink
apply initial suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
Ousret committed Mar 21, 2024
1 parent 7eb10b5 commit 8c3c77a
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 42 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,19 @@ This project adheres to [Semantic Versioning](https://semver.org/).
- Added support for specifying the local port with `--local-port`. ([#1456](https://github.com/httpie/cli/issues/1456)) ([#1531](https://github.com/httpie/cli/pull/1531))
- Added support for forcing either IPv4 or IPv6 to reach the remote HTTP server with `-6` or `-4`. ([#94](https://github.com/httpie/cli/issues/94)) ([#1531](https://github.com/httpie/cli/pull/1531))
- Removed support for pyopenssl. ([#1531](https://github.com/httpie/cli/pull/1531))
- Removed support for dead SSL protocols < TLS 1.0 (e.g. sslv3) as per pyopenssl removal. ([#1531](https://github.com/httpie/cli/pull/1531))
- Dropped dependency on `requests_toolbelt` in favor of directly including `MultipartEncoder` into HTTPie due to its direct dependency to requests. ([#1531](https://github.com/httpie/cli/pull/1531))
- Dropped dependency on `multidict` in favor of implementing an internal one due to often missing pre-built wheels. ([#1522](https://github.com/httpie/cli/issues/1522)) ([#1531](https://github.com/httpie/cli/pull/1531))
- Fixed the case when multiple headers where concatenated in the response output. ([#1413](https://github.com/httpie/cli/issues/1413)) ([#1531](https://github.com/httpie/cli/pull/1531))
- Fixed an edge case where HTTPie could be lead to believe data was passed in stdin, thus sending a POST by default. ([#1551](https://github.com/httpie/cli/issues/1551)) ([#1531](https://github.com/httpie/cli/pull/1531))
This fix has the particularity to consider 0 byte long stdin buffer as absent stdin. Empty stdin buffer will be ignored.
- Slightly improved performance while downloading by setting chunk size to `-1` to retrieve packets as they arrive. ([#1531](https://github.com/httpie/cli/pull/1531))
- Added support for using the system trust store to retrieve root CAs for verifying TLS certificates. ([#1531](https://github.com/httpie/cli/pull/1531))
- Removed support for keeping the original casing of HTTP headers. This come from an outer constraint by newer protocols, namely HTTP/2+ that normalize header keys by default.
From the HTTPie user perspective, they are "prettified" on the output by default. e.g. "x-hello-world" is displayed as "X-Hello-World".

The plugins are expected to work without any changes. The only caveat would be that certain plugin explicitly require `requests`.
Future contributions may be made in order to relax the constraints where applicable.

## [3.2.2](https://github.com/httpie/cli/compare/3.2.1...3.2.2) (2022-05-19)

Expand Down
28 changes: 14 additions & 14 deletions httpie/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,10 @@
from urllib.parse import urlparse, urlunparse

import niquests
# to understand why this is required
# see https://niquests.readthedocs.io/en/latest/community/faq.html#what-is-urllib3-future
from niquests._compat import HAS_LEGACY_URLLIB3

if not HAS_LEGACY_URLLIB3:
# noinspection PyPackageRequirements
import urllib3
from urllib3.util import SKIP_HEADER, SKIPPABLE_HEADERS, parse_url
else:
# noinspection PyPackageRequirements
import urllib3_future as urllib3
from urllib3_future.util import SKIP_HEADER, SKIPPABLE_HEADERS, parse_url

from . import __version__
from .adapters import HTTPieHTTPAdapter
from .compat import urllib3, SKIP_HEADER, SKIPPABLE_HEADERS, parse_url, Timeout
from .cli.constants import HTTP_OPTIONS
from .cli.dicts import HTTPHeadersDict
from .cli.nested_json import unwrap_top_level_list_if_needed
Expand Down Expand Up @@ -99,9 +88,20 @@ def collect_messages(
source_address=source_address,
)

parsed_url = parse_url(args.url)

if args.disable_http3 is False and args.force_http3 is True:
url = parse_url(args.url)
requests_session.quic_cache_layer[(url.host, url.port or 443)] = (url.host, url.port or 443)
requests_session.quic_cache_layer[(parsed_url.host, parsed_url.port or 443)] = (parsed_url.host, parsed_url.port or 443)
# well, this one is tricky. If we allow HTTP/3, and remote host was marked as QUIC capable
# but is not anymore, we may face an indefinite hang if timeout isn't set. This could surprise some user.
elif (
args.disable_http3 is False
and requests_session.quic_cache_layer.get((parsed_url.host, parsed_url.port or 443)) is not None
and send_kwargs["timeout"] is None
):
# we only set the connect timeout, the rest is still indefinite.
send_kwargs["timeout"] = Timeout(connect=3)
setattr(args, "_failsafe_http3", True)

if httpie_session:
httpie_session.update_headers(request_kwargs['headers'])
Expand Down
17 changes: 17 additions & 0 deletions httpie/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@
from httpie.cookies import HTTPieCookiePolicy
from http import cookiejar # noqa

from niquests._compat import HAS_LEGACY_URLLIB3

# to understand why this is required
# see https://niquests.readthedocs.io/en/latest/community/faq.html#what-is-urllib3-future
# short story, urllib3 (import/top-level import) may be the legacy one https://github.com/urllib3/urllib3
# instead of urllib3-future https://github.com/jawah/urllib3.future used by Niquests
# or only the secondary entry point could be available (e.g. urllib3_future on some distro without urllib3)
if not HAS_LEGACY_URLLIB3:
# noinspection PyPackageRequirements
import urllib3 # noqa: F401
from urllib3.util import SKIP_HEADER, SKIPPABLE_HEADERS, parse_url, Timeout # noqa: F401
from urllib3.fields import RequestField # noqa: F401
else:
# noinspection PyPackageRequirements
import urllib3_future as urllib3 # noqa: F401
from urllib3_future.util import SKIP_HEADER, SKIPPABLE_HEADERS, parse_url, Timeout # noqa: F401
from urllib3_future.fields import RequestField # noqa: F401

# Request does not carry the original policy attached to the
# cookie jar, so until it is resolved we change the global cookie
Expand Down
10 changes: 9 additions & 1 deletion httpie/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from .utils import unwrap_context
from .internal.update_warnings import check_updates
from .internal.daemon_runner import is_daemon_mode, run_daemon_task
from .ssl_ import QuicCapabilityCache


# noinspection PyDefaultArgument
Expand Down Expand Up @@ -114,7 +115,14 @@ def handle_generic_error(e, annotation=None):
exit_status = ExitStatus.ERROR
except niquests.Timeout:
exit_status = ExitStatus.ERROR_TIMEOUT
env.log_error(f'Request timed out ({parsed_args.timeout}s).')
# this detects if we tried to connect with HTTP/3 when the remote isn't compatible anymore.
if hasattr(parsed_args, "_failsafe_http3"):
env.log_error(
f'Unable to connect. Was the remote specified HTTP/3 compatible but is not anymore? '
f'Remove "{QuicCapabilityCache.__file__}" to clear it out. Or set --disable-http3 flag.'
)
else:
env.log_error(f'Request timed out ({parsed_args.timeout}s).')
except niquests.TooManyRedirects:
exit_status = ExitStatus.ERROR_TOO_MANY_REDIRECTS
env.log_error(
Expand Down
9 changes: 1 addition & 8 deletions httpie/internal/encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,7 @@
import os
from uuid import uuid4

# to understand why this is required
# see https://niquests.readthedocs.io/en/latest/community/faq.html#what-is-urllib3-future
from niquests._compat import HAS_LEGACY_URLLIB3

if HAS_LEGACY_URLLIB3:
from urllib3_future.fields import RequestField
else:
from urllib3.fields import RequestField
from ..compat import RequestField


class MultipartEncoder(object):
Expand Down
15 changes: 2 additions & 13 deletions httpie/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,6 @@

import niquests

# to understand why this is required
# see https://niquests.readthedocs.io/en/latest/community/faq.html#what-is-urllib3-future
from niquests._compat import HAS_LEGACY_URLLIB3

if not HAS_LEGACY_URLLIB3:
from urllib3 import ConnectionInfo
from urllib3.util import SKIP_HEADER, SKIPPABLE_HEADERS
else:
from urllib3_future import ConnectionInfo
from urllib3_future.util import SKIP_HEADER, SKIPPABLE_HEADERS

from kiss_headers.utils import prettify_header_name

from enum import Enum, auto
Expand All @@ -26,7 +15,7 @@
OUT_RESP_HEAD,
OUT_RESP_META
)
from .compat import cached_property
from .compat import urllib3, SKIP_HEADER, SKIPPABLE_HEADERS, cached_property
from .utils import split_cookies, parse_content_type_header

ELAPSED_TIME_LABEL = 'Elapsed time'
Expand Down Expand Up @@ -152,7 +141,7 @@ def iter_lines(self, chunk_size):

@property
def metadata(self) -> str:
conn_info: ConnectionInfo = self._orig.conn_info
conn_info: urllib3.ConnectionInfo = self._orig.conn_info

metadatum = f"Connected to: {conn_info.destination_address[0]} port {conn_info.destination_address[1]}\n"

Expand Down
21 changes: 15 additions & 6 deletions httpie/ssl_.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ssl
import typing
from typing import NamedTuple, Optional, Tuple, MutableMapping
import json
import os.path
Expand Down Expand Up @@ -37,16 +38,21 @@ class QuicCapabilityCache(
See https://urllib3future.readthedocs.io/en/latest/advanced-usage.html#remembering-http-3-over-quic-support for
the implementation guide."""

__file__ = os.path.join(DEFAULT_CONFIG_DIR, "quic.json")

def __init__(self):
self._cache = {}
if not os.path.exists(DEFAULT_CONFIG_DIR):
makedirs(DEFAULT_CONFIG_DIR, exist_ok=True)
if os.path.exists(os.path.join(DEFAULT_CONFIG_DIR, "quic.json")):
with open(os.path.join(DEFAULT_CONFIG_DIR, "quic.json"), "r") as fp:
self._cache = json.load(fp)
if os.path.exists(QuicCapabilityCache.__file__):
with open(QuicCapabilityCache.__file__, "r") as fp:
try:
self._cache = json.load(fp)
except json.JSONDecodeError: # if the file is corrupted (invalid json) then, ignore it.
pass

def save(self):
with open(os.path.join(DEFAULT_CONFIG_DIR, "quic.json"), "w+") as fp:
with open(QuicCapabilityCache.__file__, "w+") as fp:
json.dump(self._cache, fp)

def __contains__(self, item: Tuple[str, int]):
Expand Down Expand Up @@ -82,8 +88,11 @@ class HTTPieCertificate(NamedTuple):
key_file: Optional[str] = None
key_password: Optional[str] = None

def to_raw_cert(self):
"""Synthesize a requests-compatible (2-item tuple of cert and key file)
def to_raw_cert(self) -> typing.Union[
typing.Tuple[typing.Optional[str], typing.Optional[str], typing.Optional[str]], # with password
typing.Tuple[typing.Optional[str], typing.Optional[str]] # without password
]:
"""Synthesize a niquests-compatible (2(or 3)-item tuple of cert, key file and optionally password)
object from HTTPie's internal representation of a certificate."""
if self.key_password:
# Niquests support 3-tuple repr in addition to the 2-tuple repr
Expand Down
7 changes: 7 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,15 @@ markers =
requires_external_processes
filterwarnings =
default
# due to urllib3.future no longer needing http.client! nothing to be concerned about.
ignore:Passing msg=\.\. is deprecated:DeprecationWarning
# this only concern the test suite / local test server with a self signed certificate.
ignore:Unverified HTTPS request is being made to host:urllib3.exceptions.InsecureRequestWarning
# the constant themselves are deprecated in the ssl module, we want to silent them in the test suite until we
# change the concerned code. Python 3.13 may remove them, so we'll need to think about it soon.
ignore:ssl\.PROTOCOL_(TLSv1|TLSv1_1|TLSv1_2) is deprecated:DeprecationWarning
ignore:ssl\.TLSVersion\.(TLSv1|TLSv1_1|TLSv1_2) is deprecated:DeprecationWarning


[metadata]
name = httpie
Expand Down

0 comments on commit 8c3c77a

Please sign in to comment.