aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mitmproxy/addons/export.py25
-rw-r--r--test/mitmproxy/addons/test_export.py28
2 files changed, 39 insertions, 14 deletions
diff --git a/mitmproxy/addons/export.py b/mitmproxy/addons/export.py
index 90e95d3e..271fc49d 100644
--- a/mitmproxy/addons/export.py
+++ b/mitmproxy/addons/export.py
@@ -1,4 +1,5 @@
import typing
+import shlex
from mitmproxy import ctx
from mitmproxy import command
@@ -18,20 +19,26 @@ def raise_if_missing_request(f: flow.Flow) -> None:
def curl_command(f: flow.Flow) -> str:
raise_if_missing_request(f)
- data = "curl "
+ args = ["curl"]
request = f.request.copy() # type: ignore
request.decode(strict=False)
for k, v in request.headers.items(multi=True):
- data += "-H '%s:%s' " % (k, v)
+ args += ["-H", shlex.quote("%s:%s" % (k, v))]
if request.method != "GET":
- data += "-X %s " % request.method
- data += "'%s'" % request.url
+ args += ["-X", shlex.quote(request.method)]
+ args.append(shlex.quote(request.url))
if request.content:
- data += " --data-binary '%s'" % strutils.bytes_to_escaped_str(
- request.content,
- escape_single_quotes=True
- )
- return data
+ try:
+ content = strutils.always_str(request.content)
+ except UnicodeDecodeError:
+ # shlex.quote doesn't support a bytes object
+ # see https://github.com/python/cpython/pull/10871
+ raise exceptions.CommandError("Request content must be valid unicode")
+ args += [
+ "--data-binary",
+ shlex.quote(strutils.always_str(request.content))
+ ]
+ return ' '.join(args)
def httpie_command(f: flow.Flow) -> str:
diff --git a/test/mitmproxy/addons/test_export.py b/test/mitmproxy/addons/test_export.py
index f4bb0f64..5c365135 100644
--- a/test/mitmproxy/addons/test_export.py
+++ b/test/mitmproxy/addons/test_export.py
@@ -1,4 +1,5 @@
import os
+import shlex
import pytest
import pyperclip
@@ -47,23 +48,40 @@ def tcp_flow():
class TestExportCurlCommand:
def test_get(self, get_request):
- result = """curl -H 'header:qvalue' -H 'content-length:0' 'http://address:22/path?a=foo&a=bar&b=baz'"""
+ result = """curl -H header:qvalue -H content-length:0 'http://address:22/path?a=foo&a=bar&b=baz'"""
assert export.curl_command(get_request) == result
def test_post(self, post_request):
- result = "curl -H 'content-length:256' -X POST 'http://address:22/path' --data-binary '{}'".format(
- str(bytes(range(256)))[2:-1]
- )
+ post_request.request.content = b'nobinarysupport'
+ result = "curl -H content-length:15 -X POST http://address:22/path --data-binary nobinarysupport"
assert export.curl_command(post_request) == result
+ def test_fails_with_binary_data(self, post_request):
+ # shlex.quote doesn't support a bytes object
+ # see https://github.com/python/cpython/pull/10871
+ with pytest.raises(exceptions.CommandError):
+ export.curl_command(post_request)
+
def test_patch(self, patch_request):
- result = """curl -H 'header:qvalue' -H 'content-length:7' -X PATCH 'http://address:22/path?query=param' --data-binary 'content'"""
+ result = """curl -H header:qvalue -H content-length:7 -X PATCH 'http://address:22/path?query=param' --data-binary content"""
assert export.curl_command(patch_request) == result
def test_tcp(self, tcp_flow):
with pytest.raises(exceptions.CommandError):
export.curl_command(tcp_flow)
+ def test_escape_single_quotes_in_body(self):
+ request = tflow.tflow(
+ req=tutils.treq(
+ method=b'POST',
+ headers=(),
+ content=b"'&#"
+ )
+ )
+ command = export.curl_command(request)
+ assert shlex.split(command)[-2] == '--data-binary'
+ assert shlex.split(command)[-1] == "'&#"
+
class TestExportHttpieCommand:
def test_get(self, get_request):