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