Skip to content

Commit 0780fc1

Browse files
committed
Fix for multibyte inputs to custom search commands
1 parent 6a9c77b commit 0780fc1

File tree

2 files changed

+41
-21
lines changed

2 files changed

+41
-21
lines changed

splunklib/searchcommands/search_command.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -852,15 +852,23 @@ def _execute(self, ifile, process):
852852
@staticmethod
853853
def _read_chunk(ifile):
854854
# noinspection PyBroadException
855+
if six.PY2:
856+
istream = ifile
857+
else:
858+
try:
859+
istream = ifile.buffer
860+
except AttributeError as error:
861+
raise RuntimeError('Failed to get underlying buffer: {}'.format(error))
862+
855863
try:
856-
header = ifile.readline()
864+
header = istream.readline()
857865
except Exception as error:
858866
raise RuntimeError('Failed to read transport header: {}'.format(error))
859867

860868
if not header:
861869
return None
862870

863-
match = SearchCommand._header.match(header)
871+
match = SearchCommand._header.match(six.ensure_str(header))
864872

865873
if match is None:
866874
raise RuntimeError('Failed to parse transport header: {}'.format(header))
@@ -870,14 +878,14 @@ def _read_chunk(ifile):
870878
body_length = int(body_length)
871879

872880
try:
873-
metadata = ifile.read(metadata_length)
881+
metadata = istream.read(metadata_length)
874882
except Exception as error:
875883
raise RuntimeError('Failed to read metadata of length {}: {}'.format(metadata_length, error))
876884

877885
decoder = MetadataDecoder()
878886

879887
try:
880-
metadata = decoder.decode(metadata)
888+
metadata = decoder.decode(six.ensure_str(metadata))
881889
except Exception as error:
882890
raise RuntimeError('Failed to parse metadata of length {}: {}'.format(metadata_length, error))
883891

@@ -887,11 +895,11 @@ def _read_chunk(ifile):
887895
body = ""
888896
try:
889897
if body_length > 0:
890-
body = ifile.read(body_length)
898+
body = istream.read(body_length)
891899
except Exception as error:
892900
raise RuntimeError('Failed to read body of length {}: {}'.format(body_length, error))
893901

894-
return metadata, body
902+
return metadata, six.ensure_str(body)
895903

896904
_header = re.compile(r'chunked\s+1.0\s*,\s*(\d+)\s*,\s*(\d+)\s*\n')
897905

tests/searchcommands/test_search_command.py

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,21 @@
3333
import os
3434
import re
3535

36+
from io import TextIOWrapper
37+
3638
import pytest
3739

40+
def build_command_input(getinfo_metadata, execute_metadata, execute_body):
41+
header = ('chunked 1.0,{},0\n{}'.format(len(six.ensure_binary(getinfo_metadata)), getinfo_metadata) +
42+
'chunked 1.0,{},{}\n{}{}'.format(len(six.ensure_binary(execute_metadata)), len(six.ensure_binary(execute_body)), execute_metadata, execute_body))
43+
44+
ifile = BytesIO(six.ensure_binary(header))
45+
46+
if not six.PY2:
47+
ifile = TextIOWrapper(ifile)
48+
49+
return ifile
50+
3851
@Configuration()
3952
class TestCommand(SearchCommand):
4053

@@ -428,11 +441,9 @@ def test_process_scpv2(self):
428441
show_configuration=('true' if show_configuration is True else 'false'))
429442

430443
execute_metadata = '{"action":"execute","finished":true}'
431-
execute_body = 'test\r\ndata\r\n'
444+
execute_body = 'test\r\ndata\r\n测试\r\n'
432445

433-
ifile = StringIO(
434-
'chunked 1.0,{},0\n{}'.format(len(getinfo_metadata), getinfo_metadata) +
435-
'chunked 1.0,{},{}\n{}{}'.format(len(execute_metadata), len(execute_body), execute_metadata, execute_body))
446+
ifile = build_command_input(getinfo_metadata, execute_metadata, execute_body)
436447

437448
command = TestCommand()
438449
result = BytesIO()
@@ -455,12 +466,17 @@ def test_process_scpv2(self):
455466
self.assertEqual(command.required_option_1, 'value_1')
456467
self.assertEqual(command.required_option_2, 'value_2')
457468

458-
self.assertEqual(
469+
expected = (
459470
'chunked 1.0,68,0\n'
460471
'{"inspector":{"messages":[["INFO","test command configuration: "]]}}\n'
461-
'chunked 1.0,17,23\n'
472+
'chunked 1.0,17,32\n'
462473
'{"finished":true}test,__mv_test\r\n'
463-
'data,\r\n',
474+
'data,\r\n'
475+
'测试,\r\n'
476+
)
477+
478+
self.assertEqual(
479+
expected,
464480
result.getvalue().decode('utf-8'))
465481

466482
self.assertEqual(command.protocol_version, 2)
@@ -620,11 +636,9 @@ def test_process_scpv2(self):
620636
show_configuration=show_configuration)
621637

622638
execute_metadata = '{"action":"execute","finished":true}'
623-
execute_body = 'test\r\ndata\r\n'
639+
execute_body = 'test\r\ndata\r\n测试\r\n'
624640

625-
ifile = StringIO(
626-
'chunked 1.0,{},0\n{}'.format(len(getinfo_metadata), getinfo_metadata) +
627-
'chunked 1.0,{},{}\n{}{}'.format(len(execute_metadata), len(execute_body), execute_metadata, execute_body))
641+
ifile = build_command_input(getinfo_metadata, execute_metadata, execute_body)
628642

629643
command = TestCommand()
630644
result = BytesIO()
@@ -666,11 +680,9 @@ def test_process_scpv2(self):
666680
show_configuration=('true' if show_configuration is True else 'false'))
667681

668682
execute_metadata = '{"action":"execute","finished":true}'
669-
execute_body = 'action\r\nraise_exception\r\n'
683+
execute_body = 'action\r\nraise_exception\r\n测试\r\n'
670684

671-
ifile = StringIO(
672-
'chunked 1.0,{},0\n{}'.format(len(getinfo_metadata), getinfo_metadata) +
673-
'chunked 1.0,{},{}\n{}{}'.format(len(execute_metadata), len(execute_body), execute_metadata, execute_body))
685+
ifile = build_command_input(getinfo_metadata, execute_metadata, execute_body)
674686

675687
command = TestCommand()
676688
result = BytesIO()

0 commit comments

Comments
 (0)