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