diff --git a/src/Http/Http.Abstractions/src/HttpRequest.cs b/src/Http/Http.Abstractions/src/HttpRequest.cs
index 4c4d0d1af15e..5f32c8c8d39e 100644
--- a/src/Http/Http.Abstractions/src/HttpRequest.cs
+++ b/src/Http/Http.Abstractions/src/HttpRequest.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
+using System.IO.Pipelines;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Routing;
@@ -102,6 +103,11 @@ public abstract class HttpRequest
/// The RequestBody Stream.
public abstract Stream Body { get; set; }
+ ///
+ /// Gets or sets the request body pipe .
+ ///
+ public abstract PipeReader BodyPipe { get; set; }
+
///
/// Checks the Content-Type header for form types.
///
diff --git a/src/Http/Http.Abstractions/src/HttpResponse.cs b/src/Http/Http.Abstractions/src/HttpResponse.cs
index 8a1e5d490829..e5af10fbfa5e 100644
--- a/src/Http/Http.Abstractions/src/HttpResponse.cs
+++ b/src/Http/Http.Abstractions/src/HttpResponse.cs
@@ -3,6 +3,7 @@
using System;
using System.IO;
+using System.IO.Pipelines;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Http
@@ -39,6 +40,11 @@ public abstract class HttpResponse
///
public abstract Stream Body { get; set; }
+ ///
+ /// Gets or sets the response body pipe
+ ///
+ public abstract PipeWriter BodyPipe { get; set; }
+
///
/// Gets or sets the value for the Content-Length response header.
///
diff --git a/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj b/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj
index 2f17e520197a..380a4bd95995 100644
--- a/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj
+++ b/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj
@@ -22,6 +22,7 @@ Microsoft.AspNetCore.Http.HttpResponse
+
diff --git a/src/Http/Http.Features/src/IRequestBodyPipeFeature.cs b/src/Http/Http.Features/src/IRequestBodyPipeFeature.cs
new file mode 100644
index 000000000000..0c996ff6917d
--- /dev/null
+++ b/src/Http/Http.Features/src/IRequestBodyPipeFeature.cs
@@ -0,0 +1,18 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.IO.Pipelines;
+
+namespace Microsoft.AspNetCore.Http.Features
+{
+ ///
+ /// Represents the HttpRequestBody as a PipeReader.
+ ///
+ public interface IRequestBodyPipeFeature
+ {
+ ///
+ /// A representing the request body, if any.
+ ///
+ PipeReader RequestBodyPipe { get; set; }
+ }
+}
diff --git a/src/Http/Http.Features/src/IResponseBodyPipeFeature.cs b/src/Http/Http.Features/src/IResponseBodyPipeFeature.cs
new file mode 100644
index 000000000000..dd8bb798a974
--- /dev/null
+++ b/src/Http/Http.Features/src/IResponseBodyPipeFeature.cs
@@ -0,0 +1,19 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO.Pipelines;
+
+namespace Microsoft.AspNetCore.Http.Features
+{
+ ///
+ /// Represents the HttpResponseBody as a PipeWriter
+ ///
+ public interface IResponseBodyPipeFeature
+ {
+ ///
+ /// A representing the response body, if any.
+ ///
+ PipeWriter ResponseBodyPipe { get; set; }
+ }
+}
diff --git a/src/Http/Http.Features/src/Microsoft.AspNetCore.Http.Features.csproj b/src/Http/Http.Features/src/Microsoft.AspNetCore.Http.Features.csproj
index f1cf8b0b9eee..9b2b7f8f15d9 100644
--- a/src/Http/Http.Features/src/Microsoft.AspNetCore.Http.Features.csproj
+++ b/src/Http/Http.Features/src/Microsoft.AspNetCore.Http.Features.csproj
@@ -11,6 +11,7 @@
+
diff --git a/src/Http/Http/src/Features/RequestBodyPipeFeature.cs b/src/Http/Http/src/Features/RequestBodyPipeFeature.cs
new file mode 100644
index 000000000000..7f66fe9815a1
--- /dev/null
+++ b/src/Http/Http/src/Features/RequestBodyPipeFeature.cs
@@ -0,0 +1,49 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO.Pipelines;
+
+namespace Microsoft.AspNetCore.Http.Features
+{
+ public class RequestBodyPipeFeature : IRequestBodyPipeFeature
+ {
+ private StreamPipeReader _internalPipeReader;
+ private PipeReader _userSetPipeReader;
+ private HttpContext _context;
+
+ public RequestBodyPipeFeature(HttpContext context)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+ _context = context;
+ }
+
+ public PipeReader RequestBodyPipe
+ {
+ get
+ {
+ if (_userSetPipeReader != null)
+ {
+ return _userSetPipeReader;
+ }
+
+ if (_internalPipeReader == null ||
+ !object.ReferenceEquals(_internalPipeReader.InnerStream, _context.Request.Body))
+ {
+ _internalPipeReader = new StreamPipeReader(_context.Request.Body);
+ _context.Response.RegisterForDispose(_internalPipeReader);
+ }
+
+ return _internalPipeReader;
+ }
+ set
+ {
+ _userSetPipeReader = value ?? throw new ArgumentNullException(nameof(value));
+ // TODO set the request body Stream to an adapted pipe https://github.com/aspnet/AspNetCore/issues/3971
+ }
+ }
+ }
+}
diff --git a/src/Http/Http/src/Features/ResponseBodyPipeFeature.cs b/src/Http/Http/src/Features/ResponseBodyPipeFeature.cs
new file mode 100644
index 000000000000..b0d9c8ffc4c4
--- /dev/null
+++ b/src/Http/Http/src/Features/ResponseBodyPipeFeature.cs
@@ -0,0 +1,49 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO.Pipelines;
+
+namespace Microsoft.AspNetCore.Http.Features
+{
+ public class ResponseBodyPipeFeature : IResponseBodyPipeFeature
+ {
+ private StreamPipeWriter _internalPipeWriter;
+ private PipeWriter _userSetPipeWriter;
+ private HttpContext _context;
+
+ public ResponseBodyPipeFeature(HttpContext context)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+ _context = context;
+ }
+
+ public PipeWriter ResponseBodyPipe
+ {
+ get
+ {
+ if (_userSetPipeWriter != null)
+ {
+ return _userSetPipeWriter;
+ }
+
+ if (_internalPipeWriter == null ||
+ !object.ReferenceEquals(_internalPipeWriter.InnerStream, _context.Response.Body))
+ {
+ _internalPipeWriter = new StreamPipeWriter(_context.Response.Body);
+ _context.Response.RegisterForDispose(_internalPipeWriter);
+ }
+
+ return _internalPipeWriter;
+ }
+ set
+ {
+ _userSetPipeWriter = value ?? throw new ArgumentNullException(nameof(value));
+ // TODO set the response body Stream to an adapted pipe https://github.com/aspnet/AspNetCore/issues/3971
+ }
+ }
+ }
+}
diff --git a/src/Http/Http/src/Internal/DefaultHttpRequest.cs b/src/Http/Http/src/Internal/DefaultHttpRequest.cs
index cf8ac92a3b5f..4803942b9351 100644
--- a/src/Http/Http/src/Internal/DefaultHttpRequest.cs
+++ b/src/Http/Http/src/Internal/DefaultHttpRequest.cs
@@ -3,6 +3,7 @@
using System;
using System.IO;
+using System.IO.Pipelines;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features;
@@ -19,6 +20,7 @@ public class DefaultHttpRequest : HttpRequest
private readonly static Func _newFormFeature = r => new FormFeature(r);
private readonly static Func _newRequestCookiesFeature = f => new RequestCookiesFeature(f);
private readonly static Func _newRouteValuesFeature = f => new RouteValuesFeature();
+ private readonly static Func _newRequestBodyPipeFeature = context => new RequestBodyPipeFeature(context);
private HttpContext _context;
private FeatureReferences _features;
@@ -57,6 +59,9 @@ public virtual void Uninitialize()
private IRouteValuesFeature RouteValuesFeature =>
_features.Fetch(ref _features.Cache.RouteValues, _newRouteValuesFeature);
+ private IRequestBodyPipeFeature RequestBodyPipeFeature =>
+ _features.Fetch(ref _features.Cache.BodyPipe, this.HttpContext, _newRequestBodyPipeFeature);
+
public override PathString PathBase
{
get { return new PathString(HttpRequestFeature.PathBase); }
@@ -162,6 +167,12 @@ public override RouteValueDictionary RouteValues
set { RouteValuesFeature.RouteValues = value; }
}
+ public override PipeReader BodyPipe
+ {
+ get { return RequestBodyPipeFeature.RequestBodyPipe; }
+ set { RequestBodyPipeFeature.RequestBodyPipe = value; }
+ }
+
struct FeatureInterfaces
{
public IHttpRequestFeature Request;
@@ -169,6 +180,7 @@ struct FeatureInterfaces
public IFormFeature Form;
public IRequestCookiesFeature Cookies;
public IRouteValuesFeature RouteValues;
+ public IRequestBodyPipeFeature BodyPipe;
}
}
}
diff --git a/src/Http/Http/src/Internal/DefaultHttpResponse.cs b/src/Http/Http/src/Internal/DefaultHttpResponse.cs
index 6a812426d850..b7ac14c25ae2 100644
--- a/src/Http/Http/src/Internal/DefaultHttpResponse.cs
+++ b/src/Http/Http/src/Internal/DefaultHttpResponse.cs
@@ -3,6 +3,7 @@
using System;
using System.IO;
+using System.IO.Pipelines;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Net.Http.Headers;
@@ -14,6 +15,7 @@ public class DefaultHttpResponse : HttpResponse
// Lambdas hoisted to static readonly fields to improve inlining https://github.com/dotnet/roslyn/issues/13624
private readonly static Func _nullResponseFeature = f => null;
private readonly static Func _newResponseCookiesFeature = f => new ResponseCookiesFeature(f);
+ private readonly static Func _newResponseBodyPipeFeature = context => new ResponseBodyPipeFeature(context);
private HttpContext _context;
private FeatureReferences _features;
@@ -41,6 +43,8 @@ public virtual void Uninitialize()
private IResponseCookiesFeature ResponseCookiesFeature =>
_features.Fetch(ref _features.Cache.Cookies, _newResponseCookiesFeature);
+ private IResponseBodyPipeFeature ResponseBodyPipeFeature =>
+ _features.Fetch(ref _features.Cache.BodyPipe, this.HttpContext, _newResponseBodyPipeFeature);
public override HttpContext HttpContext { get { return _context; } }
@@ -96,6 +100,12 @@ public override bool HasStarted
get { return HttpResponseFeature.HasStarted; }
}
+ public override PipeWriter BodyPipe
+ {
+ get { return ResponseBodyPipeFeature.ResponseBodyPipe; }
+ set { ResponseBodyPipeFeature.ResponseBodyPipe = value; }
+ }
+
public override void OnStarting(Func