You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
6.1 KiB

4 years ago
4 years ago
4 years ago
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Net;
  5. namespace Apewer.Web
  6. {
  7. /// <summary>用于网站的服务程序。</summary>
  8. public class HttpListenerProvider : ApiProvider
  9. {
  10. private HttpListenerContext context;
  11. private HttpListenerRequest request;
  12. private HttpListenerResponse response;
  13. /// <summary>创建服务程序实例。</summary>
  14. /// <exception cref="ArgumentNullException"></exception>
  15. public HttpListenerProvider(HttpListenerContext context)
  16. {
  17. if (context == null) throw new ArgumentNullException(nameof(context));
  18. this.context = context;
  19. request = context.Request;
  20. response = context.Response;
  21. }
  22. #region Implement
  23. /// <summary>写入响应前的检查,返回错误信息。</summary>
  24. public override string PreWrite()
  25. {
  26. if (response == null) return null;
  27. // 从 Response 头中移除 Server 和 X-Powered-By 属性。
  28. var keys = new List<string>(response.Headers.AllKeys);
  29. if (keys.Contains("Server")) response.Headers.Remove("Server");
  30. if (keys.Contains("X-Powered-By")) response.Headers.Remove("X-Powered-By");
  31. return null;
  32. }
  33. /// <summary>向发送缓冲区的数据,之后停止并关闭响应流。</summary>
  34. public override void End() => End(true);
  35. #endregion
  36. #region Request
  37. /// <summary>获取 HTTP 方法。</summary>
  38. public override Network.HttpMethod GetMethod() => ApiUtility.Method(request.HttpMethod);
  39. /// <summary>获取客户端的 IP 地址。</summary>
  40. public override string GetClientIP() => request.UserHostAddress;
  41. /// <summary>获取请求的 URL。</summary>
  42. public override Uri GetUrl() => request.Url;
  43. /// <summary>获取请求的 Referrer。</summary>
  44. public override string GetReferrer() => request.UrlReferrer == null ? null : request.UrlReferrer.OriginalString;
  45. /// <summary>获取请求的头。</summary>
  46. public override StringPairs GetHeaders() => StringPairs.From(request.Headers);
  47. /// <summary>获取请求的内容类型。</summary>
  48. public override string GetContentType() => request.ContentType;
  49. /// <summary>获取请求的内容长度。</summary>
  50. public override long GetContentLength() => request.ContentLength64;
  51. /// <summary>获取请求的内容。</summary>
  52. public override Stream RequestBody() => request.InputStream;
  53. #endregion
  54. #region Response
  55. /// <summary>设置 HTTP 状态。</summary>
  56. public override void SetStatus(int status, int subStatus = 0) => response.StatusCode = status;
  57. /// <summary>设置响应的头。</summary>
  58. public override string SetHeader(string name, string value)
  59. {
  60. if (response == null || string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value)) return "参数无效。";
  61. try
  62. {
  63. response.AddHeader(name, value);
  64. return null;
  65. }
  66. catch (Exception ex) { return ex.Message; }
  67. }
  68. /// <summary>设置响应的缓存秒数,设置为 0 即不允许缓存。</summary>
  69. public override void SetCache(int seconds)
  70. {
  71. if (seconds > 0)
  72. {
  73. SetHeader("Cache-Control", $"public, max-age={seconds}, s-maxage={seconds}");
  74. return;
  75. }
  76. SetHeader("Cache-Control", "no-cache, no-store, must-revalidate");
  77. SetHeader("Pragma", "no-cache");
  78. }
  79. /// <summary>设置响应的缓存秒数。</summary>
  80. public override void SetContentType(string value) => response.ContentType = value;
  81. /// <summary>设置响应的内容长度。</summary>
  82. public override void SetContentLength(long value) => response.ContentLength64 = value;
  83. /// <summary>设置响应重定向。</summary>
  84. /// <remarks>响应 302 状态。</remarks>
  85. public override void SetRedirect(string location)
  86. {
  87. try { response.Redirect(location); } catch { }
  88. }
  89. /// <summary>获取 Response 流。</summary>
  90. public override Stream ResponseBody() => response.OutputStream;
  91. #endregion
  92. #region This
  93. /// <summary>停止并关闭响应流。可指定向发送缓冲区的数据。</summary>
  94. public void End(bool flush)
  95. {
  96. if (response == null) return;
  97. try { if (flush) response.OutputStream.Flush(); } catch { }
  98. try { response.Close(); } catch { }
  99. }
  100. /// <summary>获取 Cookies。</summary>
  101. public StringPairs GetCookies()
  102. {
  103. var sp = new StringPairs();
  104. if (request != null && request.Cookies != null)
  105. {
  106. for (var i = 0; i < request.Cookies.Count; i++)
  107. {
  108. try
  109. {
  110. var cookie = request.Cookies[i];
  111. var key = cookie.Name;
  112. var value = cookie.Value ?? "";
  113. sp.Add(new KeyValuePair<string, string>(key, value));
  114. }
  115. catch { }
  116. }
  117. }
  118. return sp;
  119. }
  120. /// <summary>设置响应的 Cookie。</summary>
  121. public string SetCookie(string key, string value)
  122. {
  123. if (response == null) return null;
  124. var k = key.ToTrim();
  125. var v = value.ToTrim();
  126. if (k.IsEmpty()) return "参数 Key 无效。";
  127. try
  128. {
  129. var cookie = new Cookie(k, v);
  130. var now = DateTime.Now;
  131. cookie.Expires = v.IsEmpty() ? now.AddDays(-1) : now.AddYears(1);
  132. response.SetCookie(cookie);
  133. return null;
  134. }
  135. catch (Exception ex)
  136. {
  137. return ex.Message;
  138. }
  139. }
  140. #endregion
  141. }
  142. }