2011-04-07 17 views
23

Me gustaría tomar una cadena de cookies (como podría ser devuelta en un encabezado Set-Cookie) y poder modificar fácilmente partes de ella, específicamente la fecha de caducidad.Cómo analizar una cadena de cookies

Veo que hay varias clases de cookies diferentes, como BasicClientCookie, disponibles, pero no veo ninguna manera fácil de analizar la cadena en uno de esos objetos.

Veo en el nivel 9 de la API que agregaron HttpCookie que tiene un método de análisis, pero necesito algo para trabajar en versiones anteriores.

¿Alguna idea?

Gracias

+0

¿Qué cliente HTTP está utilizando? Android se envía con Apache Commons HttpClient. – BalusC

+0

Estoy usando HttpClient para las conexiones pero he estado usando CookieSyncManager para conservar las cookies. No estoy utilizando la CookieStore de HttpClient en este momento. – cottonBallPaws

Respuesta

10

Creo que tendrá que analizarlo manualmente. Pruebe esto:

BasicClientCookie parseRawCookie(String rawCookie) throws Exception { 
    String[] rawCookieParams = rawCookie.split(";"); 

    String[] rawCookieNameAndValue = rawCookieParams[0].split("="); 
    if (rawCookieNameAndValue.length != 2) { 
     throw new Exception("Invalid cookie: missing name and value."); 
    } 

    String cookieName = rawCookieNameAndValue[0].trim(); 
    String cookieValue = rawCookieNameAndValue[1].trim(); 
    BasicClientCookie cookie = new BasicClientCookie(cookieName, cookieValue); 
    for (int i = 1; i < rawCookieParams.length; i++) { 
     String rawCookieParamNameAndValue[] = rawCookieParams[i].trim().split("="); 

     String paramName = rawCookieParamNameAndValue[0].trim(); 

     if (paramName.equalsIgnoreCase("secure")) { 
      cookie.setSecure(true); 
     } else { 
      if (rawCookieParamNameAndValue.length != 2) { 
       throw new Exception("Invalid cookie: attribute not a flag or missing value."); 
      } 

      String paramValue = rawCookieParamNameAndValue[1].trim(); 

      if (paramName.equalsIgnoreCase("expires")) { 
       Date expiryDate = DateFormat.getDateTimeInstance(DateFormat.FULL) 
         .parse(paramValue); 
       cookie.setExpiryDate(expiryDate); 
      } else if (paramName.equalsIgnoreCase("max-age")) { 
       long maxAge = Long.parseLong(paramValue); 
       Date expiryDate = new Date(System.getCurrentTimeMillis() + maxAge); 
       cookie.setExpiryDate(expiryDate); 
      } else if (paramName.equalsIgnoreCase("domain")) { 
       cookie.setDomain(paramValue); 
      } else if (paramName.equalsIgnoreCase("path")) { 
       cookie.setPath(paramValue); 
      } else if (paramName.equalsIgnoreCase("comment")) { 
       cookie.setPath(paramValue); 
      } else { 
       throw new Exception("Invalid cookie: invalid attribute name."); 
      } 
     } 
    } 

    return cookie; 
} 

No he compilado ni ejecuto este código, pero debería ser un buen comienzo. Probablemente tendrá que meterse un poco con la fecha de análisis: no estoy seguro de que el formato de fecha utilizado en las cookies sea realmente el mismo que DateFormat.FULL. (Consulte this pregunta relacionada, que aborda el manejo del formato de fecha en las cookies). Además, tenga en cuenta que hay algunos atributos de cookies no manejados por BasicClientCookie, como version y httponly.

Finalmente, este código supone que el nombre y el valor de la cookie aparecen como el primer atributo: No estoy seguro de si eso es necesariamente cierto, pero así es como todas las cookies que he visto están ordenadas.

+0

después de if (paramName.equalsIgnoreCase ("comment")), cookie.setPath (paramValue) probablemente sea incorrecto? –

+1

Mejor hacer lo que @yanchenko sugirió y usar lo que viene en las bibliotecas nativas. Utilice una de las superclases [CookieSpec] (http://developer.android.com/reference/org/apache/http/cookie/CookieSpec.html) como [BestMatchSpec] (http://developer.android.com/reference/ org/apache/http/impl/cookie/BestMatchSpec.html) –

+1

Esto se romperá si los valores de la cookie tienen el carácter "=" en el valor –

7

Con una expresión regular como:

([^=]+)=([^\;]+);\s? 

puede analizar una galleta de la siguiente manera:

.COOKIEAUTH=5DEF0BF530F749AD46F652BDF31C372526A42FEB9D40162167CB39C4D43FC8AF1C4B6DF0C24ECB1945DFF7952C70FDA1E4AF12C1803F9D089E78348C4B41802279897807F85905D6B6D2D42896BA2A267E9F564814631B4B31EE41A483C886B14B5A1E76FD264FB230E87877CB9A4A2A7BDB0B0101BC2C1AF3A029CC54EE4FBC; 
expires=Sat, 30-Jul-2011 01:22:34 GMT; 
path=/; HttpOnly 

en unas pocas líneas de código.

8

Puedes usar Apache HttpClient para ello.
He aquí un extracto de CookieJar:

CookieSpec cookieSpec = new BrowserCompatSpec(); 

List<Cookie> parseCookies(URI uri, List<String> cookieHeaders) { 
    ArrayList<Cookie> cookies = new ArrayList<Cookie>(); 
    int port = (uri.getPort() < 0) ? 80 : uri.getPort(); 
    boolean secure = "https".equals(uri.getScheme()); 
    CookieOrigin origin = new CookieOrigin(uri.getHost(), port, 
      uri.getPath(), secure); 
    for (String cookieHeader : cookieHeaders) { 
     BasicHeader header = new BasicHeader(SM.SET_COOKIE, cookieHeader); 
     try { 
      cookies.addAll(cookieSpec.parse(header, origin)); 
     } catch (MalformedCookieException e) { 
      L.d(e); 
     } 
    } 
    return cookies; 
} 
0

La ventaja del enfoque de Yanchenko con el cliente HTTP Apache es que es valida las cookies de conformidad con la especificación basada en el origen. El enfoque de expresión regular no hará eso, pero tal vez no es necesario.

public class CookieUtil { 

    public List<Cookie> parseCookieString(String cookies) { 
     List<Cookie> cookieList = new ArrayList<Cookie>(); 
     Pattern cookiePattern = Pattern.compile("([^=]+)=([^\\;]*);?\\s?"); 
     Matcher matcher = cookiePattern.matcher(cookies); 
     while (matcher.find()) { 
      int groupCount = matcher.groupCount(); 
      System.out.println("matched: " + matcher.group(0)); 
      for (int groupIndex = 0; groupIndex <= groupCount; ++groupIndex) { 
       System.out.println("group[" + groupIndex + "]=" + matcher.group(groupIndex)); 
      } 
      String cookieKey = matcher.group(1); 
      String cookieValue = matcher.group(2); 
      Cookie cookie = new BasicClientCookie(cookieKey, cookieValue); 
      cookieList.add(cookie); 
     } 
     return cookieList; 
    } 
} 

He adjuntado un pequeño ejemplo con yanchenkos regex. Necesita ser ajustado un poco. Sin el '?' modificador de cantidad al final ';' el atributo final para cualquier cookie no se igualará. Después de eso, si te importan los otros atributos, puedes usar el código de Doug, encapsulado correctamente, para analizar los otros grupos de coincidencias.

Editar: También, tenga en cuenta el calificador '*' en el valor de la cookie. Los valores son opcionales y puede obtener cookies como "de =", es decir, sin ningún valor. Mirando nuevamente la expresión regular, no creo que maneje los atributos de seguridad y descarte de las cookies que no tienen un '='.

77

¿Qué tal java.net.HttpCookie:

List<HttpCookie> cookies = HttpCookie.parse(header); 
+3

A esto se refería el OP como no disponible hasta la API 9. –

+7

@MattWolfe Correcto, pero el 90% de las personas que encuentran esta pregunta en 2009 ya no se preocupan por la API 9. Es por eso que esta respuesta se está votando ahora. –

+0

este método de análisis parece ser sensible a mayúsculas y minúsculas para palabras como "dominio" y "ruta", por lo que debe tener cuidado.Consulte mi respuesta detallada –

5

divertido lo suficiente, pero java.net.HttpCookie clase no puede analizar cadenas de galletas con dominio y/o partes de trayectoria que esta clase exacta java.net.HttpCookie ha convertido en cadena.

Por ejemplo:

HttpCookie newCookie = new HttpCookie("cookieName", "cookieValue"); 
newCookie.setDomain("cookieDomain.com"); 
newCookie.setPath("/"); 

Como esta clase implementa Serializable ni tampoco parcelable, es tentador para almacenar las galletas en forma de cadenas. Por lo que escribir algo como:

saveMyCookieAsString(newCookie.toString()); 

Esta declaración va a salvar la cookie en el siguiente formato:

cookieName="cookieValue";$Path="/";$Domain="cookiedomain.com" 

Y a continuación, si desea restaurar esta cookie, para que pueda obtener la cadena:

String cookieAsString = restoreMyCookieString(); 

y tratar de analizarlo:

List<HttpCookie> cookiesList = HttpCookie.parse(cookieAsString); 
StringBuilder myCookieAsStringNow = new StringBuilder(); 
for(HttpCookie httpCookie: cookiesList) { 
    myCookieAsStringNow.append(httpCookie.toString()); 
} 

ahora myCookieAsStringNow.toString(); produce

cookieName=cookieValue 

dominio y la ruta partes se acaba ido. La razón: el método de análisis distingue entre mayúsculas y minúsculas de palabras como "dominio" y "ruta". método de proporcionar otra toString() como::
solución posible

public static String httpCookieToString(HttpCookie httpCookie) { 
    StringBuilder result = new StringBuilder() 
      .append(httpCookie.getName()) 
      .append("=") 
      .append("\"") 
      .append(httpCookie.getValue()) 
      .append("\""); 

    if(!TextUtils.isEmpty(httpCookie.getDomain())) { 
     result.append("; domain=") 
       .append(httpCookie.getDomain()); 
    } 
    if(!TextUtils.isEmpty(httpCookie.getPath())){ 
     result.append("; path=") 
       .append(httpCookie.getPath()); 
    } 

    return result.toString(); 
} 

Me parece gracioso (en especial, para las clases como java.net.HttpCookie que están destinadas a ser utilizadas por mucho y mucha gente) y espero que será útil para alguien.

+1

Parece que 'HttpCookie' analiza las cookies como cookies del servidor, pero las codifica como cookies de usuario-agente: tal vez esa era la intención como [su JavaDoc] (https://docs.oracle.com/javase/8/docs/api/java/net/HttpCookie.html) lee: _porta información de estado entre el servidor y el agente de usuario_. Ver también [sección de ejemplos de RFC 2109] (https://tools.ietf.org/html/rfc2109#section-5). –

0
CookieManager cookieManager = new CookieManager(); 
     CookieHandler.setDefault(cookieManager); 
     HttpCookie cookie = new HttpCookie("lang", "en"); 
     cookie.setDomain("Your URL"); 
     cookie.setPath("/"); 
     cookie.setVersion(0); 

     cookieManager.getCookieStore().add(new URI("https://Your URL/"), cookie); 
     List<HttpCookie> Cookies = cookieManager.getCookieStore().get(new URI("https://Your URL/")); 
     String s = Cookies.get(0).getValue(); 
Cuestiones relacionadas