diff --git a/fhir/fhir_connector.bal b/fhir/fhir_connector.bal index 333c7ce..608e3af 100644 --- a/fhir/fhir_connector.bal +++ b/fhir/fhir_connector.bal @@ -983,6 +983,31 @@ public isolated client class FHIRConnector { return error(string `${FHIR_CONNECTOR_ERROR}: ${e.message()}`, errorDetails = e); } } + + # Proxies an incoming HTTP request to the FHIR server, with URL rewriting applied when enabled. + # + # + requestUrl - Relative request URL to be forwarded to the configured FHIR server + # + request - Incoming HTTP request to be forwarded as-is + # + return - The upstream HTTP response, with URL rewriting applied when enabled. + @display {label: "Proxy request to FHIR server"} + remote isolated function proxy(@display {label: "Request URL"} string requestUrl, + @display {label: "Incoming Request"} http:Request request) + returns http:Response|FHIRError { + do { + log:printDebug(string `Request URL: ${requestUrl}`); + http:Response result = check self.httpClient->forward(requestUrl, check enrichRequest(request, self.pkjwtHanlder)); + if self.urlRewrite { + return generalRewriteServerUrl(result, self.baseUrl, self.replacementURL); + } + return result; + } on fail error e { + log:printError(string `${FHIR_CONNECTOR_ERROR}: ${e.message()}`, e); + if e is FHIRError { + return e; + } + return error(string `${FHIR_CONNECTOR_ERROR}: ${e.message()}`, errorDetails = e); + } + } } # Waits for the completion of a bulk export file download. diff --git a/fhir/utils.bal b/fhir/utils.bal index d138f24..4b9a5a0 100644 --- a/fhir/utils.bal +++ b/fhir/utils.bal @@ -206,7 +206,7 @@ isolated function getBundleResponse(http:Response response) returns FHIRResponse int statusCode = response.statusCode; json|xml responseBody = check extractResponseBody(response); map responseHeaders = extractHeadersFromResponse(response); - if (is2xx(statusCode)) { + if (is2xx(statusCode)) { FHIRResponse fhirResponse = {httpStatusCode: statusCode, 'resource: responseBody, serverResponseHeaders: responseHeaders}; return fhirResponse; } else { @@ -598,6 +598,69 @@ isolated function rewriteServerUrl(FHIRResponse response, string baseUrl, string } } +// Replaces base url in all headers and payload content of a generic http:Response. +isolated function generalRewriteServerUrl(http:Response response, string baseUrl, string? replacementUrl = ()) returns http:Response|FHIRError { + if replacementUrl is () { + return response; + } + + do { + var rewrite = isolated function(string inputString) returns string { + return re `${baseUrl}`.replaceAll(inputString, replacementUrl); + }; + + // Rewrite all header values (including multi-value headers) + foreach string headerName in response.getHeaderNames() { + string[] values = check response.getHeaders(headerName); + if values.length() > 0 { + response.removeHeader(headerName); + foreach string value in values { + response.addHeader(headerName, rewrite(value)); + } + } + } + + string contentType = ""; + string contentTypeCheck = ""; + string|error contentTypeResult = response.getHeader(http:CONTENT_TYPE); + if contentTypeResult is string { + contentType = contentTypeResult; + contentTypeCheck = contentType.toLowerAscii(); + } + + // Rewrite payload based on type; fallback to text when possible. + if contentTypeCheck.includes("json") { + json payload = check response.getJsonPayload(); + string rewritten = rewrite(payload.toJsonString()); + json rewrittenJson = check rewritten.fromJsonString(); + response.setPayload(rewrittenJson); + return response; + } + + if contentTypeCheck.includes("xml") { + xml payload = check response.getXmlPayload(); + string rewritten = rewrite(payload.toString()); + xml rewrittenXml = check xml:fromString(rewritten); + response.setPayload(rewrittenXml); + return response; + } + + string|error textPayload = response.getTextPayload(); + if textPayload is string { + string rewrittenText = rewrite(textPayload); + if contentType == "" { + response.setTextPayload(rewrittenText); + } else { + response.setTextPayload(rewrittenText, contentType = contentType); + } + } + + return response; + } on fail var e { + return error FHIRConnectorError(string `${FHIR_CONNECTOR_ERROR}: ${e.message()}`, errorDetails = e); + } +} + isolated function constructHttpConfigs(FHIRConnectorConfig|BulkExportConfig config) returns http:ClientConfiguration { http:ClientConfiguration httpConfig = { httpVersion: config.httpVersion,