mirror of
https://github.com/httpie/cli.git
synced 2024-11-28 18:53:21 +01:00
parent
5754e33a75
commit
684a4708d7
@ -8,6 +8,7 @@ This project adheres to `Semantic Versioning <https://semver.org/>`_.
|
||||
|
||||
`2.1.0-dev`_ (unreleased)
|
||||
-------------------------
|
||||
* Add ``--path-as-is`` to bypass dot segment (``/../`` or ``/./``) URL squashing.
|
||||
* Fixed ``--form`` file upload mixed with redirected ``stdin`` error handling.
|
||||
|
||||
|
||||
|
@ -552,6 +552,15 @@ network.add_argument(
|
||||
|
||||
"""
|
||||
)
|
||||
network.add_argument(
|
||||
'--path-as-is',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help="""
|
||||
Bypass dot segment (/../ or /./) URL squashing.
|
||||
|
||||
"""
|
||||
)
|
||||
|
||||
#######################################################################
|
||||
# SSL
|
||||
|
@ -6,6 +6,7 @@ import zlib
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
from typing import Iterable, Union
|
||||
from urllib.parse import urlparse, urlunparse
|
||||
|
||||
import requests
|
||||
from requests.adapters import HTTPAdapter
|
||||
@ -77,6 +78,11 @@ def collect_messages(
|
||||
|
||||
request = requests.Request(**request_kwargs)
|
||||
prepared_request = requests_session.prepare_request(request)
|
||||
if args.path_as_is:
|
||||
prepared_request.url = ensure_path_as_is(
|
||||
orig_url=args.url,
|
||||
prepped_url=prepared_request.url,
|
||||
)
|
||||
if args.compress and prepared_request.body:
|
||||
compress_body(prepared_request, always=args.compress > 1)
|
||||
response_count = 0
|
||||
@ -278,3 +284,30 @@ def make_request_kwargs(
|
||||
}
|
||||
|
||||
return kwargs
|
||||
|
||||
|
||||
def ensure_path_as_is(orig_url: str, prepped_url: str) -> str:
|
||||
"""
|
||||
Handle `--path-as-is` by replacing the path component of the prepared
|
||||
URL with the path component from the original URL. Other parts stay
|
||||
untouched because other (welcome) processing on the URL might have
|
||||
taken place.
|
||||
|
||||
<https://github.com/jakubroztocil/httpie/issues/895>
|
||||
|
||||
|
||||
<https://ec.haxx.se/http/http-basics#path-as-is>
|
||||
<https://curl.haxx.se/libcurl/c/CURLOPT_PATH_AS_IS.html>
|
||||
|
||||
>>> ensure_path_as_is('http://foo/../', 'http://foo/?foo=bar')
|
||||
'http://foo/../?foo=bar'
|
||||
|
||||
"""
|
||||
parsed_orig, parsed_prepped = urlparse(orig_url), urlparse(prepped_url)
|
||||
final_dict = {
|
||||
# noinspection PyProtectedMember
|
||||
**parsed_prepped._asdict(),
|
||||
'path': parsed_orig.path,
|
||||
}
|
||||
final_url = urlunparse(tuple(final_dict.values()))
|
||||
return final_url
|
||||
|
@ -55,6 +55,25 @@ def test_GET(httpbin_both):
|
||||
assert HTTP_OK in r
|
||||
|
||||
|
||||
def test_path_dot_normalization():
|
||||
r = http(
|
||||
'--offline',
|
||||
'example.org/../../etc/password',
|
||||
'param==value'
|
||||
)
|
||||
assert 'GET /etc/password?param=value' in r
|
||||
|
||||
|
||||
def test_path_as_is():
|
||||
r = http(
|
||||
'--offline',
|
||||
'--path-as-is',
|
||||
'example.org/../../etc/password',
|
||||
'param==value'
|
||||
)
|
||||
assert 'GET /../../etc/password?param=value' in r
|
||||
|
||||
|
||||
def test_DELETE(httpbin_both):
|
||||
r = http('DELETE', httpbin_both + '/delete')
|
||||
assert HTTP_OK in r
|
||||
|
Loading…
Reference in New Issue
Block a user