1 //
2 // ========================================================================
3 // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
8 //
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
11 //
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
14 //
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
17 //
18
19 package org.eclipse.jetty.rewrite.handler;
20
21 import java.io.IOException;
22 import java.util.Arrays;
23 import java.util.EnumSet;
24
25 import javax.servlet.DispatcherType;
26 import javax.servlet.ServletException;
27 import javax.servlet.http.HttpServletRequest;
28 import javax.servlet.http.HttpServletResponse;
29
30 import org.eclipse.jetty.server.Request;
31 import org.eclipse.jetty.server.handler.HandlerWrapper;
32
33 /* ------------------------------------------------------------ */
34 /**
35 *<p> Rewrite handler is responsible for managing the rules. Its capabilities
36 * is not only limited for URL rewrites such as RewritePatternRule or RewriteRegexRule.
37 * There is also handling for cookies, headers, redirection, setting status or error codes
38 * whenever the rule finds a match.
39 *
40 * <p> The rules can be matched by the either: pattern matching of PathMap
41 * (eg {@link PatternRule}), regular expressions (eg {@link RegexRule}) or certain conditions set
42 * (eg {@link MsieSslRule} - the requests must be in SSL mode).
43 *
44 * <p> The rules can be grouped into rule containers (class {@link RuleContainer}), and will only
45 * be applied if the request matches the conditions for their container
46 * (e.g., by virtual host name)
47 *
48 * <p>The list of predefined rules is:
49 * <ul>
50 * <li> {@link CookiePatternRule} - adds a new cookie in response. </li>
51 * <li> {@link HeaderPatternRule} - adds/modifies the HTTP headers in response. </li>
52 * <li> {@link RedirectPatternRule} - sets the redirect location. </li>
53 * <li> {@link ResponsePatternRule} - sets the status/error codes. </li>
54 * <li> {@link RewritePatternRule} - rewrites the requested URI. </li>
55 * <li> {@link RewriteRegexRule} - rewrites the requested URI using regular expression for pattern matching. </li>
56 * <li> {@link MsieSslRule} - disables the keep alive on SSL for IE5 and IE6. </li>
57 * <li> {@link ForwardedSchemeHeaderRule} - set the scheme according to the headers present. </li>
58 * <li> {@link VirtualHostRuleContainer} - checks whether the request matches one of a set of virtual host names.</li>
59 * </ul>
60 *
61 *
62 * Here is a typical jetty.xml configuration would be: <pre>
63 *
64 * <New id="RewriteHandler" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
65 * <Set name="rules">
66 * <Array type="org.eclipse.jetty.rewrite.handler.Rule">
67 *
68 * <Item>
69 * <New id="rewrite" class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
70 * <Set name="pattern">/*</Set>
71 * <Set name="replacement">/test</Set>
72 * </New>
73 * </Item>
74 *
75 * <Item>
76 * <New id="response" class="org.eclipse.jetty.rewrite.handler.ResponsePatternRule">
77 * <Set name="pattern">/session/</Set>
78 * <Set name="code">400</Set>
79 * <Set name="reason">Setting error code 400</Set>
80 * </New>
81 * </Item>
82 *
83 * <Item>
84 * <New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
85 * <Set name="pattern">*.jsp</Set>
86 * <Set name="name">server</Set>
87 * <Set name="value">dexter webserver</Set>
88 * </New>
89 * </Item>
90 *
91 * <Item>
92 * <New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
93 * <Set name="pattern">*.jsp</Set>
94 * <Set name="name">title</Set>
95 * <Set name="value">driven header purpose</Set>
96 * </New>
97 * </Item>
98 *
99 * <Item>
100 * <New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule">
101 * <Set name="pattern">/test/dispatch</Set>
102 * <Set name="location">http://jetty.eclipse.org</Set>
103 * </New>
104 * </Item>
105 *
106 * <Item>
107 * <New id="regexRewrite" class="org.eclipse.jetty.rewrite.handler.RewriteRegexRule">
108 * <Set name="regex">/test-jaas/$</Set>
109 * <Set name="replacement">/demo</Set>
110 * </New>
111 * </Item>
112 *
113 * <Item>
114 * <New id="forwardedHttps" class="org.eclipse.jetty.rewrite.handler.ForwardedSchemeHeaderRule">
115 * <Set name="header">X-Forwarded-Scheme</Set>
116 * <Set name="headerValue">https</Set>
117 * <Set name="scheme">https</Set>
118 * </New>
119 * </Item>
120 *
121 * <Item>
122 * <New id="virtualHost" class="org.eclipse.jetty.rewrite.handler.VirtualHostRuleContainer">
123 *
124 * <Set name="virtualHosts">
125 * <Array type="java.lang.String">
126 * <Item>eclipse.com</Item>
127 * <Item>www.eclipse.com</Item>
128 * <Item>eclipse.org</Item>
129 * <Item>www.eclipse.org</Item>
130 * </Array>
131 * </Set>
132 *
133 * <Call name="addRule">
134 * <Arg>
135 * <New class="org.eclipse.jetty.rewrite.handler.CookiePatternRule">
136 * <Set name="pattern">/*</Set>
137 * <Set name="name">CookiePatternRule</Set>
138 * <Set name="value">1</Set>
139 * </New>
140 * </Arg>
141 * </Call>
142 *
143 * </New>
144 * </Item>
145 *
146 * </Array>
147 * </Set>
148 * </New>
149 *
150 * <Set name="handler">
151 * <New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
152 * <Set name="handlers">
153 * <Array type="org.eclipse.jetty.server.Handler">
154 * <Item>
155 * <Ref id="RewriteHandler"/>
156 * </Item>
157 * <Item>
158 * <New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/>
159 * </Item>
160 * <Item>
161 * <New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
162 * </Item>
163 * <Item>
164 * <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"/>
165 * </Item>
166 * </Array>
167 * </Set>
168 * </New>
169 * </Set>
170 * </pre>
171 *
172 */
173 public class RewriteHandler extends HandlerWrapper
174 {
175 private RuleContainer _rules;
176 private EnumSet<DispatcherType> _dispatchTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC);
177
178 /* ------------------------------------------------------------ */
179 public RewriteHandler()
180 {
181 _rules = new RuleContainer();
182 }
183
184 /* ------------------------------------------------------------ */
185 /**
186 * Returns the list of rules.
187 * @return an array of {@link Rule}.
188 */
189 public Rule[] getRules()
190 {
191 return _rules.getRules();
192 }
193
194 /* ------------------------------------------------------------ */
195 /**
196 * Assigns the rules to process.
197 * @param rules an array of {@link Rule}.
198 */
199 public void setRules(Rule[] rules)
200 {
201 _rules.setRules(rules);
202 }
203
204 /*------------------------------------------------------------ */
205 /**
206 * Assigns the rules to process.
207 * @param rules a {@link RuleContainer} containing other rules to process
208 */
209 @Deprecated
210 public void setRules(RuleContainer rules)
211 {
212 _rules = rules;
213 }
214
215 /*------------------------------------------------------------ */
216 /**
217 * Assigns the rules to process.
218 * @param rules a {@link RuleContainer} containing other rules to process
219 */
220 public void setRuleContainer(RuleContainer rules)
221 {
222 _rules = rules;
223 }
224
225 /*------------------------------------------------------------ */
226 public RuleContainer getRuleContainer()
227 {
228 return _rules;
229 }
230
231 /* ------------------------------------------------------------ */
232 /**
233 * Add a Rule
234 * @param rule The rule to add to the end of the rules array
235 */
236 public void addRule(Rule rule)
237 {
238 _rules.addRule(rule);
239 }
240
241 /* ------------------------------------------------------------ */
242 /**
243 * @return the rewriteRequestURI If true, this handler will rewrite the value
244 * returned by {@link HttpServletRequest#getRequestURI()}.
245 */
246 public boolean isRewriteRequestURI()
247 {
248 return _rules.isRewriteRequestURI();
249 }
250
251 /* ------------------------------------------------------------ */
252 /**
253 * @param rewriteRequestURI true if this handler will rewrite the value
254 * returned by {@link HttpServletRequest#getRequestURI()}.
255 */
256 public void setRewriteRequestURI(boolean rewriteRequestURI)
257 {
258 _rules.setRewriteRequestURI(rewriteRequestURI);
259 }
260
261 /* ------------------------------------------------------------ */
262 /**
263 * @return true if this handler will rewrite the value
264 * returned by {@link HttpServletRequest#getPathInfo()}.
265 */
266 public boolean isRewritePathInfo()
267 {
268 return _rules.isRewritePathInfo();
269 }
270
271 /* ------------------------------------------------------------ */
272 /**
273 * @param rewritePathInfo true if this handler will rewrite the value
274 * returned by {@link HttpServletRequest#getPathInfo()}.
275 */
276 public void setRewritePathInfo(boolean rewritePathInfo)
277 {
278 _rules.setRewritePathInfo(rewritePathInfo);
279 }
280
281 /* ------------------------------------------------------------ */
282 /**
283 * @return the originalPathAttribte. If non null, this string will be used
284 * as the attribute name to store the original request path.
285 */
286 public String getOriginalPathAttribute()
287 {
288 return _rules.getOriginalPathAttribute();
289 }
290
291 /* ------------------------------------------------------------ */
292 /**
293 * @param originalPathAttribute If non null, this string will be used
294 * as the attribute name to store the original request path.
295 */
296 public void setOriginalPathAttribute(String originalPathAttribute)
297 {
298 _rules.setOriginalPathAttribute(originalPathAttribute);
299 }
300
301 /* ------------------------------------------------------------ */
302 public EnumSet<DispatcherType> getDispatcherTypes()
303 {
304 return _dispatchTypes;
305 }
306
307 /* ------------------------------------------------------------ */
308 public void setDispatcherTypes(EnumSet<DispatcherType> types)
309 {
310 _dispatchTypes=EnumSet.copyOf(types);
311 }
312
313 /* ------------------------------------------------------------ */
314 public void setDispatcherTypes(DispatcherType... types)
315 {
316 _dispatchTypes=EnumSet.copyOf(Arrays.asList(types));
317 }
318
319 /* ------------------------------------------------------------ */
320 /* (non-Javadoc)
321 * @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
322 */
323 @Override
324 public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
325 {
326 if (isStarted())
327 {
328 if (_dispatchTypes.contains(baseRequest.getDispatcherType()))
329 {
330 String returned = _rules.matchAndApply(target, request, response);
331 target = (returned == null) ? target : returned;
332 }
333
334 if (!baseRequest.isHandled())
335 super.handle(target, baseRequest, request, response);
336 }
337 }
338
339 }