Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/cookies/CanonicalCookie.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/cookies/CanonicalCookie.java b/chrome/android/java/src/org/chromium/chrome/browser/cookies/CanonicalCookie.java |
| index eead2a8143cd2a0b0c936f61b537e87c74846f5f..8cda73f44888d593c4f493f9e59820913416f9bb 100644 |
| --- a/chrome/android/java/src/org/chromium/chrome/browser/cookies/CanonicalCookie.java |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/cookies/CanonicalCookie.java |
| @@ -4,12 +4,24 @@ |
| package org.chromium.chrome.browser.cookies; |
| +import java.io.ByteArrayOutputStream; |
| import java.io.DataInputStream; |
| import java.io.DataOutputStream; |
| +import java.io.EOFException; |
| +import java.io.File; |
| +import java.io.FileInputStream; |
| import java.io.IOException; |
| +import java.util.ArrayList; |
| +import java.util.List; |
| + |
| +import javax.crypto.Cipher; |
| +import javax.crypto.CipherInputStream; |
| +import javax.crypto.CipherOutputStream; |
| /** |
| * Java representation of net/cookies/canonical_cookie.h. |
| + * |
| + * Also has static methods to write and restore list of CanonicalCookies to and from disk. |
| */ |
| class CanonicalCookie { |
| private final String mUrl; |
| @@ -22,13 +34,13 @@ class CanonicalCookie { |
| private final long mLastAccess; |
| private final boolean mSecure; |
| private final boolean mHttpOnly; |
| - private final boolean mSameSite; |
| + private final int mSameSite; |
| private final int mPriority; |
| /** Constructs a CanonicalCookie */ |
| CanonicalCookie(String url, String name, String value, String domain, String path, |
| long creation, long expiration, long lastAccess, boolean secure, boolean httpOnly, |
| - boolean sameSite, int priority) { |
| + int sameSite, int priority) { |
| mUrl = url; |
| mName = name; |
| mValue = value; |
| @@ -53,8 +65,8 @@ class CanonicalCookie { |
| return mHttpOnly; |
| } |
| - /** @return True if the cookie is Same-Site. */ |
| - boolean isSameSite() { |
| + /** @return SameSite enum */ |
| + int getSameSite() { |
| return mSameSite; |
| } |
| @@ -103,13 +115,61 @@ class CanonicalCookie { |
| return mValue; |
| } |
| - /** |
| - * Serializes for saving to disk. Does not close the stream. |
| - * It is up to the caller to do so. |
| - * |
| - * @param out Stream to write the cookie to. |
| - */ |
| - void saveToStream(DataOutputStream out) throws IOException { |
| + private static final int SERIALIZATION_VERSION = 20160426; |
| + |
| + // Not private for tests. |
| + static void saveToStream(DataOutputStream out, CanonicalCookie[] cookies) throws IOException { |
| + if (out == null) { |
| + throw new IllegalArgumentException("out arg is null"); |
| + } |
| + if (cookies == null) { |
| + throw new IllegalArgumentException("cookies arg is null"); |
| + } |
| + for (CanonicalCookie cookie : cookies) { |
| + if (cookie == null) { |
| + throw new IllegalArgumentException("cookies arg contains null value"); |
| + } |
| + } |
| + |
| + int length = cookies.length; |
| + out.writeInt(SERIALIZATION_VERSION); |
| + out.writeInt(length); |
| + for (int i = 0; i < length; ++i) { |
| + cookies[i].saveToStream(out); |
| + } |
| + } |
| + |
| + // Not private for tests. |
| + static class UnexpectedFormatException extends Exception { |
| + public UnexpectedFormatException(String message) { |
| + super(message); |
| + } |
| + } |
| + |
| + // Not private for tests. |
| + static List<CanonicalCookie> readFromStream(DataInputStream in) |
| + throws IOException, UnexpectedFormatException { |
| + if (in == null) { |
| + throw new IllegalArgumentException("in arg is null"); |
| + } |
| + |
| + final int version = in.readInt(); |
| + if (version != SERIALIZATION_VERSION) { |
| + throw new UnexpectedFormatException("Unexpected version"); |
| + } |
| + final int length = in.readInt(); |
| + if (length < 0) { |
| + throw new UnexpectedFormatException("Negative length: " + length); |
| + } |
| + |
| + ArrayList<CanonicalCookie> cookies = new ArrayList<>(length); |
| + for (int i = 0; i < length; ++i) { |
| + cookies.add(createFromStream(in)); |
| + } |
| + return cookies; |
| + } |
| + |
| + private void saveToStream(DataOutputStream out) throws IOException { |
| out.writeUTF(mUrl); |
| out.writeUTF(mName); |
| out.writeUTF(mValue); |
| @@ -120,20 +180,92 @@ class CanonicalCookie { |
| out.writeLong(mLastAccess); |
| out.writeBoolean(mSecure); |
| out.writeBoolean(mHttpOnly); |
| - out.writeBoolean(mSameSite); |
| + out.writeInt(mSameSite); |
| out.writeInt(mPriority); |
| } |
| - /** |
| - * Constructs a cookie by deserializing a single entry from the |
| - * input stream. |
| - * |
| - * @param in Stream to read a cookie entry from. |
| - */ |
| - static CanonicalCookie createFromStream(DataInputStream in) |
| - throws IOException { |
| + private static CanonicalCookie createFromStream(DataInputStream in) throws IOException { |
| + return new CanonicalCookie(in.readUTF(), in.readUTF(), in.readUTF(), in.readUTF(), |
| + in.readUTF(), in.readLong(), in.readLong(), in.readLong(), in.readBoolean(), |
| + in.readBoolean(), in.readInt(), in.readInt()); |
| + } |
| + |
| + // Not private for tests. |
| + static final String LEGACY_FORMAT_MAGIC_STRING = "c0Ok135"; |
| + |
| + // If this raises UnexpectedFormatException, then caller should rewind the stream, and try |
| + // readFromStream instead. |
| + // Not private for tests. |
| + static ArrayList<CanonicalCookie> readFromLegacyStream(DataInputStream in) |
| + throws IOException, UnexpectedFormatException { |
| + // Identify legacy format by the magic string. |
| + try { |
| + String check = in.readUTF(); |
| + if (!LEGACY_FORMAT_MAGIC_STRING.equals(check)) { |
| + throw new UnexpectedFormatException("No magic string"); |
| + } |
| + } catch (IOException e) { |
| + throw new UnexpectedFormatException("IOException while reading magic string"); |
| + } |
| + |
| + ArrayList<CanonicalCookie> cookies = new ArrayList<>(); |
| + try { |
| + while (true) { |
| + CanonicalCookie cookie = createFromLegacyStream(in); |
| + cookies.add(cookie); |
| + } |
| + } catch (EOFException ignored) { |
| + // We are done. |
| + } |
| + return cookies; |
| + } |
| + |
| + // Legacy format stored sameSite as a boolean. |
| + private static CanonicalCookie createFromLegacyStream(DataInputStream in) throws IOException { |
| return new CanonicalCookie(in.readUTF(), in.readUTF(), in.readUTF(), in.readUTF(), |
| in.readUTF(), in.readLong(), in.readLong(), in.readLong(), in.readBoolean(), |
| - in.readBoolean(), in.readBoolean(), in.readInt()); |
| + in.readBoolean(), in.readBoolean() ? 1 : 0, in.readInt()); |
| + } |
| + |
| + // This leaks implementation details from CookiesFetcher. But CookiesFetcher can't be unit |
| + // tested. |
| + public static List<CanonicalCookie> readFromFileUnknownFormat(File fileIn, Cipher cipher) |
|
Yaron
2016/04/28 03:43:10
Couldn't you at least omit "public" and leave this
boliu
2016/04/28 17:49:26
I guess .cookies is its own package, so there actu
|
| + throws IOException, UnexpectedFormatException { |
| + DataInputStream in = null; |
| + try { |
| + FileInputStream streamIn = new FileInputStream(fileIn); |
| + in = new DataInputStream(new CipherInputStream(streamIn, cipher)); |
| + return readFromLegacyStream(in); |
| + } catch (UnexpectedFormatException ignored) { |
| + // Maybe in new format. |
| + } finally { |
| + if (in != null) { |
| + in.close(); |
| + } |
| + in = null; |
|
Yaron
2016/04/28 03:43:10
Do you really need to null this out?
boliu
2016/04/28 17:49:26
I want to make sure that the "in" here and the "in
|
| + } |
| + |
| + try { |
| + FileInputStream streamIn = new FileInputStream(fileIn); |
| + in = new DataInputStream(new CipherInputStream(streamIn, cipher)); |
| + return CanonicalCookie.readFromStream(in); |
| + } finally { |
| + if (in != null) { |
| + in.close(); |
| + } |
| + in = null; |
|
Yaron
2016/04/28 03:43:10
same here
boliu
2016/04/28 17:49:25
ditto
|
| + } |
| + } |
| + |
| + // This leaks implementation details from CookiesFetcher. But CookiesFetcher can't be unit |
| + // tested. |
| + public static byte[] writeToByteArray(Cipher cipher, CanonicalCookie cookies[]) |
| + throws IOException { |
| + ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); |
| + CipherOutputStream cipherOut = new CipherOutputStream(byteOut, cipher); |
| + DataOutputStream out = new DataOutputStream(cipherOut); |
| + CanonicalCookie.saveToStream(out, cookies); |
| + out.close(); |
| + return byteOut.toByteArray(); |
| } |
| } |