|
3 | 3 | // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. |
4 | 4 | // ------------------------------------------------------------------------------------------------- |
5 | 5 |
|
| 6 | +using System; |
6 | 7 | using System.Collections.Generic; |
7 | 8 | using System.Collections.Specialized; |
8 | 9 | using System.Linq; |
9 | 10 | using System.Net; |
10 | 11 | using System.Threading.Tasks; |
11 | 12 | using System.Web; |
12 | 13 | using EnsureThat; |
| 14 | +using Hl7.Fhir.Model; |
13 | 15 | using Microsoft.AspNetCore.Http; |
| 16 | +using Microsoft.Extensions.Logging; |
14 | 17 | using Microsoft.Extensions.Primitives; |
| 18 | +using Microsoft.Health.Fhir.Api.Features.ActionResults; |
| 19 | +using Microsoft.Health.Fhir.Core.Extensions; |
15 | 20 | using Microsoft.Health.Fhir.Core.Features.Routing; |
16 | 21 |
|
17 | 22 | namespace Microsoft.Health.Fhir.Api.Features.Routing |
18 | 23 | { |
19 | 24 | public class SearchPostReroutingMiddleware |
20 | 25 | { |
21 | 26 | private readonly RequestDelegate _next; |
| 27 | + private readonly ILogger<SearchPostReroutingMiddleware> _logger; |
22 | 28 |
|
23 | | - public SearchPostReroutingMiddleware(RequestDelegate next) |
| 29 | + public SearchPostReroutingMiddleware(RequestDelegate next, ILogger<SearchPostReroutingMiddleware> logger) |
24 | 30 | { |
25 | 31 | EnsureArg.IsNotNull(next); |
26 | 32 | _next = next; |
| 33 | + _logger = logger; |
27 | 34 | } |
28 | 35 |
|
29 | 36 | public async Task Invoke(HttpContext context) |
30 | 37 | { |
31 | 38 | var request = context.Request; |
32 | 39 |
|
33 | | - if (request != null |
34 | | - && request.Method == "POST" |
35 | | - && request.Path.Value.EndsWith(KnownRoutes.Search, System.StringComparison.OrdinalIgnoreCase)) |
| 40 | + try |
36 | 41 | { |
37 | | - if (request.ContentType is null || request.HasFormContentType) |
| 42 | + if (request != null |
| 43 | + && request.Method == "POST" |
| 44 | + && request.Path.Value.EndsWith(KnownRoutes.Search, System.StringComparison.OrdinalIgnoreCase)) |
38 | 45 | { |
39 | | - if (request.HasFormContentType) |
| 46 | + if (request.ContentType is null || request.HasFormContentType) |
40 | 47 | { |
41 | | - var mergedPairs = GetUniqueFormAndQueryStringKeyValues(HttpUtility.ParseQueryString(request.QueryString.ToString()), request.Form); |
42 | | - request.Query = mergedPairs; |
| 48 | + _logger.LogInformation("Rerouting POST to GET with query parameters from form body."); |
| 49 | + |
| 50 | + if (request.HasFormContentType) |
| 51 | + { |
| 52 | + var mergedPairs = GetUniqueFormAndQueryStringKeyValues(HttpUtility.ParseQueryString(request.QueryString.ToString()), request.Form); |
| 53 | + request.Query = mergedPairs; |
| 54 | + } |
| 55 | + |
| 56 | + request.ContentType = null; |
| 57 | + request.Form = null; |
| 58 | + request.Path = request.Path.Value.Substring(0, request.Path.Value.Length - KnownRoutes.Search.Length); |
| 59 | + request.Method = "GET"; |
43 | 60 | } |
| 61 | + else |
| 62 | + { |
| 63 | + _logger.LogDebug("Rejecting POST with invalid Content-Type."); |
44 | 64 |
|
45 | | - request.ContentType = null; |
46 | | - request.Form = null; |
47 | | - request.Path = request.Path.Value.Substring(0, request.Path.Value.Length - KnownRoutes.Search.Length); |
48 | | - request.Method = "GET"; |
49 | | - } |
50 | | - else |
51 | | - { |
52 | | - context.Response.Clear(); |
53 | | - context.Response.StatusCode = (int)HttpStatusCode.BadRequest; |
54 | | - await context.Response.WriteAsync(Api.Resources.ContentTypeFormUrlEncodedExpected); |
55 | | - return; |
| 65 | + context.Response.Clear(); |
| 66 | + context.Response.StatusCode = (int)HttpStatusCode.BadRequest; |
| 67 | + |
| 68 | + var operationOutcome = new OperationOutcome |
| 69 | + { |
| 70 | + Id = Guid.NewGuid().ToString(), |
| 71 | + Issue = new List<OperationOutcome.IssueComponent>() |
| 72 | + { |
| 73 | + new OperationOutcome.IssueComponent() |
| 74 | + { |
| 75 | + Severity = OperationOutcome.IssueSeverity.Error, |
| 76 | + Code = OperationOutcome.IssueType.Invalid, |
| 77 | + Diagnostics = Api.Resources.ContentTypeFormUrlEncodedExpected, |
| 78 | + }, |
| 79 | + }, |
| 80 | + Meta = new Meta() |
| 81 | + { |
| 82 | + LastUpdated = Clock.UtcNow, |
| 83 | + }, |
| 84 | + }; |
| 85 | + |
| 86 | + await context.Response.WriteAsJsonAsync(operationOutcome); |
| 87 | + return; |
| 88 | + } |
56 | 89 | } |
57 | 90 | } |
| 91 | + catch (Exception ex) |
| 92 | + { |
| 93 | + _logger.LogError(ex, "Error occurred while rerouting POST search to GET."); |
| 94 | + throw; |
| 95 | + } |
58 | 96 |
|
59 | 97 | await _next.Invoke(context); |
60 | 98 | } |
|
0 commit comments