Don't send Content-Length for OPTIONS requests when there is no data. (#1319)

This commit is contained in:
Batuhan Taskaya 2022-04-03 16:02:41 +03:00 committed by GitHub
parent d1596dde12
commit 33ea977b64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 5 deletions

View File

@ -3,6 +3,10 @@
This document records all notable changes to [HTTPie](https://httpie.io). This document records all notable changes to [HTTPie](https://httpie.io).
This project adheres to [Semantic Versioning](https://semver.org/). This project adheres to [Semantic Versioning](https://semver.org/).
## [3.1.1.dev0](https://github.com/httpie/httpie/compare/3.1.0...HEAD) (Unreleased)
- Fixed redundant creation of `Content-Length` header on `OPTIONS` requests. ([#1310](https://github.com/httpie/httpie/issues/1310))
## [3.1.0](https://github.com/httpie/httpie/compare/3.0.2...3.1.0) (2022-03-08) ## [3.1.0](https://github.com/httpie/httpie/compare/3.0.2...3.1.0) (2022-03-08)
- **SECURITY** Fixed the [vulnerability](https://github.com/httpie/httpie/security/advisories/GHSA-9w4w-cpc8-h2fq) that caused exposure of cookies on redirects to third party hosts. ([#1312](https://github.com/httpie/httpie/pull/1312)) - **SECURITY** Fixed the [vulnerability](https://github.com/httpie/httpie/security/advisories/GHSA-9w4w-cpc8-h2fq) that caused exposure of cookies on redirects to third party hosts. ([#1312](https://github.com/httpie/httpie/pull/1312))

View File

@ -3,6 +3,6 @@ HTTPie: modern, user-friendly command-line HTTP client for the API era.
""" """
__version__ = '3.1.0' __version__ = '3.1.1.dev0'
__author__ = 'Jakub Roztocil' __author__ = 'Jakub Roztocil'
__licence__ = 'BSD' __licence__ = 'BSD'

View File

@ -9,6 +9,7 @@ URL_SCHEME_RE = re.compile(r'^[a-z][a-z0-9.+-]*://', re.IGNORECASE)
HTTP_POST = 'POST' HTTP_POST = 'POST'
HTTP_GET = 'GET' HTTP_GET = 'GET'
HTTP_OPTIONS = 'OPTIONS'
# Various separators used in args # Various separators used in args
SEPARATOR_HEADER = ':' SEPARATOR_HEADER = ':'

View File

@ -13,7 +13,7 @@ import urllib3
from . import __version__ from . import __version__
from .adapters import HTTPieHTTPAdapter from .adapters import HTTPieHTTPAdapter
from .context import Environment from .context import Environment
from .cli.constants import EMPTY_STRING from .cli.constants import EMPTY_STRING, HTTP_OPTIONS
from .cli.dicts import HTTPHeadersDict, NestedJSONArray from .cli.dicts import HTTPHeadersDict, NestedJSONArray
from .encoding import UTF8 from .encoding import UTF8
from .models import RequestsMessage from .models import RequestsMessage
@ -34,6 +34,8 @@ JSON_CONTENT_TYPE = 'application/json'
JSON_ACCEPT = f'{JSON_CONTENT_TYPE}, */*;q=0.5' JSON_ACCEPT = f'{JSON_CONTENT_TYPE}, */*;q=0.5'
DEFAULT_UA = f'HTTPie/{__version__}' DEFAULT_UA = f'HTTPie/{__version__}'
IGNORE_CONTENT_LENGTH_METHODS = frozenset([HTTP_OPTIONS])
def collect_messages( def collect_messages(
env: Environment, env: Environment,
@ -85,7 +87,7 @@ def collect_messages(
request = requests.Request(**request_kwargs) request = requests.Request(**request_kwargs)
prepared_request = requests_session.prepare_request(request) prepared_request = requests_session.prepare_request(request)
apply_missing_repeated_headers(prepared_request, request.headers) transform_headers(request, prepared_request)
if args.path_as_is: if args.path_as_is:
prepared_request.url = ensure_path_as_is( prepared_request.url = ensure_path_as_is(
orig_url=args.url, orig_url=args.url,
@ -200,9 +202,30 @@ def finalize_headers(headers: HTTPHeadersDict) -> HTTPHeadersDict:
return final_headers return final_headers
def transform_headers(
request: requests.Request,
prepared_request: requests.PreparedRequest
) -> None:
"""Apply various transformations on top of the `prepared_requests`'s
headers to change the request prepreation behavior."""
# Remove 'Content-Length' when it is misplaced by requests.
if (
prepared_request.method in IGNORE_CONTENT_LENGTH_METHODS
and prepared_request.headers.get('Content-Length') == '0'
and request.headers.get('Content-Length') != '0'
):
prepared_request.headers.pop('Content-Length')
apply_missing_repeated_headers(
request.headers,
prepared_request
)
def apply_missing_repeated_headers( def apply_missing_repeated_headers(
prepared_request: requests.PreparedRequest, original_headers: HTTPHeadersDict,
original_headers: HTTPHeadersDict prepared_request: requests.PreparedRequest
) -> None: ) -> None:
"""Update the given `prepared_request`'s headers with the original """Update the given `prepared_request`'s headers with the original
ones. This allows the requests to be prepared as usual, and then later ones. This allows the requests to be prepared as usual, and then later

View File

@ -324,3 +324,41 @@ def test_json_input_preserve_order(httpbin_both):
assert HTTP_OK in r assert HTTP_OK in r
assert r.json['data'] == \ assert r.json['data'] == \
'{"order": {"map": {"1": "first", "2": "second"}}}' '{"order": {"map": {"1": "first", "2": "second"}}}'
@pytest.mark.parametrize('extra_args, expected_content_length', [
(
['Content-Length:0'],
'0'
),
(
['Content-Length:xxx'],
'xxx',
),
(
['--raw=data'],
'4'
),
(
['query[param]=something'],
'33'
)
])
def test_options_content_length_preservation(httpbin, extra_args, expected_content_length):
r = http(
'--offline',
'OPTIONS',
httpbin + '/anything',
*extra_args
)
assert f'Content-Length: {expected_content_length}' in r
@pytest.mark.parametrize('method', ['options', 'Options', 'OPTIONS'])
def test_options_dropping_redundant_content_length(httpbin, method):
r = http(
'--offline',
method,
httpbin + '/anything'
)
assert 'Content-Length' not in r