Skip to content

Commit a3e5967

Browse files
authored
Fix problems in unindexing servlet and documentation (dicoogle#744)
* Clarify and correct documentation around indexing/unindexing operations - the indexing operation does a recursive walk over a URI, but the unindexing operation does not - clarify how to specify multi-value query parameters * Fix unindex servlet in series & study unindexing - fetch the correct parameter list for expansion into queries * Sanitize DICOM UID input in unindex servlet - only accept valid DICOM UIDS in respective query parameters
1 parent 297c1be commit a3e5967

2 files changed

Lines changed: 53 additions & 6 deletions

File tree

dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/UnindexServlet.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.Collection;
2727
import java.util.List;
2828
import java.util.concurrent.ExecutionException;
29+
import java.util.regex.Pattern;
2930
import java.util.stream.Collectors;
3031
import java.util.stream.Stream;
3132
import java.util.stream.StreamSupport;
@@ -90,7 +91,13 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws S
9091
long failed = 0;
9192
long notfound = 0;
9293

93-
Collection<URI> uris = resolveURIs(paramUri, paramSop, paramSeries, paramStudy);
94+
Collection<URI> uris;
95+
try {
96+
uris = resolveURIs(paramUri, paramSop, paramSeries, paramStudy);
97+
} catch (IllegalArgumentException ex) {
98+
ResponseUtil.sendError(resp, 400, ex.getMessage());
99+
return;
100+
}
94101

95102
// if only one entry, do it inline
96103
if (uris.size() <= 1) {
@@ -145,18 +152,30 @@ private static Collection<URI> resolveURIs(String[] paramUri, String[] paramSop,
145152
return Stream.of(paramUri).map(URI::create).collect(Collectors.toList());
146153
}
147154
String attribute = null;
155+
String[] values;
148156
if (paramSop != null) {
149157
attribute = "SOPInstanceUID";
158+
values = paramSop;
150159
} else if (paramSeries != null) {
151160
attribute = "SeriesInstanceUID";
161+
values = paramSeries;
152162
} else if (paramStudy != null) {
153163
attribute = "StudyInstanceUID";
164+
values = paramStudy;
165+
} else {
166+
throw new IllegalArgumentException("No valid parameters to resolve URIs");
154167
}
155168

156169
final String dcmAttribute = attribute;
170+
171+
// validate UIDs
172+
for (String uid: values) {
173+
sanitizeUID(uid);
174+
}
175+
157176
List<String> dicomProviders = ServerSettingsManager.getSettings().getArchiveSettings().getDIMProviders();
158177
if (dicomProviders.isEmpty()) {
159-
return Arrays.stream(paramSop).flatMap(uid -> {
178+
return Arrays.stream(values).flatMap(uid -> {
160179
// translate to URIs
161180
JointQueryTask holder = new JointQueryTask() {
162181
@Override
@@ -175,11 +194,23 @@ public void onCompletion() {}
175194

176195
}
177196
String dicomProvider = dicomProviders.iterator().next();
178-
return Arrays.stream(paramSop).flatMap(uid -> {
197+
return Arrays.stream(values).flatMap(uid -> {
179198
// translate to URIs
180199
QueryInterface dicom = PluginController.getInstance().getQueryProviderByName(dicomProvider, false);
181200

182201
return StreamSupport.stream(dicom.query(dcmAttribute + ":\"" + uid + '"').spliterator(), false);
183202
}).map(r -> r.getURI()).collect(Collectors.toList());
184203
}
204+
205+
private static final Pattern UID_PATTERN = Pattern.compile("[0-9]+(\\.[0-9]+)*");
206+
207+
private static void sanitizeUID(String uid) {
208+
if (uid == null || uid.isEmpty()) {
209+
throw new IllegalArgumentException("UID parameter is null or empty");
210+
}
211+
uid = uid.trim();
212+
if (!UID_PATTERN.matcher(uid).matches()) {
213+
throw new IllegalArgumentException("Invalid DICOM UID");
214+
}
215+
}
185216
}

dicoogle_web_api.yaml

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,8 @@ paths:
629629
required: true
630630
schema:
631631
type: string
632+
explode: true
633+
style: form
632634
- in: query
633635
name: plugin
634636
description: a list of provider plugins
@@ -660,11 +662,15 @@ paths:
660662
- in: query
661663
name: uri
662664
description:
663-
a URI or array of URIs representing the root resource of the files
664-
to be unindexed
665+
A URI or array of URIs representing the files to be unindexed.
666+
Unlike [`addIndexTaskURI`](#/paths/~1management~1tasks~1index/post),
667+
there is no recursive walk
668+
and the URIs must point directly to the files.
665669
required: false
666670
schema:
667671
type: string
672+
explode: true
673+
style: form
668674
- in: query
669675
name: SOPInstanceUID
670676
description:
@@ -673,24 +679,32 @@ paths:
673679
required: false
674680
schema:
675681
type: string
682+
explode: true
683+
style: form
676684
- in: query
677685
name: SeriesInstanceUID
678686
description: a UID or list of UIDs representing the DICOM series to be unindexed
679687
required: false
680688
schema:
681689
type: string
690+
explode: true
691+
style: form
682692
- in: query
683693
name: StudyInstanceUID
684694
description: a UID or list of UIDs representing the DICOM studies to be unindexed
685695
required: false
686696
schema:
687697
type: string
698+
explode: true
699+
style: form
688700
- in: query
689701
name: provider
690702
description: a list of provider plugins
691703
required: false
692704
schema:
693705
type: string
706+
explode: true
707+
style: form
694708
responses:
695709
"200":
696710
description: Successful operation
@@ -701,7 +715,7 @@ paths:
701715
tags:
702716
- Index
703717
summary: Request that the file at the given URI is permanently removed
704-
operationId: addUnindexTaskURI
718+
operationId: addRemoveTaskURI
705719
parameters:
706720
- in: query
707721
name: uri
@@ -711,6 +725,8 @@ paths:
711725
required: true
712726
schema:
713727
type: string
728+
explode: true
729+
style: form
714730
responses:
715731
"200":
716732
description: Successful operation

0 commit comments

Comments
 (0)