Ejemplo n.º 1
0
        /// <summary>
        /// Modifies our application startup to enable CSRF, and reparse thrown exceptions into messages and status codes.
        /// </summary>
        /// <remarks>
        /// To use this functionality, within every 'form' block, after all the inputs add '@Html.AntiForgeryToken()'.
        /// Then, within your POST reception, call 'this.ValidateCsrfToken();, catch the CsrfValidationException, and handle the result appropriately.
        /// </remarks>
        protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
        {
            base.ApplicationStartup(container, pipelines);
            Csrf.Enable(pipelines);

            pipelines.BeforeRequest += (ctx) =>
            {
                NancyContext context = ctx as NancyContext;
                logger.Info(context.Request.UserHostAddress + ": " + context.Request.Url);

                if (Global.SystemStats.AddCall(context.Request.UserHostAddress))
                {
                    logger.Info($"Throttling a request from {context.Request.UserHostAddress}");
                    return(this.GenerateJsonException(new ExcessiveQueriesException(), HttpStatusCode.TooManyRequests));
                }

                // Technically this is 7.4% over 1 MiB. I'm not going to be pedantic.
                int           maxIterations = 12;
                int           hundredKiB    = 100 * 1024;
                byte[]        hundredK      = new byte[hundredKiB];
                RequestStream requestStream = context.Request.Body;
                for (int i = 0; i < maxIterations; i++)
                {
                    // This unfortunately means we're processing the request stream twice.
                    if (requestStream.Read(hundredK, 0, hundredKiB) != hundredKiB)
                    {
                        // The request is under 1 MiB, so continue processing. Reset the stream so deserializing the JSON works.
                        requestStream.Seek(0, SeekOrigin.Begin);
                        return(null);
                    }
                }

                logger.Info($"Request from {context.Request.UserHostAddress} to {context.Request.Url} over 1 MiB");
                return(this.GenerateJsonException(new ExcessiveNapackException(), HttpStatusCode.BadRequest));
            };

            StaticConfiguration.DisableErrorTraces = false;
            pipelines.OnError += (context, exception) =>
            {
                HttpStatusCode code            = HttpStatusCode.InternalServerError;
                Exception      parsedException = exception as Exception;
                if (parsedException != null)
                {
                    if (!exceptionStatusCodeMapping.TryGetValue(parsedException.GetType(), out code))
                    {
                        code = HttpStatusCode.InternalServerError;
                    }
                }
                else
                {
                    parsedException = new Exception("Unable to decode the detected exception!");
                }

                logger.Warn($"Hit a {parsedException.GetType()} exception: {parsedException.Message}");
                return(this.GenerateJsonException(parsedException, code));
            };
        }
        public static async Task <string> AsStringAsync(this RequestStream request, CancellationToken ct)
        {
            using (var reader = new StreamReader(request))
            {
                var result = await reader.ReadToEndAsync();

                ct.ThrowIfCancellationRequested();
                // set streams position to beginning
                request.Seek(0, SeekOrigin.Begin);
                return(result);
            }
        }