HttpHandler.fortunes.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. using BeetleX;
  2. using BeetleX.Buffers;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Globalization;
  6. using System.Text;
  7. using System.Text.Encodings.Web;
  8. using System.Text.Unicode;
  9. using System.Threading.Tasks;
  10. namespace PlatformBenchmarks
  11. {
  12. public partial class HttpHandler
  13. {
  14. private readonly static AsciiString _fortunesTableStart = "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>";
  15. private readonly static AsciiString _fortunesRowStart = "<tr><td>";
  16. private readonly static AsciiString _fortunesColumn = "</td><td>";
  17. private readonly static AsciiString _fortunesRowEnd = "</td></tr>";
  18. private readonly static AsciiString _fortunesTableEnd = "</table></body></html>";
  19. protected HtmlEncoder HtmlEncoder { get; } = CreateHtmlEncoder();
  20. private static HtmlEncoder CreateHtmlEncoder()
  21. {
  22. var settings = new TextEncoderSettings(UnicodeRanges.BasicLatin, UnicodeRanges.Katakana, UnicodeRanges.Hiragana);
  23. settings.AllowCharacter('\u2014'); // allow EM DASH through
  24. return HtmlEncoder.Create(settings);
  25. }
  26. public async Task fortunes(PipeStream stream, HttpToken token, ISession session)
  27. {
  28. try
  29. {
  30. var data = await token.Db.LoadFortunesRows();
  31. stream.Write(_HtmlResultPreamble.Data, 0, _HtmlResultPreamble.Length);
  32. token.ContentLength = stream.Allocate(HttpHandler._LengthSize);
  33. GMTDate.Default.Write(stream);
  34. token.ContentPostion = stream.CacheLength;
  35. var html = token.GetHtmlBufferWriter();
  36. html.Reset();
  37. html.Write(_fortunesTableStart.Data, 0, _fortunesTableStart.Length);
  38. foreach (var item in data)
  39. {
  40. html.Write(_fortunesRowStart.Data, 0, _fortunesRowStart.Length);
  41. WriteNumeric(html, (uint)item.Id);
  42. html.Write(_fortunesColumn.Data, 0, _fortunesColumn.Length);
  43. html.Write(HtmlEncoder.Encode(item.Message));
  44. html.Write(_fortunesRowEnd.Data, 0, _fortunesRowEnd.Length);
  45. }
  46. html.Write(_fortunesTableEnd.Data, 0, _fortunesTableEnd.Length);
  47. stream.Write(html.Data, 0, html.Length);
  48. }
  49. catch (Exception e_)
  50. {
  51. HttpServer.ApiServer.Log(BeetleX.EventArgs.LogType.Error, null, $"fortunes error {e_.Message}@{e_.StackTrace}");
  52. stream.Write(e_.Message);
  53. }
  54. OnCompleted(stream, session, token);
  55. }
  56. internal void WriteNumeric(HtmlBufferWriter writer, uint number)
  57. {
  58. const byte AsciiDigitStart = (byte)'0';
  59. if (number < 10)
  60. {
  61. writer.Write((byte)(number + AsciiDigitStart));
  62. }
  63. else if (number < 100)
  64. {
  65. var tens = (byte)((number * 205u) >> 11); // div10, valid to 1028
  66. var span = new byte[2];
  67. span[0] = (byte)(tens + AsciiDigitStart);
  68. span[1] = (byte)(number - (tens * 10) + AsciiDigitStart);
  69. writer.Write(span, 0, 2);
  70. }
  71. else if (number < 1000)
  72. {
  73. var digit0 = (byte)((number * 41u) >> 12); // div100, valid to 1098
  74. var digits01 = (byte)((number * 205u) >> 11); // div10, valid to 1028
  75. var span = new byte[3];
  76. span[0] = (byte)(digit0 + AsciiDigitStart);
  77. span[1] = (byte)(digits01 - (digit0 * 10) + AsciiDigitStart);
  78. span[2] = (byte)(number - (digits01 * 10) + AsciiDigitStart);
  79. writer.Write(span, 0, 3);
  80. }
  81. }
  82. internal void WriteNumeric(PipeStream stream, uint number)
  83. {
  84. const byte AsciiDigitStart = (byte)'0';
  85. if (number < 10)
  86. {
  87. stream.WriteByte((byte)(number + AsciiDigitStart));
  88. }
  89. else if (number < 100)
  90. {
  91. var tens = (byte)((number * 205u) >> 11); // div10, valid to 1028
  92. var span = new byte[2];
  93. span[0] = (byte)(tens + AsciiDigitStart);
  94. span[1] = (byte)(number - (tens * 10) + AsciiDigitStart);
  95. stream.Write(span, 0, 2);
  96. }
  97. else if (number < 1000)
  98. {
  99. var digit0 = (byte)((number * 41u) >> 12); // div100, valid to 1098
  100. var digits01 = (byte)((number * 205u) >> 11); // div10, valid to 1028
  101. var span = new byte[3];
  102. span[0] = (byte)(digit0 + AsciiDigitStart);
  103. span[1] = (byte)(digits01 - (digit0 * 10) + AsciiDigitStart);
  104. span[2] = (byte)(number - (digits01 * 10) + AsciiDigitStart);
  105. stream.Write(span, 0, 3);
  106. }
  107. }
  108. }
  109. }