1. Project Clover database Sat Feb 2 2019 06:45:20 CET
  2. Package com.xpn.xwiki.web

File ActionFilter.java

 

Coverage histogram

../../../../img/srcFileCovDistChart9.png
41% of files have more coverage

Code metrics

12
28
4
1
169
77
11
0.39
7
4
2.75

Classes

Class Line # Actions
ActionFilter 61 28 0% 11 5
0.886363688.6%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package com.xpn.xwiki.web;
21   
22    import java.io.IOException;
23    import java.util.Enumeration;
24   
25    import javax.servlet.Filter;
26    import javax.servlet.FilterChain;
27    import javax.servlet.FilterConfig;
28    import javax.servlet.RequestDispatcher;
29    import javax.servlet.ServletException;
30    import javax.servlet.ServletRequest;
31    import javax.servlet.ServletResponse;
32    import javax.servlet.http.HttpServletRequest;
33   
34    import org.slf4j.Logger;
35    import org.slf4j.LoggerFactory;
36    import org.xwiki.configuration.ConfigurationSource;
37   
38    import com.xpn.xwiki.XWiki;
39    import com.xpn.xwiki.internal.XWikiCfgConfigurationSource;
40   
41    /**
42    * A filter that dispatches requests to the right action, depending on the button that was pressed in the editing form.
43    * This is needed since the browser cannot send the form data to different URLs depending on the button pressed, and an
44    * XHTML form has only one target URL. In previous versions of XWiki this was accomplished using javascript code, with a
45    * fall-back on a pseudo-dispatcher inside the {@link PreviewAction}, which was on obvious case of bad code design.
46    * <p>
47    * The filter dispatches requests based on the presence of a request parameter starting with <tt>action_</tt> followed
48    * by the name of the struts action that should actually process the request. For example, the button that does
49    * <tt>Save and Continue</tt> looks like:
50    *
51    * <pre>
52    * &lt;input type=&quot;submit&quot; name=&quot;action_saveandcontinue&quot; value=&quot;...&quot;/&gt;
53    * </pre>
54    *
55    * As a result, when clicking the button, the request is not sent to the form's target (<tt>preview</tt>), but is
56    * actually forwarded internally to <tt>/bin/saveandcontinue/The/Document</tt>.
57    *
58    * @version $Id: 946ce7bfc97972acc668e75e9ef3e19a034611d2 $
59    * @since 1.8M1
60    */
 
61    public class ActionFilter implements Filter
62    {
63    /** Logging helper. */
64    private static final Logger LOGGER = LoggerFactory.getLogger(ActionFilter.class);
65   
66    /** The query property name prefix that indicates the target action. */
67    private static final String ACTION_PREFIX = "action_";
68   
69    /** URL path separator. */
70    private static final String PATH_SEPARATOR = "/";
71   
72    /**
73    * The name of the request attribute that specifies if the action has been already dispatched. This flag is required
74    * to prevent recursive dispatch loop and allows us to map this filter to INCLUDE and FORWARD. The value of this
75    * request attribute is a string. The associated boolean value is determined using {@link Boolean#valueOf(String)}.
76    */
77    private static final String ATTRIBUTE_ACTION_DISPATCHED = ActionFilter.class.getName() + ".actionDispatched";
78   
 
79  39 toggle @Override
80    public void init(FilterConfig filterConfig) throws ServletException
81    {
82    }
83   
 
84  40801 toggle @SuppressWarnings("unchecked")
85    @Override
86    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
87    ServletException
88    {
89    // Only HTTP requests can be dispatched.
90  40804 if (request instanceof HttpServletRequest
91    && !Boolean.valueOf((String) request.getAttribute(ATTRIBUTE_ACTION_DISPATCHED))) {
92  40561 HttpServletRequest hrequest = (HttpServletRequest) request;
93  40568 Enumeration<String> parameterNames = hrequest.getParameterNames();
94  134563 while (parameterNames.hasMoreElements()) {
95  94251 String parameter = parameterNames.nextElement();
96  94242 if (parameter.startsWith(ACTION_PREFIX)) {
97  255 String targetURL = getTargetURL(hrequest, parameter);
98  255 RequestDispatcher dispatcher = hrequest.getRequestDispatcher(targetURL);
99  255 if (dispatcher != null) {
100  255 LOGGER.debug("Forwarding request to " + targetURL);
101  255 request.setAttribute(ATTRIBUTE_ACTION_DISPATCHED, "true");
102  255 dispatcher.forward(hrequest, response);
103    // Allow multiple calls to this filter as long as they are not nested.
104  255 request.removeAttribute(ATTRIBUTE_ACTION_DISPATCHED);
105    // If the request was forwarder to another path, don't continue the normal processing chain.
106  255 return;
107    }
108    }
109    }
110    }
111    // Let the request pass through unchanged.
112  40560 chain.doFilter(request, response);
113    }
114   
 
115  37 toggle @Override
116    public void destroy()
117    {
118    // No finalization needed.
119    }
120   
121    /**
122    * Compose a new URL path based on the original request and the specified action. The result is relative to the
123    * application context, so that it can be used with {@link HttpServletRequest#getRequestDispatcher(String)}. For
124    * example, calling this method with a request for <tt>/xwiki/bin/edit/Some/Document</tt> and <tt>action_save</tt>,
125    * the result is <tt>/bin/save/Some/Document</tt>.
126    *
127    * @param request the original request
128    * @param action the action parameter, starting with <tt>action_</tt>
129    * @return The rebuilt URL path, with the specified action in place of the original Struts action. Note that unlike
130    * the HTTP path, this does not contain the application context part.
131    */
 
132  255 toggle private String getTargetURL(HttpServletRequest request, String action)
133    {
134  255 String newAction = PATH_SEPARATOR + action.substring(ACTION_PREFIX.length());
135   
136    // Extract the document name from the requested path. We don't use getPathInfo() since it is decoded
137    // by the container, thus it will not work when XWiki uses a non-UTF-8 encoding.
138  255 String path = request.getRequestURI();
139   
140    // First step, remove the context path, if any.
141  255 path = XWiki.stripSegmentFromPath(path, request.getContextPath());
142   
143    // Second step, remove the servlet path, if any.
144  255 String servletPath = request.getServletPath();
145  255 path = XWiki.stripSegmentFromPath(path, servletPath);
146   
147    // Third step, remove the struts mapping. This step is mandatory, so this filter will fail if the
148    // requested action was a hidden (default) 'view', like in '/bin/Main/'. This is OK, since forms
149    // don't use 'view' as a target.
150  255 int index = path.indexOf(PATH_SEPARATOR, 1);
151   
152    // We need to also get rid of the wiki name in case of a XEM in usepath mode
153  255 ConfigurationSource configuration =
154    Utils.getComponent(ConfigurationSource.class, XWikiCfgConfigurationSource.ROLEHINT);
155  255 if ("1".equals(configuration.getProperty("xwiki.virtual.usepath", "1"))) {
156  255 if (servletPath.equals(PATH_SEPARATOR
157    + configuration.getProperty("xwiki.virtual.usepath.servletpath", "wiki"))) {
158    // Move the wiki name together with the servlet path
159  0 servletPath += path.substring(0, index);
160  0 index = path.indexOf(PATH_SEPARATOR, index + 1);
161    }
162    }
163   
164  255 String document = path.substring(index);
165   
166    // Compose the target URL starting with the servlet path.
167  255 return servletPath + newAction + document;
168    }
169    }