web-dev-qa-db-fra.com

Comment analyser une chaîne de cookie

J'aimerais prendre une chaîne de cookie (car elle pourrait être renvoyée dans un en-tête Set-Cookie) et pouvoir en modifier facilement certaines parties, en particulier la date d'expiration.

Je vois qu'il existe plusieurs classes de cookies, telles que BasicClientCookie, mais je ne vois pas de moyen facile d'analyser la chaîne dans l'un de ces objets.

Je vois qu'au niveau 9 de l'API, ils ont ajouté HttpCookie qui dispose d'une méthode d'analyse, mais j'ai besoin de quelque chose pour fonctionner dans les versions précédentes.

Des idées?

Merci

25
cottonBallPaws

Je crois que vous devrez l'analyser manuellement. Essaye ça:

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

Je n'ai pas compilé ni exécuté ce code, mais cela devrait être un bon début. Vous aurez probablement à vous soucier de l’analyse de la date: je ne suis pas sûr que le format de date utilisé dans les cookies soit identique à DateFormat.FULL. (Consultez this question liée, qui traite du format de date dans les cookies.) Notez également que certains attributs de cookie ne sont pas gérés par BasicClientCookie, tels que version et httponly.

Enfin, ce code suppose que le nom et la valeur du cookie apparaissent comme le premier attribut: je ne suis pas sûr que ce soit nécessairement vrai, mais c'est ainsi que chaque cookie que j'ai vu est commandé.

11
Doug Paul

Que diriez-vous de Java.net.HttpCookie :

List<HttpCookie> cookies = HttpCookie.parse(header);
87
yegor256

Vous pouvez utiliser les installations de Apache HttpClient pour cela.
Voici un extrait 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;
}
8
yanchenko

Avec une expression régulière comme: 

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

vous pouvez analyser un cookie comme ceci:

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

en quelques lignes de code.

6
krewmarco

C'est assez drôle, mais la classe Java.net.HttpCookie ne peut pas analyser les chaînes de cookie avec des parties de domaine et/ou de chemin que cette classe Java.net.HttpCookie a converties en chaînes.

Par exemple:

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

Comme cette classe n'implémente ni Serializable ni Parcelable, il est tentant de stocker les cookies sous forme de chaînes. Donc, vous écrivez quelque chose comme:

saveMyCookieAsString(newCookie.toString());

Cette déclaration enregistrera le cookie au format suivant:

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

Et puis vous voulez restaurer ce cookie, vous obtenez donc la chaîne:

String cookieAsString = restoreMyCookieString();

et essayez de l'analyser:

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

maintenant myCookieAsStringNow.toString(); produit

cookieName=cookieValue

Les parties de domaine et de chemin sont juste sont parties . La raison: la méthode parse est sensible à la casse pour des mots tels que "domaine" et "chemin". 
Solution possible: fournissez une autre méthode toString () telle que:

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

Je trouve cela amusant (en particulier pour les classes comme Java.net.HttpCookie qui sont destinées à être utilisées par beaucoup de gens) et j’espère que cela sera utile pour quelqu'un.

6
Vitaly Zinchenko

Si vous avez installé le codec HTTP Netty, vous pouvez également utiliser io.netty.handler.codec.http.cookie.ServerCookieDecoder.LAX|STRICT. Très pratique. 

0
Matiss
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();
0
Code_Worm

L’avantage de l’approche de Yanchenko avec le client Apache Http est de valider les cookies conformément aux spécifications basées sur l’origine. L'approche de l'expression régulière ne fera pas cela, mais peut-être que vous n'en aurez pas besoin.

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

J'ai joint un petit exemple en utilisant yanchenkos regex. Il doit être légèrement modifié. Sans le '?' quantité modifère sur la fin ';' l'attribut final pour chaque cookie ne sera pas apparié. Après cela, si vous vous souciez des autres attributs, vous pouvez utiliser le code de Doug, correctement encapsulé, pour analyser les autres groupes de correspondance.

Edit: Notez également le qualificatif '*' sur la valeur du cookie lui-même. Les valeurs sont facultatives et vous pouvez obtenir des cookies du type "de =", c’est-à-dire sans valeur. En regardant la regex à nouveau, je ne pense pas que cela gérera les attributs de cookies sécurisés et rejetés qui n’ont pas de '='.

0
Ed Ost