// Add the given parameter to the list. Remove if date is null. private void SetDate(string parameter, DateTimeOffset?date) { var dateParameter = NameValueHeaderValue.Find(_parameters, parameter); if (date == null) { // Remove parameter if (dateParameter != null) { _parameters !.Remove(dateParameter); } } else { // Must always be quoted var dateString = HeaderUtilities.FormatDate(date.GetValueOrDefault(), quoted: true); if (dateParameter != null) { dateParameter.Value = dateString; } else { Parameters.Add(new NameValueHeaderValue(parameter, dateString)); } } }
public void ContentIsNotModified_IfModifiedSince_LastModifiedOverridesDateHeader() { var utcNow = DateTimeOffset.UtcNow; var sink = new TestSink(); var context = TestUtils.CreateTestContext(sink); context.CachedResponseHeaders = new HeaderDictionary(); context.HttpContext.Request.Headers[HeaderNames.IfModifiedSince] = HeaderUtilities.FormatDate(utcNow); // Verify modifications in the past succeeds context.CachedResponseHeaders[HeaderNames.Date] = HeaderUtilities.FormatDate(utcNow + TimeSpan.FromSeconds(10)); context.CachedResponseHeaders[HeaderNames.LastModified] = HeaderUtilities.FormatDate(utcNow - TimeSpan.FromSeconds(10)); Assert.True(ResponseCachingMiddleware.ContentIsNotModified(context)); Assert.Single(sink.Writes); // Verify modifications at present context.CachedResponseHeaders[HeaderNames.Date] = HeaderUtilities.FormatDate(utcNow + TimeSpan.FromSeconds(10)); context.CachedResponseHeaders[HeaderNames.LastModified] = HeaderUtilities.FormatDate(utcNow); Assert.True(ResponseCachingMiddleware.ContentIsNotModified(context)); Assert.Equal(2, sink.Writes.Count); // Verify modifications in the future fails context.CachedResponseHeaders[HeaderNames.Date] = HeaderUtilities.FormatDate(utcNow - TimeSpan.FromSeconds(10)); context.CachedResponseHeaders[HeaderNames.LastModified] = HeaderUtilities.FormatDate(utcNow + TimeSpan.FromSeconds(10)); Assert.False(ResponseCachingMiddleware.ContentIsNotModified(context)); // Verify logging TestUtils.AssertLoggedMessages( sink.Writes, LoggedMessage.NotModifiedIfModifiedSinceSatisfied, LoggedMessage.NotModifiedIfModifiedSinceSatisfied); }
public async Task FinalizeCacheHeadersAsync_ResponseValidity_UseSharedMaxAgeIfAvailable() { var clock = new TestClock { UtcNow = DateTimeOffset.UtcNow }; var sink = new TestSink(); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, options: new ResponseCachingOptions { SystemClock = clock }); var context = TestUtils.CreateTestContext(); context.ResponseTime = clock.UtcNow; context.HttpContext.Response.Headers[HeaderNames.CacheControl] = new CacheControlHeaderValue() { MaxAge = TimeSpan.FromSeconds(12), SharedMaxAge = TimeSpan.FromSeconds(13) }.ToString(); context.HttpContext.Response.Headers[HeaderNames.Expires] = HeaderUtilities.FormatDate(clock.UtcNow + TimeSpan.FromSeconds(11)); await middleware.FinalizeCacheHeadersAsync(context); Assert.Equal(TimeSpan.FromSeconds(13), context.CachedResponseValidFor); Assert.Empty(sink.Writes); }
public void ReturnsSameResultAsRfc1123String(DateTimeOffset dateTime, bool quoted) { var formatted = dateTime.ToString(Rfc1123Format); var expected = quoted ? $"\"{formatted}\"" : formatted; var actual = HeaderUtilities.FormatDate(dateTime, quoted); Assert.Equal(expected, actual); }
public void ToString_UseDifferentValues_MatchExpectation() { Assert.Equal("Sat, 31 Jul 2010 15:38:57 GMT", HeaderUtilities.FormatDate(new DateTimeOffset(2010, 7, 31, 15, 38, 57, TimeSpan.Zero))); Assert.Equal("Fri, 01 Jan 2010 01:01:01 GMT", HeaderUtilities.FormatDate(new DateTimeOffset(2010, 1, 1, 1, 1, 1, TimeSpan.Zero))); }
/// <inheritdoc /> public override string ToString() { if (_entityTag == null) { return(HeaderUtilities.FormatDate(_lastModified.GetValueOrDefault())); } return(_entityTag.ToString()); }
/// <summary> /// Append string representation of this <see cref="SetCookieHeaderValue"/> to given /// <paramref name="builder"/>. /// </summary> /// <param name="builder"> /// The <see cref="StringBuilder"/> to receive the string representation of this /// <see cref="SetCookieHeaderValue"/>. /// </param> public void AppendToStringBuilder(StringBuilder builder) { builder.Append(_name.AsSpan()); builder.Append('='); builder.Append(_value.AsSpan()); if (Expires.HasValue) { AppendSegment(builder, ExpiresToken, HeaderUtilities.FormatDate(Expires.GetValueOrDefault())); } if (MaxAge.HasValue) { AppendSegment(builder, MaxAgeToken, HeaderUtilities.FormatNonNegativeInt64((long)MaxAge.GetValueOrDefault().TotalSeconds)); } if (Domain != null) { AppendSegment(builder, DomainToken, Domain); } if (Path != null) { AppendSegment(builder, PathToken, Path); } if (Secure) { AppendSegment(builder, SecureToken, null); } // Allow for Unspecified (-1) to skip SameSite if (SameSite == SameSiteMode.None) { AppendSegment(builder, SameSiteToken, SameSiteNoneToken); } else if (SameSite == SameSiteMode.Lax) { AppendSegment(builder, SameSiteToken, SameSiteLaxToken); } else if (SameSite == SameSiteMode.Strict) { AppendSegment(builder, SameSiteToken, SameSiteStrictToken); } if (HttpOnly) { AppendSegment(builder, HttpOnlyToken, null); } foreach (var extension in Extensions) { AppendSegment(builder, extension, null); } }
internal static void SetDate([NotNull] this IHeaderDictionary headers, [NotNull] string name, DateTimeOffset?value) { if (value.HasValue) { headers[name] = HeaderUtilities.FormatDate(value.Value); } else { headers.Remove(name); } }
/// <summary> /// Sets date values from a provided ticks value /// </summary> /// <param name="value">A DateTimeOffset value</param> private void SetDateValues(DateTimeOffset value) { var dateValue = HeaderUtilities.FormatDate(value); var dateBytes = new byte[DatePreambleBytes.Length + dateValue.Length]; DatePreambleBytes.CopyTo(dateBytes); Encoding.ASCII.GetBytes(dateValue, dateBytes.AsSpan(DatePreambleBytes.Length)); var dateValues = new DateHeaderValues(dateBytes, dateValue); Volatile.Write(ref _dateValues, dateValues); }
public void ContentIsNotModified_IfNoneMatch_Overrides_IfModifiedSince_ToFalse() { var utcNow = DateTimeOffset.UtcNow; var sink = new TestSink(); var context = TestUtils.CreateTestContext(sink); context.CachedResponseHeaders = new HeaderDictionary(); // This would pass the IfModifiedSince checks context.HttpContext.Request.Headers[HeaderNames.IfModifiedSince] = HeaderUtilities.FormatDate(utcNow); context.CachedResponseHeaders[HeaderNames.LastModified] = HeaderUtilities.FormatDate(utcNow - TimeSpan.FromSeconds(10)); context.HttpContext.Request.Headers[HeaderNames.IfNoneMatch] = "\"E1\""; Assert.False(ResponseCachingMiddleware.ContentIsNotModified(context)); Assert.Empty(sink.Writes); }
/// <summary> /// Sets date values from a provided ticks value /// </summary> /// <param name="value">A DateTimeOffset value</param> private void SetDateValues(DateTimeOffset value) { var dateValue = HeaderUtilities.FormatDate(value); var dateBytes = new byte[_datePreambleBytes.Length + dateValue.Length]; Buffer.BlockCopy(_datePreambleBytes, 0, dateBytes, 0, _datePreambleBytes.Length); Encoding.ASCII.GetBytes(dateValue, 0, dateValue.Length, dateBytes, _datePreambleBytes.Length); var dateValues = new DateHeaderValues { Bytes = dateBytes, String = dateValue }; Volatile.Write(ref _dateValues, dateValues); }
public async Task FinalizeCacheHeadersAsync_AddsDate_IfNoneSpecified() { var utcNow = DateTimeOffset.UtcNow; var sink = new TestSink(); var middleware = TestUtils.CreateTestMiddleware(testSink: sink); var context = TestUtils.CreateTestContext(); // ResponseTime is the actual value that's used to set the Date header in FinalizeCacheHeadersAsync context.ResponseTime = utcNow; Assert.True(StringValues.IsNullOrEmpty(context.HttpContext.Response.Headers[HeaderNames.Date])); await middleware.FinalizeCacheHeadersAsync(context); Assert.Equal(HeaderUtilities.FormatDate(utcNow), context.HttpContext.Response.Headers[HeaderNames.Date]); Assert.Empty(sink.Writes); }
public async Task FinalizeCacheHeadersAsync_DoNotAddDate_IfSpecified() { var utcNow = DateTimeOffset.MinValue; var sink = new TestSink(); var middleware = TestUtils.CreateTestMiddleware(testSink: sink); var context = TestUtils.CreateTestContext(); context.HttpContext.Response.Headers[HeaderNames.Date] = HeaderUtilities.FormatDate(utcNow); context.ResponseTime = utcNow + TimeSpan.FromSeconds(10); Assert.Equal(HeaderUtilities.FormatDate(utcNow), context.HttpContext.Response.Headers[HeaderNames.Date]); await middleware.FinalizeCacheHeadersAsync(context); Assert.Equal(HeaderUtilities.FormatDate(utcNow), context.HttpContext.Response.Headers[HeaderNames.Date]); Assert.Empty(sink.Writes); }
public async Task PreconditionIfUnmodifiedSinceSuccessEqualTest() { // Arrange Client.DefaultRequestHeaders.Add("If-Unmodified-Since", HeaderUtilities.FormatDate(LastModified)); // Act HttpResponseMessage response = await Client.GetAsync("/file/physical/true/true"); string responseString = await response.Content.ReadAsStringAsync(); // Assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("0123456789abcdefghijklmnopgrstuvwxyzABCDEFGHIJKLMNOPGRSTUVWXYZ", responseString); Assert.Equal("bytes", response.Headers.AcceptRanges.ToString()); Assert.Equal(EntityTag, response.Headers.ETag); Assert.Null(response.Content.Headers.ContentRange); }
public async Task PreconditionIfUnmodifiedSinceFailTest() { // Arrange Client.DefaultRequestHeaders.Add("If-Unmodified-Since", HeaderUtilities.FormatDate(LastModified.AddSeconds(-1))); // Act HttpResponseMessage response = await Client.GetAsync("/file/physical/true/true"); string responseString = await response.Content.ReadAsStringAsync(); // Assert Assert.Equal(HttpStatusCode.PreconditionFailed, response.StatusCode); Assert.Equal(string.Empty, responseString); Assert.NotEqual("bytes", response.Headers.AcceptRanges.ToString()); Assert.Equal(EntityTag, response.Headers.ETag); Assert.Null(response.Content.Headers.ContentRange); }
public async Task PreconditionIfUnmodifiedSinceSuccessEqualTest() { // Arrange this.Client.DefaultRequestHeaders.Add("If-Unmodified-Since", HeaderUtilities.FormatDate(this.LastModified)); // Act HttpResponseMessage response = await this.Client.GetAsync("/test/file/physical/true/true"); string responseString = await response.Content.ReadAsStringAsync(); // Assert Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, "StatusCode != OK"); Assert.AreEqual("0123456789abcdefghijklmnopgrstuvwxyzABCDEFGHIJKLMNOPGRSTUVWXYZ", responseString, "no full file"); Assert.AreEqual("bytes", response.Headers.AcceptRanges.ToString(), "AcceptRanges != bytes"); Assert.AreEqual(this.EntityTag, response.Headers.ETag, "ETag != EntityTag"); Assert.IsNull(response.Content.Headers.ContentRange, "Content-Range != null"); Assert.AreEqual("attachment", response.Content.Headers.ContentDisposition.DispositionType, "DispositionType != attachment"); }
public async Task PreconditionIfUnmodifiedSinceFailTest() { // Arrange this.Client.DefaultRequestHeaders.Add("If-Unmodified-Since", HeaderUtilities.FormatDate(this.LastModified.AddSeconds(-1))); // Act HttpResponseMessage response = await this.Client.GetAsync("/test/file/physical/true/true"); string responseString = await response.Content.ReadAsStringAsync(); // Assert Assert.AreEqual(HttpStatusCode.PreconditionFailed, response.StatusCode, "StatusCode != PreconditionFailed"); Assert.AreEqual(string.Empty, responseString, "response is not empty"); Assert.AreNotEqual("bytes", response.Headers.AcceptRanges.ToString(), "AcceptRanges == bytes"); Assert.AreEqual(this.EntityTag, response.Headers.ETag, "ETag != EntityTag"); Assert.IsNull(response.Content.Headers.ContentRange, "Content-Range != null"); Assert.AreEqual("attachment", response.Content.Headers.ContentDisposition.DispositionType, "DispositionType != attachment"); }
public void ContentIsNotModified_IfNoneMatch_Overrides_IfModifiedSince_ToTrue() { var utcNow = DateTimeOffset.UtcNow; var sink = new TestSink(); var context = TestUtils.CreateTestContext(sink); context.CachedResponseHeaders = new HeaderDictionary(); // This would fail the IfModifiedSince checks context.HttpContext.Request.Headers[HeaderNames.IfModifiedSince] = HeaderUtilities.FormatDate(utcNow); context.CachedResponseHeaders[HeaderNames.LastModified] = HeaderUtilities.FormatDate(utcNow + TimeSpan.FromSeconds(10)); context.HttpContext.Request.Headers[HeaderNames.IfNoneMatch] = EntityTagHeaderValue.Any.ToString(); Assert.True(ResponseCachingMiddleware.ContentIsNotModified(context)); TestUtils.AssertLoggedMessages( sink.Writes, LoggedMessage.NotModifiedIfNoneMatchStar); }
public void IsResponseCacheable_NoExpiryRequirements_IsAllowed() { var sink = new TestSink(); var context = TestUtils.CreateTestContext(sink); context.HttpContext.Response.StatusCode = StatusCodes.Status200OK; context.HttpContext.Response.Headers.CacheControl = new CacheControlHeaderValue() { Public = true }.ToString(); var utcNow = DateTimeOffset.UtcNow; context.HttpContext.Response.Headers.Date = HeaderUtilities.FormatDate(utcNow); context.ResponseTime = DateTimeOffset.MaxValue; Assert.True(new ResponseCachingPolicyProvider().IsResponseCacheable(context)); Assert.Empty(sink.Writes); }
public void IsResponseCacheable_SharedMaxAgeOverridesMaxAge_ToAllowed() { var utcNow = DateTimeOffset.UtcNow; var sink = new TestSink(); var context = TestUtils.CreateTestContext(sink); context.HttpContext.Response.StatusCode = StatusCodes.Status200OK; context.HttpContext.Response.Headers.CacheControl = new CacheControlHeaderValue() { Public = true, MaxAge = TimeSpan.FromSeconds(10), SharedMaxAge = TimeSpan.FromSeconds(15) }.ToString(); context.HttpContext.Response.Headers.Date = HeaderUtilities.FormatDate(utcNow); context.ResponseTime = utcNow + TimeSpan.FromSeconds(11); Assert.True(new ResponseCachingPolicyProvider().IsResponseCacheable(context)); Assert.Empty(sink.Writes); }
public async Task IsResponseCacheable_NoExpiryRequirements_IsAllowed() { var sink = new TestSink(); var context = TestUtils.CreateTestContext(testSink: sink); context.HttpContext.Response.StatusCode = StatusCodes.Status200OK; var utcNow = DateTimeOffset.UtcNow; context.HttpContext.Response.Headers.Date = HeaderUtilities.FormatDate(utcNow); context.ResponseTime = DateTimeOffset.MaxValue; var policy = new OutputCachePolicyBuilder().Build(); await policy.ServeResponseAsync(context, default); Assert.True(context.AllowCacheStorage); Assert.True(context.AllowCacheLookup); Assert.Empty(sink.Writes); }
public void IsCachedEntryFresh_MaxAgeOverridesExpiry_ToFresh() { var utcNow = DateTimeOffset.UtcNow; var sink = new TestSink(); var context = TestUtils.CreateTestContext(sink); context.CachedEntryAge = TimeSpan.FromSeconds(9); context.ResponseTime = utcNow + context.CachedEntryAge; context.CachedResponseHeaders = new HeaderDictionary(); context.CachedResponseHeaders[HeaderNames.CacheControl] = new CacheControlHeaderValue() { Public = true, MaxAge = TimeSpan.FromSeconds(10) }.ToString(); context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(utcNow); Assert.True(new ResponseCachingPolicyProvider().IsCachedEntryFresh(context)); Assert.Empty(sink.Writes); }
public async Task FinalizeCacheHeadersAsync_AddsDate_IfNoneSpecified() { var clock = new TestClock { UtcNow = DateTimeOffset.UtcNow }; var sink = new TestSink(); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, options: new ResponseCachingOptions { SystemClock = clock }); var context = TestUtils.CreateTestContext(); Assert.True(StringValues.IsNullOrEmpty(context.HttpContext.Response.Headers[HeaderNames.Date])); await middleware.FinalizeCacheHeadersAsync(context); Assert.Equal(HeaderUtilities.FormatDate(clock.UtcNow), context.HttpContext.Response.Headers[HeaderNames.Date]); Assert.Empty(sink.Writes); }
public async Task PreconditionIfModifiedSinceSuccessPutTest() { // Arrange Client.DefaultRequestHeaders.Add("If-Modified-Since", HeaderUtilities.FormatDate(LastModified.AddSeconds(-1))); // Act HttpResponseMessage response = await Client.PutAsync("/file/file", new StringContent(string.Empty)); response.EnsureSuccessStatusCode(); string responseString = await response.Content.ReadAsStringAsync(); // Assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("0123456789abcdefghijklmnopgrstuvwxyzABCDEFGHIJKLMNOPGRSTUVWXYZ", responseString); Assert.Equal("bytes", response.Headers.AcceptRanges.ToString()); Assert.Equal(EntityTag, response.Headers.ETag); Assert.Null(response.Content.Headers.ContentRange); Assert.Equal("attachment", response.Content.Headers.ContentDisposition.DispositionType); }
public void IsCachedEntryFresh_AtExpiry_IsNotFresh() { var utcNow = DateTimeOffset.UtcNow; var sink = new TestSink(); var context = TestUtils.CreateTestContext(sink); context.ResponseTime = utcNow; context.CachedEntryAge = TimeSpan.Zero; context.CachedResponseHeaders = new HeaderDictionary(); context.CachedResponseHeaders[HeaderNames.CacheControl] = new CacheControlHeaderValue() { Public = true }.ToString(); context.CachedResponseHeaders[HeaderNames.Expires] = HeaderUtilities.FormatDate(utcNow); Assert.False(new ResponseCachingPolicyProvider().IsCachedEntryFresh(context)); TestUtils.AssertLoggedMessages( sink.Writes, LoggedMessage.ExpirationExpiresExceeded); }
public void IsResponseCacheable_MaxAgeOverridesExpiry_ToNotAllowed() { var utcNow = DateTimeOffset.UtcNow; var sink = new TestSink(); var context = TestUtils.CreateTestContext(sink); context.HttpContext.Response.StatusCode = StatusCodes.Status200OK; context.HttpContext.Response.Headers.CacheControl = new CacheControlHeaderValue() { Public = true, MaxAge = TimeSpan.FromSeconds(10) }.ToString(); context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(utcNow); context.HttpContext.Response.Headers.Date = HeaderUtilities.FormatDate(utcNow); context.ResponseTime = utcNow + TimeSpan.FromSeconds(10); Assert.False(new ResponseCachingPolicyProvider().IsResponseCacheable(context)); TestUtils.AssertLoggedMessages( sink.Writes, LoggedMessage.ExpirationMaxAgeExceeded); }
internal static void SetDate(this IHeaderDictionary headers, string name, DateTimeOffset?value) { if (headers == null) { throw new ArgumentNullException(nameof(headers)); } if (name == null) { throw new ArgumentNullException(nameof(name)); } if (value.HasValue) { headers[name] = HeaderUtilities.FormatDate(value.Value); } else { headers.Remove(name); } }
public async Task PreconditionIfRangeLastModifiedEqualTest() { // Arrange Client.DefaultRequestHeaders.Add("Range", "bytes=1-1"); Client.DefaultRequestHeaders.Add("If-Range", HeaderUtilities.FormatDate(LastModified)); // Act HttpResponseMessage response = await Client.GetAsync("/file/physical/true/true"); response.EnsureSuccessStatusCode(); string responseString = await response.Content.ReadAsStringAsync(); // Assert Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode); Assert.Equal("1", responseString); Assert.Equal("bytes", response.Headers.AcceptRanges.ToString()); Assert.Equal(EntityTag, response.Headers.ETag); Assert.NotNull(response.Content.Headers.ContentRange); Assert.Equal("bytes 1-1/62", response.Content.Headers.ContentRange.ToString()); }
public async Task IfUnmodifiedSinceComparison_OnlyUsesWholeSeconds(DateTimeOffset ifUnmodifiedSince, int expectedStatusCode) { // Arrange var httpContext = GetHttpContext(); httpContext.Request.Headers[HeaderNames.IfUnmodifiedSince] = HeaderUtilities.FormatDate(ifUnmodifiedSince); var actionContext = CreateActionContext(httpContext); // Represents 4/9/2018 11:24:22 AM +00:00 // Ticks rounded down to seconds: 636588698620000000 var ticks = 636588698625969382; var result = new EmptyFileResult("application/test") { LastModified = new DateTimeOffset(ticks, TimeSpan.Zero) }; // Act await result.ExecuteResultAsync(actionContext); // Assert Assert.Equal(expectedStatusCode, httpContext.Response.StatusCode); }
public void FinalizeCacheHeadersAsync_ResponseValidity_UseExpiryIfAvailable() { var clock = new TestClock { UtcNow = DateTimeOffset.MinValue }; var sink = new TestSink(); var middleware = TestUtils.CreateTestMiddleware(testSink: sink, options: new ResponseCachingOptions { SystemClock = clock }); var context = TestUtils.CreateTestContext(); context.ResponseTime = clock.UtcNow; context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(clock.UtcNow + TimeSpan.FromSeconds(11)); middleware.FinalizeCacheHeaders(context); Assert.Equal(TimeSpan.FromSeconds(11), context.CachedResponseValidFor); Assert.Empty(sink.Writes); }