/// <summary> /// Perform the dispatching function of the service /// </summary> internal bool Dispatch(RestRequestMessage requestMessage, RestResponseMessage responseMessage) { try { this.m_traceSource.TraceEvent(TraceEventType.Verbose, 0, "Begin service dispatch of {0} {1} > {2}", requestMessage.Method, requestMessage.Url, this.m_service.Name); // Endpoint var ep = this.m_service.Endpoints.FirstOrDefault(o => o.Dispatcher.CanDispatch(requestMessage)); // Find the endpoint if (ep == null) { throw new FaultException(404, "Resource not Found"); } RestOperationContext.Current.ServiceEndpoint = ep; // Apply the policy on the specified context foreach (var pol in this.m_servicePolicies) { RestOperationContext.Current.AddAppliedPolicy(pol); pol.Apply(requestMessage); } return(ep.Dispatcher.Dispatch(this, requestMessage, responseMessage)); } catch (Exception e) { return(this.HandleFault(e, responseMessage)); } }
/// <summary> /// Process the request from the <paramref name="state"/> passed /// on the action. /// </summary> private void DoProcessRequestInternal(Object accept) { { var context = accept as HttpListenerContext; try { RestOperationContext.Current = new RestOperationContext(context); var requestMessage = new RestRequestMessage(context.Request); using (var responseMessage = new RestResponseMessage(context.Response)) { this.m_serviceDispatcher.Dispatch(requestMessage, responseMessage); if (requestMessage.Method.ToLowerInvariant() != "head") { responseMessage.FlushResponseStream(); } } } catch (Exception e) { this.m_traceSource.TraceEvent(TraceEventType.Error, e.HResult, e.ToString()); } finally { RestOperationContext.Current.Dispose(); } } }
/// <summary> /// After receive a request look for the language /// </summary> /// <param name="request"></param> public void AfterReceiveRequest(RestRequestMessage request) { try { RestOperationContext.Current.Data.Add("originalLanguage", Thread.CurrentThread.CurrentUICulture.Name); var langPrincipal = AuthenticationContext.Current.Principal.GetClaimValue(SanteDBClaimTypes.Language); if (langPrincipal != null) { Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = new CultureInfo(langPrincipal); } else if (RestOperationContext.Current.Data.TryGetValue("Session", out object dataSession) && dataSession is ISession session && session.Claims.Any(o => o.Type == SanteDBClaimTypes.Language)) { langPrincipal = session.Claims.First(o => o.Type == SanteDBClaimTypes.Language)?.Value; Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = new CultureInfo(langPrincipal); } else if (request.Headers["Accept-Language"] != null) { var language = request.Headers["Accept-Language"].Split(','); Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = new CultureInfo(language[0]); } if (request.Headers["X-SdbLanguage"] != null) // Language override { var language = request.Headers["X-SdbLanguage"].Split(','); Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = new CultureInfo(language[0]); } RestOperationContext.Current.Data.Add("lang", Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName); }
private void HandleClientDisconnected(RestDataRequestMessage message, ClientDisconnectedMessage messageContent, ref RestResponse response, RestRequestMessage request) { _context.RemoveUserBySessionCredentials(message.SessionCredentials); response.SetSuccessful(true, "ResultFromServerTask"); }
// @TODO: ClientWantsToConnectCustomGameMessage private void HandleRequestJoinCustomGameMessage(RestDataRequestMessage message, RequestJoinCustomGameMessage messageContent, ref RestResponse response, RestRequestMessage request) { User ServerOwner = _context.FindServerHosterBy(messageContent.CustomBattleId); User JoiningUser = _context.FindUserBySessionCredentials(message.SessionCredentials); if (ServerOwner == default || JoiningUser == default) { return; } if (ServerOwner.HostedServer == null) { return; } /*@TODO: * //var result = JoinCustomGameResultMessage.CreateSuccess(new JoinGameData(properties,0,0 )); * ServerOwner.QueuedMessages.Add(new ClientWantsToConnectCustomGameMessage(new PlayerJoinGameData[]{new PlayerJoinGameData(JoiningUser.PlayerData,JoiningUser.PlayerData.LastPlayerName) },msg.Password )); * * response.EnqueueMessage(new RestDataResponseMessage(result)); */ ServerOwner.QueuedMessages.Enqueue(new RestDataResponseMessage( new ClientWantsToConnectCustomGameMessage( new[] { new PlayerJoinGameData(JoiningUser.PlayerData, JoiningUser.PlayerData.LastPlayerName, null) }, messageContent.Password))); response.SetSuccessful(true, "ResultFromServerTask"); }
/// <summary> /// After receiving a request increment the max /// </summary> public void AfterReceiveRequest(RestRequestMessage request) { Interlocked.Increment(ref this.m_currentLoad); if (this.m_currentLoad > this.m_maxConcurrency) { RestOperationContext.Current.OutgoingResponse.Headers.Add("Retry-After", "1200"); throw new FaultException(429, "Too Many Requests"); } }
/// <summary> /// Apply the authorization policy rule /// </summary> public void Apply(RestRequestMessage request) { try { this.m_traceSource.TraceInfo("CheckAccess"); // Http message inbound var httpMessage = RestOperationContext.Current.IncomingRequest; // Get the authorize header String authorization = httpMessage.Headers["Authorization"]; if (authorization == null) { if (httpMessage.HttpMethod == "OPTIONS" || httpMessage.HttpMethod == "PING") { Core.Security.AuthenticationContext.Current = new Core.Security.AuthenticationContext(Core.Security.AuthenticationContext.AnonymousPrincipal); return; } else { throw new SecurityTokenException("Missing Authorization header"); } } // Authorization method var auth = authorization.Split(' ').Select(o => o.Trim()).ToArray(); switch (auth[0].ToLowerInvariant()) { case "bearer": this.CheckBearerAccess(auth[1]); break; case "urn:ietf:params:oauth:token-type:jwt": // Will use JWT authorization this.CheckJwtAccess(auth[1]); break; default: throw new SecurityTokenException("Invalid authentication scheme"); } } catch (UnauthorizedAccessException e) { this.m_traceSource.TraceEvent(EventLevel.Error, "Token Error (From: {0}) : {1}", RestOperationContext.Current.IncomingRequest.RemoteEndPoint, e); throw; } catch (Exception e) { this.m_traceSource.TraceEvent(EventLevel.Error, "Token Error (From: {0}) : {1}", RestOperationContext.Current.IncomingRequest.RemoteEndPoint, e); throw new SecurityTokenException(e.Message, e); } finally { // Disposed context so reset the auth RestOperationContext.Current.Disposed += (o, e) => Core.Security.AuthenticationContext.Current = new Core.Security.AuthenticationContext(Core.Security.AuthenticationContext.AnonymousPrincipal); } }
/// <summary> /// Apply the demand /// </summary> public void Apply(EndpointOperation operation, RestRequestMessage request) { var methInfo = this.m_behaviorType.GetMethod(operation.Description.InvokeMethod.Name, operation.Description.InvokeMethod.GetParameters().Select(p => p.ParameterType).ToArray()); foreach (var demand in methInfo.GetCustomAttributes <DemandAttribute>()) { ApplicationServiceContext.Current.GetService <IPolicyEnforcementService>().Demand(demand.PolicyId); } }
/// <summary> /// After receiving a request /// </summary> public void AfterReceiveRequest(RestRequestMessage request) { var cReq = Interlocked.Increment(ref this.m_requests); if (cReq > this.m_settings.Limit) { throw new LimitExceededException(); } }
/// <summary> /// Apply the actual policy /// </summary> public void Apply(EndpointOperation operation, RestRequestMessage request) { var methInfo = this.m_behaviorType.GetMethod(operation.Description.InvokeMethod.Name, operation.Description.InvokeMethod.GetParameters().Select(p => p.ParameterType).ToArray()); foreach (var ppe in methInfo.GetCustomAttributes <DemandAttribute>()) { new PolicyPermission(System.Security.Permissions.PermissionState.Unrestricted, ppe.PolicyId).Demand(); } }
/// <summary> /// Apply the authorization policy rule /// </summary> public void Apply(RestRequestMessage request) { try { this.m_traceSource.TraceInfo("CheckAccess"); // Http message inbound var httpMessage = RestOperationContext.Current.IncomingRequest; // Get the authorize header String authorization = httpMessage.Headers["Authorization"]; if (authorization == null) { if (httpMessage.HttpMethod == "OPTIONS" || httpMessage.HttpMethod == "PING") { return; } else { throw new SecuritySessionException(SessionExceptionType.NotEstablished, "Missing Authorization header", null); } } // Authorization method var auth = authorization.Split(' ').Select(o => o.Trim()).ToArray(); switch (auth[0].ToLowerInvariant()) { case "bearer": var contextToken = this.CheckBearerAccess(auth[1]); RestOperationContext.Current.Disposed += (o, e) => contextToken.Dispose(); break; default: throw new SecuritySessionException(SessionExceptionType.TokenType, "Invalid authentication scheme", null); } } catch (UnauthorizedAccessException e) { this.m_traceSource.TraceError("Token Error (From: {0}) : {1}", RestOperationContext.Current.IncomingRequest.RemoteEndPoint, e); AuditUtil.AuditNetworkRequestFailure(e, RestOperationContext.Current.IncomingRequest.Url, RestOperationContext.Current.IncomingRequest.Headers, null); throw; } catch (KeyNotFoundException e) { this.m_traceSource.TraceError("Token Error (From: {0}) : {1}", RestOperationContext.Current.IncomingRequest.RemoteEndPoint, e); AuditUtil.AuditNetworkRequestFailure(e, RestOperationContext.Current.IncomingRequest.Url, RestOperationContext.Current.IncomingRequest.Headers, null); throw new SecuritySessionException(SessionExceptionType.NotEstablished, e.Message, e); } catch (Exception e) { this.m_traceSource.TraceError("Token Error (From: {0}) : {1}", RestOperationContext.Current.IncomingRequest.RemoteEndPoint, e); AuditUtil.AuditNetworkRequestFailure(e, RestOperationContext.Current.IncomingRequest.Url, RestOperationContext.Current.IncomingRequest.Headers, null); throw new SecuritySessionException(SessionExceptionType.Other, e.Message, e); } }
/// <summary> /// Apply the policy to the request /// </summary> public void Apply(RestRequestMessage request) { try { this.m_traceSource.TraceInfo("Entering OAuth BasicAuthorizationAccessPolicy"); // Role service var identityService = ApplicationServiceContext.Current.GetService <IApplicationIdentityProviderService>(); var httpRequest = RestOperationContext.Current.IncomingRequest; var authHeader = httpRequest.Headers["Authorization"]; if (String.IsNullOrEmpty(authHeader) || !authHeader.ToLowerInvariant().StartsWith("basic")) { throw new AuthenticationException("Invalid authentication scheme"); } authHeader = authHeader.Substring(6); var b64Data = Encoding.UTF8.GetString(Convert.FromBase64String(authHeader)).Split(':'); if (b64Data.Length != 2) { throw new SecurityException("Malformed HTTP Basic Header"); } var principal = identityService.Authenticate(b64Data[0], b64Data[1]); if (principal == null) { throw new AuthenticationException("Invalid client credentials"); } // Client secret RestOperationContext.Current.Data.Add("symm_secret", b64Data[1]); // If the current principal is set-up then add the identity if not then don't if (AuthenticationContext.Current.Principal == AuthenticationContext.AnonymousPrincipal) { AuthenticationContext.Current = new AuthenticationContext(principal); } else { (AuthenticationContext.Current.Principal as IClaimsPrincipal).AddIdentity(principal.Identity); } // Disposed context so reset the auth RestOperationContext.Current.Disposed += (o, e) => AuthenticationContext.Current = new AuthenticationContext(AuthenticationContext.AnonymousPrincipal); } catch (Exception e) { this.m_traceSource.TraceEvent(EventLevel.Error, e.ToString()); } }
/// <summary> /// After receiving the request /// </summary> /// <param name="request"></param> public void AfterReceiveRequest(RestRequestMessage request) { Guid httpCorrelator = Guid.NewGuid(); this.m_traceSource.TraceEvent(EventLevel.Verbose, "HTTP RQO {0} : {1} {2} ({3}) - {4}", RestOperationContext.Current.IncomingRequest.RemoteEndPoint, request.Method, request.Url, RestOperationContext.Current.IncomingRequest.UserAgent, httpCorrelator); httpCorrelation = new KeyValuePair <Guid, DateTime>(httpCorrelator, DateTime.Now); }
private void HandleGetPlayerBadgesMessage(RestDataRequestMessage message, GetPlayerBadgesMessage messageContent, ref RestResponse response, RestRequestMessage request) { var user = _context.FindUserBySessionCredentials(message.SessionCredentials); if (user == default) { return; } response.FunctionResult = new RestDataFunctionResult(new GetPlayerBadgesMessageResult(new[] { user.CanHost ? "badge_taleworlds_primary_dev" : "" })); response.SetSuccessful(true, "ResultFromServerTask"); }
private void HandleGetServerStatusMessage(RestDataRequestMessage message, GetServerStatusMessage messagecontent, ref RestResponse response, RestRequestMessage request) { var user = _context.FindUserBySessionCredentials(message.SessionCredentials); if (user == default) { return; } response.EnqueueMessage(new RestDataResponseMessage(new ServerStatusMessage(GetServerStatusForUser(user)))); response.SetSuccessful(true, "ResultFromServerTask"); }
/// <summary> /// Determines if the dispatcher can dispatch the supplied request message /// </summary> internal bool CanDispatch(RestRequestMessage requestMessage) { this.m_traceSource.TraceEvent(TraceEventType.Verbose, 0, "EndpointDispatcher.CanDispatch -> {0} (EPRx: {1})", requestMessage.Url, this.m_endpointRegex); // Match the path if (this.m_endpointRegex.IsMatch(requestMessage.Url.ToString())) { requestMessage.OperationPath = this.GetOperationPath(requestMessage.Url); return(true); } else { return(false); } }
/// <summary> /// Deserialize the request /// </summary> public void DeserializeRequest(EndpointOperation operation, RestRequestMessage request, object[] parameters) { try { var httpRequest = RestOperationContext.Current.IncomingRequest; var contentType = httpRequest.Headers["Content-Type"]; for (var pNumber = 0; pNumber < parameters.Length; pNumber++) { var parm = operation.Description.InvokeMethod.GetParameters()[pNumber]; // Simple parameter if (parameters[pNumber] != null) { continue; } // Use XML Serializer if (contentType?.StartsWith("application/fhir+xml") == true) { var parser = new FhirXmlParser(this.m_settings); using (var xr = XmlReader.Create(request.Body)) { parameters[pNumber] = parser.Parse(xr); } } // Use JSON Serializer else if (contentType?.StartsWith("application/fhir+json") == true) { var parser = new FhirJsonParser(this.m_settings); using (var sr = new StreamReader(request.Body)) using (var jr = new JsonTextReader(sr)) { parameters[pNumber] = parser.Parse(jr); } } else if (contentType != null) // TODO: Binaries { throw new InvalidOperationException("Invalid request format"); } } } catch (Exception e) { this.m_traceSource.TraceEvent(EventLevel.Error, e.ToString()); throw; } }
/// <summary> /// After request is received /// </summary> public void AfterReceiveRequest(RestRequestMessage request) { try { // Handle compressed requests var compressionScheme = CompressionUtil.GetCompressionScheme(RestOperationContext.Current.IncomingRequest.Headers["Content-Encoding"]); if (compressionScheme != null) { request.Body = compressionScheme.CreateDecompressionStream(request.Body); } } catch (Exception e) { this.m_traceSource.TraceEvent(EventLevel.Error, e.ToString()); } }
private void HandleEndHostingCustomGameMessage(RestDataRequestMessage message, EndHostingCustomGameMessage messageContent, ref RestResponse response, RestRequestMessage request) { var user = _context.FindUserBySessionCredentials(message.SessionCredentials); if (user != default) { user.HostedServer = null; } response.FunctionResult = new RestDataFunctionResult(new EndHostingCustomGameResult()); response.SetSuccessful(true, "ResultFromServerTask"); }
private void HandleUpdateCharacterMessage(RestDataRequestMessage message, UpdateCharacterMessage messagecontent, ref RestResponse response, RestRequestMessage request) { var user = _context.FindUserBySessionCredentials(message.SessionCredentials); if (user == default) { return; } user.PlayerData.BodyProperties = messagecontent.BodyProperties; user.PlayerData.IsFemale = messagecontent.IsFemale; response.SetSuccessful(true, "ResultFromServerTask"); }
/// <summary> /// Apply the policy to the request message /// </summary> public void Apply(RestRequestMessage request) { var authHeader = request.Headers["Authorization"]; try { // Validate the auth header if (String.IsNullOrEmpty(authHeader) && !"GET".Equals(request.Method, StringComparison.OrdinalIgnoreCase) && !"HEAD".Equals(request.Method, StringComparison.OrdinalIgnoreCase)) { throw new SecurityException("Request is not authorized"); } else if (!String.IsNullOrEmpty(authHeader)) { var tokenized = authHeader.Split(' '); if (!"basic".Equals(tokenized[0], StringComparison.OrdinalIgnoreCase)) { throw new SecurityException("Invalid authorization scheme"); } var authData = Encoding.UTF8.GetString(Convert.FromBase64String(tokenized[1])).Split(':'); if (!2.Equals(authData.Length)) { throw new SecurityException("Invalid authorization header"); } // attempt auth using config var authn = this.Authorize(authData[0], authData[1]); if (authn == null) { throw new SecurityException("Authorization failure"); } RestOperationContext.Current.Data.Add("auth", authn); } } catch (SecurityException) { RestOperationContext.Current.OutgoingResponse.AddHeader("WWW-Authenticate", "basic"); throw; } }
private void HandleResponseCustomGameClientConnectionMessage(RestDataRequestMessage message, ResponseCustomGameClientConnectionMessage messageContent, ref RestResponse response, RestRequestMessage request) { var server = _context.Users.Find(x => x.Id.SessionKey == message.SessionCredentials.SessionKey) .HostedServer; foreach (var joindata in messageContent.PlayerJoinData) { var users = _context.Users.FindAll(usr => joindata.PlayerId.ConvertToPeerId() == usr.Id.PeerId && usr.HostedServer == null); switch (joindata.CustomGameJoinResponse) { case CustomGameJoinResponse.Success: users.ForEach(u => { u.QueuedMessages.Enqueue(new RestDataResponseMessage( JoinCustomGameResultMessage.CreateSuccess(new JoinGameData( new GameServerProperties(server.entry.ServerName, server.entry.Address, server.entry.Port, server.Region, server.entry.GameModule, server.entry.GameType, server.entry.Map, "", "", server.entry.MaxPlayerCount, server.entry.IsOfficial), joindata.PeerIndex, joindata.SessionKey)))); server.PlayerCount++; }); break; default: users.ForEach(u => u.QueuedMessages.Enqueue( new RestDataResponseMessage( JoinCustomGameResultMessage.CreateFailed(joindata.CustomGameJoinResponse)))); break; } } response.SetSuccessful(true, "ResultFromServerTask"); }
/// <summary> /// Dispatch the HttpRequest message to the appropriate service /// </summary> internal bool Dispatch(ServiceDispatcher serviceDispatcher, RestRequestMessage requestMessage, RestResponseMessage responseMessage) { // Allow message inspectors to inspect the message before next stage try { this.m_traceSource.TraceEvent(TraceEventType.Verbose, 0, "Begin endpoint dispatch of {0} {1} > {2}", requestMessage.Method, requestMessage.Url, this.m_serviceEndpoint.Description.Contract); foreach (var mfi in this.m_messageInspector) { mfi.AfterReceiveRequest(requestMessage); } var ops = this.m_serviceEndpoint.Operations.Where(o => o.Dispatcher.CanDispatch(requestMessage)); if (ops.Count() == 0) { throw new FaultException(404, $"Resource not Found - {requestMessage.Url.AbsolutePath}"); } var op = ops.FirstOrDefault(o => requestMessage.Method.ToLowerInvariant() == o.Description.Method.ToLowerInvariant()); if (op == null) { throw new FaultException(405, "Method not permitted"); } RestOperationContext.Current.EndpointOperation = op; op.Dispatcher.Dispatch(serviceDispatcher, requestMessage, responseMessage); // Allow message inspectors to inspect before sending response foreach (var mfi in this.m_messageInspector) { mfi.BeforeSendResponse(responseMessage); } return(true); } catch (Exception e) { this.m_traceSource.TraceEvent(TraceEventType.Error, e.HResult, e.ToString()); return(serviceDispatcher.HandleFault(e, responseMessage)); } }
/// <summary> /// Apply the service policy /// </summary> public void Apply(RestRequestMessage request) { if (request.Headers["X-OIZMagic"] == ApplicationContext.Current.ExecutionUuid.ToString() || request.UserAgent == $"SanteDB-DC {ApplicationContext.Current.ExecutionUuid}" || ApplicationContext.Current.ExecutionUuid.ToString() == ApplicationContext.Current.ConfigurationManager.GetAppSetting("http.bypassMagic")) { ; } else { // Something wierd with the appp, show them the nice message if (request.UserAgent.StartsWith("SanteDB")) { throw new FaultException <String>(403, "Hmm, something went wrong. For security's sake we can't show the information you requested. Perhaps restarting the application will help"); } else // User is using a browser to try and access this? How dare they { RestOperationContext.Current.OutgoingResponse.ContentType = "text/html"; throw new FaultException <Stream>(403, new GZipStream(typeof(AgsMagicServiceBehavior).Assembly.GetManifestResourceStream("SanteDB.DisconnectedClient.Ags.Resources.antihaxor"), SharpCompress.Compressors.CompressionMode.Decompress)); } } }
private void HandleRegisterCustomGameMessage(RestDataRequestMessage restDataRequestMessage, RegisterCustomGameMessage messageContent, ref RestResponse response, RestRequestMessage request) { var user = _context.FindUserBySessionCredentials(restDataRequestMessage.SessionCredentials); if (user == default) { return; } user.HostedServer = new CommunityServerEntry(new GameServerEntry(CustomBattleId.NewGuid(), messageContent.ServerName, HttpContext.Connection.RemoteIpAddress.ToString(), messageContent.Port, "EU", messageContent.GameModule, messageContent.GameType, messageContent.Map, 1, messageContent.MaxPlayerCount, true, !(messageContent.GamePassword == null || messageContent.GamePassword.IsEmpty()))); Console.WriteLine( $"New Server: {HttpContext.Connection.RemoteIpAddress} {messageContent.Port}"); user.ConnectedServer = user.HostedServer.entry.Id; response.FunctionResult = new RestDataFunctionResult(new RegisterCustomGameResult(true)); response.SetSuccessful(true, "ResultFromServerTask"); }
private void HandleLogin(RestDataRequestMessage message, InitializeSession messageContent, ref RestResponse response, RestRequestMessage request) { var session = new SessionCredentials(messageContent.PeerId, SessionKey.NewGuid()); var playerdata = new PlayerData(); playerdata.FillWithNewPlayer(messageContent.PlayerId, new[] { "FreeForAll", "Captain", "Siege", "Duel", "TeamDeathMatch", "FreeForAll" }); playerdata.LastPlayerName = messageContent.PlayerName; playerdata.LastGameTypes = new[] { "Captain" }; var user = new User { Id = session, QueuedMessages = new Queue <RestResponseMessage>(), PlayerData = playerdata }; if (messageContent.PlayerId.IsValidSteamId()) { if (_context.SteamIDS.Contains(messageContent.PlayerId.Id2)) { user.CanHost = true; } } var userStatus = GetServerStatusForUser(user); _context.Users.Add(user); var initializeSessionResponse = new InitializeSessionResponse(playerdata, userStatus ); response.FunctionResult = new RestDataFunctionResult(new LoginResult(session.PeerId, session.SessionKey, initializeSessionResponse)); response.UserCertificate = session.SessionKey.ToByteArray(); response.SetSuccessful(true, "ResultFromServerTask"); }
/// <summary> /// Serialize the request for the operation /// </summary> public void DeserializeRequest(EndpointOperation operation, RestRequestMessage request, object[] parameters) { try { var httpRequest = RestOperationContext.Current.IncomingRequest; string contentTypeHeader = httpRequest.Headers["Content-Type"]; ContentType contentType = null; if (!String.IsNullOrEmpty(contentTypeHeader)) { contentType = new ContentType(contentTypeHeader); } for (int pNumber = 0; pNumber < parameters.Length; pNumber++) { var parm = operation.Description.InvokeMethod.GetParameters()[pNumber]; // TODO: Look for MessageFormatAttribute for override // Simple parameter if (parameters[pNumber] != null) { continue; // dispatcher already populated } else { switch (contentType.MediaType) { case "application/xml": if (!this.m_serializers.TryGetValue(parm.ParameterType, out XmlSerializer serializer)) { serializer = new XmlSerializer(parm.ParameterType); this.m_serializers.TryAdd(parm.ParameterType, serializer); } var requestObject = serializer.Deserialize(request.Body); parameters[pNumber] = requestObject; break; case "application/json": using (var sr = new StreamReader(request.Body)) { JsonSerializer jsz = new JsonSerializer() { TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple, TypeNameHandling = TypeNameHandling.All }; jsz.Converters.Add(new StringEnumConverter()); var dserType = parm.ParameterType; parameters[pNumber] = jsz.Deserialize(sr, dserType); } break; case "application/octet-stream": parameters[pNumber] = request.Body; break; case "application/x-www-form-urlencoded": NameValueCollection nvc = new NameValueCollection(); using (var sr = new StreamReader(request.Body)) { var ptext = sr.ReadToEnd(); var parms = ptext.Split('&'); foreach (var p in parms) { var parmData = p.Split('='); parmData[1] += new string('=', parmData.Length - 2); nvc.Add(WebUtility.UrlDecode(parmData[0]), WebUtility.UrlDecode(parmData[1])); } } parameters[pNumber] = nvc; break; default: throw new InvalidOperationException("Invalid request format"); } } } } catch (Exception e) { this.m_traceSource.TraceEvent(TraceEventType.Error, e.HResult, e.ToString()); throw; } }
/// <summary> /// Implemented below /// </summary> public abstract void DeserializeRequest(EndpointOperation operation, RestRequestMessage request, object[] parameters);
/// <summary> /// Deserialize the request /// </summary> public override void DeserializeRequest(EndpointOperation operation, RestRequestMessage request, object[] parameters) { try { #if DEBUG this.m_traceSource.TraceInfo("Received request from: {0}", RestOperationContext.Current.IncomingRequest.RemoteEndPoint); #endif var httpRequest = RestOperationContext.Current.IncomingRequest; string contentType = httpRequest.Headers["Content-Type"]?.ToLowerInvariant(); for (int pNumber = 0; pNumber < parameters.Length; pNumber++) { var parm = operation.Description.InvokeMethod.GetParameters()[pNumber]; // Simple parameter if (parameters[pNumber] != null) { continue; // dispatcher already populated } // Use XML Serializer else if (contentType?.StartsWith("application/xml") == true) { using (XmlReader bodyReader = XmlReader.Create(request.Body)) { while (bodyReader.NodeType != XmlNodeType.Element) { bodyReader.Read(); } Type eType = s_knownTypes.FirstOrDefault(o => o.GetCustomAttribute <XmlRootAttribute>()?.ElementName == bodyReader.LocalName && o.GetCustomAttribute <XmlRootAttribute>()?.Namespace == bodyReader.NamespaceURI); var serializer = XmlModelSerializerFactory.Current.CreateSerializer(eType); parameters[pNumber] = serializer.Deserialize(request.Body); } } else if (contentType?.StartsWith("application/json+sdb-viewmodel") == true) { var viewModel = httpRequest.Headers["X-SanteDB-ViewModel"] ?? httpRequest.QueryString["_viewModel"]; // Create the view model serializer var viewModelSerializer = new JsonViewModelSerializer(); viewModelSerializer.LoadSerializerAssembly(typeof(ActExtensionViewModelSerializer).Assembly); if (!String.IsNullOrEmpty(viewModel)) { var viewModelDescription = ApplicationContext.Current.GetService <IAppletManagerService>()?.Applets.GetViewModelDescription(viewModel); viewModelSerializer.ViewModel = viewModelDescription; } else { viewModelSerializer.ViewModel = m_defaultViewModel; } using (var sr = new StreamReader(request.Body)) parameters[pNumber] = viewModelSerializer.DeSerialize(sr, parm.ParameterType); } else if (contentType?.StartsWith("application/json") == true) { using (var sr = new StreamReader(request.Body)) using (var jsr = new JsonTextReader(sr)) { JsonSerializer jsz = new JsonSerializer() { SerializationBinder = new ModelSerializationBinder(parm.ParameterType), TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple, TypeNameHandling = TypeNameHandling.All }; jsz.Converters.Add(new StringEnumConverter()); // Can the binder resolve the type from the message? parameters[pNumber] = jsz.Deserialize(jsr, parm.ParameterType); } } else if (contentType == "application/octet-stream") { parameters[pNumber] = request.Body; } else if (contentType == "application/x-www-form-urlencoded") { NameValueCollection nvc = new NameValueCollection(); using (var sr = new StreamReader(request.Body)) { var ptext = sr.ReadToEnd(); var parms = ptext.Split('&'); foreach (var p in parms) { var parmData = p.Split('='); nvc.Add(WebUtility.UrlDecode(parmData[0]), WebUtility.UrlDecode(parmData[1])); } } parameters[pNumber] = nvc; } else if (contentType != null)// TODO: Binaries { throw new InvalidOperationException("Invalid request format"); } } } catch (Exception e) { this.m_traceSource.TraceError("Error de-serializing dispatch request: {0}", e.ToString()); throw; } }
private void HandleUpdateShownBadgeIdMessage(RestDataRequestMessage message, UpdateShownBadgeIdMessage messagecontent, ref RestResponse response, RestRequestMessage request) { var user = _context.FindUserBySessionCredentials(message.SessionCredentials); if (user == default) { return; } user.PlayerData.ShownBadgeId = messagecontent.ShownBadgeId; response.SetSuccessful(true, "ResultFromServerTask"); }