001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.util;
018
019import javax.servlet.http.Cookie;
020import javax.servlet.http.HttpServletResponse;
021
022import org.apache.commons.logging.Log;
023import org.apache.commons.logging.LogFactory;
024
025import org.springframework.lang.Nullable;
026import org.springframework.util.Assert;
027
028/**
029 * Helper class for cookie generation, carrying cookie descriptor settings
030 * as bean properties and being able to add and remove cookie to/from a
031 * given response.
032 *
033 * <p>Can serve as base class for components that generate specific cookies,
034 * such as CookieLocaleResolver and CookieThemeResolver.
035 *
036 * @author Juergen Hoeller
037 * @since 1.1.4
038 * @see #addCookie
039 * @see #removeCookie
040 * @see org.springframework.web.servlet.i18n.CookieLocaleResolver
041 * @see org.springframework.web.servlet.theme.CookieThemeResolver
042 */
043public class CookieGenerator {
044
045        /**
046         * Default path that cookies will be visible to: "/", i.e. the entire server.
047         */
048        public static final String DEFAULT_COOKIE_PATH = "/";
049
050
051        protected final Log logger = LogFactory.getLog(getClass());
052
053        @Nullable
054        private String cookieName;
055
056        @Nullable
057        private String cookieDomain;
058
059        private String cookiePath = DEFAULT_COOKIE_PATH;
060
061        @Nullable
062        private Integer cookieMaxAge;
063
064        private boolean cookieSecure = false;
065
066        private boolean cookieHttpOnly = false;
067
068
069        /**
070         * Use the given name for cookies created by this generator.
071         * @see javax.servlet.http.Cookie#getName()
072         */
073        public void setCookieName(@Nullable String cookieName) {
074                this.cookieName = cookieName;
075        }
076
077        /**
078         * Return the given name for cookies created by this generator.
079         */
080        @Nullable
081        public String getCookieName() {
082                return this.cookieName;
083        }
084
085        /**
086         * Use the given domain for cookies created by this generator.
087         * The cookie is only visible to servers in this domain.
088         * @see javax.servlet.http.Cookie#setDomain
089         */
090        public void setCookieDomain(@Nullable String cookieDomain) {
091                this.cookieDomain = cookieDomain;
092        }
093
094        /**
095         * Return the domain for cookies created by this generator, if any.
096         */
097        @Nullable
098        public String getCookieDomain() {
099                return this.cookieDomain;
100        }
101
102        /**
103         * Use the given path for cookies created by this generator.
104         * The cookie is only visible to URLs in this path and below.
105         * @see javax.servlet.http.Cookie#setPath
106         */
107        public void setCookiePath(String cookiePath) {
108                this.cookiePath = cookiePath;
109        }
110
111        /**
112         * Return the path for cookies created by this generator.
113         */
114        public String getCookiePath() {
115                return this.cookiePath;
116        }
117
118        /**
119         * Use the given maximum age (in seconds) for cookies created by this generator.
120         * Useful special value: -1 ... not persistent, deleted when client shuts down.
121         * <p>Default is no specific maximum age at all, using the Servlet container's
122         * default.
123         * @see javax.servlet.http.Cookie#setMaxAge
124         */
125        public void setCookieMaxAge(@Nullable Integer cookieMaxAge) {
126                this.cookieMaxAge = cookieMaxAge;
127        }
128
129        /**
130         * Return the maximum age for cookies created by this generator.
131         */
132        @Nullable
133        public Integer getCookieMaxAge() {
134                return this.cookieMaxAge;
135        }
136
137        /**
138         * Set whether the cookie should only be sent using a secure protocol,
139         * such as HTTPS (SSL). This is an indication to the receiving browser,
140         * not processed by the HTTP server itself.
141         * <p>Default is "false".
142         * @see javax.servlet.http.Cookie#setSecure
143         */
144        public void setCookieSecure(boolean cookieSecure) {
145                this.cookieSecure = cookieSecure;
146        }
147
148        /**
149         * Return whether the cookie should only be sent using a secure protocol,
150         * such as HTTPS (SSL).
151         */
152        public boolean isCookieSecure() {
153                return this.cookieSecure;
154        }
155
156        /**
157         * Set whether the cookie is supposed to be marked with the "HttpOnly" attribute.
158         * <p>Default is "false".
159         * @see javax.servlet.http.Cookie#setHttpOnly
160         */
161        public void setCookieHttpOnly(boolean cookieHttpOnly) {
162                this.cookieHttpOnly = cookieHttpOnly;
163        }
164
165        /**
166         * Return whether the cookie is supposed to be marked with the "HttpOnly" attribute.
167         */
168        public boolean isCookieHttpOnly() {
169                return this.cookieHttpOnly;
170        }
171
172
173        /**
174         * Add a cookie with the given value to the response,
175         * using the cookie descriptor settings of this generator.
176         * <p>Delegates to {@link #createCookie} for cookie creation.
177         * @param response the HTTP response to add the cookie to
178         * @param cookieValue the value of the cookie to add
179         * @see #setCookieName
180         * @see #setCookieDomain
181         * @see #setCookiePath
182         * @see #setCookieMaxAge
183         */
184        public void addCookie(HttpServletResponse response, String cookieValue) {
185                Assert.notNull(response, "HttpServletResponse must not be null");
186                Cookie cookie = createCookie(cookieValue);
187                Integer maxAge = getCookieMaxAge();
188                if (maxAge != null) {
189                        cookie.setMaxAge(maxAge);
190                }
191                if (isCookieSecure()) {
192                        cookie.setSecure(true);
193                }
194                if (isCookieHttpOnly()) {
195                        cookie.setHttpOnly(true);
196                }
197                response.addCookie(cookie);
198                if (logger.isTraceEnabled()) {
199                        logger.trace("Added cookie [" + getCookieName() + "=" + cookieValue + "]");
200                }
201        }
202
203        /**
204         * Remove the cookie that this generator describes from the response.
205         * Will generate a cookie with empty value and max age 0.
206         * <p>Delegates to {@link #createCookie} for cookie creation.
207         * @param response the HTTP response to remove the cookie from
208         * @see #setCookieName
209         * @see #setCookieDomain
210         * @see #setCookiePath
211         */
212        public void removeCookie(HttpServletResponse response) {
213                Assert.notNull(response, "HttpServletResponse must not be null");
214                Cookie cookie = createCookie("");
215                cookie.setMaxAge(0);
216                if (isCookieSecure()) {
217                        cookie.setSecure(true);
218                }
219                if (isCookieHttpOnly()) {
220                        cookie.setHttpOnly(true);
221                }
222                response.addCookie(cookie);
223                if (logger.isTraceEnabled()) {
224                        logger.trace("Removed cookie '" + getCookieName() + "'");
225                }
226        }
227
228        /**
229         * Create a cookie with the given value, using the cookie descriptor
230         * settings of this generator (except for "cookieMaxAge").
231         * @param cookieValue the value of the cookie to crate
232         * @return the cookie
233         * @see #setCookieName
234         * @see #setCookieDomain
235         * @see #setCookiePath
236         */
237        protected Cookie createCookie(String cookieValue) {
238                Cookie cookie = new Cookie(getCookieName(), cookieValue);
239                if (getCookieDomain() != null) {
240                        cookie.setDomain(getCookieDomain());
241                }
242                cookie.setPath(getCookiePath());
243                return cookie;
244        }
245
246}