blob: c30d50b420fbb1e815a6b615840a7925708bdeae [file] [log] [blame]
/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.user.client;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* Provides access to browser cookies stored on the client. Because of browser
* restrictions, you will only be able to access cookies associated with the
* current page's domain.
*/
public class Cookies {
/**
* Cached copy of cookies.
*/
static HashMap<String, String> cachedCookies = null;
/**
* Raw cookie string stored to allow cached cookies to be invalidated on
* write.
*/
// Used only in JSNI.
static String rawCookies;
/**
* Indicates whether or not cookies are enabled.
*/
private static boolean isCookieEnabled = false;
/**
* Indicates whether or not we've checked if cookies are enabled.
*/
private static boolean isCookieChecked = false;
/**
* Flag that indicates whether cookies should be URIencoded (when set) and
* URIdecoded (when retrieved). Defaults to URIencoding.
*/
private static boolean uriEncoding = true;
/**
* Gets the cookie associated with the given name.
*
* @param name the name of the cookie to be retrieved
* @return the cookie's value, or <code>null</code> if the cookie doesn't
* exist
*/
public static String getCookie(String name) {
Map<String, String> cookiesMap = ensureCookies();
return cookiesMap.get(name);
}
/**
* Gets the names of all cookies in this page's domain.
*
* @return the names of all cookies
*/
public static Collection<String> getCookieNames() {
return ensureCookies().keySet();
}
/**
* Gets the URIencode flag.
*/
public static boolean getUriEncode() {
return uriEncoding;
}
/**
* Checks whether or not cookies are enabled or disabled.
*
* @return true if a cookie can be set, false if not
*/
public static boolean isCookieEnabled() {
if (!isCookieChecked) {
// The only way to know for sure that cookies are enabled is to set and
// retrieve one. Checking navigator.cookieEnabled may return the wrong
// value if the browser has security software installed. In IE, it alerts
// the user of an unspecified security risk when the app is embedded in an
// iframe.
isCookieChecked = true;
Cookies.setCookie("__gwtCookieCheck", "isEnabled");
isCookieEnabled = "isEnabled".equals(Cookies.getCookie("__gwtCookieCheck"));
Cookies.removeCookie("__gwtCookieCheck");
}
return isCookieEnabled;
}
/**
* Removes the cookie associated with the given name.
*
* @param name the name of the cookie to be removed
*/
public static void removeCookie(String name) {
if (uriEncoding) {
name = uriEncode(name);
}
removeCookieNative(name);
}
/**
* Removes the cookie associated with the given name.
*
* @param name the name of the cookie to be removed
* @param path the path to be associated with this cookie (which should match
* the path given in {@link #setCookie})
*/
public static void removeCookie(String name, String path) {
if (uriEncoding) {
name = uriEncode(name);
}
removeCookieNative(name, path);
}
/**
* Native method to remove a cookie with a path.
*/
public static native void removeCookieNative(String name, String path) /*-{
$doc.cookie = name + "=;path=" + path + ";expires=Fri, 02-Jan-1970 00:00:00 GMT";
}-*/;
/**
* Sets a cookie. The cookie will expire when the current browser session is
* ended.
*
* @param name the cookie's name
* @param value the cookie's value
*/
public static void setCookie(String name, String value) {
setCookie(name, value, null, null, null, false);
}
/**
* Sets a cookie.
*
* @param name the cookie's name
* @param value the cookie's value
* @param expires when the cookie expires
*/
public static void setCookie(String name, String value, Date expires) {
setCookie(name, value, expires, null, null, false);
}
/**
* Sets a cookie. If uriEncoding is false, it checks the validity of name and
* value. Name: Must conform to RFC 2965. Not allowed: = , ; white space. Also
* can't begin with $. Value: No = or ;
*
* @param name the cookie's name
* @param value the cookie's value
* @param expires when the cookie expires
* @param domain the domain to be associated with this cookie
* @param path the path to be associated with this cookie
* @param secure <code>true</code> to make this a secure cookie (that is, only
* accessible over an SSL connection)
*/
public static void setCookie(String name, String value, Date expires,
String domain, String path, boolean secure) {
if (uriEncoding) {
name = uriEncode(name);
value = uriEncode(value);
} else if (!isValidCookieName(name)) {
throw new IllegalArgumentException("Illegal cookie format: " + name + " is not a valid cookie name.");
} else if (!isValidCookieValue(value)) {
throw new IllegalArgumentException("Illegal cookie format: " + value + " is not a valid cookie value.");
}
setCookieImpl(name, value, (expires == null) ? 0 : expires.getTime(),
domain, path, secure);
}
/**
* Updates the URIencode flag and empties the cached cookies set.
*/
public static void setUriEncode(boolean encode) {
if (encode != uriEncoding) {
uriEncoding = encode;
cachedCookies = null;
}
}
static native void loadCookies(HashMap<String, String> m) /*-{
var docCookie = $doc.cookie;
if (docCookie && docCookie != '') {
var crumbs = docCookie.split('; ');
for (var i = 0; i < crumbs.length; ++i) {
var name, value;
var eqIdx = crumbs[i].indexOf('=');
if (eqIdx == -1) {
name = crumbs[i];
value = '';
} else {
name = crumbs[i].substring(0, eqIdx);
value = crumbs[i].substring(eqIdx + 1);
}
if (@com.google.gwt.user.client.Cookies::uriEncoding) {
try {
name = decodeURIComponent(name);
} catch (e) {
// ignore error, keep undecoded name
}
try {
value = decodeURIComponent(value);
} catch (e) {
// ignore error, keep undecoded value
}
}
m.@java.util.Map::put(Ljava/lang/Object;Ljava/lang/Object;)(name,value);
}
}
}-*/;
private static HashMap<String, String> ensureCookies() {
if (cachedCookies == null || needsRefresh()) {
HashMap<String, String> newCachedCookies = new HashMap<String, String>();
loadCookies(newCachedCookies);
cachedCookies = newCachedCookies;
}
return cachedCookies;
}
/**
* Checks whether a cookie name is valid: can't contain '=', ';', ',', or
* whitespace. Can't begin with $.
*
* @param name the cookie's name
*/
private static boolean isValidCookieName(String name) {
if (uriEncoding) {
// check not necessary
return true;
} else if (name.contains("=") || name.contains(";") || name.contains(",")
|| name.startsWith("$") || name.matches(".*\\s+.*")) {
return false;
} else {
return true;
}
}
/**
* Checks whether a cookie value is valid. A cookie cannot contain '=' or ';'.
*
* @param value the cookie's value
*/
private static boolean isValidCookieValue(String value) {
if (uriEncoding) {
// check not necessary
return true;
}
if (value.contains("=") || value.contains(";")) {
return false;
} else {
return true;
}
}
private static native boolean needsRefresh() /*-{
var docCookie = $doc.cookie;
// Check to see if cached cookies need to be invalidated.
if (docCookie != @com.google.gwt.user.client.Cookies::rawCookies) {
@com.google.gwt.user.client.Cookies::rawCookies = docCookie;
return true;
} else {
return false;
}
}-*/;
/**
* Native method to remove a cookie.
*/
private static native void removeCookieNative(String name) /*-{
$doc.cookie = name + "=;expires=Fri, 02-Jan-1970 00:00:00 GMT";
}-*/;
private static native void setCookieImpl(String name, String value,
double expires, String domain, String path, boolean secure) /*-{
var c = name + '=' + value;
if ( expires )
c += ';expires=' + (new Date(expires)).toGMTString();
if (domain)
c += ';domain=' + domain;
if (path)
c += ';path=' + path;
if (secure)
c += ';secure';
$doc.cookie = c;
}-*/;
private static native String uriEncode(String s) /*-{
return encodeURIComponent(s);
}-*/;
private Cookies() {
}
}