HttpHandler.cs 11 KB

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