web-dev-qa-db-ja.com

Cookie文字列を解析する方法

Cookie文字列(Set-Cookieヘッダーで返される可能性があるため)を取得し、その一部、特に有効期限を簡単に変更できるようにします。

BasicClientCookieなど、いくつかの異なるCookieクラスが使用可能ですが、文字列をこれらのオブジェクトの1つに解析する簡単な方法はありません。

APIレベル9で HttpCookie が追加されましたが、これには解析メソッドがありますが、以前のバージョンで動作するには何かが必要です。

何か案は?

ありがとう

27
cottonBallPaws

手動で解析する必要があると思います。これを試して:

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

私は実際にこのコードをコンパイルしたり実行したりしていませんが、強力なスタートになるはずです。おそらく、日付の解析を少し混乱させる必要があります。Cookieで使用される日付形式が実際にDateFormat.FULLと同じであるかどうかはわかりません。 (チェックアウト this Cookieの日付形式の処理に関連する関連の質問。)また、BasicClientCookieなどのversionによって処理されないCookie属性があることに注意してください。およびhttponly

最後に、このコードは、Cookieの名前と値が最初の属性として表示されることを前提としています。それが必ずしも当てはまるかどうかはわかりませんが、これまでに見たすべてのCookieが順序付けられています。

11
Doug Paul

Java.net.HttpCookie

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

Apache HttpClientの機能を使用できます。
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

おもしろいですが、_Java.net.HttpCookie_クラスは、この正確な_Java.net.HttpCookie_クラスが文字列に変換したドメインおよび/またはパス部分を持つCookie文字列を解析できません。

例えば:

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

このクラスはSerializableもParcelableも実装していないため、Cookieを文字列として保存するのは魅力的です。したがって、次のように記述します。

_saveMyCookieAsString(newCookie.toString());
_

このステートメントは、Cookieを次の形式で保存します。

_cookieName="cookieValue";$Path="/";$Domain="cookiedomain.com"
_

そして、このクッキーを復元したいので、文字列を取得します:

_String cookieAsString = restoreMyCookieString();
_

それを解析してみてください:

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

myCookieAsStringNow.toString();は以下を生成します

_cookieName=cookieValue
_

ドメインとパスの部分は単なるgoneです。理由:解析方法では、「ドメイン」や「パス」などの単語の大文字と小文字が区別されます。
可能な回避策:次のような別のtoString()メソッドを提供します。

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

私はそれがおもしろいと思います(特に、_Java.net.HttpCookie_のようなクラスは、多くの人が使用することを目的としています)。

7

次のような正規表現で:

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

次のようにCookieを解析できます。

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

数行のコードで。

6
krewmarco

Netty HTTPコーデックがインストールされている場合は、io.netty.handler.codec.http.cookie.ServerCookieDecoder.LAX|STRICT。とても便利。

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

Apache Httpクライアントを使用したYanchenkoのアプローチの利点は、Originに基づいた仕様と一致するCookieを検証することです。正規表現のアプローチはそれを行いませんが、おそらくあなたがする必要はありません。

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

Yanchenkos正規表現を使用した小さな例を添付しました。少し調整する必要があります。 「?」なし末尾の「;」の数量修飾子Cookieの末尾の属性は一致しません。その後、他の属性に関心がある場合は、適切にカプセル化されたDougのコードを使用して、他の一致グループを解析できます。

編集:また、Cookie自体の値の「*」修飾子に注意してください。値はオプションであり、「de =」などのCookieを取得できます。つまり、値はまったくありません。正規表現をもう一度見ると、「=」を持たないセキュアなCookie属性を破棄し、Cookie属性を破棄するとは思わない。

0
Ed Ost