using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;


namespace WebManager
{
    /// <summary>    
    /// Http请求封装类，用于模拟登录等操作    
    /// 工作原理：    
    /// 1.通过chrome的NetWork面板，跟踪到请求过程中传递的 Request Headers    
    /// 2.将Request Headers 附加到请求。    
    /// 3.请求成功后，将HttpResponseHeader.SetCookie记录下来。    
    /// 4.下次请求时，附加上第3步的cookie，即可模拟登录后操作。     
    /// </summary>    
    class HttpRequestHelper    
    {        
        /// <summary>        
        ///     cookie集合，用于模拟登陆        
        /// </summary>        
        private static readonly Dictionary<string, Cookie> CookieDic = new Dictionary<string, Cookie>();         
        
        /// <summary>        
        ///     Http请求        
        /// </summary>        
        /// <param name="url"></param>        
        /// <param name="method"></param>        
        /// <param name="headers"></param>        
        /// <param name="content"></param>        
        /// <returns></returns>        
        public static string DoRequest(string url, string method, string headers, string content)       
        {         
            var request = (HttpWebRequest)WebRequest.Create(url);        
            request.Method = method;      
            if (method.Equals("GET", StringComparison.InvariantCultureIgnoreCase))       
            {            
                request.MaximumAutomaticRedirections = 100;        
                request.AllowAutoRedirect = false;            
            }            
            #region 1.设置Http头部          
            if (!string.IsNullOrWhiteSpace(headers))    
            {           
                var hsplit = headers.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var item in hsplit)
                {
                    if (!item.StartsWith(":"))
                    {
                        var kv = item.Split(':');
                        if (kv.Length == 2)
                        {
                            var key = kv[0].Trim();
                            var value = string.Join(":", kv.Skip(1)).Trim();
                            #region  设置http头                
                            switch (key.ToLower())
                            {
                                case "accept":
                                    {
                                        request.Accept = value;
                                        break;
                                    }
                                case "host":
                                    {
                                        request.Host = value;
                                        break;
                                    }
                                case "connection":
                                    {
                                        if (value == "keep-alive")
                                            request.KeepAlive = true;
                                        else
                                            request.KeepAlive = false; //just test        
                                        break;
                                    }
                                case "content-type":
                                    {
                                        request.ContentType = value;
                                        break;
                                    }
                                case "user-agent":
                                    {
                                        request.UserAgent = value;
                                        break;
                                    }
                                case "referer":
                                    {
                                        request.Referer = value;
                                        break;
                                    }
                                case "content-length":
                                    {
                                        request.ContentLength = Convert.ToInt64(value);
                                        break;
                                    }
                                case "expect":
                                    {
                                        request.Expect = value;
                                        break;
                                    }
                                case "if-modified-since":
                                    {
                                        request.IfModifiedSince = Convert.ToDateTime(value);
                                        break;
                                    }
                                case "cookie":
                                    {
                                        var cc = new CookieCollection();
                                        var cookieString = value;
                                        if (!string.IsNullOrWhiteSpace(cookieString))
                                        {
                                            var spilit = cookieString.Split(';');
                                            foreach (var ci in spilit)
                                            {
                                                var arr = ci.Split('=');
                                                if (kv.Length == 2)
                                                    cc.Add(new Cookie(arr[0].Trim(), arr[1].Trim()));
                                            }
                                        }
                                    }
                                    break;
                            }
                            #endregion
                        }
                    } 
                }   
            }       
            #endregion       

            #region 2.设置cookie      
            request.Headers[HttpRequestHeader.Cookie] = GetCookieStr();         
            #endregion    

            #region 3.发送请求数据       
            if (!string.IsNullOrWhiteSpace(content))       
            {        
                var data = Encoding.UTF8.GetBytes(content);     
                request.ContentLength = data.Length;     
                using (var stream = request.GetRequestStream())     
                {           
                    stream.Write(data, 0, data.Length);       
                    stream.Close();         
                }           
            }        
            #endregion       
            
            var response = (HttpWebResponse)request.GetResponse();   
            
            #region 4.保存cookie,用于下次请求      
            //var cookies = new CookieCollection();     
            //var s = response.Headers[HttpResponseHeader.SetCookie].Replace("HttpOnly,", "").Replace("httponly,", "");     
            //if (!string.IsNullOrWhiteSpace(s))     
            //{         
            //    var spilit = s.Split(';');      
            //    foreach (var item in spilit)      
            //    {             
            //        var kv = item.Split('=');         
            //        if (kv.Length == 2)         
            //            cookies.Add(new Cookie(kv[0].Trim(), kv[1].Trim()));      
            //    }      
            //}           
            //foreach (Cookie c in cookies)      
            //    if (CookieDic.ContainsKey(c.Name))         
            //        CookieDic[c.Name] = c;        
            //    else            
            //        CookieDic.Add(c.Name, c);   
            #endregion     
            
            var result = GetResponse(response);     
            return Unicode2String(result);    
        }      
        
        /// <summary>    
        /// 将Unicode转换为中文        
        /// </summary>        
        /// <param name="source"></param>        
        /// <returns></returns>        
        public static string Unicode2String(string source)     
        {        
            return new Regex(@"\\u([0-9A-F]{4})", RegexOptions.IgnoreCase).Replace(         
                source, x => string.Empty + Convert.ToChar(Convert.ToUInt16(x.Result("$1"), 16)));  
        }       
        /// <summary>        
        ///     从HttpWebResponse读取响应文本        
        /// </summary>        
        /// <param name="response"></param>        
        /// <returns></returns>        
        private static string GetResponse(HttpWebResponse response)      
        {           
            var defaultEncode = Encoding.UTF8;     
            var contentType = response.ContentType;      
            if (contentType.ToLower().Contains("gb2312"))       
                defaultEncode = Encoding.GetEncoding("gb2312");   
            else if (contentType.ToLower().Contains("gbk"))      
                defaultEncode = Encoding.GetEncoding("gbk");      
            else if (contentType.ToLower().Contains("zh-cn")) defaultEncode = Encoding.GetEncoding("zh-cn");        
            string responseBody;      
            if (response.ContentEncoding.ToLower().Contains("gzip"))    
                using (var stream = new GZipStream(response.GetResponseStream(), CompressionMode.Decompress))     
                {       
                    using (var reader = new StreamReader(stream))        
                    {        
                        responseBody = reader.ReadToEnd();        
                    }        
                }         
            else if (response.ContentEncoding.ToLower().Contains("deflate"))     
                using (var stream = new DeflateStream(response.GetResponseStream(), CompressionMode.Decompress))    
                {       
                    using (var reader = new StreamReader(stream, defaultEncode))          
                    {             
                        responseBody = reader.ReadToEnd();         
                    }       
                }     
            else         
                using (var stream = response.GetResponseStream())     
                {                
                    using (var reader = new StreamReader(stream, defaultEncode))            
                    {          
                        responseBody = reader.ReadToEnd();    
                    }       
                }      
            return responseBody;    
        }      
        
        private static string GetCookieStr()      
        {          
            var sb = new StringBuilder();   
            foreach (var item in CookieDic)     
                if (!item.Value.Expired)     
                {           
                    if (sb.Length == 0)    
                        sb.Append(item.Key).Append("=").Append(item.Value.Value);      
                    else              
                        sb.Append("; ").Append(item.Key).Append(" = ").Append(item.Value.Value);     
                }
            return sb.ToString();     
        } 
    }
}


