[fix]Config创建默认配置文件的开关Runtime.CreateConfigOnMissing,仅需对自动创建生效,而不应该阻止用户主动Save
智能大石头 编写于 2024-08-09 00:30:41 石头 提交于 2024-08-10 14:22:24
X
using System;
using System.IO;
using NewLife.Net.Http;
using NewLife.Net.Sockets;

namespace NewLife.Net.Proxy
{
    /// <summary>Http反向代理。把所有收到的Http请求转发到目标服务器。</summary>
    /// <remarks>
    /// 主要是修改Http请求头为正确的主机,还有可能修改Http响应。
    /// 
    /// 经典用途:
    /// 1,缓存。代理缓存某些静态资源的请求结果,减少对服务器的请求压力
    /// 2,拦截。禁止访问某些资源,返回空白页或者连接重置
    /// 3,修改请求或响应。更多的可能是修改响应的页面内容
    /// 4,记录统计。记录并统计请求的网址。
    /// 
    /// 修改Http响应的一般做法:
    /// 1,反向映射888端口到目标abc.com
    /// 2,abc.com页面响应时,所有http://abc.com/的连接都修改为http://IP:888
    /// 3,注意在内网的反向代理需要使用公网IP,而不是本机IP
    /// 4,子域名也可以修改,比如http://pic.abc.com/修改为http://IP:888/http_pic.abc.com/
    /// </remarks>
    public class HttpReverseProxy : NATProxy
    {
        /// <summary>实例化</summary>
        public HttpReverseProxy()
        {
            Port = 80;
        }

        /// <summary>创建会话</summary>
        /// <param name="session"></param>
        /// <returns></returns>
        protected override INetSession CreateSession(ISocketSession session)
        {
            return new Session();
        }

        #region 会话
        /// <summary>Http反向代理会话</summary>
        class Session : NATSession
        {
            ///// <summary>代理对象</summary>
            //public new HttpReverseProxy Proxy { get { return base.Proxy as HttpReverseProxy; } set { base.Proxy = value; } }

            private HttpHeader _Request;
            /// <summary>请求头部</summary>
            public HttpHeader Request { get { return _Request; } set { _Request = value; } }

            private String _Host;
            /// <summary>属性说明</summary>
            public String Host { get { return _Host; } set { _Host = value; } }

            private String _RawHost;
            /// <summary>属性说明</summary>
            public String RawHost { get { return _RawHost; } set { _RawHost = value; } }

            /// <summary>请求时触发。</summary>
            public event EventHandler<ReceivedEventArgs> OnRequest;

            /// <summary>收到客户端发来的数据。子类可通过重载该方法来修改数据</summary>
            /// <param name="e"></param>
            protected override void OnReceive(ReceivedEventArgs e)
            {
                // 解析请求头
                var stream = e.Stream;
                var entity = HttpHeader.Read(stream, HttpHeaderReadMode.Request);
                if (entity == null)
                {
                    base.OnReceive(e);
                    return;
                }

                WriteLog("{3}请求:{0} {1} [{2}]", entity.Method, entity.Url, entity.ContentLength, ID);

                Request = entity;
                if (OnRequest != null) OnRequest(this, e);

                var host = entity.Url.IsAbsoluteUri ? entity.Url.Host : Proxy.RemoteServer.Host;
                Host = host;
                RawHost = entity.Host;
                entity.Host = host;

                // 引用
                var r = entity.Referer;
                if (!String.IsNullOrEmpty(r))
                {
                    Uri ri = new Uri(r, UriKind.RelativeOrAbsolute);
                    if (ri.IsAbsoluteUri && ri.Authority == RawHost)
                    {
                        r = r.Replace(RawHost, host);
                        entity.Referer = r;
                    }
                }

                //// 取消压缩
                //var key = "Accept-Encoding";
                //if (entity.Headers.ContainsKey(key)) entity.Headers.Remove(key);

                // 重新构造请求
                var ms = new MemoryStream();
                entity.Write(ms);
                stream.CopyTo(ms);
                ms.Position = 0;

                e.Stream = ms;

                base.OnReceive(e);
            }

            ///// <summary>收到客户端发来的数据。子类可通过重载该方法来修改数据</summary>
            ///// <param name="e"></param>
            ///// <param name="stream">数据</param>
            ///// <returns>修改后的数据</returns>
            //protected override Stream OnReceiveRemote(NetEventArgs e, Stream stream)
            //{
            //    //var entity = HttpHeader.Read(stream, HttpHeaderReadMode.Response);
            //    //if (entity == null) return base.OnReceive(e, stream);

            //    var html = e.GetString();
            //    html = html.Replace(Host, RawHost);
            //    stream = new MemoryStream(Encoding.UTF8.GetBytes(html));

            //    return base.OnReceiveRemote(e, stream);
            //}
        }
        #endregion
    }
}