View Javadoc

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