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 }