1 package com.atlassian.plugin.servlet;
2
3 import com.atlassian.plugin.servlet.descriptors.BaseServletModuleDescriptor;
4 import org.apache.commons.lang3.StringUtils;
5
6 import javax.servlet.AsyncContext;
7 import javax.servlet.ServletRequest;
8 import javax.servlet.ServletResponse;
9 import javax.servlet.http.HttpServletRequest;
10 import javax.servlet.http.HttpServletRequestWrapper;
11 import javax.servlet.http.HttpSession;
12
13
14
15
16
17
18
19 public class PluginHttpRequestWrapper extends HttpServletRequestWrapper {
20 private final String basePath;
21 private HttpServletRequest delegate;
22 private boolean asyncSupported;
23
24 public PluginHttpRequestWrapper(HttpServletRequest request, BaseServletModuleDescriptor<?> descriptor) {
25 super(request);
26 this.delegate = request;
27 this.basePath = findBasePath(descriptor);
28 this.asyncSupported = request.isAsyncSupported() && descriptor.isAsyncSupported();
29 }
30
31 public String getServletPath() {
32 String servletPath = super.getServletPath();
33 if (basePath != null) {
34 servletPath += basePath;
35 }
36 return servletPath;
37 }
38
39 public String getPathInfo() {
40 String pathInfo = super.getPathInfo();
41 if (pathInfo != null && basePath != null) {
42 if (basePath.equals(pathInfo)) {
43 return null;
44 } else if (pathInfo.startsWith(basePath)) {
45 return pathInfo.substring(basePath.length());
46 }
47 }
48 return pathInfo;
49 }
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 private String findBasePath(BaseServletModuleDescriptor<?> descriptor) {
70 String pathInfo = super.getPathInfo();
71
72 if (pathInfo != null) {
73
74 for (String basePath : descriptor.getPaths()) {
75 if (basePath.equals(pathInfo)) {
76 return basePath;
77 }
78 }
79
80
81 final String[] pathInfoComponents = StringUtils.split(pathInfo, '/');
82 for (String basePath : descriptor.getPaths()) {
83 if (isPathMapping(basePath)) {
84 final String mappingRootPath = getMappingRootPath(basePath);
85 final String[] mappingRootPathComponents = StringUtils.split(mappingRootPath, '/');
86
87 if (arrayStartsWith(pathInfoComponents, mappingRootPathComponents)) {
88 return mappingRootPath;
89 }
90 }
91 }
92 }
93 return null;
94 }
95
96 private static boolean arrayStartsWith(String[] array, String[] prefixArray) {
97
98 if (prefixArray.length > array.length) {
99 return false;
100 }
101
102
103 for (int i = prefixArray.length - 1; i >= 0; i--) {
104 if (!prefixArray[i].equals(array[i])) {
105 return false;
106 }
107 }
108
109 return true;
110 }
111
112 private boolean isPathMapping(String path) {
113 return path.startsWith("/") && path.endsWith("/*");
114 }
115
116 private String getMappingRootPath(String pathMapping) {
117 return pathMapping.substring(0, pathMapping.length() - "/*".length());
118 }
119
120 @Override
121 public HttpSession getSession() {
122 return this.getSession(true);
123 }
124
125 @Override
126 public HttpSession getSession(final boolean create) {
127 HttpSession session = delegate.getSession(create);
128 if (session == null) {
129
130 return null;
131 } else {
132
133 return session instanceof PluginHttpSessionWrapper ? session : new PluginHttpSessionWrapper(session);
134 }
135 }
136
137
138
139
140 @Override
141 public boolean isAsyncSupported() {
142 return asyncSupported;
143 }
144
145
146
147
148 @Override
149 public AsyncContext startAsync() throws IllegalStateException {
150 if (!isAsyncSupported()) {
151 throw new IllegalStateException("One of the plugins in the filter chain does not support async");
152 }
153 return super.startAsync();
154 }
155
156
157
158
159 @Override
160 public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException {
161 if (!isAsyncSupported()) {
162 throw new IllegalStateException("One of the plugins in the filter chain does not support async");
163 }
164 return super.startAsync(servletRequest, servletResponse);
165 }
166 }