public byte[] SerializeResponse(HttpContext context)
        {
            if (context == null) throw new ArgumentNullException(nameof(context));

            var body = GetBody(context);

            if (body.Length == 0 && context.Response.StatusCode == HttpStatusCode.OK)
            {
                context.Response.StatusCode = HttpStatusCode.NoContent;
                return GeneratePrefix(context.Response);
            }

            context.Response.Headers[HttpHeaderNames.ContentLength] = body.Length.ToString();

            var prefix = GeneratePrefix(context.Response);
            var buffer = new byte[prefix.Length + body.Length];
            Array.Copy(prefix, 0, buffer, 0, prefix.Length);
            Array.Copy(body, 0, buffer, prefix.Length, body.Length);

            return buffer;

            // TODO: Delete if above code is working.
            //var prefix = GeneratePrefix(context.Response);
            ////using (var buffer = new MemoryStream(prefix.Length + body.Length))
            ////{
            ////    buffer.Write(prefix, 0, prefix.Length);

            ////    if (body.Length > 0)
            ////    {
            ////        buffer.Write(body, 0, body.Length);
            ////    }

            ////    return buffer.ToArray();
            ////}
        }
        public void WaitForRequest()
        {
            HttpRequest request;
            if (!TryReceiveHttpRequest(out request))
            {
                _cancellationTokenSource.Cancel();
                return;
            }
            
            var context = new HttpContext(request, new HttpResponse());
            PrepareResponseHeaders(context);

            if (context.Request.HttpVersion != _supportedHttpVersion)
            {
                context.Response.StatusCode = HttpStatusCode.HttpVersionNotSupported;
                SendResponse(context);

                _cancellationTokenSource.Cancel();
                return;
            }

            var isWebSocketRequest = request.Headers.ValueEquals(HttpHeaderNames.Upgrade, "websocket");
            if (isWebSocketRequest)
            {
                UpgradeToWebSocket(context);
            }
            else
            {
                HandleHttpRequest(context);
            }
        }
        private void HandleHttpRequest(HttpContext context)
        {
            ProcessHttpRequest(context);
            SendResponse(context);

            if (context.Response.Headers.GetConnectionMustBeClosed())
            {
                _cancellationTokenSource.Cancel();
            }
        }
        private byte[] GetBody(HttpContext context)
        {
            if (context.Response.StatusCode == HttpStatusCode.NotModified)
            {
                return new byte[0];
            }

            byte[] content = new byte[0];
            if (context.Response.Body != null)
            {
                content = context.Response.Body.ToByteArray();
                context.Response.Headers[HttpHeaderNames.ContentType] = context.Response.Body.MimeType;

                if (context.Request.Headers.GetClientSupportsGzipCompression())
                {
                    content = Compress(content);
                    context.Response.Headers[HttpHeaderNames.ContentEncoding] = "gzip";
                }
            }

            return content;
        }
 private void InvokeHandlerAction(HttpRequestDispatcherAction handler, HttpContext context)
 {
     try
     {
         handler.Handler(context);
     }
     catch (BadRequestException)
     {
         context.Response.StatusCode = HttpStatusCode.BadRequest;
     }
 }
 private string GenerateWebSocketAccept(HttpContext httpContext)
 {
     var webSocketKey = httpContext.Request.Headers[HttpHeaderNames.SecWebSocketKey];
     var responseKey = webSocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
     var responseKeyBuffer = Encoding.ASCII.GetBytes(responseKey).AsBuffer();
     
     var sha1 = HashAlgorithmProvider.OpenAlgorithm("SHA1");
     var sha1Buffer = sha1.HashData(responseKeyBuffer);
     
     return Convert.ToBase64String(sha1Buffer.ToArray());
 }
 private void UpgradeToWebSocket(HttpContext httpContext)
 {
     httpContext.Response.StatusCode = HttpStatusCode.SwitchingProtocols;
     httpContext.Response.Headers[HttpHeaderNames.Connection] = "Upgrade";
     httpContext.Response.Headers[HttpHeaderNames.Upgrade] = "websocket";
     httpContext.Response.Headers[HttpHeaderNames.SecWebSocketAccept] = GenerateWebSocketAccept(httpContext);
     
     SendResponse(httpContext);
     _upgradeToWebSocketSessionCallback(new UpgradedToWebSocketSessionEventArgs(httpContext.Request));
 }
        private async void SendResponse(HttpContext context)
        {
            try
            {
                var response = _responseSerializer.SerializeResponse(context);

                await _client.OutputStream.WriteAsync(response.AsBuffer());
                await _client.OutputStream.FlushAsync();
            }
            catch (IOException)
            {  
            }
        }
        private void PrepareResponseHeaders(HttpContext context)
        {
            context.Response.Headers[HttpHeaderNames.AccessControlAllowOrigin] = "*";

            if (context.Request.Headers.GetConnectionMustBeClosed())
            {
                context.Response.Headers[HttpHeaderNames.Connection] = "close";
            }
        }
        private void ProcessHttpRequest(HttpContext context)
        {
            try
            {
                var eventArgs = new HttpRequestReceivedEventArgs(context);
                _httpRequestReceivedCallback(eventArgs);

                if (!eventArgs.IsHandled)
                {
                    context.Response.StatusCode = HttpStatusCode.NotFound;
                }
            }
            catch (Exception exception)
            {
                if (context != null)
                {
                    context.Response.StatusCode = HttpStatusCode.InternalServerError;
                    context.Response.Body = new JsonBody(JsonSerializer.SerializeException(exception));
                }
            }
        }
        public HttpRequestReceivedEventArgs(HttpContext context)
        {
            if (context == null) throw new ArgumentNullException(nameof(context));

            Context = context;
        }
        private ApiContext CreateApiContext(HttpContext httpContext)
        {
            try
            {
                var request = string.IsNullOrEmpty(httpContext.Request.Body) ? new JObject() : JObject.Parse(httpContext.Request.Body);
                return new ApiContext(httpContext.Request.Uri, request, new JObject());
            }
            catch (Exception)
            {
                Log.Verbose("Received a request with no valid JSON request.");

                return null;
            }
        }
        private void DispatchHttpRequest(HttpContext httpContext)
        {
            var apiContext = CreateApiContext(httpContext);
            if (apiContext == null)
            {
                httpContext.Response.StatusCode = HttpStatusCode.BadRequest;
                return;
            }

            var eventArgs = new ApiRequestReceivedEventArgs(apiContext);
            RequestReceived?.Invoke(this, eventArgs);

            if (!eventArgs.IsHandled)
            {
                httpContext.Response.StatusCode = HttpStatusCode.BadRequest;
                return;
            }

            if (eventArgs.Context.Response == null)
            {
                eventArgs.Context.Response = new JObject();
            }

            httpContext.Response.StatusCode = ConvertResultCode(eventArgs.Context.ResultCode);

            if (apiContext.UseHash)
            {
                var serverHash = GenerateHash(apiContext.Response.ToString());
                eventArgs.Context.Response["$Hash"] = serverHash;

                var serverHashWithQuotes = "\"" + serverHash + "\"";

                string clientHash;
                if (httpContext.Request.Headers.TryGetValue(HttpHeaderNames.IfNoneMatch, out clientHash))
                {
                    if (clientHash.Equals(serverHashWithQuotes))
                    {
                        httpContext.Response.StatusCode = HttpStatusCode.NotModified;
                        return;
                    }
                }

                httpContext.Response.Headers[HttpHeaderNames.ETag] = serverHashWithQuotes;
            }

            httpContext.Response.Body = new JsonBody(eventArgs.Context.Response);
        }