|
@@ -2,7 +2,9 @@
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
|
|
using System;
|
|
using System;
|
|
|
|
+using System.Collections.Generic;
|
|
using System.IO.Pipelines;
|
|
using System.IO.Pipelines;
|
|
|
|
+using System.Text.Encodings.Web;
|
|
using System.Threading.Tasks;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
|
using Utf8Json;
|
|
using Utf8Json;
|
|
@@ -22,13 +24,24 @@ namespace PlatformBenchmarks
|
|
private readonly static AsciiString _headerContentLengthZero = "Content-Length: 0\r\n";
|
|
private readonly static AsciiString _headerContentLengthZero = "Content-Length: 0\r\n";
|
|
private readonly static AsciiString _headerContentTypeText = "Content-Type: text/plain\r\n";
|
|
private readonly static AsciiString _headerContentTypeText = "Content-Type: text/plain\r\n";
|
|
private readonly static AsciiString _headerContentTypeJson = "Content-Type: application/json\r\n";
|
|
private readonly static AsciiString _headerContentTypeJson = "Content-Type: application/json\r\n";
|
|
|
|
+ private readonly static AsciiString _headerContentTypeHtml = "Content-Type: text/html; charset=UTF-8\r\n";
|
|
|
|
|
|
private readonly static AsciiString _plainTextBody = "Hello, World!";
|
|
private readonly static AsciiString _plainTextBody = "Hello, World!";
|
|
|
|
|
|
|
|
+ private readonly static AsciiString _fortunesTableStart = "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>";
|
|
|
|
+ private readonly static AsciiString _fortunesRowStart = "<tr><td>";
|
|
|
|
+ private readonly static AsciiString _fortunesColumn = "</td><td>";
|
|
|
|
+ private readonly static AsciiString _fortunesRowEnd = "</td></tr>";
|
|
|
|
+ private readonly static AsciiString _fortunesTableEnd = "</table></body></html>";
|
|
|
|
+ private readonly static AsciiString _contentLengthGap = new string(' ', 4);
|
|
|
|
+
|
|
|
|
+ public static IDb Db { get; set; }
|
|
|
|
+
|
|
public static class Paths
|
|
public static class Paths
|
|
{
|
|
{
|
|
public readonly static AsciiString Plaintext = "/plaintext";
|
|
public readonly static AsciiString Plaintext = "/plaintext";
|
|
public readonly static AsciiString Json = "/json";
|
|
public readonly static AsciiString Json = "/json";
|
|
|
|
+ public readonly static AsciiString Fortunes = "/fortunes";
|
|
}
|
|
}
|
|
|
|
|
|
private RequestType _requestType;
|
|
private RequestType _requestType;
|
|
@@ -46,12 +59,16 @@ namespace PlatformBenchmarks
|
|
{
|
|
{
|
|
requestType = RequestType.Json;
|
|
requestType = RequestType.Json;
|
|
}
|
|
}
|
|
|
|
+ else if (Paths.Fortunes.Length <= path.Length && path.StartsWith(Paths.Fortunes))
|
|
|
|
+ {
|
|
|
|
+ requestType = RequestType.Fortunes;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
_requestType = requestType;
|
|
_requestType = requestType;
|
|
}
|
|
}
|
|
|
|
|
|
- public ValueTask ProcessRequestAsync()
|
|
|
|
|
|
+ public Task ProcessRequestAsync()
|
|
{
|
|
{
|
|
if (_requestType == RequestType.PlainText)
|
|
if (_requestType == RequestType.PlainText)
|
|
{
|
|
{
|
|
@@ -61,12 +78,16 @@ namespace PlatformBenchmarks
|
|
{
|
|
{
|
|
Json(Writer);
|
|
Json(Writer);
|
|
}
|
|
}
|
|
|
|
+ else if (_requestType == RequestType.Fortunes)
|
|
|
|
+ {
|
|
|
|
+ return Fortunes(Writer);
|
|
|
|
+ }
|
|
else
|
|
else
|
|
{
|
|
{
|
|
Default(Writer);
|
|
Default(Writer);
|
|
}
|
|
}
|
|
|
|
|
|
- return default;
|
|
|
|
|
|
+ return Task.CompletedTask;
|
|
}
|
|
}
|
|
|
|
|
|
private static void PlainText(PipeWriter pipeWriter)
|
|
private static void PlainText(PipeWriter pipeWriter)
|
|
@@ -126,6 +147,53 @@ namespace PlatformBenchmarks
|
|
writer.Commit();
|
|
writer.Commit();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private async Task Fortunes(PipeWriter pipeWriter)
|
|
|
|
+ {
|
|
|
|
+ OutputFortunes(pipeWriter, await Db.LoadFortunesRows());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void OutputFortunes(PipeWriter pipeWriter, List<Fortune> model)
|
|
|
|
+ {
|
|
|
|
+ var writer = GetWriter(pipeWriter);
|
|
|
|
+
|
|
|
|
+ // HTTP 1.1 OK
|
|
|
|
+ writer.Write(_http11OK);
|
|
|
|
+
|
|
|
|
+ // Server headers
|
|
|
|
+ writer.Write(_headerServer);
|
|
|
|
+
|
|
|
|
+ // Date header
|
|
|
|
+ writer.Write(DateHeader.HeaderBytes);
|
|
|
|
+
|
|
|
|
+ // Content-Type header
|
|
|
|
+ writer.Write(_headerContentTypeHtml);
|
|
|
|
+
|
|
|
|
+ // Content-Length header
|
|
|
|
+ writer.Write(_headerContentLength);
|
|
|
|
+
|
|
|
|
+ var lengthWriter = writer;
|
|
|
|
+ writer.Write(_contentLengthGap);
|
|
|
|
+
|
|
|
|
+ // End of headers
|
|
|
|
+ writer.Write(_eoh);
|
|
|
|
+
|
|
|
|
+ var bodyStart = writer.Buffered;
|
|
|
|
+ // Body
|
|
|
|
+ writer.Write(_fortunesTableStart);
|
|
|
|
+ foreach (var item in model)
|
|
|
|
+ {
|
|
|
|
+ writer.Write(_fortunesRowStart);
|
|
|
|
+ writer.WriteNumeric((uint)item.Id);
|
|
|
|
+ writer.Write(_fortunesColumn);
|
|
|
|
+ writer.WriteUtf8String(HtmlEncoder.Encode(item.Message));
|
|
|
|
+ writer.Write(_fortunesRowEnd);
|
|
|
|
+ }
|
|
|
|
+ writer.Write(_fortunesTableEnd);
|
|
|
|
+ lengthWriter.WriteNumeric((uint)(writer.Buffered - bodyStart));
|
|
|
|
+
|
|
|
|
+ writer.Commit();
|
|
|
|
+ }
|
|
|
|
+
|
|
private static void Default(PipeWriter pipeWriter)
|
|
private static void Default(PipeWriter pipeWriter)
|
|
{
|
|
{
|
|
var writer = GetWriter(pipeWriter);
|
|
var writer = GetWriter(pipeWriter);
|
|
@@ -151,7 +219,8 @@ namespace PlatformBenchmarks
|
|
{
|
|
{
|
|
NotRecognized,
|
|
NotRecognized,
|
|
PlainText,
|
|
PlainText,
|
|
- Json
|
|
|
|
|
|
+ Json,
|
|
|
|
+ Fortunes
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|