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.

285 lines
9.7 KiB

  1. #if NETFRAMEWORK
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Net;
  6. using System.Net.Security;
  7. using System.Security.Cryptography.X509Certificates;
  8. using System.Web;
  9. namespace Apewer.Web.HttpProxy
  10. {
  11. sealed class HttpHandler : IHttpHandler
  12. {
  13. public bool IsReusable { get { return false; } }
  14. public void ProcessRequest(HttpContext context)
  15. {
  16. if (context.Request.HttpMethod.ToLower().Contains("options")) return;
  17. context.Response.Buffer = true;
  18. try
  19. {
  20. Proxy(context);
  21. }
  22. catch (Exception exception)
  23. {
  24. try
  25. {
  26. context.Response.Clear();
  27. context.Response.ContentType = "text/plain";
  28. context.Response.Write(exception.ToString());
  29. }
  30. catch { }
  31. }
  32. }
  33. // const int SegmentalUrlOffset = 0;
  34. static void Proxy(HttpContext context)
  35. {
  36. var url = GetUrl(context.Request.Url);
  37. context.Response.Headers.Add("-Proxy-Url", url);
  38. context.Response.Headers.Add("-Proxy-Http-X-Forwarded-For", Variable("http_x_forwarded_for"));
  39. context.Response.Headers.Add("-Proxy-Remote-Addr", Variable("remote_addr"));
  40. // 忽略跨域选项请求。
  41. if (context.Request.HttpMethod.ToLower().Contains("options")) return;
  42. // 阻止浏览器请求网站图标。
  43. if (context.Request.Url.AbsolutePath.ToLower() == "/favicon.ico") return;
  44. // 阻止搜索引擎收录。
  45. if (context.Request.Url.AbsolutePath.ToLower() == "/robot.txt")
  46. {
  47. context.Response.ContentType = "text/plain";
  48. context.Response.Write("User-agent: *\nDisallow: / \n");
  49. return;
  50. }
  51. var ShowStack = false;
  52. try
  53. {
  54. context.Response.Buffer = false;
  55. var request = GetRequest(url, context.Request);
  56. var response = GetResponse(request);
  57. WriteHeaders(response, context.Response);
  58. WriteStream(response, context.Response);
  59. }
  60. catch (System.Net.Sockets.SocketException exception) // 无法连接服务器。
  61. {
  62. context.Response.ContentType = "text/plain";
  63. context.Response.Write(ShowStack ? exception.ToString() : exception.Message);
  64. }
  65. catch (System.Net.WebException exception) // 无法连接服务器;超时。
  66. {
  67. context.Response.ContentType = "text/plain";
  68. context.Response.Write(ShowStack ? exception.ToString() : exception.Message);
  69. }
  70. catch (System.UriFormatException exception) // 链接无效。
  71. {
  72. context.Response.ContentType = "text/plain";
  73. context.Response.Write(ShowStack ? exception.ToString() : exception.Message);
  74. }
  75. context.Response.Flush();
  76. context.Response.Close();
  77. }
  78. static string GetUrl(Uri uri)
  79. {
  80. var paq = uri.PathAndQuery;
  81. var array = uri.PathAndQuery.Split('/');
  82. if (array.Length < 2) return null;
  83. var lower = string.IsNullOrEmpty(array[1]) ? null : array[1].ToLower();
  84. var start = 1;
  85. var fragments = new List<string>();
  86. switch (lower)
  87. {
  88. case "http:":
  89. case "https:":
  90. fragments.Add(lower);
  91. start = 2;
  92. break;
  93. default:
  94. start = 1;
  95. var scheme = uri.Scheme.ToLower();
  96. if (!scheme.EndsWith(":")) scheme = scheme + ":";
  97. fragments.Add(scheme);
  98. break;
  99. }
  100. fragments.Add("");
  101. for (var i = start; i < array.Length; i++) fragments.Add(array[i]);
  102. var url = string.Join("/", fragments.ToArray());
  103. return url;
  104. }
  105. static HttpWebRequest GetRequest(string url, HttpRequest input)
  106. {
  107. var https = url.ToLower().Trim().StartsWith("https");
  108. if (https) ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(ValidateCallback);
  109. var request = (HttpWebRequest)WebRequest.Create(url);
  110. request.Method = input.HttpMethod;
  111. request.AllowAutoRedirect = true;
  112. request.Timeout = 60000;
  113. // Headers
  114. foreach (var key in input.Headers.AllKeys)
  115. {
  116. try
  117. {
  118. if (string.IsNullOrEmpty(key)) continue;
  119. var value = input.Headers[key];
  120. if (string.IsNullOrEmpty(value)) continue;
  121. var lower = key.ToLower();
  122. if (lower == "accept") continue;
  123. else if (lower == "accept-encoding") continue;
  124. else if (lower == "ali-swift-log-host") continue;
  125. else if (lower == "ali-swift-stat-host") continue;
  126. else if (lower == "cache-control") continue;
  127. else if (lower == "connection") continue;
  128. else if (lower == "dnt") continue;
  129. else if (lower == "eagleeye-traceid") continue;
  130. else if (lower == "host") continue;
  131. else if (lower == "if-modified-since") request.IfModifiedSince = new DateTime(1970, 1, 1, 0, 0, 0, 0);
  132. else if (lower == "referer") request.Referer = value;
  133. else if (lower == "timing-allow-origin") continue;
  134. else if (lower == "user-agent") request.UserAgent = value;
  135. else if (lower == "via") continue;
  136. else if (lower == "x-alicdn-da-via") continue;
  137. else request.Headers.Add(key, value);
  138. }
  139. catch { }
  140. }
  141. // POST
  142. if (request.Method.ToLower().Contains("post")) ReadStream(input.InputStream, request.GetRequestStream());
  143. return request;
  144. }
  145. static HttpWebResponse GetResponse(HttpWebRequest request)
  146. {
  147. return (HttpWebResponse)request.GetResponse();
  148. }
  149. static void WriteHeaders(HttpWebResponse response, HttpResponse output)
  150. {
  151. foreach (var key in response.Headers.AllKeys)
  152. {
  153. try
  154. {
  155. if (string.IsNullOrEmpty(key)) continue;
  156. var value = response.Headers[key];
  157. if (string.IsNullOrEmpty(value)) continue;
  158. output.Headers.Add("-Origin-" + key, value);
  159. var lower = key.ToLower();
  160. if (lower == "access-control-allow-origin") continue;
  161. else if (lower == "access-control-allow-methods") continue;
  162. else if (lower == "connection") continue;
  163. else if (lower == "content-type") output.ContentType = value;
  164. else if (lower == "timing-allow-origin") continue;
  165. else if (lower == "transfer-encoding") continue;
  166. else if (lower == "x-content-type-options") continue;
  167. else output.Headers.Add(key, value);
  168. }
  169. catch { }
  170. }
  171. }
  172. static void WriteStream(HttpWebResponse response, HttpResponse output)
  173. {
  174. ReadStream(response.GetResponseStream(), output.OutputStream);
  175. }
  176. static bool ValidateCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
  177. {
  178. //return (errors == SslPolicyErrors.None) ? true : false;
  179. return true;
  180. }
  181. static string QueryString(string name)
  182. {
  183. try
  184. {
  185. if (!string.IsNullOrEmpty(name)) return HttpContext.Current.Request.QueryString[name];
  186. }
  187. finally { }
  188. return "";
  189. }
  190. static Int32 GetInt32(string text)
  191. {
  192. try
  193. {
  194. if (!string.IsNullOrEmpty(text)) return Convert.ToInt32(text);
  195. }
  196. catch { }
  197. return 0;
  198. }
  199. static long ReadStream(Stream source, Stream destination)
  200. {
  201. var buffer = 1024;
  202. if (source == null) return 0;
  203. if (destination == null) return 0;
  204. if (!source.CanRead) return 0;
  205. if (!destination.CanWrite) return 0;
  206. if (buffer < 1) return 0;
  207. long result = 0;
  208. try
  209. {
  210. while (true)
  211. {
  212. var temp = new byte[buffer];
  213. var count = source.Read(temp, 0, temp.Length);
  214. if (count == 0) break;
  215. destination.Write(temp, 0, count);
  216. result += count;
  217. }
  218. }
  219. finally { }
  220. return result;
  221. }
  222. static string Variable(string name)
  223. {
  224. var result = "";
  225. if (!string.IsNullOrEmpty(name))
  226. {
  227. string vname = name.ToLower();
  228. try { result = HttpContext.Current.Request.ServerVariables[vname]; }
  229. finally { }
  230. }
  231. return result ?? "";
  232. }
  233. static string ClientIP()
  234. {
  235. string vip = Variable("http_x_forwarded_for");
  236. if (string.IsNullOrEmpty(vip)) vip = Variable("remote_addr");
  237. return vip;
  238. }
  239. }
  240. }
  241. #endif