2011-01-25 7 views
9

Consideremos una respuesta web con esta cabecera:asignación del encabezado cadena de cookie para CookieCollection y viceversa

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

esta cabecera se asigna a CookieCollection en .NET. Y también cuando tratamos con un CookieCollection, finalmente se convertirá a un header string.

Estoy buscando la manera de hacer estas conversiones de dos maneras. Seguramente .NET lo tiene en su biblioteca interna. Creo que cualquier clase que construye modelo de objetos de texto y viceversa debe soportar dos métodos (aquí 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(); 

¿Cómo puedo lograr que con CookieCollection?

Respuesta

10

Creo que está buscando CookieContainer. Ver el método SetCookies.

+0

'CookieContainer.GetCookieHeader()' omly devuelve 'key = value' y otros textos como' domain' y 'path' se pierden. – Xaqron

+0

SetCookies parece omitir las cookies caducadas – Slava

17

sé que esto ya ha sido contestada, pero que le gustaría utilizar este código: http://snipplr.com/view/4427/

he publicado aquí en caso de que el enlace se cae en algún momento:

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; 
} 

Este código funciona mejor que el propio analizador de cookies de Microsoft y esto es realmente lo que el analizador oficial de cookies debería estar haciendo. No tengo ni idea de por qué Microsoft no ha solucionado esto todavía, ya que es un problema muy común. Leerá en cookies separadas por coma y analizará correctamente todas las partes de cada cookie, incluidos el nombre, el vencimiento, la ruta, el valor y el dominio.

+1

Esta solución funcionó muy bien para mí. El método CookieContainer.SetCookies arrojó un error de análisis para mí quejándose de "path =/wp-content/plugins" en un sitio de wordpress. "Manualmente" analizando las cookies y agregando el CookieCollection al CookieContainer era la única salida. Tu código me ahorró mucho tiempo. Muchas gracias. – CoolCodeBro

+1

Esto es genial, gracias. – vtortola

+1

¿Fallaría si el valor de la cookie contuviera una coma? –

2

Aquí está mi clase de extensión que uso para hacer esto.

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(',', ' '); 
     } 
    } 

} 
Cuestiones relacionadas