Only call PrepareDateValues if not already called for tick
This commit is contained in:
parent
388841c1d8
commit
a3b0f809de
|
|
@ -13,15 +13,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DateHeaderValueManager : IDisposable
|
public class DateHeaderValueManager : IDisposable
|
||||||
{
|
{
|
||||||
|
private static readonly byte[] _datePreambleBytes = Encoding.ASCII.GetBytes("\r\nDate: ");
|
||||||
|
|
||||||
private readonly ISystemClock _systemClock;
|
private readonly ISystemClock _systemClock;
|
||||||
private readonly TimeSpan _timeWithoutRequestsUntilIdle;
|
private readonly TimeSpan _timeWithoutRequestsUntilIdle;
|
||||||
private readonly TimeSpan _timerInterval;
|
private readonly TimeSpan _timerInterval;
|
||||||
|
private readonly object _timerLocker = new object();
|
||||||
|
|
||||||
|
private DateHeaderValues _dateValues;
|
||||||
|
|
||||||
private volatile string _dateValue;
|
|
||||||
private volatile bool _activeDateBytes;
|
|
||||||
private readonly byte[] _dateBytes0 = Encoding.ASCII.GetBytes("\r\nDate: DDD, dd mmm yyyy hh:mm:ss GMT");
|
|
||||||
private readonly byte[] _dateBytes1 = Encoding.ASCII.GetBytes("\r\nDate: DDD, dd mmm yyyy hh:mm:ss GMT");
|
|
||||||
private object _timerLocker = new object();
|
|
||||||
private volatile bool _isDisposed = false;
|
private volatile bool _isDisposed = false;
|
||||||
private volatile bool _hadRequestsSinceLastTimerTick = false;
|
private volatile bool _hadRequestsSinceLastTimerTick = false;
|
||||||
private Timer _dateValueTimer;
|
private Timer _dateValueTimer;
|
||||||
|
|
@ -55,19 +55,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
||||||
/// Returns a value representing the current server date/time for use in the HTTP "Date" response header
|
/// Returns a value representing the current server date/time for use in the HTTP "Date" response header
|
||||||
/// in accordance with http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.18
|
/// in accordance with http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.18
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The value.</returns>
|
/// <returns>The value in string and byte[] format.</returns>
|
||||||
public virtual string GetDateHeaderValue()
|
public DateHeaderValues GetDateHeaderValues()
|
||||||
{
|
{
|
||||||
_hadRequestsSinceLastTimerTick = true;
|
if (!_hadRequestsSinceLastTimerTick)
|
||||||
PrepareDateValues();
|
{
|
||||||
return _dateValue;
|
PrepareDateValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] GetDateHeaderValueBytes()
|
return _dateValues;
|
||||||
{
|
|
||||||
_hadRequestsSinceLastTimerTick = true;
|
|
||||||
PrepareDateValues();
|
|
||||||
return _activeDateBytes ? _dateBytes0 : _dateBytes1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -78,6 +74,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
||||||
if (!_isDisposed)
|
if (!_isDisposed)
|
||||||
{
|
{
|
||||||
_isDisposed = true;
|
_isDisposed = true;
|
||||||
|
_hadRequestsSinceLastTimerTick = false;
|
||||||
|
|
||||||
lock (_timerLocker)
|
lock (_timerLocker)
|
||||||
{
|
{
|
||||||
|
|
@ -125,6 +122,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
||||||
{
|
{
|
||||||
_timerIsRunning = false;
|
_timerIsRunning = false;
|
||||||
_dateValueTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
_dateValueTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
|
_hadRequestsSinceLastTimerTick = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -158,16 +156,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void PrepareDateValues()
|
private void PrepareDateValues()
|
||||||
{
|
{
|
||||||
if (_isDisposed)
|
_hadRequestsSinceLastTimerTick = !_isDisposed;
|
||||||
|
if (!_timerIsRunning)
|
||||||
{
|
{
|
||||||
SetDateValues(_systemClock.UtcNow);
|
StartTimer();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!_timerIsRunning)
|
|
||||||
{
|
|
||||||
StartTimer();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -178,9 +170,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
||||||
private void SetDateValues(DateTimeOffset value)
|
private void SetDateValues(DateTimeOffset value)
|
||||||
{
|
{
|
||||||
// See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.18 for required format of Date header
|
// See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.18 for required format of Date header
|
||||||
_dateValue = value.ToString(Constants.RFC1123DateFormat);
|
var dateValue = value.ToString(Constants.RFC1123DateFormat);
|
||||||
Encoding.ASCII.GetBytes(_dateValue, 0, _dateValue.Length, !_activeDateBytes ? _dateBytes0 : _dateBytes1, "\r\nDate: ".Length);
|
var dateBytes = new byte[_datePreambleBytes.Length + dateValue.Length];
|
||||||
_activeDateBytes = !_activeDateBytes;
|
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 class DateHeaderValues
|
||||||
|
{
|
||||||
|
public byte[] Bytes;
|
||||||
|
public string String;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -589,12 +589,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
|
||||||
|
|
||||||
var responseHeaders = _frameHeaders.ResponseHeaders;
|
var responseHeaders = _frameHeaders.ResponseHeaders;
|
||||||
responseHeaders.Reset();
|
responseHeaders.Reset();
|
||||||
responseHeaders.SetRawDate(
|
var dateHeaderValues = DateHeaderValueManager.GetDateHeaderValues();
|
||||||
DateHeaderValueManager.GetDateHeaderValue(),
|
responseHeaders.SetRawDate(dateHeaderValues.String, dateHeaderValues.Bytes);
|
||||||
DateHeaderValueManager.GetDateHeaderValueBytes());
|
responseHeaders.SetRawServer("Kestrel", Headers.BytesServer);
|
||||||
responseHeaders.SetRawServer(
|
|
||||||
"Kestrel",
|
|
||||||
Headers.BytesServer);
|
|
||||||
responseHeaders.SetRawContentLength("0", _bytesContentLengthZero);
|
responseHeaders.SetRawContentLength("0", _bytesContentLengthZero);
|
||||||
|
|
||||||
ResponseHeaders = responseHeaders;
|
ResponseHeaders = responseHeaders;
|
||||||
|
|
|
||||||
|
|
@ -78,9 +78,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
|
||||||
|
|
||||||
public void Initialize(DateHeaderValueManager dateValueManager)
|
public void Initialize(DateHeaderValueManager dateValueManager)
|
||||||
{
|
{
|
||||||
ResponseHeaders.SetRawDate(
|
var dateHeaderValues = dateValueManager.GetDateHeaderValues();
|
||||||
dateValueManager.GetDateHeaderValue(),
|
ResponseHeaders.SetRawDate(dateHeaderValues.String, dateHeaderValues.Bytes);
|
||||||
dateValueManager.GetDateHeaderValueBytes());
|
|
||||||
ResponseHeaders.SetRawServer("Kestrel", BytesServer);
|
ResponseHeaders.SetRawServer("Kestrel", BytesServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result = dateHeaderValueManager.GetDateHeaderValue();
|
result = dateHeaderValueManager.GetDateHeaderValues().String;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
@ -54,9 +54,9 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result1 = dateHeaderValueManager.GetDateHeaderValue();
|
result1 = dateHeaderValueManager.GetDateHeaderValues().String;
|
||||||
systemClock.UtcNow = future;
|
systemClock.UtcNow = future;
|
||||||
result2 = dateHeaderValueManager.GetDateHeaderValue();
|
result2 = dateHeaderValueManager.GetDateHeaderValues().String;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
@ -85,11 +85,11 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result1 = dateHeaderValueManager.GetDateHeaderValue();
|
result1 = dateHeaderValueManager.GetDateHeaderValues().String;
|
||||||
systemClock.UtcNow = future;
|
systemClock.UtcNow = future;
|
||||||
// Wait for longer than the idle timeout to ensure the timer is stopped
|
// Wait for longer than the idle timeout to ensure the timer is stopped
|
||||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||||
result2 = dateHeaderValueManager.GetDateHeaderValue();
|
result2 = dateHeaderValueManager.GetDateHeaderValues().String;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
@ -114,10 +114,10 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
var timerInterval = TimeSpan.FromSeconds(10);
|
var timerInterval = TimeSpan.FromSeconds(10);
|
||||||
var dateHeaderValueManager = new DateHeaderValueManager(systemClock, timeWithoutRequestsUntilIdle, timerInterval);
|
var dateHeaderValueManager = new DateHeaderValueManager(systemClock, timeWithoutRequestsUntilIdle, timerInterval);
|
||||||
|
|
||||||
var result1 = dateHeaderValueManager.GetDateHeaderValue();
|
var result1 = dateHeaderValueManager.GetDateHeaderValues().String;
|
||||||
dateHeaderValueManager.Dispose();
|
dateHeaderValueManager.Dispose();
|
||||||
systemClock.UtcNow = future;
|
systemClock.UtcNow = future;
|
||||||
var result2 = dateHeaderValueManager.GetDateHeaderValue();
|
var result2 = dateHeaderValueManager.GetDateHeaderValues().String;
|
||||||
|
|
||||||
Assert.Equal(now.ToString(Constants.RFC1123DateFormat), result1);
|
Assert.Equal(now.ToString(Constants.RFC1123DateFormat), result1);
|
||||||
Assert.Equal(future.ToString(Constants.RFC1123DateFormat), result2);
|
Assert.Equal(future.ToString(Constants.RFC1123DateFormat), result2);
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
// 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 Microsoft.AspNetCore.Server.Kestrel.Http;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.KestrelTests
|
|
||||||
{
|
|
||||||
public class TestDateHeaderValueManager : DateHeaderValueManager
|
|
||||||
{
|
|
||||||
public override string GetDateHeaderValue()
|
|
||||||
{
|
|
||||||
return DateTimeOffset.UtcNow.ToString("r");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
AppLifetime = new LifetimeNotImplemented();
|
AppLifetime = new LifetimeNotImplemented();
|
||||||
Log = new TestKestrelTrace();
|
Log = new TestKestrelTrace();
|
||||||
ThreadPool = new LoggingThreadPool(Log);
|
ThreadPool = new LoggingThreadPool(Log);
|
||||||
DateHeaderValueManager = new TestDateHeaderValueManager();
|
DateHeaderValueManager = new DateHeaderValueManager();
|
||||||
|
|
||||||
ServerOptions = new KestrelServerOptions();
|
ServerOptions = new KestrelServerOptions();
|
||||||
ServerOptions.ShutdownTimeout = TimeSpan.FromSeconds(5);
|
ServerOptions.ShutdownTimeout = TimeSpan.FromSeconds(5);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue