From 55baabe2d8a06fa8d52ffb245392c63364204029 Mon Sep 17 00:00:00 2001 From: Noel Evans Date: Tue, 24 Sep 2024 22:21:54 +0100 Subject: [PATCH 1/3] Options with multiple values get split to send to subprocess When an option like --custom-header Authorization my-token is received this must be broken in to 3 strings to be given to subprocess.Popen - 'custom-header' - 'Authorization' - 'my-token' With the previous code where "Authorization my-token" was one string, Popen does not correctly pass both arguments with --custom-header. Consequently wkhtmltopdf ignores any --custom-header instruction sent to it from django-wkhtml. The problem can be seen by running these commands: >>> import subprocess >>> cmd = ['curl', '--dump-header output', 'https://api.github.com'] >>> subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() (b'', b"curl: option --dump-header output: is unknown\ncurl: try 'curl --help' for more information\n") If you change the above command to be cmd = ['curl', '--dump-header', 'output', 'https://api.github.com'] then the call works and makes a file called "output" containing header information. --- wkhtmltopdf/tests/tests.py | 5 +++++ wkhtmltopdf/utils.py | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/wkhtmltopdf/tests/tests.py b/wkhtmltopdf/tests/tests.py index c9f2187..1cfd18e 100644 --- a/wkhtmltopdf/tests/tests.py +++ b/wkhtmltopdf/tests/tests.py @@ -59,6 +59,11 @@ def test_options_to_args(self): file_name='file-name'), ['--file-name', 'file-name', '--heart', u'♥']) + self.assertEqual(_options_to_args( + custom_header='Authentication mytoken', + cookie='key1 value1'), + ['--cookie', 'key1', 'value1', + '--custom-header', 'Authentication', 'mytoken']) def test_wkhtmltopdf(self): """Should run wkhtmltopdf to generate a PDF""" diff --git a/wkhtmltopdf/utils.py b/wkhtmltopdf/utils.py index 68034b8..dcdf336 100644 --- a/wkhtmltopdf/utils.py +++ b/wkhtmltopdf/utils.py @@ -46,6 +46,7 @@ '--enable-toc-back-links', '--footer-line', '--no-footer-line', '--header-line', '--no-header-line', '--disable-dotted-lines', '--disable-toc-links', '--verbose'] +MULTI_VALUE_OPTIONS = ['--custom-header', '--cookie'] def _options_to_args(**options): @@ -60,12 +61,16 @@ def _options_to_args(**options): formatted_flag = '--%s' % name if len(name) > 1 else '-%s' % name formatted_flag = formatted_flag.replace('_', '-') accepts_no_arguments = formatted_flag in NO_ARGUMENT_OPTIONS + is_multi_value_option = formatted_flag in MULTI_VALUE_OPTIONS if value is None or (value is False and accepts_no_arguments): continue flags.append(formatted_flag) if accepts_no_arguments: continue - flags.append(six.text_type(value)) + if is_multi_value_option: + flags.extend(value.split()) + else: + flags.append(six.text_type(value)) return flags From 597701504a9b4b20b5438168653eaa13b486b3f4 Mon Sep 17 00:00:00 2001 From: Noel Evans Date: Thu, 26 Sep 2024 22:11:35 +0100 Subject: [PATCH 2/3] Be more robust about expected pairs of options --- wkhtmltopdf/tests/tests.py | 2 ++ wkhtmltopdf/utils.py | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/wkhtmltopdf/tests/tests.py b/wkhtmltopdf/tests/tests.py index 1cfd18e..ad0f7cd 100644 --- a/wkhtmltopdf/tests/tests.py +++ b/wkhtmltopdf/tests/tests.py @@ -64,6 +64,8 @@ def test_options_to_args(self): cookie='key1 value1'), ['--cookie', 'key1', 'value1', '--custom-header', 'Authentication', 'mytoken']) + with self.assertRaises(ValueError): + _options_to_args(custom_header='Authentication') def test_wkhtmltopdf(self): """Should run wkhtmltopdf to generate a PDF""" diff --git a/wkhtmltopdf/utils.py b/wkhtmltopdf/utils.py index dcdf336..976b63a 100644 --- a/wkhtmltopdf/utils.py +++ b/wkhtmltopdf/utils.py @@ -68,7 +68,9 @@ def _options_to_args(**options): if accepts_no_arguments: continue if is_multi_value_option: - flags.extend(value.split()) + k, v = value.split(maxsplit=1) + flags.append(six.text_type(k)) + flags.append(six.text_type(v)) else: flags.append(six.text_type(value)) return flags From 12fe1407709239f56fbefd008029ab903e37768b Mon Sep 17 00:00:00 2001 From: Noel Evans Date: Thu, 26 Sep 2024 22:15:32 +0100 Subject: [PATCH 3/3] Add other options that come in key-value pairs --- wkhtmltopdf/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wkhtmltopdf/utils.py b/wkhtmltopdf/utils.py index 976b63a..2ff4548 100644 --- a/wkhtmltopdf/utils.py +++ b/wkhtmltopdf/utils.py @@ -46,7 +46,7 @@ '--enable-toc-back-links', '--footer-line', '--no-footer-line', '--header-line', '--no-header-line', '--disable-dotted-lines', '--disable-toc-links', '--verbose'] -MULTI_VALUE_OPTIONS = ['--custom-header', '--cookie'] +MULTI_VALUE_OPTIONS = ['--custom-header', '--cookie', '--post', '--replace'] def _options_to_args(**options):