2011-04-07 18 views
23

Vorrei prendere una stringa di cookie (come potrebbe essere restituita in un'intestazione Set-Cookie) ed essere in grado di modificare facilmente parti di esso, in particolare la data di scadenza.Come analizzare una stringa di cookie

Vedo che esistono diverse classi di cookie, come BasicClientCookie, disponibili ma non vedo alcun modo semplice per analizzare la stringa in uno di questi oggetti.

Vedo in api livello 9 hanno aggiunto HttpCookie che ha un metodo di analisi, ma ho bisogno di qualcosa per funzionare nelle versioni precedenti.

Qualche idea?

Grazie

+0

Quale client HTTP utilizzate? Android viene fornito con Apache Commons HttpClient. – BalusC

+0

Sto usando HttpClient per le connessioni, ma ho usato CookieSyncManager per mantenere i cookie. Al momento non sto utilizzando il CookieStore di HttpClient. – cottonBallPaws

risposta

10

Credo che dovrai analizzarlo manualmente. Prova:

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

In realtà non ho compilato o eseguito questo codice, ma dovrebbe essere un buon inizio. Probabilmente dovrai fare un po 'di confusione con l'analisi della data: non sono sicuro che il formato della data utilizzato nei cookie sia in realtà lo stesso di DateFormat.FULL. (Consulta la domanda correlata this, quali indirizzi gestiscono il formato della data nei cookie.) Inoltre, tieni presente che alcuni attributi dei cookie non sono gestiti da BasicClientCookie come version e httponly.

Infine, questo codice presuppone che il nome e il valore del cookie appaiano come primo attributo: non sono sicuro che sia necessariamente vero, ma è così che ogni cookie che abbia mai visto è ordinato.

+0

dopo if (paramName.equalsIgnoreCase ("comment")), cookie.setPath (paramValue) è probabilmente sbagliato? –

+1

È meglio fare ciò che @yanchenko ha suggerito e utilizzare ciò che viene fornito nelle librerie native. Utilizza una delle superclash [CookieSpec] (http://developer.android.com/reference/org/apache/http/cookie/CookieSpec.html) come [BestMatchSpec] (http://developer.android.com/reference/ org/apache/http/impl/cookie/BestMatchSpec.html) –

+1

Questo si interromperà se i valori del cookie hanno il carattere "=" nel valore –

7

Con un'espressione regolare come:

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

si può analizzare un biscotto come questo:

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

in poche righe di codice.

8

È possibile utilizzare le strutture Apache HttpClient per quello.
Ecco un estratto da 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

Il vantaggio dell'approccio di Yanchenko con il client HTTP Apache è cioè convalida i biscotti coerenti con le specifiche in base alla provenienza. L'approccio alle espressioni regolari non lo farà, ma forse non è necessario.

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

Ho allegato un piccolo esempio di regex yanchenkos. Deve essere modificato solo un po '. Senza il '?' quantità modifca sul trailing ';' l'attributo finale per qualsiasi cookie non verrà abbinato. Dopodiché, se ti preoccupi degli altri attributi, puoi usare il codice di Doug, correttamente incapsulato, per analizzare gli altri gruppi di corrispondenza.

Modifica: inoltre, notare il qualificatore '*' sul valore del cookie stesso. I valori sono facoltativi e puoi ottenere cookie come "de =", cioè nessun valore. Guardando di nuovo la regex, non penso che gestirà gli attributi di cookie sicuri e di scarto che non hanno un '='.

77

Come su java.net.HttpCookie:

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

Questo è ciò a cui l'OP si riferiva come non disponibile fino api 9. –

+7

@MattWolfe Corretto, ma il 90% delle persone che trovano questa domanda nel 2009 non si preoccupano più dell'API 9. Ecco perché questa risposta viene ora svalutata. –

+0

questo metodo di analisi sembra essere case sensitive a parole come "dominio" e "percorso", quindi è necessario fare attenzione.Vedere la mia risposta dettagliata –

5

Abbastanza divertente, ma java.net.HttpCookie classe non può analizzare le stringhe di cookie con il dominio e/o parti di percorso che questo esatto classe java.net.HttpCookie ha convertite in stringhe.

Ad esempio:

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

Dato che questa classe implementa Serializable né né Parcelable, si sta tentando di memorizzare i cookie come stringhe. Così si scrive qualcosa di simile:

saveMyCookieAsString(newCookie.toString()); 

Questa dichiarazione salverà il cookie nel seguente formato:

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

E poi si desidera ripristinare questo cookie, in modo da ottenere la stringa:

String cookieAsString = restoreMyCookieString(); 

e cercare di analizzarlo:

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

ora myCookieAsStringNow.toString(); produce

cookieName=cookieValue 

di dominio e il percorso parti sono solo andati. Il motivo: il metodo parse è sensibile al maiuscolo/minuscolo per parole come "dominio" e "percorso". metodo di fornire un altro toString() come::
possibile soluzione

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

trovo divertente (soprattutto, per le classi come java.net.HttpCookie che mirano ad essere utilizzato da un sacco e molte persone) e spero che sarà utile per qualcuno

+1

Sembra che 'HttpCookie' analizzi i cookie come cookie del server, ma li stringa come cookie di user-agent - forse era l'intenzione come [il suo JavaDoc] (https://docs.oracle.com/javase/8/docs/api/java/net/HttpCookie.html) legge: _farca le informazioni di stato tra server e user_ agent. Vedi anche [sezione degli esempi di 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(); 
Problemi correlati