View Javadoc
1   /**
2    * This file Copyright (c) 2010-2015 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.module.blossom.support;
35  
36  import java.io.IOException;
37  import java.util.ArrayList;
38  import java.util.List;
39  
40  import javax.servlet.RequestDispatcher;
41  import javax.servlet.ServletException;
42  import javax.servlet.ServletRequest;
43  import javax.servlet.ServletResponse;
44  import javax.servlet.http.HttpServletRequest;
45  import javax.servlet.http.HttpServletRequestWrapper;
46  
47  import org.springframework.web.util.WebUtils;
48  
49  /**
50   * Request wrapper that makes the request appear like a forward operation. It overrides the request path elements and
51   * exposes the special attributes for a forward request if they are not already set.
52   *
53   * @since 1.2
54   */
55  public class ForwardRequestWrapper extends SpecialAttributeRequestWrapper {
56  
57      private static final String FORWARD_ATTRIBUTES_COMMON_PREFIX = "javax.servlet.forward.";
58      private static final String[] FORWARD_ATTRIBUTE_NAMES = new String[]{
59              WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE,
60              WebUtils.FORWARD_CONTEXT_PATH_ATTRIBUTE,
61              WebUtils.FORWARD_SERVLET_PATH_ATTRIBUTE,
62              WebUtils.FORWARD_PATH_INFO_ATTRIBUTE,
63              WebUtils.FORWARD_QUERY_STRING_ATTRIBUTE};
64  
65      private final List<Object> previousChainState = new ArrayList<Object>(48);
66      private boolean overridePathElements = true;
67      private final String requestUri;
68      private final String contextPath;
69      private final String servletPath;
70      private final String pathInfo;
71  
72      public ForwardRequestWrapper(HttpServletRequest request, String requestUri, String contextPath, String servletPath, String pathInfo) {
73          super(request);
74          this.requestUri = requestUri;
75          this.contextPath = contextPath;
76          this.servletPath = servletPath;
77          this.pathInfo = pathInfo;
78          if (request.getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE) == null) {
79              setOverriddenAttributes(
80                      FORWARD_ATTRIBUTES_COMMON_PREFIX,
81                      FORWARD_ATTRIBUTE_NAMES,
82                      new Object[]{
83                              request.getRequestURI(),
84                              request.getContextPath(),
85                              request.getServletPath(),
86                              request.getPathInfo(),
87                              request.getQueryString()}
88              );
89          } else {
90              super.setEnabled(false);
91          }
92  
93          // Disable all IncludeRequestWrappers already in chain, their attributes must not be visible
94          // Disable all ForwardRequestWrappers already in chain to increase performance, they won't have any effect anyway
95          ServletRequest wrapper = request;
96          while (wrapper instanceof HttpServletRequestWrapper) {
97              if (wrapper instanceof IncludeRequestWrapper) {
98                  IncludeRequestWrapper includeRequestWrapper = (IncludeRequestWrapper) wrapper;
99                  previousChainState.add(includeRequestWrapper);
100                 previousChainState.add(includeRequestWrapper.isEnabled());
101                 includeRequestWrapper.setEnabled(false);
102             } else if (wrapper instanceof ForwardRequestWrapper) {
103                 ForwardRequestWrapper forwardRequestWrapper = (ForwardRequestWrapper) wrapper;
104                 previousChainState.add(forwardRequestWrapper);
105                 previousChainState.add(forwardRequestWrapper.isOverridePathElements());
106                 previousChainState.add(forwardRequestWrapper.isEnabled());
107                 forwardRequestWrapper.setOverridePathElements(false);
108                 forwardRequestWrapper.setEnabled(false);
109             }
110             wrapper = ((HttpServletRequestWrapper) wrapper).getRequest();
111         }
112     }
113 
114     public void restore() {
115         for (int i = 0; i < previousChainState.size(); ) {
116             Object wrapper = previousChainState.get(i++);
117             if (wrapper instanceof IncludeRequestWrapper) {
118                 IncludeRequestWrapper includeRequestWrapper = (IncludeRequestWrapper) wrapper;
119                 includeRequestWrapper.setEnabled((Boolean) previousChainState.get(i++));
120             } else {
121                 ForwardRequestWrapper forwardRequestWrapper = (ForwardRequestWrapper) wrapper;
122                 forwardRequestWrapper.setOverridePathElements((Boolean) previousChainState.get(i++));
123                 forwardRequestWrapper.setEnabled((Boolean) previousChainState.get(i++));
124             }
125         }
126     }
127 
128     public boolean isOverridePathElements() {
129         return overridePathElements;
130     }
131 
132     public void setOverridePathElements(boolean overridePathElements) {
133         this.overridePathElements = overridePathElements;
134     }
135 
136     @Override
137     public String getRequestURI() {
138         if (overridePathElements) {
139             return requestUri;
140         }
141         return super.getRequestURI();
142     }
143 
144     @Override
145     public String getServletPath() {
146         if (overridePathElements) {
147             return servletPath;
148         }
149         return super.getServletPath();
150     }
151 
152     @Override
153     public String getContextPath() {
154         if (overridePathElements) {
155             return contextPath;
156         }
157         return super.getContextPath();
158     }
159 
160     @Override
161     public String getPathInfo() {
162         if (overridePathElements) {
163             return pathInfo;
164         }
165         return super.getPathInfo();
166     }
167 
168     @Override
169     public RequestDispatcher getRequestDispatcher(final String path) {
170 
171         if (!overridePathElements) {
172             return super.getRequestDispatcher(path);
173         }
174 
175         final RequestDispatcher dispatcher = super.getRequestDispatcher(path);
176 
177         return new RequestDispatcher() {
178 
179             @Override
180             public void forward(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
181                 boolean previousValue = overridePathElements;
182                 overridePathElements = false;
183                 try {
184                     dispatcher.forward(servletRequest, servletResponse);
185                 } finally {
186                     overridePathElements = previousValue;
187                 }
188             }
189 
190             @Override
191             public void include(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
192                 dispatcher.include(servletRequest, servletResponse);
193             }
194         };
195     }
196 }