using System; using System.Collections.Generic; using System.Text; using System.Web; using System.Net; using System.Collections; namespace SalarSoft.ASProxy.BuiltIn.DataManagement { // CallMeLaNN: // Its better I extract the code one issue by one issue // since my code already quite messy because of just testing to make sure it work. // It work, but to be compatible with your environment, then we go through code by code. class Class1 { // Here actually I am not using cookie header format, but I use my own key=value pair. // You can change to make it compatible like cookie header like // cookiename=cookievalue instead of Name=cookiename; Value=cookievalue (I seperate name and value for faster coding and good parsing) // expires=... instead of Expires=... // but actually not necessary to be same like cookie header format because this will never use at http header, but just only stored in 'browser group cookie' and only used by this CookieManager. // This Fix will create Cookie by setting all required property value. // This will store Expires, HttpOnly etc that will managed by CookieContainer. // string -> cookie object // Note: I am not sure if this work with your modified RestoreCookiesFromResponse() public void ApplyRequestToCookieContainer(CookieContainer container, HttpRequest userRequest, Uri webUri, bool onWebRequest) { if (container == null || userRequest == null || webUri == null) return; string cookieName = GetCookieName(webUri); HttpCookie reqCookie = userRequest.Cookies[cookieName]; if (reqCookie == null) return; //HttpCookie jsCookie; // If cookie value in encoded version, decode it first. This is second layer decode. (optional but required if encoded) string header = HttpUtility.UrlDecode(reqCookie.Value); if (string.IsNullOrEmpty(header.Trim())) return; // Use standard & as seperator in 'cookie value' instead of , because Expires can contain comma for GMT date time format and split by , will doing the wrong split. string[] cookies = header.Trim().Split('&'); string[] cookieProperties; string name, value; Cookie cookieObj; foreach (string cookie in cookies) { if (string.IsNullOrEmpty(cookie.Trim())) continue; cookieProperties = cookie.Trim().Split(';'); // cookie properties seperated by ; cookieObj = new Cookie(); foreach (string cookieProperty in cookieProperties) { string prop = cookieProperty.Trim(); if (string.IsNullOrEmpty(prop)) continue; // Can't use split by equal sign method since 'cookie value' can contain equal sign (like in google, PREF='ID=...') and break this parsing, // instead, find the first equal sign. // cookieKVP = prop.Split('='); int equIndex = prop.IndexOf('='); name = prop.Substring(0, equIndex).Trim(); value = prop.Substring(equIndex + 1, prop.Length - equIndex - 1).Trim(); // Note that this long property name (Name, Value, Expires, Domain, etc) can be do in short form (N, V, E, D, etc) to minimize cookie size. if (name == "Name") cookieObj.Name = value; else if (name == "Value") cookieObj.Value = HttpUtility.UrlDecode(value); // This is first layer decode. This is compulsory. else if (name == "Expires") cookieObj.Expires = DateTime.Parse(value); else if (name == "Domain") cookieObj.Domain = value; else if (name == "Path") cookieObj.Path = value; else if (name == "HttpOnly") cookieObj.HttpOnly = bool.Parse(value); else if (name == "Expired") cookieObj.Expired = bool.Parse(value); else if (name == "Secure") cookieObj.Secure = bool.Parse(value); else if (name == "Port") // noted that I am not sure about port number, not tested yet to filter it. cookieObj.Port = value; else if (name == "Version") cookieObj.Version = int.Parse(value); else if (name == "Discard") cookieObj.Discard = bool.Parse(value); else if (name == "Comment") cookieObj.Comment = value; else if (name == "CommentUri") cookieObj.CommentUri = new Uri(value); } container.Add(cookieObj); } BugFix_CookieContainer(container); // if there is cookies //for (int i = 0; i < userRequest.Cookies.Count; i++) //{ // HttpCookie cookie = userRequest.Cookies[i]; // if (IsASProxyCookie(cookie.Name)) // { // // BUGFIX: cookies header shouldn't be decoded // //string val = HttpUtility.UrlDecode(cookie.Value); // string val = cookie.Value; // // // CallMeLaNN: We should get host from current web request, not cookie name. // Uri host = GetASProxyCookieHost(cookie.Name); // if (host != null) // container.SetCookies(host, val); // } //} } // encode/serialize (group all cookies) by using key value pair (actually not exactly same like cookie header) // cookie object -> string private string GetCookieHeader(CookieCollection cookieCollection) { string result = ""; if (cookieCollection != null) { string cookieStr = null; for (int i = 0; i < cookieCollection.Count; i++) { Cookie cookie = cookieCollection[i]; // generate cookie // string cookieStr = CallCookieToServerString(cookie); // removed by CallMeLaNN // The If condition below only write/included if different than default value to minimize cookie size. // Note that this long property name can be do in short form and remove space to minimize cookie size. // Required values, I think: cookieStr = "Name=" + cookie.Name; // this actual 'cookie value' should be encoded to avoid ,&% and other special char used in the 'cookie value' that will break a seperator and parsing later. This is first layer encode. Compulsory. if (!string.IsNullOrEmpty(cookie.Value)) cookieStr += "; Value=" + HttpUtility.UrlEncode(cookie.Value); if (cookie.Expires != DateTime.MinValue) cookieStr += "; Expires=" + cookie.Expires.ToString(); if (!string.IsNullOrEmpty(cookie.Domain)) cookieStr += "; Domain=" + cookie.Domain; if (!string.IsNullOrEmpty(cookie.Path)) cookieStr += "; Path=" + cookie.Path; if (cookie.HttpOnly) cookieStr += "; HttpOnly=" + cookie.HttpOnly.ToString(); if (cookie.Expired) cookieStr += "; Expired=" + cookie.Expired.ToString(); if (cookie.Secure) cookieStr += "; Secure=" + cookie.Secure.ToString(); // Additional and rarely used or I don't know, just add if any values: if (!string.IsNullOrEmpty(cookie.Port)) cookieStr += "; Port=" + cookie.Port; if (cookie.Version != 0) cookieStr += "; Version=" + cookie.Version.ToString(); if (cookie.Discard) cookieStr += "; Discard=" + cookie.Discard.ToString(); if (!string.IsNullOrEmpty(cookie.Comment)) cookieStr += "; Comment=" + cookie.Comment.ToString(); if (cookie.CommentUri != null) cookieStr += "; CommentUri=" + cookie.CommentUri.AbsoluteUri; if (!string.IsNullOrEmpty(result)) // Use standard & as seperator in cookie value instead of , because Expires can contain comma for GMT date time format. result = result + "& " + cookieStr; else result = cookieStr; } } return result; } } }