Example #1
0
    public async Task TryServeFromCacheAsync_CachedResponseFound_OverwritesExistingHeaders()
    {
        var cache      = new TestResponseCache();
        var sink       = new TestSink();
        var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache, keyProvider: new TestResponseCachingKeyProvider("BaseKey"));
        var context    = TestUtils.CreateTestContext();

        context.HttpContext.Response.Headers["MyHeader"] = "OldValue";
        cache.Set(
            "BaseKey",
            new CachedResponse()
        {
            Headers = new HeaderDictionary()
            {
                { "MyHeader", "NewValue" }
            },
            Body = new CachedResponseBody(new List <byte[]>(0), 0)
        },
            TimeSpan.Zero);

        Assert.True(await middleware.TryServeFromCacheAsync(context));
        Assert.Equal("NewValue", context.HttpContext.Response.Headers["MyHeader"]);
        Assert.Equal(1, cache.GetCount);
        TestUtils.AssertLoggedMessages(
            sink.Writes,
            LoggedMessage.CachedResponseServed);
    }
Example #2
0
    public async Task FinalizeCacheBody_Cache_IfContentLengthAbsent()
    {
        var cache      = new TestResponseCache();
        var sink       = new TestSink();
        var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
        var context    = TestUtils.CreateTestContext();

        context.ShouldCacheResponse = true;
        middleware.ShimResponseStream(context);

        await context.HttpContext.Response.WriteAsync(new string('0', 10));

        context.CachedResponse = new CachedResponse()
        {
            Headers = new HeaderDictionary()
        };
        context.BaseKey = "BaseKey";
        context.CachedResponseValidFor = TimeSpan.FromSeconds(10);

        middleware.FinalizeCacheBody(context);

        Assert.Equal(1, cache.SetCount);
        TestUtils.AssertLoggedMessages(
            sink.Writes,
            LoggedMessage.ResponseCached);
    }
Example #3
0
    public async Task FinalizeCacheBody_DoNotCache_IfContentLengthMismatches(string method)
    {
        var cache      = new TestResponseCache();
        var sink       = new TestSink();
        var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
        var context    = TestUtils.CreateTestContext();

        context.ShouldCacheResponse = true;
        middleware.ShimResponseStream(context);
        context.HttpContext.Response.ContentLength = 9;
        context.HttpContext.Request.Method         = method;

        await context.HttpContext.Response.WriteAsync(new string('0', 10));

        context.CachedResponse         = new CachedResponse();
        context.BaseKey                = "BaseKey";
        context.CachedResponseValidFor = TimeSpan.FromSeconds(10);

        middleware.FinalizeCacheBody(context);

        Assert.Equal(0, cache.SetCount);
        TestUtils.AssertLoggedMessages(
            sink.Writes,
            LoggedMessage.ResponseContentLengthMismatchNotCached);
    }
Example #4
0
    public async Task FinalizeCacheBody_RequestHead_Cache_IfContentLengthPresent_AndBodyAbsentOrOfSameLength(bool includeBody)
    {
        var cache      = new TestResponseCache();
        var sink       = new TestSink();
        var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
        var context    = TestUtils.CreateTestContext();

        context.ShouldCacheResponse = true;
        middleware.ShimResponseStream(context);
        context.HttpContext.Response.ContentLength = 10;
        context.HttpContext.Request.Method         = "HEAD";

        if (includeBody)
        {
            // A response to HEAD should not include a body, but it may be present
            await context.HttpContext.Response.WriteAsync(new string('0', 10));
        }

        context.CachedResponse         = new CachedResponse();
        context.BaseKey                = "BaseKey";
        context.CachedResponseValidFor = TimeSpan.FromSeconds(10);

        middleware.FinalizeCacheBody(context);

        Assert.Equal(1, cache.SetCount);
        TestUtils.AssertLoggedMessages(
            sink.Writes,
            LoggedMessage.ResponseCached);
    }
Example #5
0
    public void FinalizeCacheHeadersAsync_UpdateCachedVaryByRules_IfEquivalentToPrevious()
    {
        var cache      = new TestResponseCache();
        var sink       = new TestSink();
        var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
        var context    = TestUtils.CreateTestContext();

        context.HttpContext.Response.Headers.Vary = new StringValues(new[] { "headerA", "HEADERB" });
        context.HttpContext.Features.Set <IResponseCachingFeature>(new ResponseCachingFeature()
        {
            VaryByQueryKeys = new StringValues(new[] { "queryB", "QUERYA" })
        });
        var cachedVaryByRules = new CachedVaryByRules()
        {
            VaryByKeyPrefix = FastGuid.NewGuid().IdString,
            Headers         = new StringValues(new[] { "HEADERA", "HEADERB" }),
            QueryKeys       = new StringValues(new[] { "QUERYA", "QUERYB" })
        };

        context.CachedVaryByRules = cachedVaryByRules;

        middleware.FinalizeCacheHeaders(context);

        // An update to the cache is always made but the entry should be the same
        Assert.Equal(1, cache.SetCount);
        Assert.Same(cachedVaryByRules, context.CachedVaryByRules);
        TestUtils.AssertLoggedMessages(
            sink.Writes,
            LoggedMessage.VaryByRulesUpdated);
    }
Example #6
0
    public void FinalizeCacheHeadersAsync_UpdateCachedVaryByRules_IfNotEquivalentToPrevious()
    {
        var cache      = new TestResponseCache();
        var sink       = new TestSink();
        var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
        var context    = TestUtils.CreateTestContext();

        context.HttpContext.Response.Headers.Vary = new StringValues(new[] { "headerA", "HEADERB", "HEADERc" });
        context.HttpContext.Features.Set <IResponseCachingFeature>(new ResponseCachingFeature()
        {
            VaryByQueryKeys = new StringValues(new[] { "queryB", "QUERYA" })
        });
        var cachedVaryByRules = new CachedVaryByRules()
        {
            Headers   = new StringValues(new[] { "HeaderA", "HeaderB" }),
            QueryKeys = new StringValues(new[] { "QueryA", "QueryB" })
        };

        context.CachedVaryByRules = cachedVaryByRules;

        middleware.FinalizeCacheHeaders(context);

        Assert.Equal(1, cache.SetCount);
        Assert.NotSame(cachedVaryByRules, context.CachedVaryByRules);
        TestUtils.AssertLoggedMessages(
            sink.Writes,
            LoggedMessage.VaryByRulesUpdated);
    }
Example #7
0
    public async Task TryServeFromCacheAsync_VaryByRuleFound_CachedResponseFound_Succeeds()
    {
        var cache      = new TestResponseCache();
        var sink       = new TestSink();
        var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache, keyProvider: new TestResponseCachingKeyProvider("BaseKey", new[] { "VaryKey", "VaryKey2" }));
        var context    = TestUtils.CreateTestContext();

        cache.Set(
            "BaseKey",
            new CachedVaryByRules(),
            TimeSpan.Zero);
        cache.Set(
            "BaseKeyVaryKey2",
            new CachedResponse()
        {
            Headers = new HeaderDictionary(),
            Body    = new CachedResponseBody(new List <byte[]>(0), 0)
        },
            TimeSpan.Zero);

        Assert.True(await middleware.TryServeFromCacheAsync(context));
        Assert.Equal(3, cache.GetCount);
        TestUtils.AssertLoggedMessages(
            sink.Writes,
            LoggedMessage.CachedResponseServed);
    }
Example #8
0
    public async Task TryServeFromCacheAsync_CachedResponseNotFound_Fails()
    {
        var cache      = new TestResponseCache();
        var sink       = new TestSink();
        var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache, keyProvider: new TestResponseCachingKeyProvider("BaseKey"));
        var context    = TestUtils.CreateTestContext();

        Assert.False(await middleware.TryServeFromCacheAsync(context));
        Assert.Equal(1, cache.GetCount);
        TestUtils.AssertLoggedMessages(
            sink.Writes,
            LoggedMessage.NoResponseServed);
    }
Example #9
0
    public async Task TryServeFromCacheAsync_OnlyIfCached_Serves504()
    {
        var cache      = new TestResponseCache();
        var sink       = new TestSink();
        var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache, keyProvider: new TestResponseCachingKeyProvider());
        var context    = TestUtils.CreateTestContext();

        context.HttpContext.Request.Headers.CacheControl = new CacheControlHeaderValue()
        {
            OnlyIfCached = true
        }.ToString();

        Assert.True(await middleware.TryServeFromCacheAsync(context));
        Assert.Equal(StatusCodes.Status504GatewayTimeout, context.HttpContext.Response.StatusCode);
        TestUtils.AssertLoggedMessages(
            sink.Writes,
            LoggedMessage.GatewayTimeoutServed);
    }
Example #10
0
    public async Task FinalizeCacheBody_DoNotCache_IfShouldCacheResponseFalse()
    {
        var cache      = new TestResponseCache();
        var sink       = new TestSink();
        var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
        var context    = TestUtils.CreateTestContext();

        middleware.ShimResponseStream(context);
        await context.HttpContext.Response.WriteAsync(new string('0', 10));

        context.ShouldCacheResponse = false;

        middleware.FinalizeCacheBody(context);

        Assert.Equal(0, cache.SetCount);
        TestUtils.AssertLoggedMessages(
            sink.Writes,
            LoggedMessage.ResponseNotCached);
    }
Example #11
0
    public void FinalizeCacheHeadersAsync_UpdateCachedVaryByRules_NullOrEmptyRules(StringValues vary)
    {
        var cache      = new TestResponseCache();
        var sink       = new TestSink();
        var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
        var context    = TestUtils.CreateTestContext();

        context.HttpContext.Response.Headers.Vary = vary;
        context.HttpContext.Features.Set <IResponseCachingFeature>(new ResponseCachingFeature()
        {
            VaryByQueryKeys = vary
        });

        middleware.FinalizeCacheHeaders(context);

        // Vary rules should not be updated
        Assert.Equal(0, cache.SetCount);
        Assert.Empty(sink.Writes);
    }
Example #12
0
    public async Task TryServeFromCacheAsync_CachedResponseFound_Serves304IfPossible()
    {
        var cache      = new TestResponseCache();
        var sink       = new TestSink();
        var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache, keyProvider: new TestResponseCachingKeyProvider("BaseKey"));
        var context    = TestUtils.CreateTestContext();

        context.HttpContext.Request.Headers.IfNoneMatch = "*";

        cache.Set(
            "BaseKey",
            new CachedResponse()
        {
            Body = new CachedResponseBody(new List <byte[]>(0), 0)
        },
            TimeSpan.Zero);

        Assert.True(await middleware.TryServeFromCacheAsync(context));
        Assert.Equal(1, cache.GetCount);
        TestUtils.AssertLoggedMessages(
            sink.Writes,
            LoggedMessage.NotModifiedServed);
    }
Example #13
0
    internal static ResponseCachingMiddleware CreateTestMiddleware(
        RequestDelegate next           = null,
        IResponseCache cache           = null,
        ResponseCachingOptions options = null,
        TestSink testSink = null,
        IResponseCachingKeyProvider keyProvider       = null,
        IResponseCachingPolicyProvider policyProvider = null)
    {
        if (next == null)
        {
            next = httpContext => Task.CompletedTask;
        }
        if (cache == null)
        {
            cache = new TestResponseCache();
        }
        if (options == null)
        {
            options = new ResponseCachingOptions();
        }
        if (keyProvider == null)
        {
            keyProvider = new ResponseCachingKeyProvider(new DefaultObjectPoolProvider(), Options.Create(options));
        }
        if (policyProvider == null)
        {
            policyProvider = new TestResponseCachingPolicyProvider();
        }

        return(new ResponseCachingMiddleware(
                   next,
                   Options.Create(options),
                   testSink == null ? (ILoggerFactory)NullLoggerFactory.Instance : new TestLoggerFactory(testSink, true),
                   policyProvider,
                   cache,
                   keyProvider));
    }