/// <summary>Process the request.</summary> /// <param name="context">The context.</param> /// <returns>An asynchronous result that yields a HttpResponseMessage.</returns> internal static async Task <HttpResponseMessage> Process(HttpContext context) { string fhirServerUrl = ProcessorUtils.GetFhirServerUrlR4(context.Request); if (context.Request.Path.Value.Length > 4) { context.Request.Path = new PathString(context.Request.Path.Value.Substring(3)); } // proxy this call ForwardContext proxiedContext = context.ForwardTo(fhirServerUrl); // send to server and await response HttpResponseMessage response = await proxiedContext.Send().ConfigureAwait(false); // get copies of data when we care switch (context.Request.Method.ToUpperInvariant()) { case "GET": ProcessGet(ref context, ref response); break; default: // ignore break; } // return the originator response, plus any modifications we've done return(response); }
/// <summary>Process the given context.</summary> /// <param name="context">The context.</param> /// <returns>An asynchronous result that yields a HttpResponseMessage.</returns> internal static async Task <HttpResponseMessage> Process(HttpContext context) { // create our response object HttpResponseMessage response = new HttpResponseMessage(); if (ProcessorUtils.IsOperation(context.Request, out string operationName, out string prevComponent)) { response.StatusCode = System.Net.HttpStatusCode.NotImplemented; return(response); } // get copies of data when we care switch (context.Request.Method.ToUpperInvariant()) { case "GET": ProcessGet(ref context, ref response); break; default: // tell client we didn't understand response.StatusCode = System.Net.HttpStatusCode.NotImplemented; break; } // return the originator response, plus any modifications we've done return(response); }
/// <summary>Process an HTTP GET in FHIR R5</summary> /// <param name="context"> [in,out] The context.</param> /// <param name="response">[in,out] The response.</param> internal static void ProcessGet(ref HttpContext context, ref HttpResponseMessage response) { // check for an ID string requestUrl = context.Request.Path; if (requestUrl.EndsWith('/')) { requestUrl = requestUrl.Substring(0, requestUrl.Length - 1); } string id = requestUrl.Substring(requestUrl.LastIndexOf('/') + 1); if (id.ToLowerInvariant() == "subscription") { ProcessorUtils.SerializeR5(ref response, SubscriptionManagerR5.GetSubscriptionsBundle()); } else if (SubscriptionManagerR5.TryGetSubscription(id, out Subscription foundSub)) { ProcessorUtils.SerializeR5(ref response, foundSub); } else { response.StatusCode = HttpStatusCode.NotFound; } }
/// <summary>Process the operation get ws binding token described by response.</summary> /// <param name="context"> [in,out] The context.</param> /// <param name="response"> [in,out] The response.</param> /// <param name="previousComponent">The previous component.</param> internal static void ProcessOperationGetWsBindingToken( ref HttpContext context, ref HttpResponseMessage response, string previousComponent) { List <string> ids = new List <string>(); if (previousComponent != "Subscription") { ids.Add(previousComponent); } else { try { using (TextReader reader = new StreamReader(context.Request.Body)) { string requestContent = reader.ReadToEndAsync().Result; Parameters opParams = _fhirParser.Parse <Parameters>(requestContent); foreach (Parameters.ParameterComponent param in opParams.Parameter) { if (param.Name == "ids") { ids.Add((param.Value as Id).ToString()); } } } } catch (Exception ex) { response.StatusCode = HttpStatusCode.BadRequest; response.Content = new StringContent("Caught exception: " + ex.Message); return; } } foreach (string id in ids) { if (!SubscriptionManagerR4.Exists(id)) { response.StatusCode = HttpStatusCode.BadRequest; response.Content = new StringContent($"Invalid subscription id: {id}"); return; } } SubscriptionWsBindingToken token = SubscriptionWsBindingToken.GetTokenR4(ids); WebsocketManager.RegisterToken(token); Parameters parameters = new Parameters(); parameters.Add("token", new FhirString(token.Token.ToString())); parameters.Add("expiration", new FhirDateTime(new DateTimeOffset(token.ExpiresAt))); parameters.Add("subscriptions", new FhirString(string.Join(',', ids))); ProcessorUtils.SerializeR4(ref response, parameters); }
/// <summary>Process the request.</summary> /// <param name="context">The context.</param> /// <returns>An asynchronous result that yields a HttpResponseMessage.</returns> internal static async Task <HttpResponseMessage> Process(HttpContext context) { string fhirServerUrl = ProcessorUtils.GetFhirServerUrlR4(context.Request); // determine if we need to ask the server for a current version of the resource switch (context.Request.Method) { case "PUT": case "POST": case "DELETE": // figure out if we need to ask the server about this break; default: // don't need to check for existing copy break; } if (context.Request.Path.Value.Length > 4) { context.Request.Path = new PathString(context.Request.Path.Value.Substring(3)); } // proxy this call ForwardContext proxiedContext = context.ForwardTo(fhirServerUrl); // send to server and await response HttpResponseMessage response = await proxiedContext.Send().ConfigureAwait(false); //// get copies of data when we care //switch (context.Request.Method.ToUpperInvariant()) //{ // case "PUT": // case "POST": // // grab the message body to look at // string responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); // // run this Encounter through our Subscription Manager // SubscriptionManager.ProcessEncounter(responseContent, response.Headers.Location); // break; // default: // // just proxy // break; //} // return the results of the proxied call return(response); }
/// <summary>Process the operation topic list R4.</summary> /// <param name="response">[in,out] The response.</param> internal static void ProcessOperationTopicList( ref HttpResponseMessage response) { Parameters topics = new Parameters(); foreach (string topicUrl in SubscriptionTopicManager.GetTopicUrlList()) { topics.Add("subscription-topic-canonical", new Canonical(topicUrl)); } ProcessorUtils.SerializeR4(ref response, topics); }
/// <summary>Process the request.</summary> /// <param name="context">The context.</param> /// <returns>An asynchronous result that yields a HttpResponseMessage.</returns> internal static async Task <HttpResponseMessage> Process(HttpContext context) { // create our response objects HttpResponseMessage response = new HttpResponseMessage(); if (ProcessorUtils.IsOperation(context.Request, out string operationName, out string prevComponent)) { ProcessOperation(ref context, ref response, operationName, prevComponent); return(response); } // get copies of data when we care switch (context.Request.Method.ToUpperInvariant()) { case "GET": ProcessGet(ref context, ref response); break; case "PUT": response.StatusCode = System.Net.HttpStatusCode.NotImplemented; break; case "POST": ProcessPost(ref context, ref response); break; case "DELETE": // ask the subscription manager to deal with this if (SubscriptionManagerR5.HandleDelete(context.Request)) { response.StatusCode = System.Net.HttpStatusCode.NoContent; } else { response.StatusCode = System.Net.HttpStatusCode.InternalServerError; } break; default: // tell client we didn't understand response.StatusCode = System.Net.HttpStatusCode.NotImplemented; break; } // return the originator response, plus any modifications we've done return(response); }
/// <summary>Process the operation status R5.</summary> /// <param name="context"> [in,out] The context.</param> /// <param name="response"> [in,out] The response.</param> /// <param name="previousComponent">The previous component.</param> internal static void ProcessOperationStatus( ref HttpContext context, ref HttpResponseMessage response, string previousComponent) { List <string> ids = new List <string>(); if (previousComponent != "Subscription") { ids.Add(previousComponent); } else { foreach (KeyValuePair <string, StringValues> query in context.Request.Query) { if (query.Key == "ids") { ids.AddRange(query.Value); } } } // create a bundle for this message message Bundle bundle = new Bundle() { Type = Bundle.BundleType.Searchset, Timestamp = new DateTimeOffset(DateTime.Now), Meta = new Meta(), Entry = new List <Bundle.EntryComponent>(), }; foreach (string id in ids) { if (SubscriptionManagerR5.TryGetSubscriptionStatus(id, out SubscriptionStatus status, 0, true)) { bundle.Entry.Add(new Bundle.EntryComponent() { FullUrl = Program.UrlForR5ResourceId(status.TypeName, status.Id), Resource = status, Search = new Bundle.SearchComponent() { Mode = Bundle.SearchEntryMode.Match, }, }); } } ProcessorUtils.SerializeR5(ref response, bundle); }
/// <summary>Process the request.</summary> /// <param name="context">The context.</param> /// <returns>An asynchronous result that yields a HttpResponseMessage.</returns> internal static async Task <HttpResponseMessage> Process(HttpContext context) { string fhirServerUrl = ProcessorUtils.GetFhirServerUrlR4(context.Request); if (context.Request.Path.Value.Length > 4) { context.Request.Path = new PathString(context.Request.Path.Value.Substring(3)); } // context.Request.Headers["Accept-Encoding"] = ""; // proxy this call ForwardContext proxiedContext = context.ForwardTo(fhirServerUrl); // send to server and await response HttpResponseMessage response = await proxiedContext.Send().ConfigureAwait(false); // get copies of data when we care switch (context.Request.Method.ToUpperInvariant()) { case "PUT": case "POST": // grab the message body to look at string responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); if (response.IsSuccessStatusCode) { // run this Encounter through our Subscription Manager SubscriptionManagerR4.ProcessEncounter( responseContent, response.Headers.Location); } break; default: // ignore break; } // return the results of the proxied call return(response); }
/// <summary>Process an R4 metadata GET.</summary> /// <param name="context"> [in,out] The context.</param> /// <param name="response">[in,out] The response.</param> private static void ProcessGet( ref HttpContext context, ref HttpResponseMessage response) { // check for a valid capability statement try { // grab the message body to look at string responseContent = response.Content.ReadAsStringAsync().Result; CapabilityStatement capabilities = _fhirParser.Parse <CapabilityStatement>(responseContent); if (capabilities.Software == null) { capabilities.Software = new CapabilityStatement.SoftwareComponent() { Name = $"Argo-Proxy: {Program.FhirServerUrlR5}", Version = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location).FileVersion.ToString(), }; } else { capabilities.Software.Name = $"Argo-Proxy: {capabilities.Software.Name}"; capabilities.Software.Version = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location).FileVersion.ToString() + ": " + capabilities.Software.Version; } capabilities.Implementation = new CapabilityStatement.ImplementationComponent() { Description = $"Argonaut Subscription Proxy to: {Program.FhirServerUrlR5}", Url = Program.PublicUrl, }; // only support application/fhir+json capabilities.Format = new string[] { "application/fhir+json" }; // make sure Subscription is present bool foundSubscription = false; bool foundWebSocketUrl = false; for (int restIndex = 0; restIndex < capabilities.Rest.Count; restIndex++) { for (int resourceIndex = 0; resourceIndex < capabilities.Rest[restIndex].Resource.Count; resourceIndex++) { switch (capabilities.Rest[restIndex].Resource[resourceIndex].TypeName) { case "Subscription": foundSubscription = true; capabilities.Rest[restIndex].Resource[resourceIndex] = BuildSubscriptionResourceComponent(); break; } } if (capabilities.Rest[restIndex].Extension != null) { for (int extIndex = 0; extIndex < capabilities.Rest[restIndex].Extension.Count; extIndex++) { if (capabilities.Rest[restIndex].Extension[extIndex].Url == ExtensionCapabilityWebsocket) { foundWebSocketUrl = true; capabilities.Rest[restIndex].Extension[extIndex].Value = new Hl7.Fhir.Model.FhirUri(Program.WebsocketUrl); } } } } if (!foundSubscription) { capabilities.Rest[0].Resource.Add(BuildSubscriptionResourceComponent()); } if (!foundWebSocketUrl) { if (capabilities.Rest[0].Extension == null) { capabilities.Rest[0].Extension = new System.Collections.Generic.List <Hl7.Fhir.Model.Extension>(); } capabilities.Rest[0].Extension.Add(new Hl7.Fhir.Model.Extension() { Url = ExtensionCapabilityWebsocket, Value = new Hl7.Fhir.Model.FhirUri(Program.WebsocketUrl), }); } // serialize ProcessorUtils.SerializeR4(ref response, capabilities); } catch (Exception ex) { // write to console Console.WriteLine($"Failed to parse capability statement, {ex.Message}"); } }
/// <summary>Process the get.</summary> /// <param name="context"> [in,out] The context.</param> /// <param name="response">[in,out] The response message.</param> internal static void ProcessGet(ref HttpContext context, ref HttpResponseMessage response) { ProcessorUtils.SerializeR5(ref response, SubscriptionTopicManager.GetTopicsBundle()); }