| 1 17 18 19 package org.apache.catalina.servlets; 20 21 22 import java.io.BufferedInputStream ; 23 import java.io.ByteArrayInputStream ; 24 import java.io.ByteArrayOutputStream ; 25 import java.io.File ; 26 import java.io.FileInputStream ; 27 import java.io.IOException ; 28 import java.io.InputStream ; 29 import java.io.InputStreamReader ; 30 import java.io.OutputStreamWriter ; 31 import java.io.PrintWriter ; 32 import java.io.RandomAccessFile ; 33 import java.io.Reader ; 34 import java.io.StringReader ; 35 import java.io.StringWriter ; 36 import java.util.ArrayList ; 37 import java.util.Iterator ; 38 import java.util.StringTokenizer ; 39 40 import javax.naming.InitialContext ; 41 import javax.naming.NameClassPair ; 42 import javax.naming.NamingEnumeration ; 43 import javax.naming.NamingException ; 44 import javax.naming.directory.DirContext ; 45 import javax.servlet.ServletException ; 46 import javax.servlet.ServletOutputStream ; 47 import javax.servlet.UnavailableException ; 48 import javax.servlet.http.HttpServlet ; 49 import javax.servlet.http.HttpServletRequest ; 50 import javax.servlet.http.HttpServletResponse ; 51 import javax.xml.transform.Source ; 52 import javax.xml.transform.Transformer ; 53 import javax.xml.transform.TransformerException ; 54 import javax.xml.transform.TransformerFactory ; 55 import javax.xml.transform.stream.StreamResult ; 56 import javax.xml.transform.stream.StreamSource ; 57 58 import org.apache.catalina.Globals; 59 import org.apache.catalina.util.ServerInfo; 60 import org.apache.catalina.util.StringManager; 61 import org.apache.catalina.util.URLEncoder; 62 import org.apache.naming.resources.CacheEntry; 63 import org.apache.naming.resources.ProxyDirContext; 64 import org.apache.naming.resources.Resource; 65 import org.apache.naming.resources.ResourceAttributes; 66 67 68 76 77 public class DefaultServlet 78 extends HttpServlet { 79 80 81 83 84 87 protected int debug = 0; 88 89 90 93 protected int input = 2048; 94 95 96 99 protected boolean listings = false; 100 101 102 105 protected boolean readOnly = true; 106 107 108 111 protected int output = 2048; 112 113 114 117 protected static URLEncoder urlEncoder; 118 119 120 123 protected String localXsltFile = null; 124 125 126 129 protected String globalXsltFile = null; 130 131 132 135 protected String readmeFile = null; 136 137 138 141 protected ProxyDirContext resources = null; 142 143 144 148 protected String fileEncoding = null; 149 150 151 154 protected int sendfileSize = 48 * 1024; 155 156 157 160 protected static ArrayList FULL = new ArrayList (); 161 162 163 165 166 169 static { 170 urlEncoder = new URLEncoder(); 171 urlEncoder.addSafeCharacter('-'); 172 urlEncoder.addSafeCharacter('_'); 173 urlEncoder.addSafeCharacter('.'); 174 urlEncoder.addSafeCharacter('*'); 175 urlEncoder.addSafeCharacter('/'); 176 } 177 178 179 182 protected static final String mimeSeparation = "CATALINA_MIME_BOUNDARY"; 183 184 185 188 protected static final String RESOURCES_JNDI_NAME = "java:/comp/Resources"; 189 190 191 194 protected static StringManager sm = 195 StringManager.getManager(Constants.Package); 196 197 198 201 protected static final int BUFFER_SIZE = 4096; 202 203 204 206 207 210 public void destroy() { 211 } 212 213 214 217 public void init() throws ServletException { 218 219 if (getServletConfig().getInitParameter("debug") != null) 220 debug = Integer.parseInt(getServletConfig().getInitParameter("debug")); 221 222 if (getServletConfig().getInitParameter("input") != null) 223 input = Integer.parseInt(getServletConfig().getInitParameter("input")); 224 225 if (getServletConfig().getInitParameter("output") != null) 226 output = Integer.parseInt(getServletConfig().getInitParameter("output")); 227 228 listings = Boolean.parseBoolean(getServletConfig().getInitParameter("listings")); 229 230 if (getServletConfig().getInitParameter("readonly") != null) 231 readOnly = Boolean.parseBoolean(getServletConfig().getInitParameter("readonly")); 232 233 if (getServletConfig().getInitParameter("sendfileSize") != null) 234 sendfileSize = 235 Integer.parseInt(getServletConfig().getInitParameter("sendfileSize")) * 1024; 236 237 fileEncoding = getServletConfig().getInitParameter("fileEncoding"); 238 239 globalXsltFile = getServletConfig().getInitParameter("globalXsltFile"); 240 localXsltFile = getServletConfig().getInitParameter("localXsltFile"); 241 readmeFile = getServletConfig().getInitParameter("readmeFile"); 242 243 if (input < 256) 245 input = 256; 246 if (output < 256) 247 output = 256; 248 249 if (debug > 0) { 250 log("DefaultServlet.init: input buffer size=" + input + 251 ", output buffer size=" + output); 252 } 253 254 resources = (ProxyDirContext) getServletContext() 256 .getAttribute(Globals.RESOURCES_ATTR); 257 if (resources == null) { 258 try { 259 resources = 260 (ProxyDirContext) new InitialContext () 261 .lookup(RESOURCES_JNDI_NAME); 262 } catch (NamingException e) { 263 throw new ServletException ("No resources", e); 265 } 266 } 267 268 if (resources == null) { 269 throw new UnavailableException ("No resources"); 270 } 271 272 } 273 274 275 277 278 283 protected String getRelativePath(HttpServletRequest request) { 284 285 if (request.getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR) != null) { 287 String result = (String ) request.getAttribute( 288 Globals.INCLUDE_PATH_INFO_ATTR); 289 if (result == null) 290 result = (String ) request.getAttribute( 291 Globals.INCLUDE_SERVLET_PATH_ATTR); 292 if ((result == null) || (result.equals(""))) 293 result = "/"; 294 return (result); 295 } 296 297 String result = request.getPathInfo(); 299 if (result == null) { 300 result = request.getServletPath(); 301 } 302 if ((result == null) || (result.equals(""))) { 303 result = "/"; 304 } 305 return (result); 306 307 } 308 309 310 319 protected void doGet(HttpServletRequest request, 320 HttpServletResponse response) 321 throws IOException , ServletException { 322 323 serveResource(request, response, true); 325 326 } 327 328 329 338 protected void doHead(HttpServletRequest request, 339 HttpServletResponse response) 340 throws IOException , ServletException { 341 342 serveResource(request, response, false); 344 345 } 346 347 348 357 protected void doPost(HttpServletRequest request, 358 HttpServletResponse response) 359 throws IOException , ServletException { 360 doGet(request, response); 361 } 362 363 364 373 protected void doPut(HttpServletRequest req, HttpServletResponse resp) 374 throws ServletException , IOException { 375 376 if (readOnly) { 377 resp.sendError(HttpServletResponse.SC_FORBIDDEN); 378 return; 379 } 380 381 String path = getRelativePath(req); 382 383 boolean exists = true; 384 try { 385 resources.lookup(path); 386 } catch (NamingException e) { 387 exists = false; 388 } 389 390 boolean result = true; 391 392 File contentFile = null; 394 395 Range range = parseContentRange(req, resp); 396 397 InputStream resourceInputStream = null; 398 399 if (range != null) { 404 contentFile = executePartialPut(req, range, path); 405 resourceInputStream = new FileInputStream (contentFile); 406 } else { 407 resourceInputStream = req.getInputStream(); 408 } 409 410 try { 411 Resource newResource = new Resource(resourceInputStream); 412 if (exists) { 414 resources.rebind(path, newResource); 415 } else { 416 resources.bind(path, newResource); 417 } 418 } catch(NamingException e) { 419 result = false; 420 } 421 422 if (result) { 423 if (exists) { 424 resp.setStatus(HttpServletResponse.SC_NO_CONTENT); 425 } else { 426 resp.setStatus(HttpServletResponse.SC_CREATED); 427 } 428 } else { 429 resp.sendError(HttpServletResponse.SC_CONFLICT); 430 } 431 432 } 433 434 435 440 protected File executePartialPut(HttpServletRequest req, Range range, 441 String path) 442 throws IOException { 443 444 File tempDir = (File ) getServletContext().getAttribute 448 ("javax.servlet.context.tempdir"); 449 String convertedResourcePath = path.replace('/', '.'); 451 File contentFile = new File (tempDir, convertedResourcePath); 452 if (contentFile.createNewFile()) { 453 contentFile.deleteOnExit(); 455 } 456 457 RandomAccessFile randAccessContentFile = 458 new RandomAccessFile (contentFile, "rw"); 459 460 Resource oldResource = null; 461 try { 462 Object obj = resources.lookup(path); 463 if (obj instanceof Resource) 464 oldResource = (Resource) obj; 465 } catch (NamingException e) { 466 ; 467 } 468 469 if (oldResource != null) { 471 BufferedInputStream bufOldRevStream = 472 new BufferedInputStream (oldResource.streamContent(), 473 BUFFER_SIZE); 474 475 int numBytesRead; 476 byte[] copyBuffer = new byte[BUFFER_SIZE]; 477 while ((numBytesRead = bufOldRevStream.read(copyBuffer)) != -1) { 478 randAccessContentFile.write(copyBuffer, 0, numBytesRead); 479 } 480 481 bufOldRevStream.close(); 482 } 483 484 randAccessContentFile.setLength(range.length); 485 486 randAccessContentFile.seek(range.start); 488 int numBytesRead; 489 byte[] transferBuffer = new byte[BUFFER_SIZE]; 490 BufferedInputStream requestBufInStream = 491 new BufferedInputStream (req.getInputStream(), BUFFER_SIZE); 492 while ((numBytesRead = requestBufInStream.read(transferBuffer)) != -1) { 493 randAccessContentFile.write(transferBuffer, 0, numBytesRead); 494 } 495 randAccessContentFile.close(); 496 requestBufInStream.close(); 497 498 return contentFile; 499 500 } 501 502 503 512 protected void doDelete(HttpServletRequest req, HttpServletResponse resp) 513 throws ServletException , IOException { 514 515 if (readOnly) { 516 resp.sendError(HttpServletResponse.SC_FORBIDDEN); 517 return; 518 } 519 520 String path = getRelativePath(req); 521 522 boolean exists = true; 523 try { 524 resources.lookup(path); 525 } catch (NamingException e) { 526 exists = false; 527 } 528 529 if (exists) { 530 boolean result = true; 531 try { 532 resources.unbind(path); 533 } catch (NamingException e) { 534 result = false; 535 } 536 if (result) { 537 resp.setStatus(HttpServletResponse.SC_NO_CONTENT); 538 } else { 539 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); 540 } 541 } else { 542 resp.sendError(HttpServletResponse.SC_NOT_FOUND); 543 } 544 545 } 546 547 548 559 protected boolean checkIfHeaders(HttpServletRequest request, 560 HttpServletResponse response, 561 ResourceAttributes resourceAttributes) 562 throws IOException { 563 564 return checkIfMatch(request, response, resourceAttributes) 565 && checkIfModifiedSince(request, response, resourceAttributes) 566 && checkIfNoneMatch(request, response, resourceAttributes) 567 && checkIfUnmodifiedSince(request, response, resourceAttributes); 568 569 } 570 571 572 577 protected String getETag(ResourceAttributes resourceAttributes) { 578 String result = null; 579 if ((result = resourceAttributes.getETag(true)) != null) { 580 return result; 581 } else if ((result = resourceAttributes.getETag()) != null) { 582 return result; 583 } else { 584 return "W/\"" + resourceAttributes.getContentLength() + "-" 585 + resourceAttributes.getLastModified() + "\""; 586 } 587 } 588 589 590 595 protected String rewriteUrl(String path) { 596 return urlEncoder.encode( path ); 597 } 598 599 600 603 protected void displaySize(StringBuffer buf, int filesize) { 604 605 int leftside = filesize / 1024; 606 int rightside = (filesize % 1024) / 103; if (leftside == 0 && rightside == 0 && filesize != 0) 609 rightside = 1; 610 buf.append(leftside).append(".").append(rightside); 611 buf.append(" KB"); 612 613 } 614 615 616 626 protected void serveResource(HttpServletRequest request, 627 HttpServletResponse response, 628 boolean content) 629 throws IOException , ServletException { 630 631 String path = getRelativePath(request); 633 if (debug > 0) { 634 if (content) 635 log("DefaultServlet.serveResource: Serving resource '" + 636 path + "' headers and data"); 637 else 638 log("DefaultServlet.serveResource: Serving resource '" + 639 path + "' headers only"); 640 } 641 642 CacheEntry cacheEntry = resources.lookupCache(path); 643 644 if (!cacheEntry.exists) { 645 String requestUri = (String ) request.getAttribute( 648 Globals.INCLUDE_REQUEST_URI_ATTR); 649 if (requestUri == null) { 650 requestUri = request.getRequestURI(); 651 } else { 652 response.getWriter().write( 657 sm.getString("defaultServlet.missingResource", 658 requestUri)); 659 } 660 661 response.sendError(HttpServletResponse.SC_NOT_FOUND, 662 requestUri); 663 return; 664 } 665 666 if (cacheEntry.context == null) { 669 if (path.endsWith("/") || (path.endsWith("\\"))) { 670 String requestUri = (String ) request.getAttribute( 673 Globals.INCLUDE_REQUEST_URI_ATTR); 674 if (requestUri == null) { 675 requestUri = request.getRequestURI(); 676 } 677 response.sendError(HttpServletResponse.SC_NOT_FOUND, 678 requestUri); 679 return; 680 } 681 } 682 683 if (cacheEntry.context == null) { 686 687 boolean included = 689 (request.getAttribute(Globals.INCLUDE_CONTEXT_PATH_ATTR) != null); 690 if (!included 691 && !checkIfHeaders(request, response, cacheEntry.attributes)) { 692 return; 693 } 694 695 } 696 697 String contentType = cacheEntry.attributes.getMimeType(); 699 if (contentType == null) { 700 contentType = getServletContext().getMimeType(cacheEntry.name); 701 cacheEntry.attributes.setMimeType(contentType); 702 } 703 704 ArrayList ranges = null; 705 long contentLength = -1L; 706 707 if (cacheEntry.context != null) { 708 709 if (!listings) { 712 response.sendError(HttpServletResponse.SC_NOT_FOUND, 713 request.getRequestURI()); 714 return; 715 } 716 contentType = "text/html;charset=UTF-8"; 717 718 } else { 719 720 722 ranges = parseRange(request, response, cacheEntry.attributes); 723 724 response.setHeader("ETag", getETag(cacheEntry.attributes)); 726 727 response.setHeader("Last-Modified", 729 cacheEntry.attributes.getLastModifiedHttp()); 730 731 contentLength = cacheEntry.attributes.getContentLength(); 733 if (contentLength == 0L) { 736 content = false; 737 } 738 739 } 740 741 ServletOutputStream ostream = null; 742 PrintWriter writer = null; 743 744 if (content) { 745 746 748 try { 749 ostream = response.getOutputStream(); 750 } catch (IllegalStateException e) { 751 if ( (contentType == null) 754 || (contentType.startsWith("text")) 755 || (contentType.endsWith("xml")) ) { 756 writer = response.getWriter(); 757 } else { 758 throw e; 759 } 760 } 761 762 } 763 764 if ( (cacheEntry.context != null) 765 || ( ((ranges == null) || (ranges.isEmpty())) 766 && (request.getHeader("Range") == null) ) 767 || (ranges == FULL) ) { 768 769 if (contentType != null) { 771 if (debug > 0) 772 log("DefaultServlet.serveFile: contentType='" + 773 contentType + "'"); 774 response.setContentType(contentType); 775 } 776 if ((cacheEntry.resource != null) && (contentLength >= 0)) { 777 if (debug > 0) 778 log("DefaultServlet.serveFile: contentLength=" + 779 contentLength); 780 if (contentLength < Integer.MAX_VALUE) { 781 response.setContentLength((int) contentLength); 782 } else { 783 response.setHeader("content-length", "" + contentLength); 785 } 786 } 787 788 InputStream renderResult = null; 789 if (cacheEntry.context != null) { 790 791 if (content) { 792 renderResult = 794 render(request.getContextPath(), cacheEntry); 795 } 796 797 } 798 799 if (content) { 801 try { 802 response.setBufferSize(output); 803 } catch (IllegalStateException e) { 804 } 806 if (ostream != null) { 807 if (!checkSendfile(request, response, cacheEntry, contentLength, null)) 808 copy(cacheEntry, renderResult, ostream); 809 } else { 810 copy(cacheEntry, renderResult, writer); 811 } 812 } 813 814 } else { 815 816 if ((ranges == null) || (ranges.isEmpty())) 817 return; 818 819 821 response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); 822 823 if (ranges.size() == 1) { 824 825 Range range = (Range) ranges.get(0); 826 response.addHeader("Content-Range", "bytes " 827 + range.start 828  
|