Skip to content

Commit 6b10262

Browse files
author
hackermd
committed
Specify boundary of multipart messages explicitly
1 parent 9dbcc1e commit 6b10262

File tree

2 files changed

+33
-19
lines changed

2 files changed

+33
-19
lines changed

src/dicomweb_client/api.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import logging
55
import email
66
import six
7+
from urllib3.filepost import choose_boundary
78
from io import BytesIO
89
from collections import OrderedDict
910

@@ -466,7 +467,10 @@ def _http_get_multipart_application_dicom(self, url, **params):
466467
DICOM data sets
467468
468469
'''
469-
content_type = 'multipart/related; type="application/dicom"'
470+
content_type = (
471+
'multipart/related; type="application/dicom"; '
472+
'boundary="--{boundary}"'.format(boundary=choose_boundary())
473+
)
470474
resp = self._http_get(url, params, {'Accept': content_type})
471475
datasets = self._decode_multipart_message(resp.content, resp.headers)
472476
return [pydicom.dcmread(BytesIO(ds)) for ds in datasets]
@@ -488,7 +492,10 @@ def _http_get_multipart_application_octet_stream(self, url, **params):
488492
content of HTTP message body parts
489493
490494
'''
491-
content_type = 'multipart/related; type="application/octet-stream"'
495+
content_type = (
496+
'multipart/related; type="application/octet-stream"; '
497+
'boundary="--{boundary}"'.format(boundary=choose_boundary())
498+
)
492499
resp = self._http_get(url, params, {'Accept': content_type})
493500
return self._decode_multipart_message(resp.content, resp.headers)
494501

@@ -515,8 +522,11 @@ def _http_get_multipart_image(self, url, image_format, **params):
515522
raise ValueError(
516523
'Image format "{}" is not supported.'.format(image_format)
517524
)
518-
content_type = 'multipart/related; type="image/{image_format}"'.format(
519-
image_format=image_format
525+
content_type = (
526+
'multipart/related; type="image/{image_format}"; '
527+
'boundary="--{boundary}"'.format(
528+
image_format=image_format, boundary=choose_boundary()
529+
)
520530
)
521531
resp = self._http_get(url, params, {'Accept': content_type})
522532
return self._decode_multipart_message(resp.content, resp.headers)

src/dicomweb_client/tests/test_api.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def test_search_for_studies(httpserver, client, cache_dir):
1515
assert client.search_for_studies() == parsed_content
1616
request = httpserver.requests[0]
1717
assert request.path == '/studies'
18-
assert request.accept_mimetypes == [('application/dicom+json', 1)]
18+
assert request.accept_mimetypes[0][0] == 'application/dicom+json'
1919

2020

2121
def test_search_for_studies_limit_offset(httpserver, client, cache_dir):
@@ -34,7 +34,7 @@ def test_search_for_studies_limit_offset(httpserver, client, cache_dir):
3434
request.query_string.decode() == 'offset=1&limit=2'
3535
)
3636
assert request.path == '/studies'
37-
assert request.accept_mimetypes == [('application/dicom+json', 1)]
37+
assert request.accept_mimetypes[0][0] == 'application/dicom+json'
3838

3939

4040
def test_search_for_series(httpserver, client, cache_dir):
@@ -47,7 +47,7 @@ def test_search_for_series(httpserver, client, cache_dir):
4747
assert client.search_for_series() == parsed_content
4848
request = httpserver.requests[0]
4949
assert request.path == '/series'
50-
assert request.accept_mimetypes == [('application/dicom+json', 1)]
50+
assert request.accept_mimetypes[0][0] == 'application/dicom+json'
5151

5252

5353
def test_search_for_series_limit_offset(httpserver, client, cache_dir):
@@ -65,7 +65,7 @@ def test_search_for_series_limit_offset(httpserver, client, cache_dir):
6565
request.query_string.decode() == 'offset=1&limit=2'
6666
)
6767
assert request.path == '/studies'
68-
assert request.accept_mimetypes == [('application/dicom+json', 1)]
68+
assert request.accept_mimetypes[0][0] == 'application/dicom+json'
6969

7070

7171
def test_search_for_instances(httpserver, client, cache_dir):
@@ -78,7 +78,7 @@ def test_search_for_instances(httpserver, client, cache_dir):
7878
assert client.search_for_instances() == parsed_content
7979
request = httpserver.requests[0]
8080
assert request.path == '/instances'
81-
assert request.accept_mimetypes == [('application/dicom+json', 1)]
81+
assert request.accept_mimetypes[0][0] == 'application/dicom+json'
8282

8383

8484
def test_search_for_instances_limit_offset(httpserver, client, cache_dir):
@@ -95,7 +95,7 @@ def test_search_for_instances_limit_offset(httpserver, client, cache_dir):
9595
request.query_string.decode() == 'offset=1&limit=2'
9696
)
9797
assert request.path == '/instances'
98-
assert request.accept_mimetypes == [('application/dicom+json', 1)]
98+
assert request.accept_mimetypes[0][0] == 'application/dicom+json'
9999

100100

101101
def test_search_for_instances_includefields(httpserver, client, cache_dir):
@@ -112,7 +112,7 @@ def test_search_for_instances_includefields(httpserver, client, cache_dir):
112112
request.query_string.decode() == query_string_opt_2
113113
)
114114
assert request.path == '/instances'
115-
assert request.accept_mimetypes == [('application/dicom+json', 1)]
115+
assert request.accept_mimetypes[0][0] == 'application/dicom+json'
116116

117117

118118
def test_retrieve_instance_metadata(httpserver, client, cache_dir):
@@ -135,7 +135,7 @@ def test_retrieve_instance_metadata(httpserver, client, cache_dir):
135135
'/{sop_instance_uid}/metadata'.format(**locals())
136136
)
137137
assert request.path == expected_path
138-
assert request.accept_mimetypes == [('application/dicom+json', 1)]
138+
assert request.accept_mimetypes[0][0] == 'application/dicom+json'
139139

140140

141141
def test_retrieve_instance(httpserver, client, cache_dir):
@@ -163,16 +163,17 @@ def test_retrieve_instance(httpserver, client, cache_dir):
163163
'/{sop_instance_uid}'.format(**locals())
164164
)
165165
assert request.path == expected_path
166-
assert request.accept_mimetypes == [
167-
('multipart/related; type="application/dicom"', 1)
168-
]
166+
assert request.accept_mimetypes[0][0][:45] == headers['content-type'][:45]
169167

170168

171169
def test_retrieve_instance_pixeldata_jpeg(httpserver, client, cache_dir):
172170
cache_filename = os.path.join(cache_dir, 'retrieve_instance_pixeldata.jpg')
173171
with open(cache_filename, 'rb') as f:
174172
content = f.read()
175-
headers = {'content-type': 'multipart/related; type="image/jpeg"'}
173+
headers = {
174+
'content-type':
175+
'multipart/related; type="image/jpeg"; boundary="boundary"'
176+
}
176177
httpserver.serve_content(content=content, code=200, headers=headers)
177178
study_instance_uid = '1.2.3'
178179
series_instance_uid = '1.2.4'
@@ -190,14 +191,17 @@ def test_retrieve_instance_pixeldata_jpeg(httpserver, client, cache_dir):
190191
'/{sop_instance_uid}/frames/{frame_list}'.format(**locals())
191192
)
192193
assert request.path == expected_path
193-
assert request.accept_mimetypes == [(headers['content-type'], 1)]
194+
assert request.accept_mimetypes[0][0][:38] == headers['content-type'][:38]
194195

195196

196197
def test_retrieve_instance_pixeldata_jp2(httpserver, client, cache_dir):
197198
cache_filename = os.path.join(cache_dir, 'retrieve_instance_pixeldata.jp2')
198199
with open(cache_filename, 'rb') as f:
199200
content = f.read()
200-
headers = {'content-type': 'multipart/related; type="image/jp2"'}
201+
headers = {
202+
'content-type':
203+
'multipart/related; type="image/jp2"; boundary="boundary"'
204+
}
201205
httpserver.serve_content(content=content, code=200, headers=headers)
202206
study_instance_uid = '1.2.3'
203207
series_instance_uid = '1.2.4'
@@ -215,4 +219,4 @@ def test_retrieve_instance_pixeldata_jp2(httpserver, client, cache_dir):
215219
'/{sop_instance_uid}/frames/{frame_list}'.format(**locals())
216220
)
217221
assert request.path == expected_path
218-
assert request.accept_mimetypes == [(headers['content-type'], 1)]
222+
assert request.accept_mimetypes[0][0][:37] == headers['content-type'][:37]

0 commit comments

Comments
 (0)