1 11 package org.apache.catalina.ssi; 12 13 14 import java.io.IOException ; 15 import java.io.UnsupportedEncodingException ; 16 import java.net.URL ; 17 import java.net.URLConnection ; 18 import java.net.URLDecoder ; 19 import java.util.Collection ; 20 import java.util.Date ; 21 import java.util.Enumeration ; 22 import javax.servlet.RequestDispatcher ; 23 import javax.servlet.ServletContext ; 24 import javax.servlet.ServletException ; 25 import javax.servlet.http.HttpServletRequest ; 26 import javax.servlet.http.HttpServletResponse ; 27 import org.apache.catalina.connector.Request; 28 import org.apache.coyote.Constants; 29 30 37 public class SSIServletExternalResolver implements SSIExternalResolver { 38 protected final String VARIABLE_NAMES[] = {"AUTH_TYPE", "CONTENT_LENGTH", 39 "CONTENT_TYPE", "DOCUMENT_NAME", "DOCUMENT_URI", 40 "GATEWAY_INTERFACE", "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING", 41 "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION", "HTTP_HOST", 42 "HTTP_REFERER", "HTTP_USER_AGENT", "PATH_INFO", "PATH_TRANSLATED", 43 "QUERY_STRING", "QUERY_STRING_UNESCAPED", "REMOTE_ADDR", 44 "REMOTE_HOST", "REMOTE_PORT", "REMOTE_USER", "REQUEST_METHOD", 45 "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_ADDR", 46 "SERVER_NAME", "SERVER_PORT", "SERVER_PROTOCOL", "SERVER_SOFTWARE", 47 "UNIQUE_ID"}; 48 protected ServletContext context; 49 protected HttpServletRequest req; 50 protected HttpServletResponse res; 51 protected boolean isVirtualWebappRelative; 52 protected int debug; 53 protected String inputEncoding; 54 55 public SSIServletExternalResolver(ServletContext context, 56 HttpServletRequest req, HttpServletResponse res, 57 boolean isVirtualWebappRelative, int debug, String inputEncoding) { 58 this.context = context; 59 this.req = req; 60 this.res = res; 61 this.isVirtualWebappRelative = isVirtualWebappRelative; 62 this.debug = debug; 63 this.inputEncoding = inputEncoding; 64 } 65 66 67 public void log(String message, Throwable throwable) { 68 if (throwable != null) { 72 context.log(message, throwable); 73 } else { 74 context.log(message); 75 } 76 } 77 78 79 public void addVariableNames(Collection variableNames) { 80 for (int i = 0; i < VARIABLE_NAMES.length; i++) { 81 String variableName = VARIABLE_NAMES[i]; 82 String variableValue = getVariableValue(variableName); 83 if (variableValue != null) { 84 variableNames.add(variableName); 85 } 86 } 87 Enumeration e = req.getAttributeNames(); 88 while (e.hasMoreElements()) { 89 String name = (String )e.nextElement(); 90 if (!isNameReserved(name)) { 91 variableNames.add(name); 92 } 93 } 94 } 95 96 97 protected Object getReqAttributeIgnoreCase(String targetName) { 98 Object object = null; 99 if (!isNameReserved(targetName)) { 100 object = req.getAttribute(targetName); 101 if (object == null) { 102 Enumeration e = req.getAttributeNames(); 103 while (e.hasMoreElements()) { 104 String name = (String )e.nextElement(); 105 if (targetName.equalsIgnoreCase(name) 106 && !isNameReserved(name)) { 107 object = req.getAttribute(name); 108 if (object != null) { 109 break; 110 } 111 } 112 } 113 } 114 } 115 return object; 116 } 117 118 119 protected boolean isNameReserved(String name) { 120 return name.startsWith("java.") || name.startsWith("javax.") 121 || name.startsWith("sun."); 122 } 123 124 125 public void setVariableValue(String name, String value) { 126 if (!isNameReserved(name)) { 127 req.setAttribute(name, value); 128 } 129 } 130 131 132 public String getVariableValue(String name) { 133 String retVal = null; 134 Object object = getReqAttributeIgnoreCase(name); 135 if (object != null) { 136 retVal = object.toString(); 137 } else { 138 retVal = getCGIVariable(name); 139 } 140 return retVal; 141 } 142 143 144 protected String getCGIVariable(String name) { 145 String retVal = null; 146 String [] nameParts = name.toUpperCase().split("_"); 147 int requiredParts = 2; 148 if (nameParts.length == 1) { 149 if (nameParts[0].equals("PATH")) { 150 requiredParts = 1; 151 retVal = null; } 153 } 154 else if (nameParts[0].equals("AUTH")) { 155 if (nameParts[1].equals("TYPE")) { 156 retVal = req.getAuthType(); 157 } 158 } else if(nameParts[0].equals("CONTENT")) { 159 if (nameParts[1].equals("LENGTH")) { 160 int contentLength = req.getContentLength(); 161 if (contentLength >= 0) { 162 retVal = Integer.toString(contentLength); 163 } 164 } else if (nameParts[1].equals("TYPE")) { 165 retVal = req.getContentType(); 166 } 167 } else if (nameParts[0].equals("DOCUMENT")) { 168 if (nameParts[1].equals("NAME")) { 169 String requestURI = req.getRequestURI(); 170 retVal = requestURI.substring(requestURI.lastIndexOf('/') + 1); 171 } else if (nameParts[1].equals("URI")) { 172 retVal = req.getRequestURI(); 173 } 174 } else if (name.equalsIgnoreCase("GATEWAY_INTERFACE")) { 175 retVal = "CGI/1.1"; 176 } else if (nameParts[0].equals("HTTP")) { 177 if (nameParts[1].equals("ACCEPT")) { 178 String accept = null; 179 if (nameParts.length == 2) { 180 accept = "Accept"; 181 } else if (nameParts[2].equals("ENCODING")) { 182 requiredParts = 3; 183 accept = "Accept-Encoding"; 184 } else if (nameParts[2].equals("LANGUAGE")) { 185 requiredParts = 3; 186 accept = "Accept-Language"; 187 } 188 if (accept != null) { 189 Enumeration acceptHeaders = req.getHeaders(accept); 190 if (acceptHeaders != null) 191 if (acceptHeaders.hasMoreElements()) { 192 StringBuffer rv = new StringBuffer ( 193 (String ) acceptHeaders.nextElement()); 194 while (acceptHeaders.hasMoreElements()) { 195 rv.append(", "); 196 rv.append((String ) acceptHeaders.nextElement()); 197 } 198 retVal = rv.toString(); 199 } 200 } 201 } 202 else if (nameParts[1].equals("CONNECTION")) { 203 retVal = req.getHeader("Connection"); 204 } 205 else if (nameParts[1].equals("HOST")) { 206 retVal = req.getHeader("Host"); 207 } 208 else if (nameParts[1].equals("REFERER")) { 209 retVal = req.getHeader("Referer"); 210 } 211 else if (nameParts[1].equals("USER")) 212 if (nameParts.length == 3) 213 if (nameParts[2].equals("AGENT")) { 214 requiredParts = 3; 215 retVal = req.getHeader("User-Agent"); 216 } 217 218 } else if (nameParts[0].equals("PATH")) { 219 if (nameParts[1].equals("INFO")) { 220 retVal = req.getPathInfo(); 221 } else if (nameParts[1].equals("TRANSLATED")) { 222 retVal = req.getPathTranslated(); 223 } 224 } else if (nameParts[0].equals("QUERY")) { 225 if (nameParts[1].equals("STRING")) { 226 String queryString = req.getQueryString(); 227 if (nameParts.length == 2) { 228 retVal = nullToEmptyString(queryString); 230 } else if (nameParts[2].equals("UNESCAPED")) { 231 requiredParts = 3; 232 if (queryString != null) { 233 String queryStringEncoding = 235 Constants.DEFAULT_CHARACTER_ENCODING; 236 237 String uriEncoding = null; 238 boolean useBodyEncodingForURI = false; 239 240 String requestEncoding = req.getCharacterEncoding(); 243 if (req instanceof Request ) { 244 uriEncoding = 245 ((Request )req).getConnector().getURIEncoding(); 246 useBodyEncodingForURI = ((Request )req) 247 .getConnector().getUseBodyEncodingForURI(); 248 } 249 250 if (uriEncoding != null) { 252 queryStringEncoding = uriEncoding; 253 } else if(useBodyEncodingForURI) { 254 if (requestEncoding != null) { 255 queryStringEncoding = requestEncoding; 256 } 257 } 258 259 try { 260 retVal = URLDecoder.decode(queryString, 261 queryStringEncoding); 262 } catch (UnsupportedEncodingException e) { 263 retVal = queryString; 264 } 265 } 266 } 267 } 268 } else if(nameParts[0].equals("REMOTE")) { 269 if (nameParts[1].equals("ADDR")) { 270 retVal = req.getRemoteAddr(); 271 } else if (nameParts[1].equals("HOST")) { 272 retVal = req.getRemoteHost(); 273 } else if (nameParts[1].equals("IDENT")) { 274 retVal = null; } else if (nameParts[1].equals("PORT")) { 276 retVal = Integer.toString( req.getRemotePort()); 277 } else if (nameParts[1].equals("USER")) { 278 retVal = req.getRemoteUser(); 279 } 280 } else if(nameParts[0].equals("REQUEST")) { 281 if (nameParts[1].equals("METHOD")) { 282 retVal = req.getMethod(); 283 } 284 else if (nameParts[1].equals("URI")) { 285 retVal = (String ) req.getAttribute( 287 "javax.servlet.forward.request_uri"); 288 if (retVal == null) retVal=req.getRequestURI(); 289 } 290 } else if (nameParts[0].equals("SCRIPT")) { 291 String scriptName = req.getServletPath(); 292 if (nameParts[1].equals("FILENAME")) { 293 retVal = context.getRealPath(scriptName); 294 } 295 else if (nameParts[1].equals("NAME")) { 296 retVal = scriptName; 297 } 298 } else if (nameParts[0].equals("SERVER")) { 299 if (nameParts[1].equals("ADDR")) { 300 retVal = req.getLocalAddr(); 301 } 302 if (nameParts[1].equals("NAME")) { 303 retVal = req.getServerName(); 304 } else if (nameParts[1].equals("PORT")) { 305 retVal = Integer.toString(req.getServerPort()); 306 } else if (nameParts[1].equals("PROTOCOL")) { 307 retVal = req.getProtocol(); 308 } else if (nameParts[1].equals("SOFTWARE")) { 309 StringBuffer rv = new StringBuffer (context.getServerInfo()); 310 rv.append(" "); 311 rv.append(System.getProperty("java.vm.name")); 312 rv.append("/"); 313 rv.append(System.getProperty("java.vm.version")); 314 rv.append(" "); 315 rv.append(System.getProperty("os.name")); 316 retVal = rv.toString(); 317 } 318 } else if (name.equalsIgnoreCase("UNIQUE_ID")) { 319 retVal = req.getRequestedSessionId(); 320 } 321 if (requiredParts != nameParts.length) return null; 322 return retVal; 323 } 324 325 public Date getCurrentDate() { 326 return new Date (); 327 } 328 329 330 protected String nullToEmptyString(String string) { 331 String retVal = string; 332 if (retVal == null) { 333 retVal = ""; 334 } 335 return retVal; 336 } 337 338 339 protected String getPathWithoutFileName(String servletPath) { 340 String retVal = null; 341 int lastSlash = servletPath.lastIndexOf('/'); 342 if (lastSlash >= 0) { 343 retVal = servletPath.substring(0, lastSlash + 1); 345 } 346 return retVal; 347 } 348 349 350 protected String getPathWithoutContext(String servletPath) { 351 String retVal = null; 352 int secondSlash = servletPath.indexOf('/', 1); 353 if (secondSlash >= 0) { 354 retVal = servletPath.substring(secondSlash); 356 } 357 return retVal; 358 } 359 360 361 protected String getAbsolutePath(String path) throws IOException { 362 String pathWithoutContext = SSIServletRequestUtil.getRelativePath(req); 363 String prefix = getPathWithoutFileName(pathWithoutContext); 364 if (prefix == null) { 365 throw new IOException ("Couldn't remove filename from path: " 366 + pathWithoutContext); 367 } 368 String fullPath = prefix + path; 369 String retVal = SSIServletRequestUtil.normalize(fullPath); 370 if (retVal == null) { 371 throw new IOException ("Normalization yielded null on path: " 372 + fullPath); 373 } 374 return retVal; 375 } 376 377 378 protected ServletContextAndPath getServletContextAndPathFromNonVirtualPath( 379 String nonVirtualPath) throws IOException { 380 if (nonVirtualPath.startsWith("/") || nonVirtualPath.startsWith("\\")) { 381 throw new IOException ("A non-virtual path can't be absolute: " 382 + nonVirtualPath); 383 } 384 if (nonVirtualPath.indexOf("../") >= 0) { 385 throw new IOException ("A non-virtual path can't contain '../' : " 386 + nonVirtualPath); 387 } 388 String path = getAbsolutePath(nonVirtualPath); 389 ServletContextAndPath csAndP = new ServletContextAndPath( 390 context, path); 391 return csAndP; 392 } 393 394 395 protected ServletContextAndPath getServletContextAndPathFromVirtualPath( 396 String virtualPath) throws IOException { 397 398 if (!virtualPath.startsWith("/") && !virtualPath.startsWith("\\")) { 399 return new ServletContextAndPath(context, 400 getAbsolutePath(virtualPath)); 401 } else { 402 String normalized = SSIServletRequestUtil.normalize(virtualPath); 403 if (isVirtualWebappRelative) { 404 return new ServletContextAndPath(context, normalized); 405 } else { 406 ServletContext normContext = context.getContext(normalized); 407 if (normContext == null) { 408 throw new IOException ("Couldn't get context for path: " 409 + normalized); 410 } 411 if (!isRootContext(normContext)) { 416 String noContext = getPathWithoutContext(normalized); 417 if (noContext == null) { 418 throw new IOException ( 419 "Couldn't remove context from path: " 420 + normalized); 421 } 422 return new ServletContextAndPath(normContext, noContext); 423 } else { 424 return new ServletContextAndPath(normContext, normalized); 425 } 426 } 427 } 428 } 429 430 431 protected boolean isRootContext(ServletContext servletContext) { 440 return servletContext == servletContext.getContext("/"); 441 } 442 443 444 protected ServletContextAndPath getServletContextAndPath( 445 String originalPath, boolean virtual) throws IOException { 446 ServletContextAndPath csAndP = null; 447 if (debug > 0) { 448 log("SSIServletExternalResolver.getServletContextAndPath( " 449 + originalPath + ", " + virtual + ")", null); 450 } 451 if (virtual) { 452 csAndP = getServletContextAndPathFromVirtualPath(originalPath); 453 } else { 454 csAndP = getServletContextAndPathFromNonVirtualPath(originalPath); 455 } 456 return csAndP; 457 } 458 459 460 protected URLConnection getURLConnection(String originalPath, 461 boolean virtual) throws IOException { 462 ServletContextAndPath csAndP = getServletContextAndPath(originalPath, 463 virtual); 464 ServletContext context = csAndP.getServletContext(); 465 String path = csAndP.getPath(); 466 URL url = context.getResource(path); 467 if (url == null) { 468 throw new IOException ("Context did not contain resource: " + path); 469 } 470 URLConnection urlConnection = url.openConnection(); 471 return urlConnection; 472 } 473 474 475 public long getFileLastModified(String path, boolean virtual) 476 throws IOException { 477 long lastModified = 0; 478 try { 479 URLConnection urlConnection = getURLConnection(path, virtual); 480 lastModified = urlConnection.getLastModified(); 481 } catch (IOException e) { 482 } 484 return lastModified; 485 } 486 487 488 public long getFileSize(String path, boolean virtual) throws IOException { 489 long fileSize = -1; 490 try { 491 URLConnection urlConnection = getURLConnection(path, virtual); 492 fileSize = urlConnection.getContentLength(); 493 } catch (IOException e) { 494 } 496 return fileSize; 497 } 498 499 500 public String getFileText(String originalPath, boolean virtual) 504 throws IOException { 505 try { 506 ServletContextAndPath csAndP = getServletContextAndPath( 507 originalPath, virtual); 508 ServletContext context = csAndP.getServletContext(); 509 String path = csAndP.getPath(); 510 RequestDispatcher rd = context.getRequestDispatcher(path); 511 if (rd == null) { 512 throw new IOException ( 513 "Couldn't get request dispatcher for path: " + path); 514 } 515 ByteArrayServletOutputStream basos = 516 new ByteArrayServletOutputStream(); 517 ResponseIncludeWrapper responseIncludeWrapper = 518 new ResponseIncludeWrapper(context, req, res, basos); 519 rd.include(req, responseIncludeWrapper); 520 responseIncludeWrapper.flushOutputStreamOrWriter(); 522 byte[] bytes = basos.toByteArray(); 523 524 String retVal; 526 if (inputEncoding == null) { 527 retVal = new String ( bytes ); 528 } else { 529 retVal = new String (bytes, inputEncoding); 530 } 531 532 if (retVal.equals("") && !req.getMethod().equalsIgnoreCase( 537 org.apache.coyote.http11.Constants.HEAD)) { 538 throw new IOException ("Couldn't find file: " + path); 539 } 540 return retVal; 541 } catch (ServletException e) { 542 throw new IOException ("Couldn't include file: " + originalPath 543 + " because of ServletException: " + e.getMessage()); 544 } 545 } 546 547 protected class ServletContextAndPath { 548 protected ServletContext servletContext; 549 protected String path; 550 551 552 public ServletContextAndPath(ServletContext servletContext, 553 String path) { 554 this.servletContext = servletContext; 555 this.path = path; 556 } 557 558 559 public ServletContext getServletContext() { 560 return servletContext; 561 } 562 563 564 public String getPath() { 565 return path; 566 } 567 } 568 } | Popular Tags |