/* * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xwiki.container.servlet.filters; import java.io.Serializable; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; /** * Allows to save a request and restore it later from the stored request identifier (SRID). * * @version $Id: fe7206aa864c24c03c09e2b1813e6efa04f510b3 $ * @since 2.5M1 */ public final class SavedRequestManager { /** The name of the parameter used for identifying a saved request in a new request. */ private static final String SAVED_REQUESTS_IDENTIFIER = "srid"; /** The key used for storing request data in the HTTP session. */ private static final String SAVED_REQUESTS_KEY = SavedRequest.class.getCanonicalName() + "_SavedRequests"; /** * Saved request data. Only request parameter are stored, along with the requested URL. */ public static class SavedRequest implements Serializable { /** Unique serialization identifier. */ private static final long serialVersionUID = 8779129900717599986L; /** Saved request data. */ private Map<String, String[]> parameters; /** * The request URL; does not include the query string. The data is reused only if the new URL matches this * value. */ private String requestUrl; /** * Constructor that copies the needed information from a request. * * @param request the request that needs to be saved */ @SuppressWarnings("unchecked") public SavedRequest(HttpServletRequest request) { this.parameters = new HashMap<String, String[]>(request.getParameterMap()); this.requestUrl = request.getRequestURL().toString(); } /** * Gets the value for a parameter, just like {@link javax.servlet.ServletRequest#getParameter(String)}. * * @param name the name of the parameter * @return The first value for this parameter, or <code>null</code> if no value was sent for this parameter. * @see javax.servlet.ServletRequest#getParameter(String) * @see #getParameterValues(String) */ public String getParameter(String name) { String[] values = this.parameters.get(name); if (values != null && values.length > 0) { return values[0]; } return null; } /** * Gets all the values stored for a parameter, just like * {@link javax.servlet.ServletRequest#getParameterValues(String)}. * * @param name the name of the parameter * @return All the values for this parameter, or <code>null</code> if no value was sent for this parameter. * @see javax.servlet.ServletRequest#getParameterValues(String) * @see #getParameter(String) */ public String[] getParameterValues(String name) { return this.parameters.get(name); } /** * Gets all the stored parameters, just like {@link javax.servlet.ServletRequest#getParameterMap()}. * * @return A map with all the stored parameters. * @see javax.servlet.ServletRequest#getParameterMap() */ public Map<String, String[]> getParameterMap() { return this.parameters; } /** * Retrieves the original URL used for this request, as a future request will be able to reuse this data only if * it is for the same document. Does not contain the query string. * * @return A <code>String</code> representation of the URL corresponding to this request. */ public String getRequestUrl() { return this.requestUrl; } } /** * Forbid instantiation {@link SavedRequestManager}. */ private SavedRequestManager() { } /** * @return the SAVED_REQUESTS_IDENTIFIER */ public static String getSavedRequestIdentifier() { return SAVED_REQUESTS_IDENTIFIER; } /** * @return the SAVED_REQUESTS_KEY */ public static String getSavedRequestKey() { return SAVED_REQUESTS_KEY; } /** * Saves the data from a request and stores it in the current session. This method is not thread safe, and does not * guarantee that saved requests are not overwritten, but given that this should only happen sparingly, and that * each client uses his own session to save this kind of information, this is not a real issue. * * @param request the request to save * @return the identifier of the saved request */ @SuppressWarnings("unchecked") public static String saveRequest(HttpServletRequest request) { // Saved requests are stored in the request session HttpSession session = request.getSession(); // Retrieve (and eventually initialize) the list of stored requests Map<String, SavedRequest> savedRequests = (Map<String, SavedRequest>) session.getAttribute(getSavedRequestKey()); if (savedRequests == null) { savedRequests = new HashMap<String, SavedRequest>(); session.setAttribute(getSavedRequestKey(), savedRequests); } // Save the request data SavedRequest savedRequest = new SavedRequest(request); // Generate a random key to identify this request String key; do { key = RandomStringUtils.randomAlphanumeric(8); } while (savedRequests.containsKey(key)); // Store the saved request savedRequests.put(key, savedRequest); // Return the generated identifier return key; } /** * Retrieves the original URL requested before a detour. This method returns something different from * <code>null</code> only when there's a <em>srid</em> parameter in the current request, indicating that there was * another request which data was saved, related to the current request. * * @param request the current request * @return the original requested URL that triggered a detour, or <code>null</code> if there isn't any original * request information */ @SuppressWarnings("unchecked") public static String getOriginalUrl(HttpServletRequest request) { HttpSession session = request.getSession(); Map<String, SavedRequest> savedRequests = (Map<String, SavedRequest>) session.getAttribute(getSavedRequestKey()); if (savedRequests != null) { String identifier = request.getParameter(getSavedRequestIdentifier()); if (!StringUtils.isEmpty(identifier)) { SavedRequest savedRequest = savedRequests.get(request.getParameter(getSavedRequestIdentifier())); if (savedRequest != null) { return savedRequest.getRequestUrl() + "?srid=" + identifier; } } } return null; } }