1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.shiro.web.servlet;
20
21 import javax.servlet.ServletContext;
22 import javax.servlet.http.HttpServletRequest;
23 import javax.servlet.http.HttpServletResponse;
24 import javax.servlet.http.HttpServletResponseWrapper;
25 import javax.servlet.http.HttpSession;
26 import java.io.IOException;
27 import java.net.MalformedURLException;
28 import java.net.URL;
29 import java.net.URLEncoder;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 public class ShiroHttpServletResponse extends HttpServletResponseWrapper {
46
47
48
49 private static final String DEFAULT_SESSION_ID_PARAMETER_NAME = ShiroHttpSession.DEFAULT_SESSION_ID_NAME;
50
51 private ServletContext context;
52
53 private ShiroHttpServletRequest request;
54
55 public ShiroHttpServletResponse(HttpServletResponse wrapped, ServletContext context, ShiroHttpServletRequest request) {
56 super(wrapped);
57 this.context = context;
58 this.request = request;
59 }
60
61 @SuppressWarnings({"UnusedDeclaration"})
62 public ServletContext getContext() {
63 return context;
64 }
65
66 @SuppressWarnings({"UnusedDeclaration"})
67 public void setContext(ServletContext context) {
68 this.context = context;
69 }
70
71 public ShiroHttpServletRequest getRequest() {
72 return request;
73 }
74
75 @SuppressWarnings({"UnusedDeclaration"})
76 public void setRequest(ShiroHttpServletRequest request) {
77 this.request = request;
78 }
79
80
81
82
83
84
85
86 public String encodeRedirectURL(String url) {
87 if (isEncodeable(toAbsolute(url))) {
88 return toEncoded(url, request.getSession().getId());
89 } else {
90 return url;
91 }
92 }
93
94 @Deprecated
95 public String encodeRedirectUrl(String s) {
96 return encodeRedirectURL(s);
97 }
98
99
100
101
102
103
104
105
106 public String encodeURL(String url) {
107 String absolute = toAbsolute(url);
108 if (isEncodeable(absolute)) {
109
110 if (url.equalsIgnoreCase("")) {
111 url = absolute;
112 }
113 return toEncoded(url, request.getSession().getId());
114 } else {
115 return url;
116 }
117 }
118
119 @Deprecated
120 public String encodeUrl(String s) {
121 return encodeURL(s);
122 }
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138 protected boolean isEncodeable(final String location) {
139
140
141 if (Boolean.FALSE.equals(request.getAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED))) {
142 return (false);
143 }
144
145 if (location == null) {
146 return (false);
147 }
148
149
150 if (location.startsWith("#")) {
151 return (false);
152 }
153
154
155 final HttpServletRequest hreq = request;
156 final HttpSession session = hreq.getSession(false);
157 if (session == null) {
158 return (false);
159 }
160 if (hreq.isRequestedSessionIdFromCookie()) {
161 return (false);
162 }
163
164 return doIsEncodeable(hreq, session, location);
165 }
166
167 @SuppressWarnings({"checkstyle:CyclomaticComplexity", "checkstyle:NPathComplexity", "checkstyle:MagicNumber"})
168 private boolean doIsEncodeable(HttpServletRequest hreq, HttpSession session, String location) {
169
170 URL url;
171 try {
172 url = new URL(location);
173 } catch (MalformedURLException e) {
174 return (false);
175 }
176
177
178 if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol())) {
179 return (false);
180 }
181 if (!hreq.getServerName().equalsIgnoreCase(url.getHost())) {
182 return (false);
183 }
184 int serverPort = hreq.getServerPort();
185 if (serverPort == -1) {
186 if ("https".equals(hreq.getScheme())) {
187 serverPort = 443;
188 } else {
189 serverPort = 80;
190 }
191 }
192 int urlPort = url.getPort();
193 if (urlPort == -1) {
194 if ("https".equals(url.getProtocol())) {
195 urlPort = 443;
196 } else {
197 urlPort = 80;
198 }
199 }
200 if (serverPort != urlPort) {
201 return (false);
202 }
203
204 String contextPath = getRequest().getContextPath();
205 if (contextPath != null) {
206 String file = url.getFile();
207 if ((file == null) || !file.startsWith(contextPath)) {
208 return (false);
209 }
210 String tok = ";" + DEFAULT_SESSION_ID_PARAMETER_NAME + "=" + session.getId();
211 if (file.indexOf(tok, contextPath.length()) >= 0) {
212 return (false);
213 }
214 }
215
216
217 return (true);
218
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232 @SuppressWarnings("checkstyle:MagicNumber")
233 private String toAbsolute(String location) {
234
235 if (location == null) {
236 return (location);
237 }
238
239 boolean leadingSlash = location.startsWith("/");
240
241 if (leadingSlash || !hasScheme(location)) {
242
243 StringBuilder buf = new StringBuilder();
244
245 String scheme = request.getScheme();
246 String name = request.getServerName();
247 int port = request.getServerPort();
248
249 try {
250 buf.append(scheme).append("://").append(name);
251 if ((scheme.equals("http") && port != 80)
252 || (scheme.equals("https") && port != 443)) {
253 buf.append(':').append(port);
254 }
255 if (!leadingSlash) {
256 String relativePath = request.getRequestURI();
257 int pos = relativePath.lastIndexOf('/');
258 relativePath = relativePath.substring(0, pos);
259
260 String encodedURI = URLEncoder.encode(relativePath, getCharacterEncoding());
261 buf.append(encodedURI).append('/');
262 }
263 buf.append(location);
264 } catch (IOException e) {
265 IllegalArgumentException iae = new IllegalArgumentException(location);
266 iae.initCause(e);
267 throw iae;
268 }
269
270 return buf.toString();
271
272 } else {
273 return location;
274 }
275 }
276
277
278
279
280
281
282
283
284 public static boolean isSchemeChar(char c) {
285 return Character.isLetterOrDigit(c) || c == '+' || c == '-' || c == '.';
286 }
287
288
289
290
291
292
293
294
295 private boolean hasScheme(String uri) {
296 int len = uri.length();
297 for (int i = 0; i < len; i++) {
298 char c = uri.charAt(i);
299 if (c == ':') {
300 return i > 0;
301 } else if (!isSchemeChar(c)) {
302 return false;
303 }
304 }
305 return false;
306 }
307
308
309
310
311
312
313
314
315 protected String toEncoded(String url, String sessionId) {
316
317 if ((url == null) || (sessionId == null)) {
318 return (url);
319 }
320
321 String path = url;
322 String query = "";
323 String anchor = "";
324 int question = url.indexOf('?');
325 if (question >= 0) {
326 path = url.substring(0, question);
327 query = url.substring(question);
328 }
329 int pound = path.indexOf('#');
330 if (pound >= 0) {
331 anchor = path.substring(pound);
332 path = path.substring(0, pound);
333 }
334 StringBuilder sb = new StringBuilder(path);
335
336 if (sb.length() > 0) {
337 sb.append(";");
338 sb.append(DEFAULT_SESSION_ID_PARAMETER_NAME);
339 sb.append("=");
340 sb.append(sessionId);
341 }
342 sb.append(anchor);
343 sb.append(query);
344 return (sb.toString());
345
346 }
347 }