2 changed files with 338 additions and 0 deletions
@ -0,0 +1,285 @@ |
|||||
|
#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
|
@ -0,0 +1,53 @@ |
|||||
|
#if NETFRAMEWORK
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Web; |
||||
|
|
||||
|
namespace Apewer.Web.HttpProxy |
||||
|
{ |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
sealed class HttpModule : IHttpModule |
||||
|
{ |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public void Dispose() { } |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public void Init(HttpApplication context) |
||||
|
{ |
||||
|
context.PreSendRequestHeaders += new EventHandler(ByContext); |
||||
|
} |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
void ByContext(object sender, EventArgs e) |
||||
|
{ |
||||
|
var context = HttpContext.Current; |
||||
|
if (context == null) return; |
||||
|
|
||||
|
var keys = new List<string>(); |
||||
|
keys.AddRange(context.Response.Headers.AllKeys); |
||||
|
if (keys.Contains("Server")) context.Response.Headers.Remove("Server"); |
||||
|
if (keys.Contains("X-Powered-By")) context.Response.Headers.Remove("X-Powered-By"); |
||||
|
} |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
void ByApplication(object sender, EventArgs e) |
||||
|
{ |
||||
|
var app = sender as HttpApplication; |
||||
|
if (app == null) return; |
||||
|
if (app.Request == null) return; |
||||
|
if (app.Request.IsLocal == false) return; |
||||
|
if (app.Context == null) return; |
||||
|
if (app.Context.Response == null) return; |
||||
|
if (app.Context.Response.Headers == null) return; |
||||
|
var headers = app.Context.Response.Headers; |
||||
|
app.Context.Response.Headers.Remove("Server"); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
#endif
|
Loading…
Reference in new issue