]> git.feebdaed.xyz Git - 0xmirror/mitmproxy.git/commitdiff
fix missing content-length header in curl export (#7810)
authorMatthew Heguy <10162554+mheguy@users.noreply.github.com>
Sun, 3 Aug 2025 16:46:19 +0000 (12:46 -0400)
committerGitHub <noreply@github.com>
Sun, 3 Aug 2025 16:46:19 +0000 (18:46 +0200)
* fix missing content-length header in curl export

* [autofix.ci] apply automated fixes

* Simplify logic and remove redundant tests

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
CHANGELOG.md
mitmproxy/addons/export.py
test/mitmproxy/addons/test_export.py

index d8b3aef528dc3c7071960c7712953462340b13f5..f56468cd2cec3236c812bbc5b2cd06bf5e1345d4 100644 (file)
@@ -7,6 +7,8 @@
 
 ## Unreleased: mitmproxy next
 
+- fix: missing content-length header in curl export
+  ([#7810](https://github.com/mitmproxy/mitmproxy/pull/7810), @mheguy)
 - fix: update log message with correct header name
   ([#7802](https://github.com/mitmproxy/mitmproxy/pull/7802), @kristof-mattei)
 - Update deprecated `windows-2019` runner to `windows-2025`.
index 0513a113640901158b8658ccf1aa501c01dc2213..4f136bcbad88e922244170cd51444a7d198f8322 100644 (file)
@@ -24,14 +24,14 @@ def cleanup_request(f: flow.Flow) -> http.Request:
     return request
 
 
-def pop_headers(request: http.Request) -> http.Request:
-    # Remove some headers that are redundant for curl/httpie export
+def pop_headers(request: http.Request) -> None:
+    """Remove some headers that are redundant for curl/httpie export."""
     request.headers.pop("content-length", None)
+
     if request.headers.get("host", "") == request.host:
         request.headers.pop("host")
     if request.headers.get(":authority", "") == request.host:
         request.headers.pop(":authority")
-    return request
 
 
 def cleanup_response(f: flow.Flow) -> http.Response:
@@ -62,7 +62,8 @@ def request_content_for_console(request: http.Request) -> str:
 
 def curl_command(f: flow.Flow) -> str:
     request = cleanup_request(f)
-    request = pop_headers(request)
+    pop_headers(request)
+
     args = ["curl"]
 
     server_addr = f.server_conn.peername[0] if f.server_conn.peername else None
@@ -83,6 +84,12 @@ def curl_command(f: flow.Flow) -> str:
             args += ["-H", f"{k}: {v}"]
 
     if request.method != "GET":
+        if not request.content:
+            # curl will not calculate content-length if there is no content
+            # some server/verb combinations require content-length headers
+            # (ex. nginx and POST)
+            args += ["-H", "content-length: 0"]
+
         args += ["-X", request.method]
 
     args.append(request.pretty_url)
@@ -95,7 +102,7 @@ def curl_command(f: flow.Flow) -> str:
 
 def httpie_command(f: flow.Flow) -> str:
     request = cleanup_request(f)
-    request = pop_headers(request)
+    pop_headers(request)
 
     # TODO: Once https://github.com/httpie/httpie/issues/414 is implemented, we
     # should ensure we always connect to the IP address specified in the flow,
index f03a3b482025ad580cf6b7ee3ea88e9057846b2f..2585c213068d71e82db29f5184ea15b9ed24d832 100644 (file)
@@ -88,6 +88,13 @@ class TestExportCurlCommand:
         result = "curl -X POST http://address:22/path -d nobinarysupport"
         assert export_curl(post_request) == result
 
+    def test_post_with_no_content_has_explicit_content_length_header(
+        self, export_curl, post_request
+    ):
+        post_request.request.content = None
+        result = "curl -H 'content-length: 0' -X POST http://address:22/path"
+        assert export_curl(post_request) == result
+
     def test_fails_with_binary_data(self, export_curl, post_request):
         # shlex.quote doesn't support a bytes object
         # see https://github.com/python/cpython/pull/10871