From b12fc156ceef37024e47bd7e40e6152c28295cdd Mon Sep 17 00:00:00 2001 From: Bryce Yung Date: Tue, 9 Dec 2025 18:43:01 -0500 Subject: [PATCH 1/2] Fix: Correctly unescape key/value parts in KeyValueArgType --- httpie/cli/argtypes.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/httpie/cli/argtypes.py b/httpie/cli/argtypes.py index 8f19c3c51e..dced7ce397 100644 --- a/httpie/cli/argtypes.py +++ b/httpie/cli/argtypes.py @@ -92,13 +92,20 @@ def __call__(self, s: str) -> KeyValueArg: # Starting first, longest separator found. sep = found[min(found.keys())] - key, value = token.split(sep, 1) + key_part, value_part = token.split(sep, 1) - # Any preceding tokens are part of the key. - key = ''.join(tokens[:i]) + key + # The key is composed of: + # 1. Any preceding tokens (unescaped by str(t) in join) + # 2. The key part of the current token (re-tokenize to + # handle internal escapes correctly) + key_tokens = tokens[:i] + self.tokenize(key_part) + key = ''.join(str(t) for t in key_tokens) - # Any following tokens are part of the value. - value += ''.join(tokens[i + 1:]) + # The value is composed of: + # 1. The value part of the current token (re-tokenize) + # 2. Any succeeding tokens (unescaped by str(t) in join) + value_tokens = self.tokenize(value_part) + tokens[i + 1:] + value = ''.join(str(t) for t in value_tokens) break @@ -272,4 +279,4 @@ def response_mime_type(mime_type: str) -> str: if mime_type.count('/') != 1: raise argparse.ArgumentTypeError( f'{mime_type!r} doesn’t look like a mime type; use type/subtype') - return mime_type + return mime_type \ No newline at end of file From b0cf79a029e1b80d0007a63714ee9e9b9d7f47e2 Mon Sep 17 00:00:00 2001 From: Bryce Yung Date: Tue, 9 Dec 2025 19:10:24 -0500 Subject: [PATCH 2/2] Fix: Correctly unescape key/value parts in KeyValueArgType --- httpie/cli/argtypes.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/httpie/cli/argtypes.py b/httpie/cli/argtypes.py index dced7ce397..d38a883cf1 100644 --- a/httpie/cli/argtypes.py +++ b/httpie/cli/argtypes.py @@ -95,16 +95,17 @@ def __call__(self, s: str) -> KeyValueArg: key_part, value_part = token.split(sep, 1) # The key is composed of: - # 1. Any preceding tokens (unescaped by str(t) in join) - # 2. The key part of the current token (re-tokenize to - # handle internal escapes correctly) - key_tokens = tokens[:i] + self.tokenize(key_part) + # 1. Any preceding tokens (already Escaped or regular strings) + # 2. The key part of the current token (re-tokenize to catch internal escapes) + key_tokens = tokens[:i] + key_tokens.extend(self.tokenize(key_part)) key = ''.join(str(t) for t in key_tokens) # The value is composed of: - # 1. The value part of the current token (re-tokenize) - # 2. Any succeeding tokens (unescaped by str(t) in join) - value_tokens = self.tokenize(value_part) + tokens[i + 1:] + # 1. The value part of the current token (re-tokenize to catch internal escapes) + # 2. Any succeeding tokens + value_tokens = self.tokenize(value_part) + value_tokens.extend(tokens[i + 1:]) value = ''.join(str(t) for t in value_tokens) break @@ -279,4 +280,4 @@ def response_mime_type(mime_type: str) -> str: if mime_type.count('/') != 1: raise argparse.ArgumentTypeError( f'{mime_type!r} doesn’t look like a mime type; use type/subtype') - return mime_type \ No newline at end of file + return mime_type