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 = null;
52
53 private ShiroHttpServletRequest request = null;
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
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 public String encodeUrl(String s) {
120 return encodeURL(s);
121 }
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137 protected boolean isEncodeable(final String location) {
138
139
140 if (Boolean.FALSE.equals(request.getAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED)))
141 return (false);
142
143 if (location == null)
144 return (false);
145
146
147 if (location.startsWith("#"))
148 return (false);
149
150
151 final HttpServletRequest hreq = request;
152 final HttpSession session = hreq.getSession(false);
153 if (session == null)
154 return (false);
155 if (hreq.isRequestedSessionIdFromCookie())
156 return (false);
157
158 return doIsEncodeable(hreq, session, location);
159 }
160
161 private boolean doIsEncodeable(HttpServletRequest hreq, HttpSession session, String location) {
162
163 URL url;
164 try {
165 url = new URL(location);
166 } catch (MalformedURLException e) {
167 return (false);
168 }
169
170
171 if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol()))
172 return (false);
173 if (!hreq.getServerName().equalsIgnoreCase(url.getHost()))
174 return (false);
175 int serverPort = hreq.getServerPort();
176 if (serverPort == -1) {
177 if ("https".equals(hreq.getScheme()))
178 serverPort = 443;
179 else
180 serverPort = 80;
181 }
182 int urlPort = url.getPort();
183 if (urlPort == -1) {
184 if ("https".equals(url.getProtocol()))
185 urlPort = 443;
186 else
187 urlPort = 80;
188 }
189 if (serverPort != urlPort)
190 return (false);
191
192 String contextPath = getRequest().getContextPath();
193 if (contextPath != null) {
194 String file = url.getFile();
195 if ((file == null) || !file.startsWith(contextPath))
196 return (false);
197 String tok = ";" + DEFAULT_SESSION_ID_PARAMETER_NAME + "=" + session.getId();
198 if (file.indexOf(tok, contextPath.length()) >= 0)
199 return (false);
200 }
201
202
203 return (true);
204
205 }
206
207
208
209
210
211
212
213
214
215
216
217
218 private String toAbsolute(String location) {
219
220 if (location == null)
221 return (location);
222
223 boolean leadingSlash = location.startsWith("/");
224
225 if (leadingSlash || !hasScheme(location)) {
226
227 StringBuilder buf = new StringBuilder();
228
229 String scheme = request.getScheme();
230 String name = request.getServerName();
231 int port = request.getServerPort();
232
233 try {
234 buf.append(scheme).append("://").append(name);
235 if ((scheme.equals("http") && port != 80)
236 || (scheme.equals("https") && port != 443)) {
237 buf.append(':').append(port);
238 }
239 if (!leadingSlash) {
240 String relativePath = request.getRequestURI();
241 int pos = relativePath.lastIndexOf('/');
242 relativePath = relativePath.substring(0, pos);
243
244 String encodedURI = URLEncoder.encode(relativePath, getCharacterEncoding());
245 buf.append(encodedURI).append('/');
246 }
247 buf.append(location);
248 } catch (IOException e) {
249 IllegalArgumentException iae = new IllegalArgumentException(location);
250 iae.initCause(e);
251 throw iae;
252 }
253
254 return buf.toString();
255
256 } else {
257 return location;
258 }
259 }
260
261
262
263
264
265
266
267
268 public static boolean isSchemeChar(char c) {
269 return Character.isLetterOrDigit(c) ||
270 c == '+' || c == '-' || c == '.';
271 }
272
273
274
275
276
277
278
279
280 private boolean hasScheme(String uri) {
281 int len = uri.length();
282 for (int i = 0; i < len; i++) {
283 char c = uri.charAt(i);
284 if (c == ':') {
285 return i > 0;
286 } else if (!isSchemeChar(c)) {
287 return false;
288 }
289 }
290 return false;
291 }
292
293
294
295
296
297
298
299
300 protected String toEncoded(String url, String sessionId) {
301
302 if ((url == null) || (sessionId == null))
303 return (url);
304
305 String path = url;
306 String query = "";
307 String anchor = "";
308 int question = url.indexOf('?');
309 if (question >= 0) {
310 path = url.substring(0, question);
311 query = url.substring(question);
312 }
313 int pound = path.indexOf('#');
314 if (pound >= 0) {
315 anchor = path.substring(pound);
316 path = path.substring(0, pound);
317 }
318 StringBuilder sb = new StringBuilder(path);
319 if (sb.length() > 0) {
320 sb.append(";");
321 sb.append(DEFAULT_SESSION_ID_PARAMETER_NAME);
322 sb.append("=");
323 sb.append(sessionId);
324 }
325 sb.append(anchor);
326 sb.append(query);
327 return (sb.toString());
328
329 }
330 }