From 447b770bfabea2fcc0ba649395a33834fa3c94e4 Mon Sep 17 00:00:00 2001 From: chgl Date: Thu, 23 Nov 2023 18:30:47 +0100 Subject: [PATCH] fix: race condition caused by non-thread-safe FhirClient --- .../Pseudonymization/GPas/GPasFhirClient.cs | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/src/FhirPseudonymizer/Pseudonymization/GPas/GPasFhirClient.cs b/src/FhirPseudonymizer/Pseudonymization/GPas/GPasFhirClient.cs index f544dfd..432dac8 100644 --- a/src/FhirPseudonymizer/Pseudonymization/GPas/GPasFhirClient.cs +++ b/src/FhirPseudonymizer/Pseudonymization/GPas/GPasFhirClient.cs @@ -1,4 +1,3 @@ -using System.Text; using FhirPseudonymizer.Config; using Hl7.Fhir.Model; using Hl7.Fhir.Rest; @@ -36,13 +35,7 @@ IMemoryCache originalValueCache { this.logger = logger; - Client = clientFactory.CreateClient("gPAS"); - - FhirClient = new FhirClient( - Client.BaseAddress, - Client, - settings: new() { PreferredFormat = ResourceFormat.Json } - ); + HttpClient = clientFactory.CreateClient("gPAS"); PseudonymCache = pseudonymCache; OriginalValueCache = originalValueCache; @@ -77,14 +70,13 @@ IMemoryCache originalValueCache private IMemoryCache PseudonymCache { get; } private IMemoryCache OriginalValueCache { get; } - private HttpClient Client { get; } + private HttpClient HttpClient { get; } private FhirJsonParser FhirParser { get; } = new(); private FhirJsonSerializer FhirSerializer { get; } = new(); private TimeSpan SlidingExpiration { get; } private TimeSpan AbsoluteExpiration { get; } private Func> GetOrCreatePseudonymForResolver { get; } private Func> GetOriginalValueForResolver { get; } - private FhirClient FhirClient { get; } public async Task GetOrCreatePseudonymFor( string value, @@ -154,7 +146,7 @@ private async Task GetOriginalValueForV1(string pseudonym, string domain ["pseudonym"] = pseudonym }; - var response = await Client.GetAsync( + var response = await HttpClient.GetAsync( QueryHelpers.AddQueryString("$de-pseudonymize", query) ); response.EnsureSuccessStatusCode(); @@ -178,7 +170,7 @@ private async Task GetOriginalValueForV2(string pseudonym, string domain var responseParameters = await RequestGetOriginalValueForV2( pseudonym, domain, - "$de-pseudonymize" + "de-pseudonymize" ); var pseudonymResultSet = responseParameters.Get("pseudonym-result-set").First(); @@ -202,7 +194,7 @@ private async Task GetOriginalValueForV2x(string pseudonym, string domai var responseParameters = await RequestGetOriginalValueForV2( pseudonym, domain, - "$dePseudonymize" + "dePseudonymize" ); var firstResponseParameter = responseParameters.Parameter.FirstOrDefault(); @@ -229,7 +221,7 @@ private async Task GetOrCreatePseudonymForV1(string value, string domain // this currently uses a HttpClient instead of the FhirClient to leverage // Polly, tracing, and metrics support. Once FhirClient allows for overriding the HttpClient, // we can simplify this code a lot: https://github.com/FirelyTeam/firely-net-sdk/issues/1483 - var response = await Client.GetAsync( + var response = await HttpClient.GetAsync( QueryHelpers.AddQueryString("$pseudonymize-allow-create", query) ); response.EnsureSuccessStatusCode(); @@ -280,11 +272,17 @@ private async Task RequestGetOrCreatePseudonymForV2( string operation ) { + using var fhirClient = new FhirClient( + HttpClient.BaseAddress, + HttpClient, + settings: new() { PreferredFormat = ResourceFormat.Json } + ); + var parameters = new Parameters() .Add("target", new FhirString(domain)) .Add("original", new FhirString(value)); - var response = await FhirClient.WholeSystemOperationAsync(operation, parameters); + var response = await fhirClient.WholeSystemOperationAsync(operation, parameters); return response as Parameters; } @@ -295,21 +293,18 @@ private async Task RequestGetOriginalValueForV2( string operation ) { + using var fhirClient = new FhirClient( + HttpClient.BaseAddress, + HttpClient, + settings: new() { PreferredFormat = ResourceFormat.Json } + ); + var parameters = new Parameters() .Add("target", new FhirString(domain)) .Add("pseudonym", new FhirString(pseudonym)); - var parametersBody = await FhirSerializer.SerializeToStringAsync(parameters); - using var content = new StringContent( - parametersBody, - Encoding.UTF8, - "application/fhir+json" - ); - - var response = await Client.PostAsync(operation, content); - response.EnsureSuccessStatusCode(); + var response = await fhirClient.WholeSystemOperationAsync(operation, parameters); - var responseContent = await response.Content.ReadAsStringAsync(); - return FhirParser.Parse(responseContent); + return response as Parameters; } }