public void WebsocketBroadcast()
        {
            Task.Run(async() =>
            {
                string data = client.UploadString($"{Address}/security/GetToken", JsonConvert.SerializeObject(new SecurityUser()
                {
                    Username = AdminUsername,
                    Password = AdminPassword
                }));
                APIWrap <Token> tokenResult = JsonConvert.DeserializeObject <APIWrap <Token> >(data);


                ClientWebSocket socket = new ClientWebSocket();
                await socket.ConnectAsync(new Uri("ws://localhost:9990/websocket"), CancellationToken.None);

                ClientWebSocket socket2 = new ClientWebSocket();
                await socket2.ConnectAsync(new Uri("ws://localhost:9990/adminsocket?t=" + tokenResult.Result.AccessToken), CancellationToken.None);
                await socket2.SendAsync(new ArraySegment <byte>(Encoding.UTF8.GetBytes("Broadcast:AdminPing")), WebSocketMessageType.Text, true, CancellationToken.None);


                byte[] buffer = new byte[1024];
                WebSocketReceiveResult result = await socket.ReceiveAsync(new ArraySegment <byte>(buffer), CancellationToken.None);
                string resp = Encoding.UTF8.GetString(buffer, 0, result.Count);
                Assert.AreEqual(resp, "AdminPing");
            }).Wait();
        }
        public void WebSocketAuthenticated()
        {
            Task.Run(async() =>
            {
                string data = client.UploadString($"{Address}/security/GetToken", JsonConvert.SerializeObject(new SecurityUser()
                {
                    Username = AdminUsername,
                    Password = AdminPassword
                }));
                APIWrap <Token> tokenResult = JsonConvert.DeserializeObject <APIWrap <Token> >(data);

                bool didSuccess = false;
                bool didCrash   = false;
                try
                {
                    ClientWebSocket socket = new ClientWebSocket();
                    await socket.ConnectAsync(new Uri("ws://localhost:9990/adminsocket"), CancellationToken.None);
                    await socket.SendAsync(new ArraySegment <byte>(Encoding.UTF8.GetBytes("Ping")), WebSocketMessageType.Text, true, CancellationToken.None);
                    byte[] buffer = new byte[1024];
                    WebSocketReceiveResult result = await socket.ReceiveAsync(new ArraySegment <byte>(buffer), CancellationToken.None);
                    string resp = Encoding.UTF8.GetString(buffer, 0, result.Count);
                    didSuccess  = true;
                }
                catch (Exception ex)
                {
                    didCrash = true;
                }

                Assert.IsTrue(!didSuccess && didCrash);


                ClientWebSocket socket2 = new ClientWebSocket();
                await socket2.ConnectAsync(new Uri("ws://localhost:9990/adminsocket?t=" + tokenResult.Result.AccessToken), CancellationToken.None);
                await socket2.SendAsync(new ArraySegment <byte>(Encoding.UTF8.GetBytes("Ping")), WebSocketMessageType.Text, true, CancellationToken.None);
                byte[] buffer2 = new byte[1024];
                WebSocketReceiveResult result2 = await socket2.ReceiveAsync(new ArraySegment <byte>(buffer2), CancellationToken.None);
                string resultString            = Encoding.UTF8.GetString(buffer2, 0, result2.Count);

                Assert.AreEqual(resultString, "Pong");
            }).Wait();
        }
        public void Authentication()
        {
            string data = client.DownloadString($"{Address}/controller/AuthTest");

            Assert.AreNotEqual("true", data, $"Server should not allow access to this controller");

            APIWrap result = JsonConvert.DeserializeObject <APIWrap>(data);

            Assert.IsFalse(result.Success, $"Call should not be succesfull");
            Assert.AreEqual(typeof(ForbiddenException).Name, result.Exception.Type, $"Server giving wrong exception");

            data = client.UploadString($"{Address}/security/GetToken", JsonConvert.SerializeObject(new SecurityUser()
            {
                Username = "******",
                Password = "******"
            }));
            APIWrap <Token> tokenResult = JsonConvert.DeserializeObject <APIWrap <Token> >(data);

            Assert.IsTrue(tokenResult.Success, $"Failed GetToken due to [{tokenResult.Exception?.Type}]:{tokenResult.Exception?.Message}");

            data = client.DownloadString($"{Address}/controller/AuthTest?t={tokenResult.Result.AccessToken}");
            Assert.AreEqual("true", data, $"No access given to controller despite authentication");

            data = client.DownloadString($"{Address}/controller/AuthLvl5Test?t={tokenResult.Result.AccessToken}");
            Assert.AreNotEqual("true", data, $"Server should not allow access to this controller");

            result = JsonConvert.DeserializeObject <APIWrap>(data);
            Assert.IsFalse(result.Success, $"Call should not be succesfull");
            Assert.AreEqual(typeof(ForbiddenException).Name, result.Exception.Type, $"Server giving wrong exception");

            data = client.UploadString($"{Address}/security/GetToken", JsonConvert.SerializeObject(new SecurityUser()
            {
                Username = AdminUsername,
                Password = AdminPassword
            }));
            tokenResult = JsonConvert.DeserializeObject <APIWrap <Token> >(data);
            Assert.IsTrue(tokenResult.Success, $"Failed GetToken for admin due to [{tokenResult.Exception?.Type}]:{tokenResult.Exception?.Message}");

            data = client.DownloadString($"{Address}/controller/AuthLvl5Test?t={tokenResult.Result.AccessToken}");
            Assert.AreEqual("true", data, $"No access given to admin controller despite authentication");
        }
        public bool ExecuteController(string methodName, HttpRequest request)
        {
            string mn = methodName.ToLower();

            if (Calls.ContainsKey(methodName))
            {
                if (request.IsClosed)
                {
                    return(true);
                }

                BodyType responseType = Server.DefaultResponseType;

                //Header override
                string accept = request.GetHeader("Accept");
                if (!string.IsNullOrEmpty(accept))
                {
                    switch (accept.ToLower())
                    {
                    case "text/json":
                    case "application/json":
                        responseType = BodyType.JSON;
                        break;

                    case "text/xml":
                    case "application/xml":
                        responseType = BodyType.XML;
                        break;

                    default:
                        //Not supported ResponseType
                        break;
                    }
                }

                try
                {
                    CallDescriptor call = Calls[methodName];

                    //Pre-Controller logic
                    request.Server.PreControllerCheck(request, call);
                    if (request.IsClosed)
                    {
                        return(true);
                    }

                    //With descriptor
                    if (call.Descriptor != null)
                    {
                        responseType = call.Descriptor.ResponseType;
                        if (responseType == BodyType.Undefined)
                        {
                            responseType = Server.DefaultResponseType;
                        }

                        if (call.Descriptor.HasParameters)
                        {
                            foreach (string enforced in call.Descriptor.Parameters)
                            {
                                if (!request.Parameters.ContainsKey(enforced))
                                {
                                    throw new ArgumentException($"Missing parameter {enforced}");
                                }
                            }
                        }
                    }

                    object    result = null;
                    Exception ex     = null;

                    try
                    {
                        if (call.TokenRequirements != null)
                        {
                            if (!request.Authenticated || call.TokenRequirements.LevelRequired > request.AuthenticationLevel)
                            {
                                throw new ForbiddenException("You don't have permission to access this API method");
                            }
                            if (call.TokenRequirements.RequestAttributes != null && call.TokenRequirements.RequestAttributes.Length > 0)
                            {
                                foreach (string attr in call.TokenRequirements.RequestAttributes)
                                {
                                    if (!request.Attributes.Contains(attr))
                                    {
                                        throw new ForbiddenException("You don't have permission to access this API method at this moment");
                                    }
                                }
                            }
                        }
                        //Caching
                        if (call.CacheHeader != null)
                        {
                            switch (call.CacheHeader.Cache)
                            {
                            case CachingType.Cache:
                                request.Response.Headers.Add("cache-control", "max-age=" + call.CacheHeader.Validity.ToString());
                                break;

                            case CachingType.Prevent:
                                request.Response.Headers.Add("cache-control", "no-cache, no-store, must-revalidate");
                                request.Response.Headers.Add("Pragma", "no-cache");
                                request.Response.Headers.Add("Expires", "0");
                                break;
                            }
                        }

                        //Parse Parameters
                        object[] paras = GetParameters(call, request);

                        //Handling
                        result = call.Info.Invoke(GetInstance(request), paras.ToArray());
                        if (request.DisableAutoHandling)
                        {
                            return(true);
                        }
                    }
                    catch (TargetInvocationException tx)
                    {
                        ex = tx.InnerException;
                    }
                    catch (Exception x)
                    {
                        ex = x;
                    }

                    if (!request.IsClosed && (result != null || ex != null))
                    {
                        Type resultType;
                        if (ex != null)
                        {
                            resultType = typeof(Exception);
                            result     = new APIWrap(ex);
                            if (!Server.Debug)
                            {
                                ((APIWrap)result).Exception.StackTrace = "";
                            }
                            if (responseType == BodyType.Raw || responseType == BodyType.Razor)
                            {
                                responseType = Server.DefaultResponseType;
                            }
                            HandleResult(Server, request, call, responseType, result, false);
                        }
                        else
                        {
                            HandleResult(Server, request, call, responseType, result, UseWrap);
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (responseType == BodyType.Razor)
                    {
                        responseType = Server.DefaultResponseType;
                    }

                    request.Write(new APIWrap(ex), responseType);
                }

                if (!request.IsClosed)
                {
                    request.Close();
                }

                return(true);
            }
            else
            {
                return(false);
            }
        }
        private static void HandleResult(HttpServer server, HttpRequest request, CallDescriptor call, BodyType responseType, object result, bool useWrap)
        {
            Type resultType = result.GetType();

            if (useWrap && responseType != BodyType.Raw && responseType != BodyType.Razor)
            {
                result = new APIWrap(result);
            }

            if (!server?.IsAllowedResponse(responseType) ?? false)
            {
                throw new Exceptions.ConfigurationException("Requested response type is not allowed");
            }
            switch (responseType)
            {
            case BodyType.Razor:
                HandleRazor(request, call, result);
                break;

            case BodyType.Raw:
                if (resultType == typeof(byte[]))
                {
                    request.Response.ContentType = "application/octet-stream";
                    request.Write((byte[])result);
                }
                else
                {
                    request.Response.ContentType = "text/plain";
                    request.Write(result.ToString());
                }
                break;

            case BodyType.JSON:
                request.Response.ContentType = "application/json";

                JsonSerializerSettings settings = call.JsonSerialization?.Response;
                if (settings != null)
                {
                    request.Write(JsonConvert.SerializeObject(result, settings));
                }
                else
                {
                    request.Write(JsonConvert.SerializeObject(result));
                }
                break;

            case BodyType.XML:
                if (useWrap)
                {
                    XmlParser.AddSubType(typeof(APIWrap), resultType);
                }
                request.Response.ContentType = "application/xml";
                request.Write(XmlParser.Serialize(result));
                break;

            case BodyType.UrlEncoded:
                throw new NotSupportedException();

            case BodyType.MultipartStream:
                throw new NotSupportedException();
            }
        }