1 7 package winstone; 8 9 import java.io.IOException ; 10 import java.util.ArrayList ; 11 import java.util.List ; 12 import java.util.Map ; 13 14 import javax.servlet.ServletException ; 15 import javax.servlet.ServletRequest ; 16 import javax.servlet.ServletRequestWrapper ; 17 import javax.servlet.ServletResponse ; 18 import javax.servlet.ServletResponseWrapper ; 19 20 29 public class RequestDispatcher implements javax.servlet.RequestDispatcher , 30 javax.servlet.FilterChain { 31 32 static final String INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri"; 33 static final String INCLUDE_CONTEXT_PATH = "javax.servlet.include.context_path"; 34 static final String INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path"; 35 static final String INCLUDE_PATH_INFO = "javax.servlet.include.path_info"; 36 static final String INCLUDE_QUERY_STRING = "javax.servlet.include.query_string"; 37 38 static final String FORWARD_REQUEST_URI = "javax.servlet.forward.request_uri"; 39 static final String FORWARD_CONTEXT_PATH = "javax.servlet.forward.context_path"; 40 static final String FORWARD_SERVLET_PATH = "javax.servlet.forward.servlet_path"; 41 static final String FORWARD_PATH_INFO = "javax.servlet.forward.path_info"; 42 static final String FORWARD_QUERY_STRING = "javax.servlet.forward.query_string"; 43 44 static final String ERROR_STATUS_CODE = "javax.servlet.error.status_code"; 45 static final String ERROR_EXCEPTION_TYPE = "javax.servlet.error.exception_type"; 46 static final String ERROR_MESSAGE = "javax.servlet.error.message"; 47 static final String ERROR_EXCEPTION = "javax.servlet.error.exception"; 48 static final String ERROR_REQUEST_URI = "javax.servlet.error.request_uri"; 49 static final String ERROR_SERVLET_NAME = "javax.servlet.error.servlet_name"; 50 51 private WebAppConfiguration webAppConfig; 52 private ServletConfiguration servletConfig; 53 54 private String servletPath; 55 private String pathInfo; 56 private String queryString; 57 private String requestURI; 58 59 private Integer errorStatusCode; 60 private Throwable errorException; 61 private String errorSummaryMessage; 62 63 private AuthenticationHandler authHandler; 64 65 private Mapping forwardFilterPatterns[]; 66 private Mapping includeFilterPatterns[]; 67 private FilterConfiguration matchingFilters[]; 68 private int matchingFiltersEvaluated; 69 70 private Boolean doInclude; 71 private boolean isErrorDispatch; 72 private boolean useRequestAttributes; 73 74 private WebAppConfiguration includedWebAppConfig; 75 private ServletConfiguration includedServletConfig; 76 77 82 public RequestDispatcher(WebAppConfiguration webAppConfig, ServletConfiguration servletConfig) { 83 this.servletConfig = servletConfig; 84 this.webAppConfig = webAppConfig; 85 86 this.matchingFiltersEvaluated = 0; 87 } 88 89 public void setForNamedDispatcher(Mapping forwardFilterPatterns[], 90 Mapping includeFilterPatterns[]) { 91 this.forwardFilterPatterns = forwardFilterPatterns; 92 this.includeFilterPatterns = includeFilterPatterns; 93 this.matchingFilters = null; this.useRequestAttributes = false; 95 this.isErrorDispatch = false; 96 } 97 98 public void setForURLDispatcher(String servletPath, String pathInfo, 99 String queryString, String requestURIInsideWebapp, 100 Mapping forwardFilterPatterns[], Mapping includeFilterPatterns[]) { 101 this.servletPath = servletPath; 102 this.pathInfo = pathInfo; 103 this.queryString = queryString; 104 this.requestURI = requestURIInsideWebapp; 105 106 this.forwardFilterPatterns = forwardFilterPatterns; 107 this.includeFilterPatterns = includeFilterPatterns; 108 this.matchingFilters = null; this.useRequestAttributes = true; 110 this.isErrorDispatch = false; 111 } 112 113 public void setForErrorDispatcher(String servletPath, String pathInfo, 114 String queryString, int statusCode, String summaryMessage, 115 Throwable exception, String errorHandlerURI, 116 Mapping errorFilterPatterns[]) { 117 this.servletPath = servletPath; 118 this.pathInfo = pathInfo; 119 this.queryString = queryString; 120 this.requestURI = errorHandlerURI; 121 122 this.errorStatusCode = new Integer (statusCode); 123 this.errorException = exception; 124 this.errorSummaryMessage = summaryMessage; 125 this.matchingFilters = getMatchingFilters(errorFilterPatterns, this.webAppConfig, 126 servletPath + (pathInfo == null ? "" : pathInfo), 127 getName(), "ERROR", (servletPath != null)); 128 this.useRequestAttributes = true; 129 this.isErrorDispatch = true; 130 } 131 132 public void setForInitialDispatcher(String servletPath, String pathInfo, 133 String queryString, String requestURIInsideWebapp, Mapping requestFilterPatterns[], 134 AuthenticationHandler authHandler) { 135 this.servletPath = servletPath; 136 this.pathInfo = pathInfo; 137 this.queryString = queryString; 138 this.requestURI = requestURIInsideWebapp; 139 this.authHandler = authHandler; 140 this.matchingFilters = getMatchingFilters(requestFilterPatterns, this.webAppConfig, 141 servletPath + (pathInfo == null ? "" : pathInfo), 142 getName(), "REQUEST", (servletPath != null)); 143 this.useRequestAttributes = false; 144 this.isErrorDispatch = false; 145 } 146 147 public String getName() { 148 return this.servletConfig.getServletName(); 149 } 150 151 157 public void include(ServletRequest request, ServletResponse response) 158 throws ServletException , IOException { 159 160 if (this.doInclude == null) { 162 Logger.log(Logger.DEBUG, Launcher.RESOURCES, 163 "RequestDispatcher.IncludeMessage", new String [] { 164 getName(), this.requestURI }); 165 166 WinstoneRequest wr = getUnwrappedRequest(request); 167 wr.addIncludeQueryParameters(this.queryString); 169 170 if (useRequestAttributes) { 172 wr.addIncludeAttributes(this.webAppConfig.getContextPath() + this.requestURI, 173 this.webAppConfig.getContextPath(), this.servletPath, this.pathInfo, this.queryString); 174 } 175 WinstoneResponse wresp = getUnwrappedResponse(response); 177 wresp.startIncludeBuffer(); 178 179 this.includedServletConfig = wr.getServletConfig(); 180 this.includedWebAppConfig = wr.getWebAppConfig(); 181 wr.setServletConfig(this.servletConfig); 182 wr.setWebAppConfig(this.webAppConfig); 183 wresp.setWebAppConfig(this.webAppConfig); 184 185 this.doInclude = Boolean.TRUE; 186 } 187 188 if (this.matchingFilters == null) { 189 this.matchingFilters = getMatchingFilters(this.includeFilterPatterns, this.webAppConfig, 190 this.servletPath + (this.pathInfo == null ? "" : this.pathInfo), 191 getName(), "INCLUDE", (this.servletPath != null)); 192 } 193 try { 194 if (this.matchingFiltersEvaluated < this.matchingFilters.length) { 196 doFilter(request, response); 197 finishInclude(request, response); 198 } else { 199 try { 200 this.servletConfig.execute(request, response, 201 this.webAppConfig.getContextPath() + this.requestURI); 202 } finally { 203 if (this.matchingFilters.length == 0) { 204 finishInclude(request, response); 205 } 206 } 207 } 208 } catch (Throwable err) { 209 finishInclude(request, response); 210 if (err instanceof ServletException ) { 211 throw (ServletException ) err; 212 } else if (err instanceof IOException ) { 213 throw (IOException ) err; 214 } else if (err instanceof Error ) { 215 throw (Error ) err; 216 } else { 217 throw (RuntimeException ) err; 218 } 219 } 220 } 221 222 private void finishInclude(ServletRequest request, ServletResponse response) 223 throws IOException { 224 WinstoneRequest wr = getUnwrappedRequest(request); 225 wr.removeIncludeQueryString(); 226 227 if (useRequestAttributes) { 229 wr.removeIncludeAttributes(); 230 } 231 WinstoneResponse wresp = getUnwrappedResponse(response); 233 wresp.finishIncludeBuffer(); 234 235 if (this.includedServletConfig != null) { 236 wr.setServletConfig(this.includedServletConfig); 237 this.includedServletConfig = null; 238 } 239 240 if (this.includedWebAppConfig != null) { 241 wr.setWebAppConfig(this.includedWebAppConfig); 242 wresp.setWebAppConfig(this.includedWebAppConfig); 243 this.includedWebAppConfig = null; 244 } 245 } 246 247 254 public void forward(ServletRequest request, ServletResponse response) 255 throws ServletException , IOException { 256 257 if (this.doInclude == null) { 259 Logger.log(Logger.DEBUG, Launcher.RESOURCES, 260 "RequestDispatcher.ForwardMessage", new String [] { 261 getName(), this.requestURI }); 262 if (response.isCommitted()) { 263 throw new IllegalStateException (Launcher.RESOURCES.getString( 264 "RequestDispatcher.ForwardCommitted")); 265 } 266 267 WinstoneRequest req = getUnwrappedRequest(request); 268 WinstoneResponse rsp = getUnwrappedResponse(response); 269 270 rsp.resetBuffer(); 272 req.clearIncludeStackForForward(); 273 rsp.clearIncludeStackForForward(); 274 275 if (useRequestAttributes) { 277 req.setAttribute(FORWARD_REQUEST_URI, req.getRequestURI()); 278 req.setAttribute(FORWARD_CONTEXT_PATH, req.getContextPath()); 279 req.setAttribute(FORWARD_SERVLET_PATH, req.getServletPath()); 280 req.setAttribute(FORWARD_PATH_INFO, req.getPathInfo()); 281 req.setAttribute(FORWARD_QUERY_STRING, req.getQueryString()); 282 283 if (this.isErrorDispatch) { 284 req.setAttribute(ERROR_REQUEST_URI, req.getRequestURI()); 285 req.setAttribute(ERROR_STATUS_CODE, this.errorStatusCode); 286 req.setAttribute(ERROR_MESSAGE, 287 errorSummaryMessage != null ? errorSummaryMessage : ""); 288 if (req.getServletConfig() != null) { 289 req.setAttribute(ERROR_SERVLET_NAME, req.getServletConfig().getServletName()); 290 } 291 292 if (this.errorException != null) { 293 req.setAttribute(ERROR_EXCEPTION_TYPE, this.errorException.getClass()); 294 req.setAttribute(ERROR_EXCEPTION, this.errorException); 295 } 296 297 rsp.setErrorStatusCode(this.errorStatusCode.intValue()); 299 request = req; 300 response = rsp; 301 } 302 } 303 304 req.setServletPath(this.servletPath); 305 req.setPathInfo(this.pathInfo); 306 req.setRequestURI(this.webAppConfig.getContextPath() + this.requestURI); 307 req.setForwardQueryString(this.queryString); 308 req.setWebAppConfig(this.webAppConfig); 309 req.setServletConfig(this.servletConfig); 310 req.setRequestAttributeListeners(this.webAppConfig.getRequestAttributeListeners()); 311 312 rsp.setWebAppConfig(this.webAppConfig); 313 314 if (this.matchingFilters == null) { 316 this.matchingFilters = getMatchingFilters(this.forwardFilterPatterns, this.webAppConfig, 317 this.servletPath + (this.pathInfo == null ? "" : this.pathInfo), 318 getName(), "FORWARD", (this.servletPath != null)); 319 } 320 321 else if (!this.isErrorDispatch && !continueAfterSecurityCheck(request, response)) { 324 return; 325 } 326 327 this.doInclude = Boolean.FALSE; 328 } 329 330 if (this.matchingFiltersEvaluated < this.matchingFilters.length) { 332 doFilter(request, response); 333 } else { 334 this.servletConfig.execute(request, response, this.webAppConfig.getContextPath() + this.requestURI); 335 WinstoneResponse rsp = getUnwrappedResponse(response); 336 rsp.flushBuffer(); 337 rsp.getWinstoneOutputStream().setClosed(true); 338 } 339 } 340 341 private boolean continueAfterSecurityCheck(ServletRequest request, 342 ServletResponse response) throws IOException , ServletException { 343 if (this.authHandler != null) { 345 return this.authHandler.processAuthentication(request, response, 346 this.servletPath + (this.pathInfo == null ? "" : this.pathInfo)); 347 } else { 348 return true; 349 } 350 } 351 352 356 public void doFilter(ServletRequest request, ServletResponse response) 357 throws ServletException , IOException { 358 while (this.matchingFiltersEvaluated < this.matchingFilters.length) { 360 361 FilterConfiguration filter = this.matchingFilters[this.matchingFiltersEvaluated++]; 362 Logger.log(Logger.DEBUG, Launcher.RESOURCES, 363 "RequestDispatcher.ExecutingFilter", filter.getFilterName()); 364 filter.execute(request, response, this); 365 return; 366 } 367 368 if (this.doInclude == null) 370 return; else if (this.doInclude.booleanValue()) 372 include(request, response); 373 else 374 forward(request, response); 375 } 376 377 381 private static FilterConfiguration[] getMatchingFilters(Mapping filterPatterns[], 382 WebAppConfiguration webAppConfig, String fullPath, String servletName, 383 String filterChainType, boolean isURLBasedMatch) { 384 385 String cacheKey = null; 386 if (isURLBasedMatch) { 387 cacheKey = filterChainType + ":URI:" + fullPath; 388 } else { 389 cacheKey = filterChainType + ":Servlet:" + servletName; 390 } 391 FilterConfiguration matchingFilters[] = null; 392 Map cache = webAppConfig.getFilterMatchCache(); 393 synchronized (cache) { 394 matchingFilters = (FilterConfiguration []) cache.get(cacheKey); 395 if (matchingFilters == null) { 396 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, 397 "RequestDispatcher.CalcFilterChain", cacheKey); 398 List outFilters = new ArrayList (); 399 for (int n = 0; n < filterPatterns.length; n++) { 400 Mapping filterPattern = filterPatterns[n]; 402 403 if ((filterPattern.getLinkName() != null) 405 && (filterPattern.getLinkName().equals(servletName) || 406 filterPattern.getLinkName().equals("*"))) { 407 outFilters.add(webAppConfig.getFilters().get(filterPattern.getMappedTo())); 408 } 409 else if ((filterPattern.getLinkName() == null) && isURLBasedMatch 411 && filterPattern.match(fullPath, null, null)) { 412 outFilters.add(webAppConfig.getFilters().get(filterPattern.getMappedTo())); 413 } 414 } 415 matchingFilters = (FilterConfiguration []) outFilters.toArray(new FilterConfiguration[0]); 416 cache.put(cacheKey, matchingFilters); 417 } else { 418 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, 419 "RequestDispatcher.UseCachedFilterChain", cacheKey); 420 } 421 } 422 return matchingFilters; 423 } 424 425 428 protected WinstoneRequest getUnwrappedRequest(ServletRequest request) { 429 ServletRequest workingRequest = request; 430 while (workingRequest instanceof ServletRequestWrapper ) { 431 workingRequest = ((ServletRequestWrapper ) workingRequest).getRequest(); 432 } 433 return (WinstoneRequest) workingRequest; 434 } 435 436 439 protected WinstoneResponse getUnwrappedResponse(ServletResponse response) { 440 ServletResponse workingResponse = response; 441 while (workingResponse instanceof ServletResponseWrapper ) { 442 workingResponse = ((ServletResponseWrapper ) workingResponse).getResponse(); 443 } 444 return (WinstoneResponse) workingResponse; 445 } 446 } 447 | Popular Tags |