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
285 lines
9.7 KiB
#if NETFRAMEWORK
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Net.Security;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using System.Web;
|
|
|
|
namespace Apewer.Web.HttpProxy
|
|
{
|
|
|
|
sealed class HttpHandler : IHttpHandler
|
|
{
|
|
|
|
public bool IsReusable { get { return false; } }
|
|
|
|
public void ProcessRequest(HttpContext context)
|
|
{
|
|
if (context.Request.HttpMethod.ToLower().Contains("options")) return;
|
|
|
|
context.Response.Buffer = true;
|
|
try
|
|
{
|
|
Proxy(context);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
try
|
|
{
|
|
context.Response.Clear();
|
|
context.Response.ContentType = "text/plain";
|
|
context.Response.Write(exception.ToString());
|
|
}
|
|
catch { }
|
|
}
|
|
}
|
|
|
|
// const int SegmentalUrlOffset = 0;
|
|
|
|
static void Proxy(HttpContext context)
|
|
{
|
|
var url = GetUrl(context.Request.Url);
|
|
|
|
context.Response.Headers.Add("-Proxy-Url", url);
|
|
context.Response.Headers.Add("-Proxy-Http-X-Forwarded-For", Variable("http_x_forwarded_for"));
|
|
context.Response.Headers.Add("-Proxy-Remote-Addr", Variable("remote_addr"));
|
|
|
|
// 忽略跨域选项请求。
|
|
if (context.Request.HttpMethod.ToLower().Contains("options")) return;
|
|
|
|
// 阻止浏览器请求网站图标。
|
|
if (context.Request.Url.AbsolutePath.ToLower() == "/favicon.ico") return;
|
|
|
|
// 阻止搜索引擎收录。
|
|
if (context.Request.Url.AbsolutePath.ToLower() == "/robot.txt")
|
|
{
|
|
context.Response.ContentType = "text/plain";
|
|
context.Response.Write("User-agent: *\nDisallow: / \n");
|
|
return;
|
|
}
|
|
|
|
var ShowStack = false;
|
|
try
|
|
{
|
|
context.Response.Buffer = false;
|
|
|
|
var request = GetRequest(url, context.Request);
|
|
var response = GetResponse(request);
|
|
|
|
WriteHeaders(response, context.Response);
|
|
WriteStream(response, context.Response);
|
|
}
|
|
catch (System.Net.Sockets.SocketException exception) // 无法连接服务器。
|
|
{
|
|
context.Response.ContentType = "text/plain";
|
|
context.Response.Write(ShowStack ? exception.ToString() : exception.Message);
|
|
}
|
|
catch (System.Net.WebException exception) // 无法连接服务器;超时。
|
|
{
|
|
context.Response.ContentType = "text/plain";
|
|
context.Response.Write(ShowStack ? exception.ToString() : exception.Message);
|
|
}
|
|
catch (System.UriFormatException exception) // 链接无效。
|
|
{
|
|
context.Response.ContentType = "text/plain";
|
|
context.Response.Write(ShowStack ? exception.ToString() : exception.Message);
|
|
}
|
|
|
|
context.Response.Flush();
|
|
context.Response.Close();
|
|
}
|
|
|
|
static string GetUrl(Uri uri)
|
|
{
|
|
var paq = uri.PathAndQuery;
|
|
var array = uri.PathAndQuery.Split('/');
|
|
if (array.Length < 2) return null;
|
|
|
|
var lower = string.IsNullOrEmpty(array[1]) ? null : array[1].ToLower();
|
|
var start = 1;
|
|
var fragments = new List<string>();
|
|
switch (lower)
|
|
{
|
|
case "http:":
|
|
case "https:":
|
|
fragments.Add(lower);
|
|
start = 2;
|
|
break;
|
|
default:
|
|
start = 1;
|
|
var scheme = uri.Scheme.ToLower();
|
|
if (!scheme.EndsWith(":")) scheme = scheme + ":";
|
|
fragments.Add(scheme);
|
|
break;
|
|
}
|
|
fragments.Add("");
|
|
|
|
for (var i = start; i < array.Length; i++) fragments.Add(array[i]);
|
|
var url = string.Join("/", fragments.ToArray());
|
|
return url;
|
|
}
|
|
|
|
static HttpWebRequest GetRequest(string url, HttpRequest input)
|
|
{
|
|
var https = url.ToLower().Trim().StartsWith("https");
|
|
if (https) ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(ValidateCallback);
|
|
|
|
var request = (HttpWebRequest)WebRequest.Create(url);
|
|
request.Method = input.HttpMethod;
|
|
request.AllowAutoRedirect = true;
|
|
|
|
request.Timeout = 60000;
|
|
|
|
// Headers
|
|
foreach (var key in input.Headers.AllKeys)
|
|
{
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(key)) continue;
|
|
|
|
var value = input.Headers[key];
|
|
if (string.IsNullOrEmpty(value)) continue;
|
|
|
|
var lower = key.ToLower();
|
|
if (lower == "accept") continue;
|
|
else if (lower == "accept-encoding") continue;
|
|
else if (lower == "ali-swift-log-host") continue;
|
|
else if (lower == "ali-swift-stat-host") continue;
|
|
else if (lower == "cache-control") continue;
|
|
else if (lower == "connection") continue;
|
|
else if (lower == "dnt") continue;
|
|
else if (lower == "eagleeye-traceid") continue;
|
|
else if (lower == "host") continue;
|
|
else if (lower == "if-modified-since") request.IfModifiedSince = new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
|
else if (lower == "referer") request.Referer = value;
|
|
else if (lower == "timing-allow-origin") continue;
|
|
else if (lower == "user-agent") request.UserAgent = value;
|
|
else if (lower == "via") continue;
|
|
else if (lower == "x-alicdn-da-via") continue;
|
|
else request.Headers.Add(key, value);
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
// POST
|
|
if (request.Method.ToLower().Contains("post")) ReadStream(input.InputStream, request.GetRequestStream());
|
|
|
|
return request;
|
|
}
|
|
|
|
static HttpWebResponse GetResponse(HttpWebRequest request)
|
|
{
|
|
return (HttpWebResponse)request.GetResponse();
|
|
}
|
|
|
|
static void WriteHeaders(HttpWebResponse response, HttpResponse output)
|
|
{
|
|
foreach (var key in response.Headers.AllKeys)
|
|
{
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(key)) continue;
|
|
|
|
var value = response.Headers[key];
|
|
if (string.IsNullOrEmpty(value)) continue;
|
|
|
|
output.Headers.Add("-Origin-" + key, value);
|
|
|
|
var lower = key.ToLower();
|
|
if (lower == "access-control-allow-origin") continue;
|
|
else if (lower == "access-control-allow-methods") continue;
|
|
else if (lower == "connection") continue;
|
|
else if (lower == "content-type") output.ContentType = value;
|
|
else if (lower == "timing-allow-origin") continue;
|
|
else if (lower == "transfer-encoding") continue;
|
|
else if (lower == "x-content-type-options") continue;
|
|
else output.Headers.Add(key, value);
|
|
}
|
|
catch { }
|
|
}
|
|
}
|
|
|
|
static void WriteStream(HttpWebResponse response, HttpResponse output)
|
|
{
|
|
ReadStream(response.GetResponseStream(), output.OutputStream);
|
|
}
|
|
|
|
static bool ValidateCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
|
|
{
|
|
//return (errors == SslPolicyErrors.None) ? true : false;
|
|
return true;
|
|
}
|
|
|
|
static string QueryString(string name)
|
|
{
|
|
try
|
|
{
|
|
if (!string.IsNullOrEmpty(name)) return HttpContext.Current.Request.QueryString[name];
|
|
}
|
|
finally { }
|
|
return "";
|
|
}
|
|
|
|
static Int32 GetInt32(string text)
|
|
{
|
|
try
|
|
{
|
|
if (!string.IsNullOrEmpty(text)) return Convert.ToInt32(text);
|
|
}
|
|
catch { }
|
|
return 0;
|
|
}
|
|
|
|
static long ReadStream(Stream source, Stream destination)
|
|
{
|
|
var buffer = 1024;
|
|
|
|
if (source == null) return 0;
|
|
if (destination == null) return 0;
|
|
if (!source.CanRead) return 0;
|
|
if (!destination.CanWrite) return 0;
|
|
if (buffer < 1) return 0;
|
|
|
|
long result = 0;
|
|
try
|
|
{
|
|
while (true)
|
|
{
|
|
var temp = new byte[buffer];
|
|
var count = source.Read(temp, 0, temp.Length);
|
|
if (count == 0) break;
|
|
destination.Write(temp, 0, count);
|
|
result += count;
|
|
}
|
|
}
|
|
finally { }
|
|
return result;
|
|
}
|
|
|
|
static string Variable(string name)
|
|
{
|
|
var result = "";
|
|
if (!string.IsNullOrEmpty(name))
|
|
{
|
|
string vname = name.ToLower();
|
|
try { result = HttpContext.Current.Request.ServerVariables[vname]; }
|
|
finally { }
|
|
}
|
|
return result ?? "";
|
|
}
|
|
|
|
static string ClientIP()
|
|
{
|
|
string vip = Variable("http_x_forwarded_for");
|
|
if (string.IsNullOrEmpty(vip)) vip = Variable("remote_addr");
|
|
return vip;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|