示例#1
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 TaskHelpers.Completed();
                };

                // 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();
                    }
                }
            };
        }
示例#2
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();
            }
        }
示例#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();
            });
        }
示例#4
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();
            });
        }
示例#5
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;
            response.Body = triggerStream;

            // Hook SendFileFunc

            var sendFile = response.SendFileAsync;
            if (sendFile != null)
            {
                response.SendFileAsync = (name, offset, count, cancel) =>
                {
                    if (!finalizeHeadersExecuted)
                    {
                        finalizeHeaders();
                    }

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

                    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, cancel))
                        .Then(() => orriginalStream.WriteAsync(EndOfChunk.Array, EndOfChunk.Offset, EndOfChunk.Count));
                };
            }

            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();
            });
        }
示例#6
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;
        }