Skip to content
This repository has been archived by the owner on Dec 20, 2018. It is now read-only.

ResponseBuffering middleware #6

Merged
merged 1 commit into from
Aug 13, 2015
Merged

ResponseBuffering middleware #6

merged 1 commit into from
Aug 13, 2015

Conversation

Tratcher
Copy link
Member

aspnet/Hosting#299

This PR seeks to formalize the discussion from https://github.com/aspnet/HttpAbstractions/wiki/Rolling-Notes about how response buffering components should behave. In this case we've implemented a fully buffered response. Buffering is disabled via a feature interface or by calling Flush.

The one notable departure from the notes is that we use Stream.SetLength to truncate/reset the buffer, where Position is just used to move around your write marker.

@davidfowl @lodejard @Eilon

@dnfclas
Copy link

dnfclas commented Jul 31, 2015

Hi @Tratcher, I'm your friendly neighborhood .NET Foundation Pull Request Bot (You can call me DNFBOT). Thanks for your contribution!
You've already signed the contribution license agreement. Thanks!

The agreement was validated by .NET Foundation and real humans are currently evaluating your PR.

TTYL, DNFBOT;

@@ -0,0 +1,16 @@
{
"version": "1.0.0-*",
"description": "Microsoft.AspNet.Buffering Class Library",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Description could use some improvement 😄

@Eilon
Copy link
Member

Eilon commented Aug 2, 2015

Just some fairly small comments, the code overall looks good. I like the new unit tests.

@Tratcher
Copy link
Member Author

Tratcher commented Aug 3, 2015

Open question: Should there be a (configurable) limit on how much data to buffer before disabling buffering and flushing?

@Tratcher
Copy link
Member Author

Tratcher commented Aug 3, 2015

Updated

}
else
{
base.EndWrite(asyncResult);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_innerStream?

@Tratcher Tratcher force-pushed the tratcher/responseBuffer branch from 372df7e to 32e1ecd Compare August 3, 2015 17:12
public static class ResponseBufferingMiddlewareExtensions
{
/// <summary>
/// Enabled full buffering of response bodies. This can be disabled on a per request basis using IHttpBufferingFeature.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure where my comment went... Enables on the first word here.

@Eilon
Copy link
Member

Eilon commented Aug 3, 2015

Looks :shipit: to me.


namespace Microsoft.AspNet.Buffering
{
internal class HttpBufferingFeature : IHttpBufferingFeature
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q : Curious what is the idea for exceptions thrown when serializers throw exceptions(example in MVC)? Like if we know the response is being buffered, then we can send back a friendly error message. But with this interface it doesn't seem to be possible to check 'if' the response is buffered...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can check HttpResponse.HasStarted or HttpResponse.Body.CanSeek to know if the response body is buffered and/or if the headers can still be modified. Then Set Position and SetLength 0 zero to clear the body.

That said, MVC probably shouldn't render serialization exceptions inline. Throw it and let the exception handling logic decide.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'd be surprised if MVC does anything.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do something here for input, but it's easily circumvented. What @Tratcher is suggesting is a better choice than what we have.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe there was also talk of HttpResponse convenience API for that case:

bool HttpResponse.CanClear { get{
  true if Response.Body.CanSeek && !ResponseHeadersSent
}}
void HttpResponse.Clear() {
  reset body and headers.
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since they're very straightforward we should add these methods also, can you do that as this PR?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the wrong repo/project to add them to. I think they'd go into Microsoft.AspNet.Http.Extensions.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ha, d'oh! Oh course.

@kichalla
Copy link
Member

kichalla commented Aug 3, 2015

:shipit:

@Tratcher
Copy link
Member Author

Tratcher commented Aug 3, 2015

@davidfowl @lodejard waiting on an explicit sign-off to confirm the design concepts.


public async Task Invoke(HttpContext httpContext)
{
var originalBufferingFeature = httpContext.GetFeature<IHttpBufferingFeature>();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if httpContext.Response.HasStarted== true, or originalResponseBody.CanSeek == true, then this middleware should probably no-op instead of wrap.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If HasStarted, Invoke shouldn't even be called. Do we have any scenarios where middleware writes to the response and then calls next?

@Tratcher
Copy link
Member Author

Tratcher commented Aug 7, 2015

Updated with Louis's feedback about preventing random access to the buffer. Added a sample.

@Tratcher
Copy link
Member Author

@lodejard

Restrict buffer to reset. Add sample. Cleanup.
@Tratcher Tratcher force-pushed the tratcher/responseBuffer branch from 8c70662 to c91cc89 Compare August 13, 2015 17:08
@Tratcher Tratcher merged commit c91cc89 into dev Aug 13, 2015
@Tratcher Tratcher deleted the tratcher/responseBuffer branch August 13, 2015 17:11
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants