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 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 }