View Javadoc

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   *     &lt;New id="RewriteHandler" class="org.eclipse.jetty.rewrite.handler.RewriteHandler"&gt;
65   *       &lt;Set name="rules"&gt;
66   *         &lt;Array type="org.eclipse.jetty.rewrite.handler.Rule"&gt;
67   * 
68   *           &lt;Item&gt;
69   *             &lt;New id="rewrite" class="org.eclipse.jetty.rewrite.handler.RewritePatternRule"&gt;
70   *               &lt;Set name="pattern"&gt;/*&lt;/Set&gt;
71   *               &lt;Set name="replacement"&gt;/test&lt;/Set&gt;
72   *             &lt;/New&gt;
73   *           &lt;/Item&gt;
74   * 
75   *           &lt;Item&gt;
76   *             &lt;New id="response" class="org.eclipse.jetty.rewrite.handler.ResponsePatternRule"&gt;
77   *               &lt;Set name="pattern"&gt;/session/&lt;/Set&gt;
78   *               &lt;Set name="code"&gt;400&lt;/Set&gt;
79   *               &lt;Set name="reason"&gt;Setting error code 400&lt;/Set&gt;
80   *             &lt;/New&gt;
81   *           &lt;/Item&gt;
82   * 
83   *           &lt;Item&gt;
84   *             &lt;New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule"&gt;
85   *               &lt;Set name="pattern"&gt;*.jsp&lt;/Set&gt;
86   *               &lt;Set name="name"&gt;server&lt;/Set&gt;
87   *               &lt;Set name="value"&gt;dexter webserver&lt;/Set&gt;
88   *             &lt;/New&gt;
89   *           &lt;/Item&gt;
90   * 
91   *           &lt;Item&gt;
92   *             &lt;New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule"&gt;
93   *               &lt;Set name="pattern"&gt;*.jsp&lt;/Set&gt;
94   *               &lt;Set name="name"&gt;title&lt;/Set&gt;
95   *               &lt;Set name="value"&gt;driven header purpose&lt;/Set&gt;
96   *             &lt;/New&gt;
97   *           &lt;/Item&gt;
98   * 
99   *           &lt;Item&gt;
100  *             &lt;New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule"&gt;
101  *               &lt;Set name="pattern"&gt;/test/dispatch&lt;/Set&gt;
102  *               &lt;Set name="location"&gt;http://jetty.eclipse.org&lt;/Set&gt;
103  *             &lt;/New&gt;
104  *           &lt;/Item&gt;
105  * 
106  *           &lt;Item&gt;
107  *             &lt;New id="regexRewrite" class="org.eclipse.jetty.rewrite.handler.RewriteRegexRule"&gt;
108  *               &lt;Set name="regex"&gt;/test-jaas/$&lt;/Set&gt;
109  *               &lt;Set name="replacement"&gt;/demo&lt;/Set&gt;
110  *             &lt;/New&gt;
111  *           &lt;/Item&gt;
112  * 
113  *           &lt;Item&gt;
114  *             &lt;New id="forwardedHttps" class="org.eclipse.jetty.rewrite.handler.ForwardedSchemeHeaderRule"&gt;
115  *               &lt;Set name="header"&gt;X-Forwarded-Scheme&lt;/Set&gt;
116  *               &lt;Set name="headerValue"&gt;https&lt;/Set&gt;
117  *               &lt;Set name="scheme"&gt;https&lt;/Set&gt;
118  *             &lt;/New&gt;
119  *           &lt;/Item&gt;
120  * 
121  *           &lt;Item&gt;
122  *             &lt;New id="virtualHost" class="org.eclipse.jetty.rewrite.handler.VirtualHostRuleContainer"&gt;
123  * 
124  *               &lt;Set name="virtualHosts"&gt;
125  *                 &lt;Array type="java.lang.String"&gt;
126  *                   &lt;Item&gt;eclipse.com&lt;/Item&gt;
127  *                   &lt;Item&gt;www.eclipse.com&lt;/Item&gt;
128  *                   &lt;Item&gt;eclipse.org&lt;/Item&gt;
129  *                   &lt;Item&gt;www.eclipse.org&lt;/Item&gt;
130  *                 &lt;/Array&gt;
131  *               &lt;/Set&gt;
132  * 
133  *               &lt;Call name="addRule"&gt;
134  *                 &lt;Arg&gt;
135  *                   &lt;New class="org.eclipse.jetty.rewrite.handler.CookiePatternRule"&gt;
136  *                     &lt;Set name="pattern"&gt;/*&lt;/Set&gt;
137  *                     &lt;Set name="name"&gt;CookiePatternRule&lt;/Set&gt;
138  *                     &lt;Set name="value"&gt;1&lt;/Set&gt;
139  *                   &lt;/New&gt;
140  *                 &lt;/Arg&gt;
141  *               &lt;/Call&gt;
142  *               
143  *             &lt;/New&gt;
144  *           &lt;/Item&gt;
145  * 
146  *         &lt;/Array&gt;
147  *       &lt;/Set&gt;
148  *     &lt;/New&gt;
149  * 
150  *     &lt;Set name="handler"&gt;
151  *       &lt;New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection"&gt;
152  *         &lt;Set name="handlers"&gt;
153  *           &lt;Array type="org.eclipse.jetty.server.Handler"&gt;
154  *             &lt;Item&gt;
155  *               &lt;Ref id="RewriteHandler"/&gt;
156  *             &lt;/Item&gt;
157  *             &lt;Item&gt;
158  *               &lt;New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/&gt;
159  *             &lt;/Item&gt;
160  *             &lt;Item&gt;
161  *               &lt;New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/&gt;
162  *             &lt;/Item&gt;
163  *             &lt;Item&gt;
164  *               &lt;New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"/&gt;
165  *             &lt;/Item&gt;
166  *           &lt;/Array&gt;
167  *         &lt;/Set&gt;
168  *       &lt;/New&gt;
169  *     &lt;/Set&gt;
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     public void setRules(RuleContainer rules)
210     {
211         _rules = rules;
212     }
213 
214     /* ------------------------------------------------------------ */
215     /**
216      * Add a Rule
217      * @param rule The rule to add to the end of the rules array
218      */
219     public void addRule(Rule rule)
220     {
221         _rules.addRule(rule);
222     }
223 
224     /* ------------------------------------------------------------ */
225     /**
226      * @return the rewriteRequestURI If true, this handler will rewrite the value
227      * returned by {@link HttpServletRequest#getRequestURI()}.
228      */
229     public boolean isRewriteRequestURI()
230     {
231         return _rules.isRewriteRequestURI();
232     }
233 
234     /* ------------------------------------------------------------ */
235     /**
236      * @param rewriteRequestURI true if this handler will rewrite the value
237      * returned by {@link HttpServletRequest#getRequestURI()}.
238      */
239     public void setRewriteRequestURI(boolean rewriteRequestURI)
240     {
241         _rules.setRewriteRequestURI(rewriteRequestURI);
242     }
243 
244     /* ------------------------------------------------------------ */
245     /**
246      * @return true if this handler will rewrite the value
247      * returned by {@link HttpServletRequest#getPathInfo()}.
248      */
249     public boolean isRewritePathInfo()
250     {
251         return _rules.isRewritePathInfo();
252     }
253 
254     /* ------------------------------------------------------------ */
255     /**
256      * @param rewritePathInfo true if this handler will rewrite the value
257      * returned by {@link HttpServletRequest#getPathInfo()}.
258      */
259     public void setRewritePathInfo(boolean rewritePathInfo)
260     {
261         _rules.setRewritePathInfo(rewritePathInfo);
262     }
263 
264     /* ------------------------------------------------------------ */
265     /**
266      * @return the originalPathAttribte. If non null, this string will be used
267      * as the attribute name to store the original request path.
268      */
269     public String getOriginalPathAttribute()
270     {
271         return _rules.getOriginalPathAttribute();
272     }
273 
274     /* ------------------------------------------------------------ */
275     /**
276      * @param originalPathAttribute If non null, this string will be used
277      * as the attribute name to store the original request path.
278      */
279     public void setOriginalPathAttribute(String originalPathAttribute)
280     {
281         _rules.setOriginalPathAttribute(originalPathAttribute);
282     }
283 
284     /* ------------------------------------------------------------ */
285     public EnumSet<DispatcherType> getDispatcherTypes()
286     {
287         return _dispatchTypes;
288     }
289     
290     /* ------------------------------------------------------------ */
291     public void setDispatcherTypes(EnumSet<DispatcherType> types)
292     {
293         _dispatchTypes=EnumSet.copyOf(types);
294     }
295     
296     /* ------------------------------------------------------------ */
297     public void setDispatcherTypes(DispatcherType... types)
298     {
299         _dispatchTypes=EnumSet.copyOf(Arrays.asList(types));
300     }
301 
302     /* ------------------------------------------------------------ */
303     /* (non-Javadoc)
304      * @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
305      */
306     @Override
307     public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
308     {
309         if (isStarted())
310         {
311             if (_dispatchTypes.contains(baseRequest.getDispatcherType()))
312             {
313                 String returned = _rules.matchAndApply(target, request, response);
314                 target = (returned == null) ? target : returned;
315             }
316 
317             if (!baseRequest.isHandled())
318                 super.handle(target, baseRequest, request, response);
319         }
320     }
321 
322 }