/******************************************************************************* * Copyright (c) 2014, 2016 Raymond Augé and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Raymond Augé <raymond.auge@liferay.com> - Bug 436698 * Istvan Sajtos <istvan.sajtos@liferay.com> - Bug 490608 ******************************************************************************/ package org.eclipse.equinox.http.servlet.internal.context; import java.io.*; import java.net.URLDecoder; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.*; import javax.servlet.http.*; import org.eclipse.equinox.http.servlet.internal.registration.EndpointRegistration; import org.eclipse.equinox.http.servlet.internal.registration.FilterRegistration; import org.eclipse.equinox.http.servlet.internal.servlet.*; import org.eclipse.equinox.http.servlet.internal.util.Const; import org.eclipse.equinox.http.servlet.internal.util.Params; /** * @author Raymond Augé */ public class DispatchTargets { public DispatchTargets( ContextController contextController, EndpointRegistration<?> endpointRegistration, String servletName, String requestURI, String servletPath, String pathInfo, String queryString) { this( contextController, endpointRegistration, Collections.<FilterRegistration>emptyList(), servletName, requestURI, servletPath, pathInfo, queryString); } public DispatchTargets( ContextController contextController, EndpointRegistration<?> endpointRegistration, List<FilterRegistration> matchingFilterRegistrations, String servletName, String requestURI, String servletPath, String pathInfo, String queryString) { this.contextController = contextController; this.endpointRegistration = endpointRegistration; this.matchingFilterRegistrations = matchingFilterRegistrations; this.servletName = servletName; this.requestURI = requestURI; this.servletPath = (servletPath == null) ? Const.BLANK : servletPath; this.pathInfo = pathInfo; this.queryString = queryString; } public void addRequestParameters(HttpServletRequest request) { if (queryString == null) { parameterMap = request.getParameterMap(); queryString = request.getQueryString(); return; } Map<String, String[]> parameterMapCopy = queryStringToParameterMap(queryString); for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()) { String[] values = parameterMapCopy.get(entry.getKey()); values = Params.append(values, entry.getValue()); parameterMapCopy.put(entry.getKey(), values); } parameterMap = Collections.unmodifiableMap(parameterMapCopy); } public void doDispatch( HttpServletRequest originalRequest, HttpServletResponse response, String path, DispatcherType requestedDispatcherType) throws ServletException, IOException { setDispatcherType(requestedDispatcherType); RequestAttributeSetter setter = new RequestAttributeSetter(originalRequest); if (dispatcherType == DispatcherType.INCLUDE) { setter.setAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH, contextController.getContextPath()); setter.setAttribute(RequestDispatcher.INCLUDE_PATH_INFO, getPathInfo()); setter.setAttribute(RequestDispatcher.INCLUDE_QUERY_STRING, getQueryString()); setter.setAttribute(RequestDispatcher.INCLUDE_REQUEST_URI, getRequestURI()); setter.setAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH, getServletPath()); } else if (dispatcherType == DispatcherType.FORWARD) { response.resetBuffer(); setter.setAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH, originalRequest.getContextPath()); setter.setAttribute(RequestDispatcher.FORWARD_PATH_INFO, originalRequest.getPathInfo()); setter.setAttribute(RequestDispatcher.FORWARD_QUERY_STRING, originalRequest.getQueryString()); setter.setAttribute(RequestDispatcher.FORWARD_REQUEST_URI, originalRequest.getRequestURI()); setter.setAttribute(RequestDispatcher.FORWARD_SERVLET_PATH, originalRequest.getServletPath()); } HttpServletRequest request = originalRequest; HttpServletRequestWrapperImpl requestWrapper = HttpServletRequestWrapperImpl.findHttpRuntimeRequest(originalRequest); HttpServletResponseWrapper responseWrapper = HttpServletResponseWrapperImpl.findHttpRuntimeResponse(response); boolean includeWrapperAdded = false; try { if (requestWrapper == null) { requestWrapper = new HttpServletRequestWrapperImpl(originalRequest); request = requestWrapper; } if (responseWrapper == null) { responseWrapper = new HttpServletResponseWrapperImpl(response); response = responseWrapper; } requestWrapper.push(this); if ((dispatcherType == DispatcherType.INCLUDE) && !(responseWrapper.getResponse() instanceof IncludeDispatchResponseWrapper)) { // add the include wrapper to avoid header and status writes responseWrapper.setResponse(new IncludeDispatchResponseWrapper((HttpServletResponse)responseWrapper.getResponse())); includeWrapperAdded = true; } ResponseStateHandler responseStateHandler = new ResponseStateHandler(request, response, this); responseStateHandler.processRequest(); } finally { if ((dispatcherType == DispatcherType.INCLUDE) && (responseWrapper.getResponse() instanceof IncludeDispatchResponseWrapper) && includeWrapperAdded) { // remove the include wrapper we added responseWrapper.setResponse(((IncludeDispatchResponseWrapper)responseWrapper.getResponse()).getResponse()); } requestWrapper.pop(); setter.close(); } } public ContextController getContextController() { return contextController; } public DispatcherType getDispatcherType() { return dispatcherType; } public List<FilterRegistration> getMatchingFilterRegistrations() { return matchingFilterRegistrations; } public Map<String, String[]> getParameterMap() { return parameterMap; } public String getPathInfo() { return pathInfo; } public String getQueryString() { return queryString; } public String getRequestURI() { if (requestURI == null) { return null; } return getContextController().getFullContextPath() + requestURI; } public String getServletName() { return servletName; } public String getServletPath() { return servletPath; } public EndpointRegistration<?> getServletRegistration() { return endpointRegistration; } public Map<String, Object> getSpecialOverides() { return specialOverides; } public void setDispatcherType(DispatcherType dispatcherType) { this.dispatcherType = dispatcherType; } @Override public String toString() { String value = string; if (value == null) { value = SIMPLE_NAME + '[' + contextController.getFullContextPath() + requestURI + (queryString != null ? '?' + queryString : "") + ", " + endpointRegistration.toString() + ']'; //$NON-NLS-1$ string = value; } return value; } private static Map<String, String[]> queryStringToParameterMap(String queryString) { if ((queryString == null) || (queryString.length() == 0)) { return new HashMap<String, String[]>(); } try { Map<String, String[]> parameterMap = new LinkedHashMap<String, String[]>(); String[] parameters = queryString.split(Const.AMP); for (String parameter : parameters) { int index = parameter.indexOf('='); String name = (index > 0) ? URLDecoder.decode(parameter.substring(0, index), Const.UTF8) : parameter; String[] values = parameterMap.get(name); if (values == null) { values = new String[0]; } String value = ((index > 0) && (parameter.length() > index + 1)) ? URLDecoder.decode(parameter.substring(index + 1), Const.UTF8) : null; values = Params.append(values, value); parameterMap.put(name, values); } return parameterMap; } catch (UnsupportedEncodingException unsupportedEncodingException) { throw new RuntimeException(unsupportedEncodingException); } } private static class RequestAttributeSetter implements Closeable { private final ServletRequest servletRequest; private final Map<String, Object> oldValues = new HashMap<String, Object>(); public RequestAttributeSetter(ServletRequest servletRequest) { this.servletRequest = servletRequest; } public void setAttribute(String name, Object value) { oldValues.put(name, servletRequest.getAttribute(name)); servletRequest.setAttribute(name, value); } public void close() { for (Map.Entry<String, Object> oldValue : oldValues.entrySet()) { if (oldValue.getValue() == null) { servletRequest.removeAttribute(oldValue.getKey()); } else { servletRequest.setAttribute(oldValue.getKey(), oldValue.getValue()); } } } } private static final String SIMPLE_NAME = DispatchTargets.class.getSimpleName(); private final ContextController contextController; private DispatcherType dispatcherType; private final EndpointRegistration<?> endpointRegistration; private final List<FilterRegistration> matchingFilterRegistrations; private final String pathInfo; private Map<String, String[]> parameterMap; private String queryString; private final String requestURI; private final String servletPath; private final String servletName; private final Map<String, Object> specialOverides = new ConcurrentHashMap<String, Object>(); private String string; }