blob: 496e28b1e522a3c190878c1702986fe617a3d476 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.wicket.util.cookies;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import jakarta.servlet.http.Cookie;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
import org.apache.wicket.request.Response;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.http.WebRequest;
import org.apache.wicket.request.http.WebResponse;
import org.apache.wicket.util.string.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Helper class to simplify Cookie handling.
*
* @author Juergen Donnerstag
* @author Jonathan Locke
*/
public class CookieUtils
{
private final static Logger log = LoggerFactory.getLogger(CookieUtils.class);
public static final String DEFAULT_SESSIONID_COOKIE_NAME = "JSESSIONID";
private final CookieDefaults settings;
/**
* Construct.
*/
public CookieUtils()
{
settings = new CookieDefaults();
}
/**
* Construct.
*
* @param settings
* the default settings for the saved cookies
*/
public CookieUtils(final CookieDefaults settings)
{
this.settings = settings;
}
/**
* @return Gets the settings for these utils
*/
public final CookieDefaults getSettings()
{
return settings;
}
/**
* Remove the cookie identified by the key
*
* @param key
* The cookie name
*/
public final void remove(final String key)
{
final Cookie cookie = getCookie(key);
if (cookie != null)
{
remove(cookie);
}
}
/**
* Remove the cookie identified by the form component
*
* @param formComponent
*/
public final void remove(final FormComponent<?> formComponent)
{
remove(getKey(formComponent));
}
/**
* This method gets used when a cookie key needs to be derived from a form component. By default
* the component's page relative path is used.
*
* @param component
* @return cookie key
*/
protected String getKey(final FormComponent<?> component)
{
return getSaveKey(component.getPageRelativePath());
}
/**
* Retrieve the cookie value by means of its key.
*
* @param key
* The cookie name
* @return The cookie value associated with the key
*/
public final String load(final String key)
{
final Cookie cookie = getCookie(key);
if (cookie != null)
{
return cookie.getValue();
}
return null;
}
/**
* Retrieve the cookie value associated with the formComponent and load the model object with
* the cookie value.
*
* @param formComponent
* @return The Cookie value which has also been used to set the component's model value
*/
public final String load(final FormComponent<?> formComponent)
{
String value = load(getKey(formComponent));
if (value != null)
{
// Assign the retrieved/persisted value to the component
formComponent.setModelValue(new String[] {value});
}
return value;
}
/**
* Create a Cookie with key and value and save it in the browser with the next response
*
* @param name
* The cookie name
* @param value
* The cookie value
*/
public final void save(String name, final String value)
{
Cookie cookie = getCookie(name);
if (cookie == null)
{
cookie = new Cookie(name, value);
}
else
{
cookie.setValue(value);
}
save(cookie);
}
/**
* Save the form components model value in a cookie
*
* @param formComponent
*/
public final void save(final FormComponent<?> formComponent)
{
save(getKey(formComponent), formComponent.getValue());
}
/**
* Make sure the 'key' does not contain any illegal chars. E.g. for cookies ':' is not allowed.
*
* @param key
* The key to be validated
* @return The save key
*/
protected String getSaveKey(String key)
{
if (Strings.isEmpty(key))
{
throw new IllegalArgumentException("A Cookie name can not be null or empty");
}
// cookie names cannot contain ':',
// we replace ':' with '.' but first we have to encode '.' as '..'
key = Strings.replaceAll(key, ".", "..").toString();
key = key.replace(':', '.');
return key;
}
/**
* Convenience method for deleting a cookie by name. Delete the cookie by setting its maximum
* age to zero.
*
* @param cookie
* The cookie to delete
*/
private void remove(final Cookie cookie)
{
if (cookie != null)
{
save(cookie);
// Delete the cookie by setting its maximum age to zero
cookie.setMaxAge(0);
cookie.setValue(null);
if (log.isDebugEnabled())
{
log.debug("Removed Cookie: " + cookie.getName());
}
}
}
/**
* Gets the cookie with 'name' attached to the latest WebRequest.
*
* @param name
* The name of the cookie to be looked up
*
* @return Any cookies for this request
*/
public Cookie getCookie(final String name)
{
try
{
WebRequest webRequest = getWebRequest();
Cookie cookie = webRequest.getCookie(name);
if (log.isDebugEnabled())
{
if (cookie != null)
{
log.debug("Found Cookie with name=" + name + " and request URI=" +
webRequest.getUrl().toString());
}
else
{
log.debug("Unable to find Cookie with name=" + name + " and request URI=" +
webRequest.getUrl().toString());
}
}
return cookie;
}
catch (NullPointerException ex)
{
// Ignore any app server problem here
}
return null;
}
/**
* Gets the name of the cookie where the session id is stored.
*
* @param application
* The current we application holding the {@link jakarta.servlet.ServletContext}.
*
* @return The name set in {@link jakarta.servlet.SessionCookieConfig} or the default value 'JSESSIONID' if not set
*/
public String getSessionIdCookieName(WebApplication application)
{
String jsessionCookieName = application.getServletContext().getSessionCookieConfig().getName();
return jsessionCookieName == null ? DEFAULT_SESSIONID_COOKIE_NAME : jsessionCookieName;
}
/**
* Persist/save the data using Cookies.
*
* @param cookie
* The Cookie to be persisted.
* @return The cookie provided
*/
private Cookie save(final Cookie cookie)
{
if (cookie == null)
{
return null;
}
initializeCookie(cookie);
getWebResponse().addCookie(cookie);
if (log.isDebugEnabled())
{
log.debug("Cookie saved: " + cookieToDebugString(cookie) + "; request URI=" +
getWebRequest().getUrl().toString());
}
return cookie;
}
/**
* Is called before the Cookie is saved. May be subclassed for different (dynamic) Cookie
* parameters. Static parameters can also be changed via {@link CookieDefaults}.
*
* @param cookie
*/
protected void initializeCookie(final Cookie cookie)
{
final String comment = settings.getComment();
if (comment != null)
{
cookie.setComment(comment);
}
final String domain = settings.getDomain();
if (domain != null)
{
cookie.setDomain(domain);
}
ServletWebRequest request = (ServletWebRequest)getWebRequest();
String path = request.getContainerRequest().getContextPath() + "/" +
request.getFilterPrefix();
cookie.setPath(path);
cookie.setVersion(settings.getVersion());
cookie.setSecure(settings.getSecure());
cookie.setMaxAge(settings.getMaxAge());
cookie.setHttpOnly(settings.isHttpOnly());
}
/**
* Convenience method to get the http request.
*
* @return WebRequest related to the RequestCycle
*/
private WebRequest getWebRequest()
{
return (WebRequest)RequestCycle.get().getRequest();
}
/**
* Convenience method to get the http response.
*
* @return WebResponse related to the RequestCycle
*/
private WebResponse getWebResponse()
{
RequestCycle cycle = RequestCycle.get();
Response response = cycle.getResponse();
if (!(response instanceof WebResponse))
{
response = cycle.getOriginalResponse();
}
return (WebResponse)response;
}
/**
* Gets debug info as a string for the given cookie.
*
* @param cookie
* the cookie to debug.
* @return a string that represents the internals of the cookie.
*/
private String cookieToDebugString(final Cookie cookie)
{
final LocalDateTime localDateTime = Instant.ofEpochMilli(cookie.getMaxAge()).atZone(ZoneId.systemDefault()).toLocalDateTime();
return "[Cookie " + " name = " + cookie.getName() + ", value = " + cookie.getValue() +
", domain = " + cookie.getDomain() + ", path = " + cookie.getPath() + ", maxAge = " +
localDateTime + "(" + cookie.getMaxAge() + ")" + "]";
}
}