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

Middleware throws Argument Exception if cached headers conflict with pre-existing response headers #101

Closed
BrianVallelunga opened this issue Feb 2, 2017 · 7 comments
Assignees

Comments

@BrianVallelunga
Copy link

BrianVallelunga commented Feb 2, 2017

I just encountered an error while using ResponseCache in conjunction with the Stackify APM extension on Azure. It seems something is trying to insert a duplicate X-StackifyID header. I'm not sure if it is the extension that's misbehaving, or ResponseCache, or just a combination that hadn't been thought of.

My use of the ResponseCache is pretty trivial: [ResponseCache(Duration = 30)]

The error does not occur every time, but it's pretty easy to reproduce.

exception": "System.ArgumentException: An item with the same key has already been added. Key: X-StackifyID\r\n at System.ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(Object key)\r\n at System.Collections.Generic.Dictionary2.Insert(TKey key, TValue value, Boolean add)\r\n at System.Collections.Generic.Dictionary2.Add(TKey key, TValue value)\r\n at Microsoft.AspNetCore.Server.Kestrel.Internal.Http.FrameResponseHeaders.AddValueFast(String key, StringValues value)\r\n at Microsoft.AspNetCore.Server.Kestrel.Internal.Http.FrameHeaders.System.Collections.Generic.IDictionary<System.String,Microsoft.Extensions.Primitives.StringValues>.Add(String key, StringValues value)\r\n at Microsoft.AspNetCore.Server.Kestrel.Internal.Http.FrameHeaders.System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<System.String,Microsoft.Extensions.Primitives.StringValues>>.Add(KeyValuePair2 item)\r\n at Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware.d__10.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware.d__11.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---

@JunTaoLuo JunTaoLuo self-assigned this Feb 2, 2017
@ctolkien
Copy link

ctolkien commented Feb 2, 2017

I ran into the same issue as well. I had some discussion with the Stackify guys via their support channels as I wasn't sure if the issue was in their code or in this middleware.

@BrianVallelunga
Copy link
Author

I'm also not sure if it is the site extension or their logging extension or their RequestTracerMiddleware. I removed the extension, but still see the issue.

@BrianVallelunga
Copy link
Author

I can confirm the problem is related to adding app.UseMiddleware<StackifyMiddleware.RequestTracerMiddleware>(); to my asp.net core 1.1 app.

@JunTaoLuo
Copy link
Contributor

JunTaoLuo commented Feb 3, 2017

There are a few issues here it seems.

First, response caching middleware assumes no response headers are set when it tries to serve a cached response. It seems like this is not the case here. What seems to be happening is that a preceding middleware is setting the X-StackifyID header on the response. Subsequently, the response caching middleware is causing an exception when it tries to add the same header. This is a bug that should be fixed in the response caching middleware since we should not be causing exceptions.

We are addressing this issue by overwriting pre-existing response headers when serving from cache. Note that the ordering of the middleware operations is wrong in this case. Previous middlewares in the pipeline should wait for until response caching has updated the response headers before making their own modifications, not before.

That said, this also brings into attention a few other issues:

What should be happening here is that the response is cacheable but the X-StackifyID header should probably be stripped from the response. This functionality is defined in the spec using no-cache fields RFC 7234. The issue for adding this feature is #40.

However, since there may be additional modifications that the users want to make on storing a response and serving a cached response. We will investigate what kinds of extensibility we can add to achieve this in #52.

@JunTaoLuo JunTaoLuo added the bug label Feb 3, 2017
@muratg muratg added this to the 2.0.0 milestone Feb 3, 2017
@muratg
Copy link
Contributor

muratg commented Feb 3, 2017

@JunTaoLuo could you file two more bugs (for 1.0.1 and 1.1.1) for patch candidates?

@Eilon this is a low-risk change and since we already have patches approved for ResponseCaching, I think we should consider this one too.

@JunTaoLuo JunTaoLuo changed the title Error adding duplicate key Mitigate argument exceptions by overwriting response headers when serving from cache Feb 3, 2017
@JunTaoLuo JunTaoLuo changed the title Mitigate argument exceptions by overwriting response headers when serving from cache Middleware throws Argument Exception if cached headers conflict with pre-existing response headers Feb 3, 2017
@BrianVallelunga
Copy link
Author

Thanks for the work. It would be great to get this in 1.0 and 1.1. It seems the fix was trivial.

@Eilon
Copy link
Member

Eilon commented Feb 4, 2017

@BrianVallelunga we're going to try to get it into those patch releases if we can.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants