159 lines
6.5 KiB
C#
159 lines
6.5 KiB
C#
// 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 System.Buffers;
|
|
using System.IO.Pipelines;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using BenchmarkDotNet.Attributes;
|
|
using Microsoft.AspNetCore.Http.Features;
|
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
|
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
|
using Microsoft.AspNetCore.Server.Kestrel.Performance.Mocks;
|
|
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
|
|
using Microsoft.AspNetCore.Testing;
|
|
|
|
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|
{
|
|
public class ResponseHeadersWritingBenchmark
|
|
{
|
|
private static readonly byte[] _helloWorldPayload = Encoding.ASCII.GetBytes("Hello, World!");
|
|
|
|
private TestHttp1Connection _http1Connection;
|
|
|
|
private MemoryPool<byte> _memoryPool;
|
|
|
|
[Params(
|
|
BenchmarkTypes.TechEmpowerPlaintext,
|
|
BenchmarkTypes.PlaintextChunked,
|
|
BenchmarkTypes.PlaintextWithCookie,
|
|
BenchmarkTypes.PlaintextChunkedWithCookie,
|
|
BenchmarkTypes.LiveAspNet
|
|
)]
|
|
public BenchmarkTypes Type { get; set; }
|
|
|
|
[Benchmark]
|
|
public async Task Output()
|
|
{
|
|
_http1Connection.Reset();
|
|
_http1Connection.StatusCode = 200;
|
|
_http1Connection.HttpVersionEnum = HttpVersion.Http11;
|
|
_http1Connection.KeepAlive = true;
|
|
|
|
Task writeTask = Task.CompletedTask;
|
|
switch (Type)
|
|
{
|
|
case BenchmarkTypes.TechEmpowerPlaintext:
|
|
writeTask = TechEmpowerPlaintext();
|
|
break;
|
|
case BenchmarkTypes.PlaintextChunked:
|
|
writeTask = PlaintextChunked();
|
|
break;
|
|
case BenchmarkTypes.PlaintextWithCookie:
|
|
writeTask = PlaintextWithCookie();
|
|
break;
|
|
case BenchmarkTypes.PlaintextChunkedWithCookie:
|
|
writeTask = PlaintextChunkedWithCookie();
|
|
break;
|
|
case BenchmarkTypes.LiveAspNet:
|
|
writeTask = LiveAspNet();
|
|
break;
|
|
}
|
|
|
|
await writeTask;
|
|
await _http1Connection.ProduceEndAsync();
|
|
}
|
|
|
|
private Task TechEmpowerPlaintext()
|
|
{
|
|
var responseHeaders = _http1Connection.ResponseHeaders;
|
|
responseHeaders["Content-Type"] = "text/plain";
|
|
responseHeaders.ContentLength = _helloWorldPayload.Length;
|
|
return _http1Connection.WriteAsync(new ArraySegment<byte>(_helloWorldPayload), default(CancellationToken));
|
|
}
|
|
|
|
private Task PlaintextChunked()
|
|
{
|
|
var responseHeaders = _http1Connection.ResponseHeaders;
|
|
responseHeaders["Content-Type"] = "text/plain";
|
|
return _http1Connection.WriteAsync(new ArraySegment<byte>(_helloWorldPayload), default(CancellationToken));
|
|
}
|
|
|
|
private Task LiveAspNet()
|
|
{
|
|
var responseHeaders = _http1Connection.ResponseHeaders;
|
|
responseHeaders["Content-Encoding"] = "gzip";
|
|
responseHeaders["Content-Type"] = "text/html; charset=utf-8";
|
|
responseHeaders["Strict-Transport-Security"] = "max-age=31536000; includeSubdomains";
|
|
responseHeaders["Vary"] = "Accept-Encoding";
|
|
responseHeaders["X-Powered-By"] = "ASP.NET";
|
|
return _http1Connection.WriteAsync(new ArraySegment<byte>(_helloWorldPayload), default(CancellationToken));
|
|
}
|
|
|
|
private Task PlaintextWithCookie()
|
|
{
|
|
var responseHeaders = _http1Connection.ResponseHeaders;
|
|
responseHeaders["Content-Type"] = "text/plain";
|
|
responseHeaders["Set-Cookie"] = "prov=20629ccd-8b0f-e8ef-2935-cd26609fc0bc; __qca=P0-1591065732-1479167353442; _ga=GA1.2.1298898376.1479167354; _gat=1; sgt=id=9519gfde_3347_4762_8762_df51458c8ec2; acct=t=why-is-%e0%a5%a7%e0%a5%a8%e0%a5%a9-numeric&s=why-is-%e0%a5%a7%e0%a5%a8%e0%a5%a9-numeric";
|
|
responseHeaders.ContentLength = _helloWorldPayload.Length;
|
|
return _http1Connection.WriteAsync(new ArraySegment<byte>(_helloWorldPayload), default(CancellationToken));
|
|
}
|
|
|
|
private Task PlaintextChunkedWithCookie()
|
|
{
|
|
var responseHeaders = _http1Connection.ResponseHeaders;
|
|
responseHeaders["Content-Type"] = "text/plain";
|
|
responseHeaders["Set-Cookie"] = "prov=20629ccd-8b0f-e8ef-2935-cd26609fc0bc; __qca=P0-1591065732-1479167353442; _ga=GA1.2.1298898376.1479167354; _gat=1; sgt=id=9519gfde_3347_4762_8762_df51458c8ec2; acct=t=why-is-%e0%a5%a7%e0%a5%a8%e0%a5%a9-numeric&s=why-is-%e0%a5%a7%e0%a5%a8%e0%a5%a9-numeric";
|
|
return _http1Connection.WriteAsync(new ArraySegment<byte>(_helloWorldPayload), default(CancellationToken));
|
|
}
|
|
|
|
[IterationSetup]
|
|
public void Setup()
|
|
{
|
|
_memoryPool = KestrelMemoryPool.Create();
|
|
var options = new PipeOptions(_memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false);
|
|
var pair = DuplexPipe.CreateConnectionPair(options, options);
|
|
|
|
var serviceContext = new ServiceContext
|
|
{
|
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
|
ServerOptions = new KestrelServerOptions(),
|
|
Log = new MockTrace(),
|
|
HttpParser = new HttpParser<Http1ParsingHandler>()
|
|
};
|
|
|
|
var http1Connection = new TestHttp1Connection(new Http1ConnectionContext
|
|
{
|
|
ServiceContext = serviceContext,
|
|
ConnectionFeatures = new FeatureCollection(),
|
|
MemoryPool = _memoryPool,
|
|
TimeoutControl = new MockTimeoutControl(),
|
|
Application = pair.Application,
|
|
Transport = pair.Transport
|
|
});
|
|
|
|
http1Connection.Reset();
|
|
|
|
_http1Connection = http1Connection;
|
|
}
|
|
|
|
[IterationCleanup]
|
|
public void Cleanup()
|
|
{
|
|
_memoryPool.Dispose();
|
|
}
|
|
|
|
public enum BenchmarkTypes
|
|
{
|
|
TechEmpowerPlaintext,
|
|
PlaintextChunked,
|
|
PlaintextWithCookie,
|
|
PlaintextChunkedWithCookie,
|
|
LiveAspNet
|
|
}
|
|
}
|
|
}
|