All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.aoindustries.website.SessionResponseWrapper Maven / Gradle / Ivy

/*
 * aoweb-struts-core - Core API for legacy Struts-based site framework with AOServ Platform control panels.
 * Copyright (C) 2007-2009, 2016, 2019  AO Industries, Inc.
 *     [email protected]
 *     7262 Bull Pen Cir
 *     Mobile, AL 36695
 *
 * This file is part of aoweb-struts-core.
 *
 * aoweb-struts-core 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 3 of the License, or
 * (at your option) any later version.
 *
 * aoweb-struts-core 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 aoweb-struts-core.  If not, see .
 */
package com.aoindustries.website;

import com.aoindustries.servlet.http.ServletUtil;
import com.aoindustries.tempfiles.servlet.ServletTempFileContext;
import com.aoindustries.util.WrappedException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspException;
import org.apache.struts.Globals;

/**
 * @author  AO Industries, Inc.
 */
public class SessionResponseWrapper extends HttpServletResponseWrapper {

	private static Logger getLogger(ServletContext servletContext) {
		return LogFactory.getLogger(servletContext, SessionResponseWrapper.class);
	}

	final private HttpServletRequest request;
	final private HttpServletResponse response;

	public SessionResponseWrapper(HttpServletRequest request, HttpServletResponse response) {
		super(response);
		this.request = request;
		this.response = response;
	}

	/**
	 * @deprecated  Please use encodeURL.
	 *
	 * @see  #encodeURL(String)
	 */
	@Deprecated
	@Override
	public String encodeUrl(String url) {
		return encodeURL(url);
	}

	@Override
	public String encodeURL(final String url) {
		//System.err.println("DEBUG: encodeURL: "+url);
		try {
			// If starts with http:// or https:// parse out the first part of the URL, encode the path, and reassemble.
			String protocol;
			String remaining;
			if(url.length()>7 && (protocol=url.substring(0, 7)).equalsIgnoreCase("http://")) {
				remaining = url.substring(7);
			} else if(url.length()>8 && (protocol=url.substring(0, 8)).equalsIgnoreCase("https://")) {
				remaining = url.substring(8);
			} else {
				return addNoCookieParameters(url, false);
				//return response.encodeURL(url);
			}
			int slashPos = remaining.indexOf('/');
			if(slashPos==-1) {
				return addNoCookieParameters(url, false);
				//return response.encodeURL(url);
			}
			String hostPort = remaining.substring(0, slashPos);
			int colonPos = hostPort.indexOf(':');
			String host = colonPos==-1 ? hostPort : hostPort.substring(0, colonPos);
			String encoded;
			if(host.equalsIgnoreCase(request.getServerName())) {
				encoded = protocol + hostPort + addNoCookieParameters(remaining.substring(slashPos), false);
				//encoded = protocol + hostPort + response.encodeURL(remaining.substring(slashPos));
			} else {
				// Going to an different hostname, do not add request parameters
				//System.err.println("DEBUG: encodeURL: Not adding parameters to external link: "+url);
				encoded = url;
				//encoded = response.encodeURL(url);
			}
			return encoded;
		} catch(JspException | IOException | SQLException err) {
			throw new WrappedException(err);
		}
	}

	/**
	 * @deprecated  Please use encodeRedirectURL.
	 *
	 * @see  #encodeRedirectURL(String)
	 */
	@Deprecated
	@Override
	public String encodeRedirectUrl(String url) {
		return encodeRedirectURL(url);
	}

	@Override
	public String encodeRedirectURL(String url) {
		//System.err.println("DEBUG: encodeRedirectURL: "+url);
		try {
			// If starts with http:// or https:// parse out the first part of the URL, encode the path, and reassemble.
			String protocol;
			String remaining;
			if(url.length()>7 && (protocol=url.substring(0, 7)).equalsIgnoreCase("http://")) {
				remaining = url.substring(7);
			} else if(url.length()>8 && (protocol=url.substring(0, 8)).equalsIgnoreCase("https://")) {
				remaining = url.substring(8);
			} else {
				return addNoCookieParameters(url, true);
				//return response.encodeRedirectURL(url);
			}
			int slashPos = remaining.indexOf('/');
			if(slashPos==-1) {
				return addNoCookieParameters(url, true);
				//return response.encodeRedirectURL(url);
			}
			String hostPort = remaining.substring(0, slashPos);
			int colonPos = hostPort.indexOf(':');
			String host = colonPos==-1 ? hostPort : hostPort.substring(0, colonPos);
			String encoded;
			if(host.equalsIgnoreCase(request.getServerName())) {
				encoded = protocol + hostPort + addNoCookieParameters(remaining.substring(slashPos), true);
				//encoded = protocol + hostPort + response.encodeRedirectURL(remaining.substring(slashPos));
			} else {
				// Going to an different hostname, do not add request parameters
				//System.err.println("DEBUG: encodeRedirectURL: Not adding parameters to external link: "+url);
				encoded = url;
				//encoded = response.encodeRedirectURL(url);
			}
			return encoded;
		} catch(JspException | IOException | SQLException err) {
			throw new WrappedException(err);
		}
	}

	/**
	 * @deprecated
	 */
	@Deprecated
	@Override
	public void setStatus(int sc, String sm) {
		super.setStatus(sc, sm);
	}

	/**
	 * Adds the no cookie parameters (language and layout) if needed and not already set.
	 */
	private String addNoCookieParameters(String url, boolean isRedirect) throws JspException, UnsupportedEncodingException, IOException, SQLException {
		HttpSession session = request.getSession();
		if(session.isNew() || request.isRequestedSessionIdFromURL()) {
			// Don't add for certains file types
			int pos = url.indexOf('?');
			String lowerPath = (pos==-1 ? url : url.substring(0, pos)).toLowerCase(Locale.ROOT);
			//System.err.println("DEBUG: addNoCookieParameters: lowerPath="+lowerPath);
			if(
				// Matches LocaleFilter
				// Matches NoSessionFilter
				!lowerPath.endsWith(".bmp")
				&& !lowerPath.endsWith(".css")
				&& !lowerPath.endsWith(".exe")
				&& !lowerPath.endsWith(".gif")
				&& !lowerPath.endsWith(".ico")
				&& !lowerPath.endsWith(".jpeg")
				&& !lowerPath.endsWith(".jpg")
				&& !lowerPath.endsWith(".js")
				&& !lowerPath.endsWith(".png")
				&& !lowerPath.endsWith(".svg")
				&& !lowerPath.endsWith(".txt")
				&& !lowerPath.endsWith(".zip")
			) {
				// Use the default servlet container jsessionid when any session object exists besides
				// the three values that will be encoded into the URL as parameters below.
				Enumeration attributeNames = session.getAttributeNames();
				String whyNeedsJsessionid = null;
				while(attributeNames.hasMoreElements()) {
					String name = attributeNames.nextElement();
					if(
						!Constants.AUTHENTICATION_TARGET.equals(name)
						&& !Globals.LOCALE_KEY.equals(name)
						&& !Constants.LAYOUT.equals(name)
						&& !Constants.SU_REQUESTED.equals(name)
						// JSTL 1.1
						&& !"javax.servlet.jsp.jstl.fmt.request.charset".equals(name)
						&& !"javax.servlet.jsp.jstl.fmt.locale.session".equals(name)
						// Allow session-based temporary file context
						&& !ServletTempFileContext.SESSION_ATTRIBUTE_NAME.equals(name)
					) {
						// These will always trigger jsessionid
						if(
							Constants.AO_CONN.equals(name)
							|| Constants.AUTHENTICATED_AO_CONN.equals(name)
						) {
							whyNeedsJsessionid = name;
							break;
						}
						// Must be an SessionActionForm if none of the above
						Object sessionObject = session.getAttribute(name);
						if(sessionObject instanceof SessionActionForm) {
							SessionActionForm sessionActionForm = (SessionActionForm)sessionObject;
							if(!sessionActionForm.isEmpty()) {
								whyNeedsJsessionid = name;
								break;
							}
						} else {
							throw new AssertionError("Session object is neither an expected value nor a SessionActionForm.  name="+name+", sessionObject.class="+sessionObject.getClass().getName());
						}
					}
				}
				ServletContext servletContext = session.getServletContext();
				if(whyNeedsJsessionid!=null) {
					if(ServletUtil.isGooglebot(request)) {
						// Create or update a ticket about the problem
						getLogger(servletContext).logp(
							Level.WARNING,
							SessionResponseWrapper.class.getName(),
							"addNoCookieParameters",
							"Refusing to send jsessionid to Googlebot eventhough request would normally need jsessionid.  Other search engines may be affected.  Reason: "+whyNeedsJsessionid
						);
					} else {
						// System.out.println("DEBUG: Why needs jsessionid: "+whyNeedsJsessionid);
						return isRedirect ? response.encodeRedirectURL(url) : response.encodeURL(url);
					}
				}

				// Add the Constants.AUTHENTICATION_TARGET if needed
				String authenticationTarget = (String)session.getAttribute(Constants.AUTHENTICATION_TARGET);
				if(authenticationTarget==null) authenticationTarget = request.getParameter(Constants.AUTHENTICATION_TARGET);
				//System.err.println("DEBUG: addNoCookieParameters: authenticationTarget="+authenticationTarget);
				if(authenticationTarget!=null) url = addParamIfMissing(url, Constants.AUTHENTICATION_TARGET, authenticationTarget, getCharacterEncoding());

				// Only add the language if there is more than one possibility
				SiteSettings siteSettings = SiteSettings.getInstance(servletContext);
				List languages = siteSettings.getLanguages(request);
				if(languages.size()>1) {
					Locale locale = (Locale)session.getAttribute(Globals.LOCALE_KEY);
					if(locale!=null) {
						String code = locale.getLanguage();
						// Don't add if is the default language
						Locale defaultLocale = LocaleAction.getDefaultLocale(siteSettings, request);
						if(!code.equals(defaultLocale.getLanguage())) {
							for(Skin.Language language : languages) {
								if(language.getCode().equals(code)) {
									url = addParamIfMissing(url, "language", code, getCharacterEncoding());
									break;
								}
							}
						}
					}
				}
				// Only add the layout if there is more than one possibility
				List skins = siteSettings.getSkins();
				if(skins.size()>1) {
					String layout = (String)session.getAttribute(Constants.LAYOUT);
					if(layout!=null) {
						// Don't add if is the default layout
						Skin defaultSkin = SkinAction.getDefaultSkin(skins, request);
						if(!layout.equals(defaultSkin.getName())) {
							// Make sure it is one of the allowed skins
							for(Skin skin : skins) {
								if(skin.getName().equals(layout)) {
									url = addParamIfMissing(url, "layout", layout, getCharacterEncoding());
									break;
								}
							}
						}
					}
				}
				// Add any "su"
				String su = (String)session.getAttribute(Constants.SU_REQUESTED);
				if(su!=null) url = addParamIfMissing(url, "su", su, getCharacterEncoding());
			} else {
				//System.err.println("DEBUG: encodeRedirectURL: Not adding parameters to skipped type: "+url);
			}
		}
		return url;
	}

	/**
	 * Adds a parameter if missing.
	 */
	private static String addParamIfMissing(String url, String name, String value, String encoding) throws UnsupportedEncodingException {
		String encodedName = URLEncoder.encode(name, encoding);
		if(url.indexOf('?')==-1) {
			// No params exist, just add it
			return url+'?'+encodedName+'='+URLEncoder.encode(value, encoding);
		}
		if(
			!url.contains("?"+encodedName+'=')
			&& !url.contains("&"+encodedName+'=')
		) {
			return url+'&'+encodedName+'='+URLEncoder.encode(value, encoding);
		}
		return url;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy