Skip to content

Commit

Permalink
Allow multipart/related media type for retrieved instance transaction (
Browse files Browse the repository at this point in the history
…#735)

* Allow mulipart/related media type for retrieved instance transaction
  • Loading branch information
bcarthic authored Apr 23, 2021
1 parent 68827d4 commit 2434375
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 8 deletions.
4 changes: 4 additions & 0 deletions docs/resources/conformance-statement.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,13 @@ The following `Accept` header(s) are supported for retrieving instances within a
The following `Accept` header(s) are supported for retrieving a specific instance:

- `application/dicom; transfer-syntax=*`
- `multipart/related; type="application/dicom"; transfer-syntax=*`
- `application/dicom;` (when transfer-syntax is not specified, 1.2.840.10008.1.2.1 is used as default)
- `multipart/related; type="application/dicom"` (when transfer-syntax is not specified, 1.2.840.10008.1.2.1 is used as default)
- `application/dicom; transfer-syntax=1.2.840.10008.1.2.1`
- `multipart/related; type="application/dicom"; transfer-syntax=1.2.840.10008.1.2.1`
- `application/dicom; transfer-syntax=1.2.840.10008.1.2.4.90`
- `multipart/related; type="application/dicom"; transfer-syntax=1.2.840.10008.1.2.4.90`

### Retrieve Frames

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using Microsoft.Health.Dicom.Core.Features.Retrieve;
using Microsoft.Health.Dicom.Core.Messages;
using Microsoft.Health.Dicom.Core.Messages.Retrieve;
using Microsoft.Health.Dicom.Core.Web;
using Microsoft.Health.Dicom.Tests.Common;
using Microsoft.IO;
using NSubstitute;
Expand Down Expand Up @@ -187,8 +188,10 @@ await Assert.ThrowsAsync<InstanceNotFoundException>(() => _retrieveResourceServi
DefaultCancellationToken));
}

[Fact]
public async Task GivenStoredInstances_WhenRetrieveRequestForInstance_ThenInstanceIsRetrievedSuccessfully()
[Theory]
[InlineData(PayloadTypes.SinglePart)]
[InlineData(PayloadTypes.MultipartRelated)]
public async Task GivenStoredInstances_WhenRetrieveRequestForInstance_ThenInstanceIsRetrievedSuccessfully(PayloadTypes payloadTypes)
{
// Add multiple instances to validate that we return the requested instance and ignore the other(s).
List<VersionedInstanceIdentifier> versionedInstanceIdentifiers = SetupInstanceIdentifiersList(ResourceType.Instance);
Expand All @@ -202,12 +205,15 @@ public async Task GivenStoredInstances_WhenRetrieveRequestForInstance_ThenInstan
_studyInstanceUid,
_firstSeriesInstanceUid,
_sopInstanceUid,
new[] { AcceptHeaderHelpers.CreateAcceptHeaderForGetInstance() }),
new[] { AcceptHeaderHelpers.CreateAcceptHeaderForGetInstance(payloadTypes: payloadTypes) }),
DefaultCancellationToken);

// Validate response status code and ensure response stream has expected file - it should be equivalent to what the store was set up to return.
ValidateResponseStreams(new List<DicomFile>() { streamAndStoredFile.Key }, response.ResponseStreams);

// Validate content type
Assert.Equal(KnownContentTypes.ApplicationDicom, response.ContentType);

// Dispose created streams.
streamAndStoredFile.Value.Dispose();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class RetrieveTransferSyntaxHandler : IRetrieveTransferSyntaxHandler
{
{ ResourceType.Study, DescriptorsForGetNonFrameResource(PayloadTypes.MultipartRelated) },
{ ResourceType.Series, DescriptorsForGetNonFrameResource(PayloadTypes.MultipartRelated) },
{ ResourceType.Instance, DescriptorsForGetNonFrameResource(PayloadTypes.SinglePart) },
{ ResourceType.Instance, DescriptorsForGetNonFrameResource(PayloadTypes.SinglePartOrMultipartRelated) },
{ ResourceType.Frames, DescriptorsForGetFrame() },
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ public static AcceptHeader CreateAcceptHeaderForGetSeries(string transferSyntax
quality: quality);
}

public static AcceptHeader CreateAcceptHeaderForGetInstance(string transferSyntax = "*", string mediaType = KnownContentTypes.ApplicationDicom, double? quality = null)
public static AcceptHeader CreateAcceptHeaderForGetInstance(string transferSyntax = "*", string mediaType = KnownContentTypes.ApplicationDicom, double? quality = null, PayloadTypes payloadTypes = PayloadTypes.SinglePart)
{
return CreateAcceptHeader(
transferSyntax: transferSyntax,
payloadType: PayloadTypes.SinglePart,
payloadType: payloadTypes,
mediaType: mediaType,
quality: quality);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public partial class RetrieveTransactionResourceTests
[InlineData(FromJPEG2000LosslessToExplicitVRLittleEndianTestFolder, null)]
[InlineData(FromJPEG2000LosslessToExplicitVRLittleEndianTestFolder, "1.2.840.10008.1.2.1")]
[InlineData(FromExplicitVRLittleEndianToJPEG2000LosslessTestFolder, "1.2.840.10008.1.2.4.90")]
public async Task GivenSupportedAcceptHeaders_WhenRetrieveInstance_ThenServerShouldReturnExpectedContent(string testDataFolder, string transferSyntax)
public async Task GivenSinglePartAcceptHeader_WhenRetrieveInstance_ThenServerShouldReturnExpectedContent(string testDataFolder, string transferSyntax)
{
TranscoderTestData transcoderTestData = TranscoderTestDataHelper.GetTestData(testDataFolder);
DicomFile inputDicomFile = DicomFile.Open(transcoderTestData.InputDicomFile);
Expand All @@ -53,7 +53,26 @@ public async Task GivenSupportedAcceptHeaders_WhenRetrieveInstance_ThenServerSho
}

[Theory]
[InlineData(false, DicomWebConstants.ApplicationDicomMediaType, DicomWebConstants.OriginalDicomTransferSyntax)] // use multipe part instead of single part
[InlineData(RequestOriginalContentTestFolder, "*")]
[InlineData(FromJPEG2000LosslessToExplicitVRLittleEndianTestFolder, null)]
[InlineData(FromJPEG2000LosslessToExplicitVRLittleEndianTestFolder, "1.2.840.10008.1.2.1")]
public async Task GivenMultipartAcceptHeader_WhenRetrieveInstance_ThenServerShouldReturnExpectedContent(string testDataFolder, string transferSyntax)
{
TranscoderTestData transcoderTestData = TranscoderTestDataHelper.GetTestData(testDataFolder);
DicomFile inputDicomFile = DicomFile.Open(transcoderTestData.InputDicomFile);
var instanceId = RandomizeInstanceIdentifier(inputDicomFile.Dataset);

await InternalStoreAsync(new[] { inputDicomFile });

var requestUri = new Uri(string.Format(DicomWebConstants.BaseInstanceUriFormat, instanceId.StudyInstanceUid, instanceId.SeriesInstanceUid, instanceId.SopInstanceUid), UriKind.Relative);

using HttpRequestMessage request = new HttpRequestMessageBuilder().Build(requestUri, singlePart: false, DicomWebConstants.ApplicationDicomMediaType, transferSyntax);
using HttpResponseMessage response = await _client.HttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);

Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}

[Theory]
[InlineData(true, DicomWebConstants.ApplicationOctetStreamMediaType, DicomWebConstants.OriginalDicomTransferSyntax)] // unsupported media type image/png
[InlineData(true, DicomWebConstants.ApplicationDicomMediaType, "1.2.840.10008.1.2.4.100")] // unsupported transfer syntax MPEG2
public async Task GivenUnsupportedAcceptHeaders_WhenRetrieveInstance_ThenServerShouldReturnNotAcceptable(bool singlePart, string mediaType, string transferSyntax)
Expand Down

0 comments on commit 2434375

Please sign in to comment.