webentwicklung-frage-antwort-db.com.de

So analysieren Sie eine Cookie-Zeichenfolge

Ich möchte eine Cookie-Zeichenfolge verwenden (da sie möglicherweise in einem Set-Cookie-Header zurückgegeben wird) und in der Lage sein, Teile davon, insbesondere das Ablaufdatum, leicht zu ändern.

Ich sehe, dass es verschiedene Cookie-Klassen gibt, wie z. B. BasicClientCookie, aber ich sehe keine einfache Möglichkeit, die Zeichenfolge in eines dieser Objekte zu parsen.

Ich sehe in API-Ebene 9, dass sie HttpCookie hinzugefügt haben, die eine Analyse-Methode hat, aber ich brauche etwas, um in früheren Versionen zu arbeiten.

Irgendwelche Ideen?

Vielen Dank

25
cottonBallPaws

Ich glaube, Sie müssen es manuell analysieren. Versuche dies:

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

Ich habe diesen Code nicht kompiliert oder ausgeführt, aber es sollte ein guter Anfang sein. Vermutlich müssen Sie sich beim Parsing des Datums etwas herumschlagen: Ich bin nicht sicher, ob das in Cookies verwendete Datumsformat tatsächlich dasselbe ist wie DateFormat.FULL. (Check out this Verwandte Frage, welche Adressen das Datumsformat in Cookies behandelt.) Beachten Sie auch, dass es einige Cookie-Attribute gibt, die nicht von BasicClientCookie verarbeitet werden, wie version und httponly.

In diesem Code wird schließlich davon ausgegangen, dass Name und Wert des Cookies als erstes Attribut angezeigt werden: Ich bin nicht sicher, ob dies unbedingt der Fall ist, aber so wird jeder Cookie, den ich je gesehen habe, geordnet.

11
Doug Paul

Wie wäre es mit Java.net.HttpCookie :

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

Sie können dazu die Funktionen von Apache HttpClient verwenden.
Hier ein Auszug aus 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

Mit einem regulären Ausdruck wie: 

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

sie können einen Cookie so analysieren:

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

in ein paar Zeilen Code.

6
krewmarco

Komisch genug, aber Java.net.HttpCookie-Klasse kann keine Cookie-Zeichenfolgen mit Domänen- und/oder Pfadteilen analysieren, die diese genaue Java.net.HttpCookie-Klasse in Zeichenfolgen konvertiert hat.

Zum Beispiel:

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

Da diese Klasse weder Serializable noch Parcelable implementiert, ist es verlockend, Cookies als Zeichenfolgen zu speichern. Also schreibst du so etwas wie:

saveMyCookieAsString(newCookie.toString());

Diese Anweisung speichert den Cookie im folgenden Format:

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

Und dann möchten Sie diesen Cookie wiederherstellen, damit Sie die Zeichenfolge erhalten:

String cookieAsString = restoreMyCookieString();

und versuche es zu analysieren:

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

jetzt produziert myCookieAsStringNow.toString();

cookieName=cookieValue

Domain und Pfadteile sind gerade gegangen . Der Grund: Die Analyse-Methode unterscheidet zwischen Wörtern wie "Domäne" und "Pfad". 
Mögliche Problemumgehung: Geben Sie eine andere toString () -Methode an:

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

Ich finde es lustig (besonders für Klassen wie Java.net.HttpCookie, die von vielen und vielen Leuten verwendet werden sollen) und ich hoffe, es wird für jemanden nützlich sein.

6

Wenn Sie Netty HTTP-Codec installiert haben, können Sie auch io.netty.handler.codec.http.cookie.ServerCookieDecoder.LAX|STRICT verwenden. Sehr angenehm. 

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

Der Vorteil des Yanchenko-Ansatzes mit dem Apache-HTTP-Client besteht darin, dass die Cookies im Einklang mit der Spezifikation basierend auf dem Ursprung überprüft werden. Der Ansatz für reguläre Ausdrücke macht das nicht, aber Sie müssen es vielleicht nicht.

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

Ich habe ein kleines Beispiel mit Yanchenkos Regex beigefügt. Es muss nur ein bisschen angepasst werden. Ohne das '?' Mengenmodifikator auf dem nachlaufenden ";" Das nachgestellte Attribut für ein Cookie wird nicht übereinstimmen. Wenn Sie sich danach für die anderen Attribute interessieren, können Sie den richtig gekapselten Doug-Code verwenden, um die anderen Übereinstimmungsgruppen zu analysieren.

Bearbeiten: Beachten Sie auch das '*' - Qualifikationsmerkmal für den Wert des Cookies. Die Werte sind optional und Sie können Cookies wie "de =" erhalten, d. H. Überhaupt keinen Wert. Wenn ich mir die Regex noch einmal ansehe, glaube ich nicht, dass sie mit den Attributen zum Sichern und Verwerfen von Cookies umgehen wird, die kein '=' haben.

0
Ed Ost