懒人记时 代码仓库
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

178 行
5.9 KiB

  1. using Newtonsoft.Json;
  2. using Newtonsoft.Json.Linq;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Net;
  9. using System.Text;
  10. using System.Threading;
  11. using System.Web;
  12. using System.Windows.Forms;
  13. namespace AppTime
  14. {
  15. class WebServer
  16. {
  17. HttpListener listener;
  18. Thread thread;
  19. //public HttpListenerRequest Request;
  20. //public HttpListenerResponse Response;
  21. public string WebRootPath;
  22. HashSet<string> defaultPage = new HashSet<string>(StringComparer.OrdinalIgnoreCase){
  23. "index.html",
  24. "index.htm",
  25. "default.html",
  26. "default.htm"
  27. };
  28. public void Start(int port, object controller, string webfolder = "web")
  29. {
  30. thread = new Thread(() =>
  31. {
  32. WebRootPath = webfolder = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), webfolder);
  33. var folders = Directory.GetDirectories(webfolder, "*", SearchOption.AllDirectories);
  34. var webroot = $@"http://localhost:{port}/";
  35. listener = new HttpListener();
  36. foreach (var f in folders)
  37. {
  38. listener.Prefixes.Add(webroot + f.Substring(webfolder.Length + 1).Replace("\\", "/") + "/");
  39. }
  40. listener.Prefixes.Add(webroot);
  41. listener.Start();
  42. while (true)
  43. {
  44. var ctx = listener.GetContext();
  45. //Debug.WriteLine($"Web Request:{ctx.Request.Url}");
  46. //ThreadPool.QueueUserWorkItem(_ => processRequest(ctx, webfolder, controller));
  47. new Thread(() => processRequest(
  48. ctx,
  49. webfolder,
  50. controller)
  51. )
  52. { IsBackground = true, Name = "WebServer Process Request" }.Start();
  53. }
  54. })
  55. {
  56. Name = "WebServer",
  57. IsBackground = true
  58. };
  59. thread.Start();
  60. }
  61. void processRequest(HttpListenerContext context, string webfolder, object controller)
  62. {
  63. var request = context.Request;
  64. var file = webfolder + request.RawUrl.Replace("/", "\\");
  65. string query = "";
  66. var p = file.IndexOf("?");
  67. if (p > 0)
  68. {
  69. query = file.Substring(p + 1);
  70. file = file.Substring(0, p);
  71. }
  72. var response = context.Response;
  73. byte[] data = null;
  74. if (Path.GetFileName(Path.GetDirectoryName(file)).Equals("data", StringComparison.OrdinalIgnoreCase))
  75. {
  76. try
  77. {
  78. if (string.IsNullOrWhiteSpace(query))
  79. {
  80. using var reader = new StreamReader(request.InputStream);
  81. query = reader.ReadToEnd();
  82. }
  83. var info = JObject.Parse(HttpUtility.UrlDecode(query));
  84. var method = controller.GetType().GetMethod(Path.GetFileName(file));
  85. var args = info.Value<JArray>("args").Cast<object>().ToArray();
  86. var @params = method.GetParameters();
  87. for (var i = 0; i < args.Length; i++)
  88. {
  89. if (args[i] is JObject jo)
  90. {
  91. args[i] = jo.ToObject(@params[i].ParameterType);
  92. }
  93. else
  94. {
  95. args[i] = Convert.ChangeType(args[i], @params[i].ParameterType);
  96. }
  97. }
  98. var result = method.Invoke(controller, args);
  99. if (result is byte[] bytes)
  100. {
  101. data = bytes;
  102. }
  103. else
  104. {
  105. data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(result));
  106. }
  107. }
  108. catch (Exception ex)
  109. {
  110. data = Encoding.UTF8.GetBytes($"bad request: method:{Path.GetFileName(file)} query:{query}");
  111. }
  112. }
  113. else
  114. {
  115. if (Directory.Exists(file))
  116. {
  117. var def = Directory.GetFiles(file).FirstOrDefault(f => defaultPage.Contains(Path.GetFileName(f), StringComparer.OrdinalIgnoreCase));
  118. if (def != null)
  119. {
  120. file = def;
  121. }
  122. }
  123. if (File.Exists(file))
  124. {
  125. var mime = MimeMapping.GetMimeMapping(file);
  126. response.Headers.Add("Content-type", mime);
  127. if (mime.StartsWith("text/"))
  128. {
  129. response.ContentEncoding = Encoding.GetEncoding("utf-8");
  130. data = Encoding.UTF8.GetBytes(File.ReadAllText(file, Encoding.Default));
  131. }
  132. else
  133. {
  134. data = File.ReadAllBytes(file);
  135. }
  136. }
  137. }
  138. if (data == null)
  139. {
  140. data = Encoding.UTF8.GetBytes($"file not found: {file}");
  141. }
  142. response.ContentLength64 = data.Length;
  143. var output = response.OutputStream;
  144. try
  145. {
  146. output.Write(data, 0, data.Length);
  147. }
  148. catch (HttpListenerException ex)
  149. {
  150. }
  151. output.Close();
  152. }
  153. public void Stop()
  154. {
  155. thread.Abort();
  156. listener.Stop();
  157. listener.Close();
  158. }
  159. }
  160. }