1 package com.atlassian.plugin.servlet;
2
3 import java.util.Iterator;
4
5 import javax.servlet.http.HttpServletRequest;
6 import javax.servlet.http.HttpServletRequestWrapper;
7
8 import com.atlassian.plugin.servlet.descriptors.BaseServletModuleDescriptor;
9
10 /**
11 * A request wrapper for requests bound for servlets declared in plugins. Does the necessary path
12 * munging for requests so that they look like they are
13 */
14 public class PluginHttpRequestWrapper extends HttpServletRequestWrapper
15 {
16 private final String basePath;
17
18 public PluginHttpRequestWrapper(HttpServletRequest request, BaseServletModuleDescriptor<?> descriptor)
19 {
20 super(request);
21 this.basePath = findBasePath(descriptor);
22 }
23
24 public String getServletPath()
25 {
26 String servletPath = super.getServletPath();
27 if (basePath != null)
28 {
29 servletPath += basePath;
30 }
31 return servletPath;
32 }
33
34 public String getPathInfo()
35 {
36 String pathInfo = super.getPathInfo();
37 if (pathInfo != null && basePath != null)
38 return pathInfo.substring(basePath.length());
39 return pathInfo;
40 }
41
42 /**
43 * A <a href="http://bluxte.net/blog/2006-03/29-40-33.html">commenter</a> based on the
44 * <a href="http://java.sun.com/products/servlet/2.1/html/introduction.fm.html#1499">servlet mapping spec</a>
45 * defined the mapping processing as:
46 *
47 * <ol>
48 * <li>A string beginning with a '/' character and ending with a '/*' postfix is used for path mapping.</li>
49 * <li>A string beginning with a'*.' prefix is used as an extension mapping.</li>
50 * <li>A string containing only the '/' character indicates the "default" servlet of the application. In this
51 * case the servlet path is the request URI minus the context path and the path info is null.</li>
52 * <li>All other strings are used for exact matches only.</li>
53 * </ol>
54 *
55 * To find the base path we're really only interested in the first case. Everything else will just get a null
56 * base path. So we'll iterate through the list of paths specified and for the ones that match (1) above, check if
57 * the path info returned by the super class matches. If it does, we return that base path, otherwise we move onto
58 * the next one.
59 */
60 private String findBasePath(BaseServletModuleDescriptor<?> descriptor)
61 {
62 String pathInfo = super.getPathInfo();
63 if (pathInfo != null)
64 {
65 for (Iterator<String> pathIterator = descriptor.getPaths().iterator(); pathIterator.hasNext(); )
66 {
67 String basePath = pathIterator.next();
68 if (isPathMapping(basePath) && pathInfo.startsWith(getMappingRootPath(basePath)))
69 {
70 return getMappingRootPath(basePath);
71 }
72 }
73 }
74 return null;
75 }
76
77 private boolean isPathMapping(String path)
78 {
79 return path.startsWith("/") && path.endsWith("/*");
80 }
81
82 private String getMappingRootPath(String pathMapping)
83 {
84 return pathMapping.substring(0, pathMapping.length() - 2);
85 }
86 }