HttpHandler.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. using BeetleX.Light;
  2. using BeetleX.Light.Memory;
  3. using System;
  4. using System.Buffers;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. using System.IO.Pipelines;
  8. using System.Text;
  9. using System.Text.Json;
  10. using System.Threading.Tasks;
  11. namespace PlatformBenchmarks
  12. {
  13. public partial class HttpHandler : SesionBase
  14. {
  15. private static readonly AsciiString _line = new AsciiString("\r\n");
  16. private static readonly AsciiString _2line = new AsciiString("\r\n\r\n");
  17. private static readonly AsciiString _httpsuccess = new AsciiString("HTTP/1.1 200 OK\r\n");
  18. private static readonly AsciiString _headerServer = "Server: B\r\n";
  19. private static readonly AsciiString _headerContentLength = "Content-Length: ";
  20. private static readonly AsciiString _headerContentLengthZero = "Content-Length: 0\r\n";
  21. private static readonly AsciiString _headerContentTypeText = "Content-Type: text/plain\r\n";
  22. private static readonly AsciiString _headerContentTypeHtml = "Content-Type: text/html; charset=UTF-8\r\n";
  23. private static readonly AsciiString _headerContentTypeJson = "Content-Type: application/json\r\n";
  24. private static readonly AsciiString _path_Json = "/json";
  25. private static readonly AsciiString _path_Db = "/db";
  26. private static readonly AsciiString _path_Queries = "/queries";
  27. private static readonly AsciiString _path_Plaintext = "/plaintext";
  28. private static readonly AsciiString _path_Updates = "/updates";
  29. private static readonly AsciiString _path_Fortunes = "/fortunes";
  30. private static readonly AsciiString _result_plaintext = "Hello, World!";
  31. private static readonly AsciiString _cached_worlds = "/cached-worlds";
  32. private readonly static uint _jsonPayloadSize = (uint)System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(new JsonMessage { message = "Hello, World!" }).Length;
  33. private readonly static AsciiString _jsonPreamble =
  34. _httpsuccess
  35. + _headerContentTypeJson
  36. + _headerServer
  37. + _headerContentLength + _jsonPayloadSize.ToString() + _line;
  38. private readonly static AsciiString _plaintextPreamble =
  39. _httpsuccess
  40. + _headerContentTypeText
  41. + _headerServer
  42. + _headerContentLength + _result_plaintext.Length.ToString() + _line;
  43. private readonly static AsciiString _jsonResultPreamble =
  44. _httpsuccess
  45. + _headerContentTypeJson
  46. + _headerServer;
  47. private readonly static AsciiString _HtmlResultPreamble =
  48. _httpsuccess
  49. + _headerContentTypeHtml
  50. + _headerServer;
  51. private static byte _Space = 32;
  52. public const int _LengthSize = 8;
  53. private static byte _question = 63;
  54. struct ContentLengthMemory
  55. {
  56. public Memory<byte> Data { get; set; }
  57. public void Full(int length)
  58. {
  59. _headerContentLength.Data.CopyTo(Data);
  60. var span = Data.Slice(_headerContentLength.Length).Span;
  61. var len = span.Write(length.ToString(), Encoding.ASCII);
  62. for (int i = len; i < span.Length - 2; i++)
  63. {
  64. span[i] = 32;
  65. }
  66. span[^2] = 13;
  67. span[^1] = 10;
  68. }
  69. }
  70. protected Memory<byte> GetContentLengthMemory(IStreamWriter writer)
  71. {
  72. var result = writer.WriteSequenceNetStream.GetWriteMemory(28);
  73. writer.WriteSequenceNetStream.WriteAdvance(28);
  74. return result;
  75. }
  76. public NetContext Context { get; set; }
  77. public HttpHandler()
  78. {
  79. }
  80. private Queue<RequestData> _Requests = new Queue<RequestData>();
  81. private RawDb _db;
  82. private RequestData _ReadRequest = null;
  83. public override void Connected(NetContext context)
  84. {
  85. base.Connected(context);
  86. this.Context = context;
  87. _db = new RawDb(new ConcurrentRandom(), Npgsql.NpgsqlFactory.Instance); ;
  88. }
  89. private int AnalysisUrl(ReadOnlySpan<byte> url)
  90. {
  91. for (int i = 0; i < url.Length; i++)
  92. {
  93. if (url[i] == _question)
  94. return i;
  95. }
  96. return -1;
  97. }
  98. public override void Receive(NetContext context, object message)
  99. {
  100. var stream = context.Reader.ReadSequenceNetStream;
  101. var reader = stream.GetReadOnlySequence();
  102. var len = reader.IndexOf(_line);
  103. while (len != null)
  104. {
  105. var lendata = len.Value;
  106. stream.ReadAdvance(lendata.Length);
  107. if (lendata.Length == 2)
  108. {
  109. _Requests.Enqueue(_ReadRequest);
  110. _ReadRequest = null;
  111. }
  112. else
  113. {
  114. if (_ReadRequest == null)
  115. {
  116. _ReadRequest = new RequestData();
  117. }
  118. if (_ReadRequest.Action == null)
  119. {
  120. AnalysisAction(lendata, out var type, out var querystring);
  121. _ReadRequest.Action = type;
  122. _ReadRequest.QueryString = querystring;
  123. }
  124. else
  125. {
  126. }
  127. }
  128. reader = stream.GetReadOnlySequence();
  129. len = reader.IndexOf(_line);
  130. }
  131. if (_Requests.Count > 0)
  132. {
  133. OnStartRequest(context.Writer);
  134. }
  135. }
  136. //public override void SessionReceive(IServer server, SessionReceiveEventArgs e)
  137. //{
  138. // base.SessionReceive(server, e);
  139. // PipeStream pipeStream = e.Session.Stream.ToPipeStream();
  140. // HttpToken token = (HttpToken)e.Session.Tag;
  141. // var result = pipeStream.IndexOfLine();
  142. // while (result.End != null)
  143. // {
  144. // if (result.Length == 2)
  145. // {
  146. // pipeStream.ReadFree(result.Length);
  147. // OnStartRequest(token.CurrentRequest, e.Session, token, pipeStream);
  148. // }
  149. // else
  150. // {
  151. // if (token.CurrentRequest == null)
  152. // {
  153. // var request = new RequestData();
  154. // byte[] buffer = null;
  155. // buffer = new byte[result.Length];
  156. // pipeStream.Read(buffer, 0, result.Length);
  157. // request.Data = new ArraySegment<byte>(buffer, 0, result.Length);
  158. // AnalysisAction(request);
  159. // if (request.Action == ActionType.Plaintext)
  160. // {
  161. // token.CurrentRequest = request;
  162. // }
  163. // else
  164. // {
  165. // token.CurrentRequest = request;
  166. // pipeStream.ReadFree((int)pipeStream.Length);
  167. // OnStartRequest(request, e.Session, token, pipeStream);
  168. // return;
  169. // }
  170. // }
  171. // else
  172. // {
  173. // pipeStream.ReadFree(result.Length);
  174. // }
  175. // }
  176. // if (pipeStream.Length > 0)
  177. // result = pipeStream.IndexOfLine();
  178. // else
  179. // break;
  180. // }
  181. //}
  182. private void AnalysisAction(ReadOnlySequence<byte> line, out ActionType type, out string queryString)
  183. {
  184. type = ActionType.Plaintext;
  185. queryString = default;
  186. var spanIndex = line.PositionOf((byte)32);
  187. var postion = line.GetPosition(1, spanIndex.Value);
  188. line = line.Slice(postion);
  189. spanIndex = line.PositionOf((byte)32);
  190. var url = line.Slice(0, spanIndex.Value);
  191. int baseurlLen = 0;
  192. spanIndex = url.PositionOf((byte)63);
  193. if (spanIndex != null)
  194. {
  195. baseurlLen = (int)url.Slice(0, spanIndex.Value).Length;
  196. queryString = url.Slice(baseurlLen + 1).ReadString(Encoding.ASCII);
  197. }
  198. else
  199. {
  200. baseurlLen = (int)url.Length;
  201. }
  202. Span<byte> baseUrl = stackalloc byte[baseurlLen];
  203. url.Slice(0, baseurlLen).CopyTo(baseUrl);
  204. if (baseUrl.Length == _path_Plaintext.Length && baseUrl.StartsWith(_path_Plaintext))
  205. {
  206. type = ActionType.Plaintext;
  207. }
  208. else if (baseUrl.Length == _path_Json.Length && baseUrl.StartsWith(_path_Json))
  209. {
  210. type = ActionType.Json;
  211. }
  212. else if (baseUrl.Length == _path_Db.Length && baseUrl.StartsWith(_path_Db))
  213. {
  214. type = ActionType.Db;
  215. }
  216. else if (baseUrl.Length == _path_Queries.Length && baseUrl.StartsWith(_path_Queries))
  217. {
  218. type = ActionType.Queries;
  219. }
  220. else if (baseUrl.Length == _cached_worlds.Length && baseUrl.StartsWith(_cached_worlds))
  221. {
  222. type = ActionType.Caching;
  223. }
  224. else if (baseUrl.Length == _path_Updates.Length && baseUrl.StartsWith(_path_Updates))
  225. {
  226. type = ActionType.Updates;
  227. }
  228. else if (baseUrl.Length == _path_Fortunes.Length && baseUrl.StartsWith(_path_Fortunes))
  229. {
  230. type = ActionType.Fortunes;
  231. }
  232. else
  233. {
  234. type = ActionType.Other;
  235. }
  236. }
  237. public async Task OnStartRequest(IStreamWriter stream)
  238. {
  239. bool haveData = false;
  240. while (_Requests.Count > 0)
  241. {
  242. haveData = true;
  243. var data = _Requests.Dequeue();
  244. ActionType type = data.Action.Value;
  245. if (type == ActionType.Plaintext)
  246. {
  247. Plaintext(stream);
  248. }
  249. else if (type == ActionType.Json)
  250. {
  251. Json(stream);
  252. }
  253. else if (type == ActionType.Db)
  254. {
  255. await db(stream);
  256. }
  257. else if (type == ActionType.Queries)
  258. {
  259. await queries(data.QueryString, stream);
  260. }
  261. else if (type == ActionType.Caching)
  262. {
  263. await caching(data.QueryString, stream);
  264. }
  265. else if (type == ActionType.Updates)
  266. {
  267. await updates(data.QueryString, stream);
  268. }
  269. else if (type == ActionType.Fortunes)
  270. {
  271. await fortunes(stream);
  272. }
  273. else
  274. {
  275. await Default(stream);
  276. }
  277. }
  278. if (haveData)
  279. {
  280. stream.Flush();
  281. }
  282. }
  283. private Utf8JsonWriter GetJsonWriter(IStreamWriter stream)
  284. {
  285. Utf8JsonWriter utf8JsonWriter = _utf8JsonWriter ??= new Utf8JsonWriter((Stream)stream.WriteSequenceNetStream, new JsonWriterOptions { SkipValidation = true });
  286. utf8JsonWriter.Reset((Stream)stream.WriteSequenceNetStream);
  287. return utf8JsonWriter;
  288. }
  289. [ThreadStatic]
  290. private static Utf8JsonWriter _utf8JsonWriter;
  291. public static JsonWriterOptions _jsonWriterOptions = new JsonWriterOptions
  292. {
  293. SkipValidation = true
  294. };
  295. }
  296. }