将标头cookie字符串映射到CookieCollection,反之亦然

时间:2011-01-25 10:58:00

标签: c# cookies http-headers

考虑使用此标头的网络响应:

Set-Cookie: sample=testCookie; Domain=.sample.com; Expires=Tue, 25-Jan-2012 00:49:29 GMT; Path=/

此标头将映射到CookieCollection中的.NET。而且,当我们处理CookieCollection时,它最终会转换为header string

我正在寻找某种方式纯粹以两种方式进行转换。当然.NET在它的内部库中有它。我相信任何从文本构造对象模型的类应该支持两种方法(这里CookieCollection):

// Creating cookie collection from header text
CookieCollection.TryParse(cookieHeaderString, out myCookieCollection);
// and getting the final header which would be sent by request
String cookieHeaderString = myCookieCollection.GetCookieHeaderString();

如何使用CookieCollection实现这一目标?

3 个答案:

答案 0 :(得分:18)

我知道这已经得到了解答,但您可能希望使用此代码: http://snipplr.com/view/4427/

我在这里发帖,以防链接在某些时候出现故障:

public static CookieCollection GetAllCookiesFromHeader(string strHeader, string strHost)
{
    ArrayList al = new ArrayList();
    CookieCollection cc = new CookieCollection();
    if (strHeader != string.Empty)
    {
        al = ConvertCookieHeaderToArrayList(strHeader);
        cc = ConvertCookieArraysToCookieCollection(al, strHost);
    }
    return cc;
}


private static ArrayList ConvertCookieHeaderToArrayList(string strCookHeader)
{
    strCookHeader = strCookHeader.Replace("\r", "");
    strCookHeader = strCookHeader.Replace("\n", "");
    string[] strCookTemp = strCookHeader.Split(',');
    ArrayList al = new ArrayList();
    int i = 0;
    int n = strCookTemp.Length;
    while (i < n)
    {
        if (strCookTemp[i].IndexOf("expires=", StringComparison.OrdinalIgnoreCase) > 0)
        {
            al.Add(strCookTemp[i] + "," + strCookTemp[i + 1]);
            i = i + 1;
        }
        else
        {
            al.Add(strCookTemp[i]);
        }
        i = i + 1;
    }
    return al;
}


private static CookieCollection ConvertCookieArraysToCookieCollection(ArrayList al, string strHost)
{
    CookieCollection cc = new CookieCollection();

    int alcount = al.Count;
    string strEachCook;
    string[] strEachCookParts;
    for (int i = 0; i < alcount; i++)
    {
        strEachCook = al[i].ToString();
        strEachCookParts = strEachCook.Split(';');
        int intEachCookPartsCount = strEachCookParts.Length;
        string strCNameAndCValue = string.Empty;
        string strPNameAndPValue = string.Empty;
        string strDNameAndDValue = string.Empty;
        string[] NameValuePairTemp;
        Cookie cookTemp = new Cookie();

        for (int j = 0; j < intEachCookPartsCount; j++)
        {
            if (j == 0)
            {
                strCNameAndCValue = strEachCookParts[j];
                if (strCNameAndCValue != string.Empty)
                {
                    int firstEqual = strCNameAndCValue.IndexOf("=");
                    string firstName = strCNameAndCValue.Substring(0, firstEqual);
                    string allValue = strCNameAndCValue.Substring(firstEqual + 1, strCNameAndCValue.Length - (firstEqual + 1));
                    cookTemp.Name = firstName;
                    cookTemp.Value = allValue;
                }
                continue;
            }
            if (strEachCookParts[j].IndexOf("path", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                strPNameAndPValue = strEachCookParts[j];
                if (strPNameAndPValue != string.Empty)
                {
                    NameValuePairTemp = strPNameAndPValue.Split('=');
                    if (NameValuePairTemp[1] != string.Empty)
                    {
                        cookTemp.Path = NameValuePairTemp[1];
                    }
                    else
                    {
                        cookTemp.Path = "/";
                    }
                }
                continue;
            }

            if (strEachCookParts[j].IndexOf("domain", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                strPNameAndPValue = strEachCookParts[j];
                if (strPNameAndPValue != string.Empty)
                {
                    NameValuePairTemp = strPNameAndPValue.Split('=');

                    if (NameValuePairTemp[1] != string.Empty)
                    {
                        cookTemp.Domain = NameValuePairTemp[1];
                    }
                    else
                    {
                        cookTemp.Domain = strHost;
                    }
                }
                continue;
            }
        }

        if (cookTemp.Path == string.Empty)
        {
            cookTemp.Path = "/";
        }
        if (cookTemp.Domain == string.Empty)
        {
            cookTemp.Domain = strHost;
        }
        cc.Add(cookTemp);
    }
    return cc;
}

这段代码比微软自己的cookie解析器效果更好,这正是官方cookie解析器应该做的事情。我没有任何线索,为什么微软还没有解决这个问题,因为这是一个非常普遍的问题。它将读取逗号分隔的cookie,并正确解析每个cookie的所有部分,包括名称,过期,路径,值和域。

答案 1 :(得分:12)

我认为您正在寻找CookieContainer。请参阅SetCookies方法。

答案 2 :(得分:3)

这是我用来执行此操作的扩展类。

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Net;
using System.Text.RegularExpressions;
using System.Web;

namespace YourProjectName.Extensions
{
     public static class HttpCookieExtension
    {
         static Regex rxCookieParts = new Regex(@"(?<name>.*?)\=(?<value>.*?)\;|(?<name>\bsecure\b|\bhttponly\b)", RegexOptions.Compiled |RegexOptions.Singleline|RegexOptions.IgnoreCase);
         static Regex rxRemoveCommaFromDate = new Regex(@"\bexpires\b\=.*?(\;|$)", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline);
         public static bool GetHttpCookies(this NameValueCollection collection, int index , out List<HttpCookie> cookies)
         {
             cookies = new List<HttpCookie>();

             if (collection.AllKeys[index].ToLower() != "set-cookie") return false;
             try
             {

                 string rawcookieString = rxRemoveCommaFromDate.Replace(collection[index],  new MatchEvaluator(RemoveComma));

                 string[] rawCookies = rawcookieString.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                 foreach (var rawCookie in rawCookies)
                 {
                    cookies.Add(rawCookie.ToHttpCookie());
                 }
                 return true;
             }
             catch (Exception)
             {

                 return false;
             }
         }


         public static bool GetHttpCookiesFromHeader(this string cookieHeader, out CookieCollection cookies)
         {
             cookies = new CookieCollection();


             try
             {

                 string rawcookieString = rxRemoveCommaFromDate.Replace(cookieHeader, new MatchEvaluator(RemoveComma));

                 string[] rawCookies = rawcookieString.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

                 if (rawCookies.Length == 0)
                 {
                     cookies.Add(rawcookieString.ToCookie());
                 }
                 else
                 {
                    foreach (var rawCookie in rawCookies)
                    {
                        cookies.Add(rawCookie.ToCookie());
                    }
                 }

                 return true;
             }
             catch (Exception)
             {
                 throw;
             }
         }




         public static Cookie ToCookie(this string rawCookie)
         {

             if (!rawCookie.EndsWith(";")) rawCookie += ";";

             MatchCollection maches = rxCookieParts.Matches(rawCookie);

             Cookie cookie = new Cookie(maches[0].Groups["name"].Value.Trim(), maches[0].Groups["value"].Value.Trim());

             for (int i = 1; i < maches.Count; i++)
             {
                 switch (maches[i].Groups["name"].Value.ToLower().Trim())
                 {
                     case "domain":
                         cookie.Domain = maches[i].Groups["value"].Value;
                         break;
                     case "expires":

                         DateTime dt;

                         if (DateTime.TryParse(maches[i].Groups["value"].Value, out dt))
                         {
                             cookie.Expires = dt;
                         }
                         else
                         {
                             cookie.Expires = DateTime.Now.AddDays(2);
                         }
                         break;
                     case "path":
                         cookie.Path = maches[i].Groups["value"].Value;
                         break;
                     case "secure":
                         cookie.Secure = true;
                         break;
                     case "httponly":
                         cookie.HttpOnly = true;
                         break;
                 }
             }
             return cookie;


         }

         public static HttpCookie ToHttpCookie(this string rawCookie)
         {
             MatchCollection maches = rxCookieParts.Matches(rawCookie);

             HttpCookie cookie = new HttpCookie(maches[0].Groups["name"].Value, maches[0].Groups["value"].Value);

             for (int i = 1; i < maches.Count; i++)
             {
                 switch (maches[i].Groups["name"].Value.ToLower().Trim())
                 {
                     case "domain":
                         cookie.Domain = maches[i].Groups["value"].Value;
                         break;
                     case "expires":

                         DateTime dt;

                         if (DateTime.TryParse(maches[i].Groups["value"].Value, out dt))
                         {
                             cookie.Expires = dt;
                         }
                         else
                         {
                             cookie.Expires = DateTime.Now.AddDays(2);
                         }
                         break;
                     case "path":
                         cookie.Path = maches[i].Groups["value"].Value;
                         break;
                     case "secure":
                         cookie.Secure = true;
                         break;
                     case "httponly":
                         cookie.HttpOnly = true;
                         break;
                 }
             }
             return cookie;
         }

         private static KeyValuePair<string, string> SplitToPair(this string input)
         {
            string[]  parts= input.Split(new char[] {'='},StringSplitOptions.RemoveEmptyEntries);
            return new KeyValuePair<string, string>(parts[0],parts[1]);
         }

         private static string RemoveComma(Match match)
         {
             return match.Value.Replace(',', ' ');
         }
    }

}