/*
* #%L
* BroadleafCommerce CMS Module
* %%
* Copyright (C) 2009 - 2013 Broadleaf Commerce
* %%
* 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.
* #L%
*/
package org.broadleafcommerce.cms.web;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.broadleafcommerce.cms.url.domain.URLHandler;
import org.broadleafcommerce.cms.url.service.URLHandlerService;
import org.broadleafcommerce.cms.url.type.URLRedirectType;
import org.broadleafcommerce.common.util.BLCSystemProperty;
import org.broadleafcommerce.common.util.UrlUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Responsible for setting up the site and locale used by Broadleaf Commerce components.
*
* @author bpolster
*/
@Component("blURLHandlerFilter")
public class URLHandlerFilter extends OncePerRequestFilter {
private static final Log LOG = LogFactory.getLog(URLHandlerFilter.class);
@Resource(name = "blURLHandlerService")
private URLHandlerService urlHandlerService;
@Value("${request.uri.encoding}")
public String charEncoding;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String contextPath = request.getContextPath();
String requestURIWithoutContext;
if (request.getContextPath() != null) {
requestURIWithoutContext = request.getRequestURI().substring(request.getContextPath().length());
} else {
requestURIWithoutContext = request.getRequestURI();
}
requestURIWithoutContext = URLDecoder.decode(requestURIWithoutContext, charEncoding);
URLHandler handler = urlHandlerService.findURLHandlerByURI(requestURIWithoutContext);
if (handler != null) {
if (URLRedirectType.FORWARD == handler.getUrlRedirectType()) {
request.getRequestDispatcher(handler.getNewURL()).forward(request, response);
} else if (URLRedirectType.REDIRECT_PERM == handler.getUrlRedirectType()) {
String url = UrlUtil.fixRedirectUrl(contextPath, handler.getNewURL());
url = fixQueryString(request, url);
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
response.setHeader( "Location", url);
response.setHeader( "Connection", "close" );
} else if (URLRedirectType.REDIRECT_TEMP == handler.getUrlRedirectType()) {
String url = UrlUtil.fixRedirectUrl(contextPath, handler.getNewURL());
url = fixQueryString(request, url);
response.sendRedirect(url);
}
} else {
filterChain.doFilter(request, response);
}
}
/**
* If the url does not include "//" then the system will ensure that the application context
* is added to the start of the URL.
*
* @param url
* @return
* @throws Exception
*/
protected String fixQueryString(HttpServletRequest request, String url) {
if (getPreserveQueryStringOnRedirect()) {
try {
Map parameterMap = request.getParameterMap();
if (parameterMap != null && parameterMap.size() > 0) {
Set<String> queryParams = getExistingQueryParams(url);
String symbol = "?";
for (Object keyVal : parameterMap.keySet()) {
String key = (String) keyVal;
if (!queryParams.contains(key)) {
if (url.contains("?")) {
symbol = "&";
}
String param = URLEncoder.encode(key, "UTF-8");
String value = URLEncoder.encode(request.getParameter(key), "UTF-8");
url = url + symbol + param;
if (!StringUtils.isEmpty(value)) {
url = url + "=" + value;
}
}
}
}
} catch (Exception e) {
LOG.error("Error adjusting query string in URLHandlerFilter", e);
}
return url;
}
return url;
}
public static Set<String> getExistingQueryParams(String url) throws UnsupportedEncodingException {
Set<String> query_params = new HashSet<String>();
int pos = url.indexOf("?");
if (pos > 0) {
String query = url.substring(pos);
String[] pairs = query.split("&");
for (String pair : pairs) {
int idx = pair.indexOf("=");
String param="";
String value = null;
if (idx > 0) {
param = pair.substring(0, idx);
} else {
param=pair;
}
query_params.add(param);
}
}
return query_params;
}
protected boolean getPreserveQueryStringOnRedirect() {
return BLCSystemProperty.resolveBooleanSystemProperty("preserveQueryStringOnRedirect");
}
}