Ejemplo n.º 1
0
        public Task Invoke(IDictionary <string, object> env)
        {
            IList <string> warnings = new List <string>();

            if (!TryValidateCall(env, warnings))
            {
                return(TaskHelpers.Completed());
            }

            var           req            = new Request(env);
            Stream        originalStream = req.Body;
            TriggerStream triggerStream  = new TriggerStream(originalStream);

            req.Body = triggerStream;

            // Validate response headers and values on first write.
            bool   responseValidated  = false;
            Action responseValidation = () =>
            {
                if (responseValidated)
                {
                    return;
                }

                responseValidated = true;

                if (!TryValidateResult(env, warnings))
                {
                    return;
                }

                if (warnings.Count > 0)
                {
                    req.Headers["X-OwinValidatorWarning"] = warnings.ToArray();
                }
            };

            triggerStream.OnFirstWrite = responseValidation;

            try
            {
                return(nextApp(env)
                       // Run response validation explicitly in case there was no response data written.
                       .Then(responseValidation)
                       .Catch(errorInfo =>
                {
                    SetFatalResult(env, "6.1", "An asynchronous exception was thrown from the AppFunc: <br>"
                                   + errorInfo.Exception.ToString().Replace(Environment.NewLine, "<br>"));
                    return errorInfo.Handled();
                }));
            }
            catch (Exception ex)
            {
                SetFatalResult(env, "6.1", "A synchronous exception was thrown from the AppFunc: <br>"
                               + ex.ToString().Replace(Environment.NewLine, "<br>"));
                return(TaskHelpers.Completed());
            }
        }
Ejemplo n.º 2
0
        public Task Invoke(IDictionary <string, object> env)
        {
            Request       request         = new Request(env);
            Response      response        = new Response(env);
            Stream        orriginalStream = response.OutputStream;
            TriggerStream triggerStream   = new TriggerStream(orriginalStream);

            response.OutputStream = triggerStream;
            MemoryStream buffer = null;

            triggerStream.OnFirstWrite = () =>
            {
                if (IsStatusWithNoNoEntityBody(response.StatusCode) ||
                    response.Headers.ContainsKey("Content-Length") ||
                    response.Headers.ContainsKey("Transfer-Encoding"))
                {
                    return;
                }

                // Buffer
                buffer = new MemoryStream();
                triggerStream.InnerStream = buffer;
            };

            env[OwinConstants.ResponseBody] = triggerStream;

            return(nextApp(env).Then(() =>
            {
                if (buffer != null)
                {
                    if (buffer.Length == 0)
                    {
                        response.Headers.SetHeader("Content-Length", "0");
                    }
                    else
                    {
                        response.Headers.SetHeader("Content-Length", buffer.Length.ToString(CultureInfo.InvariantCulture));

                        // Suppress the body for HEAD requests.
                        if (!"HEAD".Equals(request.Method, StringComparison.OrdinalIgnoreCase))
                        {
                            buffer.Seek(0, SeekOrigin.Begin);
                            return buffer.CopyToAsync(orriginalStream);
                        }
                    }
                }
                else if (!IsStatusWithNoNoEntityBody(response.StatusCode) &&
                         !response.Headers.ContainsKey("Content-Length") &&
                         !response.Headers.ContainsKey("Transfer-Encoding"))
                {
                    // There were no Writes.
                    response.Headers.SetHeader("Content-Length", "0");
                }
                return TaskHelpers.Completed();
            }));
        }
Ejemplo n.º 3
0
        public Task Invoke(IDictionary<string, object> env)
        {
            Request request = new Request(env);
            Response response = new Response(env);
            Stream orriginalStream = response.OutputStream;
            TriggerStream triggerStream = new TriggerStream(orriginalStream);
            response.OutputStream = triggerStream;
            MemoryStream buffer = null;

            triggerStream.OnFirstWrite = () =>
            {
                if (IsStatusWithNoNoEntityBody(response.StatusCode)
                    || response.Headers.ContainsKey("Content-Length")
                    || response.Headers.ContainsKey("Transfer-Encoding"))
                {
                    return;
                }

                // Buffer
                buffer = new MemoryStream();
                triggerStream.InnerStream = buffer;
            };

            env[OwinConstants.ResponseBody] = triggerStream;

            return nextApp(env).Then(() =>
            {
                if (buffer != null)
                {
                    if (buffer.Length == 0)
                    {
                        response.Headers.SetHeader("Content-Length", "0");
                    }
                    else
                    {
                        response.Headers.SetHeader("Content-Length", buffer.Length.ToString(CultureInfo.InvariantCulture));

                        // Suppress the body for HEAD requests.
                        if (!"HEAD".Equals(request.Method, StringComparison.OrdinalIgnoreCase))
                        {
                            buffer.Seek(0, SeekOrigin.Begin);
                            return buffer.CopyToAsync(orriginalStream);
                        }
                    }
                }
                else if (!IsStatusWithNoNoEntityBody(response.StatusCode)
                    && !response.Headers.ContainsKey("Content-Length")
                    && !response.Headers.ContainsKey("Transfer-Encoding"))
                {
                    // There were no Writes.
                    response.Headers.SetHeader("Content-Length", "0");
                }
                return TaskHelpers.Completed();
            });
        }
Ejemplo n.º 4
0
        public Task Invoke(IDictionary <string, object> env)
        {
            Response      response        = new Response(env);
            Stream        orriginalStream = response.OutputStream;
            TriggerStream triggerStream   = new TriggerStream(orriginalStream);

            response.OutputStream = triggerStream;
            FilterStream filterStream = null;

            triggerStream.OnFirstWrite = () =>
            {
                if (IsStatusWithNoNoEntityBody(response.StatusCode) ||
                    response.Headers.ContainsKey("Content-Length") ||
                    response.Headers.ContainsKey("Transfer-Encoding"))
                {
                    return;
                }

                // Buffer
                response.Headers.SetHeader("Transfer-Encoding", "chunked");
                filterStream = new FilterStream(orriginalStream, OnWriteFilter);
                triggerStream.InnerStream = filterStream;
            };

            env[OwinConstants.ResponseBody] = triggerStream;

            return(nextApp(env).Then(() =>
            {
                if (filterStream != null)
                {
                    // Write the chunked terminator
                    return orriginalStream.WriteAsync(FinalChunk.Array, FinalChunk.Offset, FinalChunk.Count);
                }
                else if (!IsStatusWithNoNoEntityBody(response.StatusCode) &&
                         !response.Headers.ContainsKey("Content-Length") &&
                         !response.Headers.ContainsKey("Transfer-Encoding"))
                {
                    // There were no Writes.
                    response.Headers.SetHeader("Transfer-Encoding", "chunked");
                    return orriginalStream.WriteAsync(FinalChunk.Array, FinalChunk.Offset, FinalChunk.Count);
                }

                return TaskHelpers.Completed();
            }));
        }
Ejemplo n.º 5
0
        public Task Invoke(IDictionary<string, object> env)
        {
            Response response = new Response(env);
            Stream orriginalStream = response.OutputStream;
            TriggerStream triggerStream = new TriggerStream(orriginalStream);
            response.OutputStream = triggerStream;
            FilterStream filterStream = null;
            triggerStream.OnFirstWrite = () =>
            {
                if (IsStatusWithNoNoEntityBody(response.StatusCode)
                    || response.Headers.ContainsKey("Content-Length")
                    || response.Headers.ContainsKey("Transfer-Encoding"))
                {
                    return;
                }

                // Buffer
                response.Headers.SetHeader("Transfer-Encoding", "chunked");
                filterStream = new FilterStream(orriginalStream, OnWriteFilter);
                triggerStream.InnerStream = filterStream;
            };

            env[OwinConstants.ResponseBody] = triggerStream;

            return nextApp(env).Then(() =>
            {
                if (filterStream != null)
                {
                    // Write the chunked terminator
                    return orriginalStream.WriteAsync(FinalChunk.Array, FinalChunk.Offset, FinalChunk.Count);
                }
                else if (!IsStatusWithNoNoEntityBody(response.StatusCode)
                    && !response.Headers.ContainsKey("Content-Length")
                    && !response.Headers.ContainsKey("Transfer-Encoding"))
                {
                    // There were no Writes.
                    response.Headers.SetHeader("Transfer-Encoding", "chunked");
                    return orriginalStream.WriteAsync(FinalChunk.Array, FinalChunk.Offset, FinalChunk.Count);
                }

                return TaskHelpers.Completed();
            });
        }
Ejemplo n.º 6
0
        public Task Invoke(IDictionary<string, object> env)
        {
            Stream orriginalStream = env.Get<Stream>(OwinConstants.ResponseBody);
            TriggerStream triggerStream = new TriggerStream(orriginalStream);
            env[OwinConstants.ResponseBody] = triggerStream;

            triggerStream.OnFirstWrite = () =>
            {
                var responseHeaders = env.Get<IDictionary<string, string[]>>(OwinConstants.ResponseHeaders);
                if (!responseHeaders.HasHeader("Content-Type"))
                {
                    responseHeaders.SetHeader("Content-Type", contentType);
                }
            };

            return nextApp(env).Then(() =>
            {
                // Make sure this gets run even if there were no writes.
                triggerStream.OnFirstWrite();
            });
        }
Ejemplo n.º 7
0
        public Task Invoke(IDictionary <string, object> env)
        {
            Stream        orriginalStream = env.Get <Stream>(OwinConstants.ResponseBody);
            TriggerStream triggerStream   = new TriggerStream(orriginalStream);

            env[OwinConstants.ResponseBody] = triggerStream;

            triggerStream.OnFirstWrite = () =>
            {
                var responseHeaders = env.Get <IDictionary <string, string[]> >(OwinConstants.ResponseHeaders);
                if (!responseHeaders.HasHeader("Content-Type"))
                {
                    responseHeaders.SetHeader("Content-Type", contentType);
                }
            };

            return(nextApp(env).Then(() =>
            {
                // Make sure this gets run even if there were no writes.
                triggerStream.OnFirstWrite();
            }));
        }
Ejemplo n.º 8
0
        public Task Invoke(IDictionary<string, object> env)
        {
            var resp = new Response(env);
            Stream orriginalStream = resp.Body;
            TriggerStream triggerStream = new TriggerStream(orriginalStream);
            resp.Body = triggerStream;

            triggerStream.OnFirstWrite = () =>
            {
                var responseHeaders = resp.Headers;
                if (!responseHeaders.HasHeader("Content-Type"))
                {
                    responseHeaders.SetHeader("Content-Type", contentType);
                }
            };

            return nextApp(env).Then(() =>
            {
                // Make sure this gets run even if there were no writes.
                triggerStream.OnFirstWrite();
            });
        }
Ejemplo n.º 9
0
        public Task Invoke(IDictionary <string, object> env)
        {
            var           resp            = new Response(env);
            Stream        orriginalStream = resp.Body;
            TriggerStream triggerStream   = new TriggerStream(orriginalStream);

            resp.Body = triggerStream;

            triggerStream.OnFirstWrite = () =>
            {
                var responseHeaders = resp.Headers;
                if (!responseHeaders.HasHeader("Content-Type"))
                {
                    responseHeaders.SetHeader("Content-Type", contentType);
                }
            };

            return(nextApp(env).Then(() =>
            {
                // Make sure this gets run even if there were no writes.
                triggerStream.OnFirstWrite();
            }));
        }
Ejemplo n.º 10
0
        public Task Invoke(IDictionary<string, object> env)
        {
            // the first non-404 result will the the one to take effect
            // any subsequent apps are not called

            var iter = apps.GetEnumerator();

            TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
            Stream outputStream = env.Get<Stream>(OwinConstants.ResponseBody);

            Action fallback = () => { };
            fallback = () =>
            {
                fallbackApp(env)
                    .Then(() => tcs.TrySetResult(null))
                    .Catch(errorInfo =>
                    {
                        tcs.TrySetException(errorInfo.Exception);
                        return errorInfo.Handled();
                    });
            };

            // Empty list
            if (!iter.MoveNext())
            {
                fallback();
                return tcs.Task;
            }

            Action loop = () => { };
            loop = () =>
            {
                var threadId = Thread.CurrentThread.ManagedThreadId;
                for (var tryAgainOnSameThread = true; tryAgainOnSameThread; )
                {
                    TriggerStream triggerStream = new TriggerStream(outputStream);
                    triggerStream.OnFirstWrite = () =>
                    {
                        if (env.Get<int>(OwinConstants.ResponseStatusCode) == 404)
                        {
                            triggerStream.InnerStream = Stream.Null;
                        }
                    };

                    env[OwinConstants.ResponseBody] = triggerStream;

                    tryAgainOnSameThread = false;
                    iter.Current.Invoke(env)
                        .Then(() =>
                        {
                            if (env.Get<int>(OwinConstants.ResponseStatusCode) != 404)
                            {
                                tcs.TrySetResult(null);
                                return;
                            }

                            // Cleanup and try the next one.
                            env.Get<IDictionary<string, string[]>>(OwinConstants.ResponseHeaders).Clear();
                            env[OwinConstants.ResponseBody] = outputStream;

                            if (iter.MoveNext())
                            {
                                // ReSharper disable AccessToModifiedClosure
                                if (threadId == Thread.CurrentThread.ManagedThreadId)
                                {
                                    tryAgainOnSameThread = true;
                                }
                                else
                                {
                                    loop();
                                }
                                // ReSharper restore AccessToModifiedClosure
                            }
                            else
                            {
                                fallback();
                            }
                        })
                        .Catch(errorInfo =>
                        {
                            tcs.TrySetException(errorInfo.Exception);
                            return errorInfo.Handled();
                        });
                }
                threadId = 0;
            };

            loop();

            return tcs.Task;
        }
Ejemplo n.º 11
0
        public static AppFunc Middleware(AppFunc app)
        {
            return env =>
            {
                Action<Exception, Action<byte[], int, int>> showErrorMessage =
                    (ex, write) =>
                        ErrorPage(env, ex, text =>
                        {
                            var data = Encoding.ASCII.GetBytes(text);
                            write(data, 0, data.Length);
                        });

                var response = new Response(env);
                Func<Exception, Task> showErrorPage = ex =>
                {
                    response.Status = "500 Internal Server Error";
                    response.ContentType = "text/html";
                    showErrorMessage(ex, response.Write);
                    return TaskHelpers.Completed();
                };

                // Don't try to modify the headers after the first write has occurred.
                TriggerStream triggerStream = new TriggerStream(response.Body);
                response.Body = triggerStream;

                bool bodyHasStarted = false;
                triggerStream.OnFirstWrite = () =>
                {
                    bodyHasStarted = true;
                };

                try
                {
                    return app(env)
                        .Catch(errorInfo =>
                        {
                            if (!bodyHasStarted)
                            {
                                showErrorPage(errorInfo.Exception).Wait();
                            }
                            else
                            {
                                showErrorMessage(errorInfo.Exception, triggerStream.Write);
                            }
                            return errorInfo.Handled();
                        });
                }
                catch (Exception exception)
                {
                    if (!bodyHasStarted)
                    {
                        return showErrorPage(exception);
                    }
                    else
                    {
                        showErrorMessage(exception, triggerStream.Write);
                        return TaskHelpers.Completed();
                    }
                }
            };
        }
Ejemplo n.º 12
0
        public Task Invoke(IDictionary <string, object> env)
        {
            // the first non-404 result will the the one to take effect
            // any subsequent apps are not called

            var iter = apps.GetEnumerator();

            TaskCompletionSource <object> tcs = new TaskCompletionSource <object>();
            var    resp         = new Response(env);
            Stream outputStream = resp.Body;

            Action fallback = () => { };

            fallback = () =>
            {
                fallbackApp(env)
                .Then(() => tcs.TrySetResult(null))
                .Catch(errorInfo =>
                {
                    tcs.TrySetException(errorInfo.Exception);
                    return(errorInfo.Handled());
                });
            };

            // Empty list
            if (!iter.MoveNext())
            {
                fallback();
                return(tcs.Task);
            }

            Action loop = () => { };

            loop = () =>
            {
                var threadId = Thread.CurrentThread.ManagedThreadId;
                for (var tryAgainOnSameThread = true; tryAgainOnSameThread;)
                {
                    TriggerStream triggerStream = new TriggerStream(outputStream);
                    triggerStream.OnFirstWrite = () =>
                    {
                        if (resp.StatusCode == 404)
                        {
                            triggerStream.InnerStream = Stream.Null;
                        }
                    };

                    env[OwinConstants.ResponseBody] = triggerStream;

                    tryAgainOnSameThread = false;
                    iter.Current.Invoke(env)
                    .Then(() =>
                    {
                        if (resp.StatusCode != 404)
                        {
                            tcs.TrySetResult(null);
                            return;
                        }

                        // Cleanup and try the next one.
                        resp.Headers.Clear();
                        resp.Body = outputStream;

                        if (iter.MoveNext())
                        {
                            // ReSharper disable AccessToModifiedClosure
                            if (threadId == Thread.CurrentThread.ManagedThreadId)
                            {
                                tryAgainOnSameThread = true;
                            }
                            else
                            {
                                loop();
                            }
                            // ReSharper restore AccessToModifiedClosure
                        }
                        else
                        {
                            fallback();
                        }
                    })
                    .Catch(errorInfo =>
                    {
                        tcs.TrySetException(errorInfo.Exception);
                        return(errorInfo.Handled());
                    });
                }
                threadId = 0;
            };

            loop();

            return(tcs.Task);
        }
Ejemplo n.º 13
0
 /// <inheritdoc/>
 public void Execute()
 {
     TriggerStream.EmitValue(true);
 }
Ejemplo n.º 14
0
 /// <inheritdoc/>
 public void Start()
 {
     TriggerStream.Start();
     EnabledStream.Start();
 }
Ejemplo n.º 15
0
        public static AppFunc Middleware(AppFunc app)
        {
            return(env =>
            {
                Action <Exception, Action <byte[], int, int> > showErrorMessage =
                    (ex, write) =>
                    ErrorPage(env, ex, text =>
                {
                    var data = Encoding.ASCII.GetBytes(text);
                    write(data, 0, data.Length);
                });

                Func <Exception, Task> showErrorPage = ex =>
                {
                    var response = new Response(env)
                    {
                        Status = "500 Internal Server Error", ContentType = "text/html"
                    };
                    showErrorMessage(ex, response.Write);
                    return response.EndAsync();
                };

                // Don't try to modify the headers after the first write has occurred.
                TriggerStream triggerStream = new TriggerStream(env.Get <Stream>(OwinConstants.ResponseBody));
                env[OwinConstants.ResponseBody] = triggerStream;

                bool bodyHasStarted = false;
                triggerStream.OnFirstWrite = () =>
                {
                    bodyHasStarted = true;
                };

                try
                {
                    return app(env)
                    .Catch(errorInfo =>
                    {
                        if (!bodyHasStarted)
                        {
                            showErrorPage(errorInfo.Exception).Wait();
                        }
                        else
                        {
                            showErrorMessage(errorInfo.Exception, triggerStream.Write);
                        }
                        return errorInfo.Handled();
                    });
                }
                catch (Exception exception)
                {
                    if (!bodyHasStarted)
                    {
                        return showErrorPage(exception);
                    }
                    else
                    {
                        showErrorMessage(exception, triggerStream.Write);
                        return TaskHelpers.Completed();
                    }
                }
            });
        }
Ejemplo n.º 16
0
        public Task Invoke(IDictionary <string, object> env)
        {
            Request       request         = new Request(env);
            Response      response        = new Response(env);
            Stream        orriginalStream = response.OutputStream;
            TriggerStream triggerStream   = new TriggerStream(orriginalStream);

            response.OutputStream = triggerStream;
            FilterStream filterStream            = null;
            bool         finalizeHeadersExecuted = false;

            Action finalizeHeaders = () =>
            {
                finalizeHeadersExecuted = true;
                if (IsStatusWithNoNoEntityBody(response.StatusCode) ||
                    response.Headers.ContainsKey("Content-Length") ||
                    response.Headers.ContainsKey("Transfer-Encoding"))
                {
                    return;
                }

                // Buffer
                response.Headers.SetHeader("Transfer-Encoding", "chunked");

                if ("HEAD".Equals(request.Method, StringComparison.OrdinalIgnoreCase))
                {
                    // Someone tried to write a body for a HEAD request. Suppress it.
                    triggerStream.InnerStream = Stream.Null;
                }
                else
                {
                    filterStream = new FilterStream(orriginalStream, OnWriteFilter);
                    triggerStream.InnerStream = filterStream;
                }
            };

            // Hook first write
            triggerStream.OnFirstWrite      = finalizeHeaders;
            env[OwinConstants.ResponseBody] = triggerStream;

            // Hook SendFileFunc
            SendFileFunc sendFile = env.Get <SendFileFunc>("sendfile.Func");

            if (sendFile != null)
            {
                SendFileFunc sendFileChunked = (name, offset, count) =>
                {
                    if (!finalizeHeadersExecuted)
                    {
                        finalizeHeaders();
                    }

                    if (filterStream == null)
                    {
                        // Due to headers we are not doing chunked, just pass through.
                        return(sendFile(name, offset, count));
                    }

                    count = count ?? new FileInfo(name).Length - offset;

                    // Insert chunking around the file body
                    ArraySegment <byte> prefix = ChunkPrefix((uint)count);
                    return(orriginalStream.WriteAsync(prefix.Array, prefix.Offset, prefix.Count)
                           .Then(() => orriginalStream.FlushAsync()) // Flush to ensure the data hits the wire before sendFile.
                           .Then(() => sendFile(name, offset, count))
                           .Then(() => orriginalStream.WriteAsync(EndOfChunk.Array, EndOfChunk.Offset, EndOfChunk.Count)));
                };
                env["sendfile.Func"] = sendFileChunked;
            }

            return(nextApp(env).Then(() =>
            {
                if (!finalizeHeadersExecuted)
                {
                    finalizeHeaders();
                }

                if (filterStream != null)
                {
                    // Write the chunked terminator
                    return orriginalStream.WriteAsync(FinalChunk.Array, FinalChunk.Offset, FinalChunk.Count);
                }

                return TaskHelpers.Completed();
            }));
        }
Ejemplo n.º 17
0
        public Task Invoke(IDictionary<string, object> env)
        {
            Request request = new Request(env);
            Response response = new Response(env);
            Stream orriginalStream = response.OutputStream;
            TriggerStream triggerStream = new TriggerStream(orriginalStream);
            response.OutputStream = triggerStream;
            FilterStream filterStream = null;
            bool finalizeHeadersExecuted = false;

            Action finalizeHeaders = () =>
            {
                finalizeHeadersExecuted = true;
                if (IsStatusWithNoNoEntityBody(response.StatusCode)
                    || response.Headers.ContainsKey("Content-Length")
                    || response.Headers.ContainsKey("Transfer-Encoding"))
                {
                    return;
                }

                // Buffer
                response.Headers.SetHeader("Transfer-Encoding", "chunked");

                if ("HEAD".Equals(request.Method, StringComparison.OrdinalIgnoreCase))
                {
                    // Someone tried to write a body for a HEAD request. Suppress it.
                    triggerStream.InnerStream = Stream.Null;
                }
                else
                {
                    filterStream = new FilterStream(orriginalStream, OnWriteFilter);
                    triggerStream.InnerStream = filterStream;
                }
            };

            // Hook first write
            triggerStream.OnFirstWrite = finalizeHeaders;
            env[OwinConstants.ResponseBody] = triggerStream;

            // Hook SendFileFunc
            SendFileFunc sendFile = env.Get<SendFileFunc>("sendfile.Func");
            if (sendFile != null)
            {
                SendFileFunc sendFileChunked = (name, offset, count) =>
                {
                    if (!finalizeHeadersExecuted)
                    {
                        finalizeHeaders();
                    }

                    if (filterStream == null)
                    {
                        // Due to headers we are not doing chunked, just pass through.
                        return sendFile(name, offset, count);
                    }

                    count = count ?? new FileInfo(name).Length - offset;

                    // Insert chunking around the file body
                    ArraySegment<byte> prefix = ChunkPrefix((uint)count);
                    return orriginalStream.WriteAsync(prefix.Array, prefix.Offset, prefix.Count)
                        .Then(() => orriginalStream.FlushAsync()) // Flush to ensure the data hits the wire before sendFile.
                        .Then(() => sendFile(name, offset, count))
                        .Then(() => orriginalStream.WriteAsync(EndOfChunk.Array, EndOfChunk.Offset, EndOfChunk.Count));
                };
                env["sendfile.Func"] = sendFileChunked;
            }

            return nextApp(env).Then(() =>
            {
                if (!finalizeHeadersExecuted)
                {
                    finalizeHeaders();
                }

                if (filterStream != null)
                {
                    // Write the chunked terminator
                    return orriginalStream.WriteAsync(FinalChunk.Array, FinalChunk.Offset, FinalChunk.Count);
                }

                return TaskHelpers.Completed();
            });
        }