1 64 65 package com.jcorporate.expresso.ext.controller; 66 67 import com.jcorporate.expresso.core.controller.ControllerException; 68 import com.jcorporate.expresso.core.controller.ControllerRequest; 69 import com.jcorporate.expresso.core.controller.ControllerResponse; 70 import com.jcorporate.expresso.core.controller.DBController; 71 import com.jcorporate.expresso.core.controller.ServletControllerRequest; 72 import com.jcorporate.expresso.core.controller.State; 73 import com.jcorporate.expresso.core.misc.ConfigManager; 74 import com.jcorporate.expresso.core.security.filters.Filter; 75 import org.apache.log4j.Logger; 76 77 import javax.servlet.Servlet ; 78 import javax.servlet.http.HttpServletRequest ; 79 import javax.servlet.http.HttpServletResponse ; 80 import javax.servlet.http.HttpSession ; 81 import java.io.BufferedInputStream ; 82 import java.io.ByteArrayOutputStream ; 83 import java.io.File ; 84 import java.io.FileInputStream ; 85 import java.io.FileNotFoundException ; 86 import java.io.IOException ; 87 import java.io.OutputStream ; 88 import java.io.PrintStream ; 89 import java.io.PushbackInputStream ; 90 import java.util.Date ; 91 import java.util.Hashtable ; 92 import java.util.Vector ; 93 94 105 106 public class ServeTextFile extends DBController { 107 108 111 static private Vector rootDirList = new Vector (); 112 113 117 transient static private Logger log = Logger.getLogger("expresso.ext.controller.ServeTextFile"); 118 119 123 transient private static Filter fileNameFilter = null; 124 125 126 130 transient private static Filter javaCodeFilter = null; 131 132 133 public final static String DEFAULT_RESERVED_KEYWORD_COLOR = "#9900CC"; 137 public final static String DEFAULT_PRIMITIVE_VAR_COLOR = "#008000"; 138 public final static String DEFAULT_SPECIAL_KEYWORD_COLOR = "#4682B4"; public final static String DEFAULT_SINGLE_QUOTE_COLOR = "#0066FF"; 140 public final static String DEFAULT_DOUBLE_QUOTE_COLOR = "#0000CC"; 141 public final static String DEFAULT_CSTYLE_COMMENT_COLOR = "#CC0033"; 142 public final static String DEFAULT_CPLUS_COMMENT_COLOR = "B22222"; public final static String DEFAULT_DECIMAL_NUMBER_COLOR = "#996600"; 144 protected final static String reservedKeywordColor = DEFAULT_RESERVED_KEYWORD_COLOR; 145 protected final static String primitiveVarColor = DEFAULT_PRIMITIVE_VAR_COLOR; 146 protected final static String specialKeywordColor = DEFAULT_SPECIAL_KEYWORD_COLOR; 147 protected final static String singleQuoteColor = DEFAULT_SINGLE_QUOTE_COLOR; 148 protected final static String doubleQuoteColor = DEFAULT_DOUBLE_QUOTE_COLOR; 149 protected final static String cstyleCommentColor = DEFAULT_CSTYLE_COMMENT_COLOR; 150 protected final static String cplusCommentColor = DEFAULT_CPLUS_COMMENT_COLOR; 151 protected final static String decimalNumberColor = DEFAULT_DECIMAL_NUMBER_COLOR; 152 153 156 class Parameters { 157 HttpServletRequest req; HttpServletResponse res; HttpSession session; String inputFilename; String filename; PrintStream out; } 164 165 169 static class ReservedWord { 170 String keyword; 171 String htmlcolor; 172 173 ReservedWord(String keyword, String htmlcolor) { 174 this.keyword = keyword; 175 this.htmlcolor = htmlcolor; 176 } 177 } 178 179 static protected final ServeTextFile.ReservedWord[] java_reserved_keywords = { 180 new ReservedWord("class", DEFAULT_RESERVED_KEYWORD_COLOR), 181 new ReservedWord("interface", DEFAULT_RESERVED_KEYWORD_COLOR), 182 new ReservedWord("extends", DEFAULT_RESERVED_KEYWORD_COLOR), 183 new ReservedWord("implements", DEFAULT_RESERVED_KEYWORD_COLOR), 184 new ReservedWord("goto", DEFAULT_RESERVED_KEYWORD_COLOR), 185 new ReservedWord("for", DEFAULT_RESERVED_KEYWORD_COLOR), 186 new ReservedWord("return", DEFAULT_RESERVED_KEYWORD_COLOR), 187 new ReservedWord("if", DEFAULT_RESERVED_KEYWORD_COLOR), 188 new ReservedWord("then", DEFAULT_RESERVED_KEYWORD_COLOR), 189 new ReservedWord("else", DEFAULT_RESERVED_KEYWORD_COLOR), 190 new ReservedWord("while", DEFAULT_RESERVED_KEYWORD_COLOR), 191 new ReservedWord("do", DEFAULT_RESERVED_KEYWORD_COLOR), 192 new ReservedWord("switch", DEFAULT_RESERVED_KEYWORD_COLOR), 193 new ReservedWord("case", DEFAULT_RESERVED_KEYWORD_COLOR), 194 new ReservedWord("default", DEFAULT_RESERVED_KEYWORD_COLOR), 195 new ReservedWord("instanceof", DEFAULT_RESERVED_KEYWORD_COLOR), 196 new ReservedWord("package", DEFAULT_RESERVED_KEYWORD_COLOR), 197 new ReservedWord("import", DEFAULT_RESERVED_KEYWORD_COLOR), 198 new ReservedWord("public", DEFAULT_RESERVED_KEYWORD_COLOR), 199 new ReservedWord("protected", DEFAULT_RESERVED_KEYWORD_COLOR), 200 new ReservedWord("private", DEFAULT_RESERVED_KEYWORD_COLOR), 201 new ReservedWord("super", DEFAULT_RESERVED_KEYWORD_COLOR), 202 new ReservedWord("new", DEFAULT_RESERVED_KEYWORD_COLOR), 203 new ReservedWord("this", DEFAULT_RESERVED_KEYWORD_COLOR), 204 new ReservedWord("try", DEFAULT_RESERVED_KEYWORD_COLOR), 205 new ReservedWord("catch", DEFAULT_RESERVED_KEYWORD_COLOR), 206 new ReservedWord("throw", DEFAULT_RESERVED_KEYWORD_COLOR), 207 new ReservedWord("throws", DEFAULT_RESERVED_KEYWORD_COLOR), 208 new ReservedWord("final", DEFAULT_RESERVED_KEYWORD_COLOR), 209 new ReservedWord("abstract", DEFAULT_RESERVED_KEYWORD_COLOR), 210 new ReservedWord("native", DEFAULT_RESERVED_KEYWORD_COLOR), 211 new ReservedWord("static", DEFAULT_RESERVED_KEYWORD_COLOR), 212 new ReservedWord("transient", DEFAULT_RESERVED_KEYWORD_COLOR), 213 new ReservedWord("void", DEFAULT_PRIMITIVE_VAR_COLOR), 214 new ReservedWord("boolean", DEFAULT_PRIMITIVE_VAR_COLOR), 215 new ReservedWord("char", DEFAULT_PRIMITIVE_VAR_COLOR), 216 new ReservedWord("int", DEFAULT_PRIMITIVE_VAR_COLOR), 217 new ReservedWord("short", DEFAULT_PRIMITIVE_VAR_COLOR), 218 new ReservedWord("long", DEFAULT_PRIMITIVE_VAR_COLOR), 219 new ReservedWord("float", DEFAULT_PRIMITIVE_VAR_COLOR), 220 new ReservedWord("double", DEFAULT_PRIMITIVE_VAR_COLOR), 221 new ReservedWord("null", DEFAULT_SPECIAL_KEYWORD_COLOR), 222 new ReservedWord("true", DEFAULT_SPECIAL_KEYWORD_COLOR), 223 new ReservedWord("false", DEFAULT_SPECIAL_KEYWORD_COLOR) 224 }; 225 226 protected static Hashtable fast_keyword_map = null; 227 228 public ServeTextFile() { 229 State s = new State("serveTextFile", "Serve A Text File"); 230 s.addRequiredParameter("filename"); 231 this.addState(s); 232 233 s = new State("serveJavaFile", "Serve a Java File"); 234 s.addRequiredParameter("filename"); 235 this.addState(s); 236 237 String baseRootDir = ConfigManager.getWebAppDir() + "/WEB-INF/src"; 238 rootDirList.add(baseRootDir); 239 baseRootDir = ConfigManager.getWebAppDir(); 240 rootDirList.add(baseRootDir); 241 242 if (fileNameFilter == null) { 243 fileNameFilter = new Filter(new String []{"|", "..", ">", "<"}, 245 new String []{"", "", "", ""}); 246 } 247 248 if (fast_keyword_map == null) { 252 fast_keyword_map = new Hashtable (java_reserved_keywords.length); 253 254 for (int k = 0; k < java_reserved_keywords.length; ++k) { 255 fast_keyword_map.put(java_reserved_keywords[k].keyword, 256 java_reserved_keywords[k]); 257 } 258 } 259 260 this.setInitialState("serveJavaFile"); 261 this.setSchema(com.jcorporate.expresso.core.ExpressoSchema.class); 262 } 263 264 274 protected ControllerResponse runServeTextFileState(ControllerRequest request, 275 ControllerResponse response) throws ControllerException { 276 277 ServletControllerRequest servRequest; 278 try { 279 servRequest = (ServletControllerRequest) request; 280 } catch (ClassCastException ex) { 281 throw new ControllerException("This controller must be run within only a http environment"); 282 } 283 284 285 HttpServletRequest req = (HttpServletRequest ) servRequest.getServletRequest(); 290 HttpServletResponse res = (HttpServletResponse ) servRequest.getServletResponse(); 291 Servlet servlet = servRequest.getCallingServlet(); 292 293 String fileSep = System.getProperty("file.separator"); 294 String inputFilename = req.getParameter("filename"); 295 296 try { 297 298 if (inputFilename == null) { 300 throw new ControllerException("filename parameter is not set."); 301 } 302 303 inputFilename = fileNameFilter.stripFilter(inputFilename); 311 312 if (inputFilename.length() == 0) { 313 throw new ControllerException("filename parameter is not set."); 314 } 315 316 if (!(inputFilename.endsWith(".java") || 317 inputFilename.endsWith(".cpp") || 318 inputFilename.endsWith(".cc") || 319 inputFilename.endsWith(".jpg") || 320 inputFilename.endsWith(".jpeg") || 321 inputFilename.endsWith(".png") || 322 inputFilename.endsWith(".jsp") || 323 inputFilename.endsWith(".txt") || 324 inputFilename.endsWith(".wm"))) { 325 throw new ControllerException("Sorry, it is forbidden to serve this type of file."); 326 } 327 328 boolean fileWasServed = false; 329 330 for (int k = 0; k < rootDirList.size(); ++k) { 331 String rootDir = (String ) rootDirList.elementAt(k); 332 File file = new File (rootDir, inputFilename); 333 String filename = file.getPath(); 334 335 if (file.exists()) { 336 if (!file.canRead()) { 337 throw new IOException ("not readable filename:`" + 338 inputFilename + "'"); 339 } 340 if (file.isDirectory()) { 341 throw new IOException ("cannot serve a directory as filename:`" + 342 inputFilename + "'"); 343 } 344 345 fileWasServed = true; 346 response.setCustomResponse(true); 350 351 String contentType = servlet.getServletConfig().getServletContext().getMimeType(filename); 353 354 if (contentType == null) { 355 contentType = "text/plain"; 356 } 357 358 if (log.isInfoEnabled()) { 359 log.info("BasicFileServeServlet: Serving file:`" + filename + 360 "' type:" + contentType); 361 } 362 363 ByteArrayOutputStream baos = new ByteArrayOutputStream (8192); 365 366 returnFile(filename, baos); 368 369 OutputStream out = res.getOutputStream(); 372 res.setContentType(contentType); 373 baos.writeTo(out); 374 out.flush(); 375 out.close(); 376 break; 377 } 378 } 379 if (!fileWasServed) { 380 throw new FileNotFoundException ("no such file: `" + 381 inputFilename + "'"); 382 } 383 } catch (FileNotFoundException ex) { 384 log.error("FileNotFoundException locating file file", ex); 385 throw new ControllerException("FileNotFoundException Error transferring file", ex); 386 } catch (java.io.IOException ioe) { 387 log.error("I/O Error transferring file", ioe); 388 throw new ControllerException("I/O Error transferring file", ioe); 389 } 390 391 return response; 392 } 393 394 protected void returnFile(String filename, OutputStream out) 395 throws FileNotFoundException , IOException { 396 FileInputStream fis = null; 397 398 try { 399 fis = new FileInputStream (filename); 400 401 byte[] buffer = new byte[8192]; 402 int bytesRead; 403 404 while ((bytesRead = fis.read(buffer)) != -1) { 405 out.write(buffer, 0, bytesRead); 406 } 407 } finally { 408 if (fis != null) { 409 fis.close(); 410 } 411 } 412 } 413 414 429 protected ControllerResponse runServeJavaFileState(ControllerRequest request, 430 ControllerResponse response) throws ControllerException { 431 ServletControllerRequest servRequest; 432 try { 433 servRequest = (ServletControllerRequest) request; 434 } catch (ClassCastException ex) { 435 throw new ControllerException("This controller must be run within only a http environment"); 436 } 437 438 439 HttpServletRequest req = (HttpServletRequest ) servRequest.getServletRequest(); 444 HttpSession session = req.getSession(true); 445 HttpServletResponse res = (HttpServletResponse ) servRequest.getServletResponse(); 446 Servlet servlet = servRequest.getCallingServlet(); 447 448 String fileSep = System.getProperty("file.separator"); 449 String inputFilename = req.getParameter("filename"); 450 451 try { 452 if (inputFilename == null) { 454 throw new ControllerException("filename parameter is not set."); 455 } 456 457 458 if (inputFilename == null) { 460 throw new ControllerException("filename parameter is not set."); 461 } 462 463 inputFilename = fileNameFilter.stripFilter(inputFilename); 471 472 if (inputFilename.length() == 0) { 473 throw new ControllerException("filename parameter is not set."); 474 } 475 476 if (!(inputFilename.endsWith(".java"))) { 477 throw new ControllerException( 478 "Sorry, it is forbidden to serve this type of file. This servlet only serves Java source files!"); 479 } 480 481 boolean fileWasServed = false; 482 483 for (int k = 0; k < rootDirList.size(); ++k) { 484 String rootDir = (String ) rootDirList.elementAt(k); 485 File file = new File (rootDir, inputFilename); 486 String filename = file.getPath(); 487 488 if (file.exists()) { 489 if (!file.canRead()) { 490 throw new IOException ("not readable filename:`" + 491 inputFilename + "'"); 492 } 493 if (file.isDirectory()) { 494 throw new IOException ("cannot serve a directory as filename:`" + 495 inputFilename + "'"); 496 } 497 498 fileWasServed = true; 499 500 response.setCustomResponse(true); 504 505 String contentType = "text/html"; 507 if (log.isInfoEnabled()) { 508 log.info("JavaFileServeServlet: Serving file:`" + filename + 509 "' type:" + contentType); 510 } 511 512 ByteArrayOutputStream baos = new ByteArrayOutputStream (32678); 514 PrintStream prs = new PrintStream (baos); 515 516 Parameters params = new Parameters(); 518 params.req = req; 519 params.res = res; 520 params.session = session; 521 params.inputFilename = inputFilename; 522 params.filename = filename; 523 params.out = prs; 524 525 returnHTMLFormattedFile(params); 527 prs.flush(); 529 OutputStream out = res.getOutputStream(); 532 res.setContentType(contentType); 533 baos.writeTo(out); 534 out.flush(); 535 out.close(); 536 break; 537 } 538 } 539 if (!fileWasServed) { 540 throw new FileNotFoundException ("no such file: `" + 541 inputFilename + "'"); 542 } 543 544 } catch (FileNotFoundException ex) { 545 log.error("FileNotFoundException locating file file", ex); 546 throw new ControllerException("FileNotFoundException Error transferring file", ex); 547 } catch (java.io.IOException ioe) { 548 log.error("I/O Error transferring file", ioe); 549 throw new ControllerException("I/O Error transferring file", ioe); 550 } 551 552 return response; 553 } 554 555 public void returnHTMLFormattedFile(Parameters params) 556 throws FileNotFoundException , IOException { 557 writeHeader(params); 558 writeContent(params); 559 writeFooter(params); 560 } 561 562 public void writeHeader(Parameters params) 563 throws FileNotFoundException , IOException { 564 PrintStream out = params.out; 565 out.println("<html>"); 566 out.println("<head>"); 567 out.println("<title>Java Source File: `" + params.inputFilename + 568 "'</title>"); 569 out.println("<meta name=\"generator\" value=\"" + 570 getClass().getName() + "\" >"); 571 out.println("<meta name=\"published_date\" value=\"" + new Date () + 572 "\" >"); 573 out.println("</head>"); 574 out.println("<body bgcolor=\"#FFFFFF\" >"); 575 576 File file = new File (params.filename); 577 out.println("<p><font face=\"Lucida, Georgia, Arial,Helvetica\" size=\"-1\" color=\"#000000\" >filename: <b>" + 578 params.inputFilename + "</b><br>"); 579 out.println("file size: <b>" + file.length() + "</b><br>"); 580 out.println("last modified: <b>" + new Date (file.lastModified()) + 581 "</b><br>"); 582 out.println("</font></p>"); 583 } 584 585 protected void writeFooter(Parameters params) 586 throws FileNotFoundException , IOException { 587 PrintStream out = params.out; 588 out.println("</body>"); 589 out.println("</html>"); 590 } 591 592 protected void writeContent(Parameters params) 593 throws FileNotFoundException , IOException { 594 PrintStream out = params.out; 595 FileInputStream fis = null; 596 BufferedInputStream bis = null; 597 PushbackInputStream pis = null; 598 boolean insideDQuote = false; 599 boolean insideSQuote = false; 600 boolean cstyleComment = false; 601 602 try { 603 604 fis = new FileInputStream (params.filename); 606 bis = new BufferedInputStream (fis, 8192); 607 pis = new PushbackInputStream (bis, 256); 608 609 out.println("<pre>"); 611 out.println("<font face=\"Courier New, Monospace, Helvetica, San-serif\" size=\"+0\" color=\"#000000\" >"); 612 613 int c1 = pis.read(); 614 615 while (c1 >= 0) { 616 617 while (Character.isWhitespace((char) c1)) { 619 out.print((char) c1); 620 c1 = pis.read(); 621 } 622 if (c1 < 0) { 623 624 break; 626 } 627 628 if (log.isDebugEnabled()) { 629 System.out.print((char) c1); 630 } 631 632 if (c1 == '/') { 633 int c2 = pis.read(); 634 635 if (c2 == '/') { 636 637 out.print("<font color=\"" + cplusCommentColor + 639 "\">//"); 640 641 if (log.isDebugEnabled()) { 642 System.out.println("C++ comment"); 643 } 644 645 c2 = pis.read(); 646 647 while (c2 != -1 && c2 != '\n') { 648 out.print(substituteEntity((char) c2)); 649 c2 = pis.read(); 650 } 651 652 out.print("</font>\n"); 653 c1 = pis.read(); continue; 655 } else if (c2 == '*') { 656 657 if (log.isDebugEnabled()) { 659 System.out.println("C comment start"); 660 } 661 cstyleComment = true; 662 out.print("<font color=\"" + cstyleCommentColor + 663 "\">/*"); 664 c1 = pis.read(); continue; 666 } else { 667 pis.unread(c2); 668 } 669 } else if (c1 == '*') { 670 int c2 = pis.read(); 671 672 if (c2 == '/') { 673 674 if (log.isDebugEnabled()) { 676 System.out.println("C comment end"); } 678 679 cstyleComment = false; 680 out.print("*/</font>"); 681 c1 = pis.read(); continue; 683 } else { 684 pis.unread(c2); 685 } 686 } 687 if (c1 == '\"' && !cstyleComment) { 688 if (!insideDQuote) { 689 out.print("<font color=\"" + doubleQuoteColor + 690 "\">""); 691 } else { 692 out.print(""</font>"); 693 } 694 695 insideDQuote = !insideDQuote; 696 if (log.isDebugEnabled()) { 697 System.out.println("double quotes:" + insideDQuote); 698 } 699 } else if (c1 == '\'' && !cstyleComment && !insideDQuote) { 700 if (!insideSQuote) { 701 out.print("<font color=\"" + singleQuoteColor + 702 "\">'"); 703 } else { 704 out.print("'</font>"); 705 } 706 707 insideSQuote = !insideSQuote; 708 if (log.isDebugEnabled()) { 709 System.out.println("single quotes:" + insideSQuote); 710 } 711 } else if (Character.isDigit((char) c1) && !cstyleComment && 712 !insideSQuote && !insideDQuote) { 713 714 boolean valid = true; 717 StringBuffer tokenBuffer = new StringBuffer (); 718 tokenBuffer.append((char) c1); 719 720 int c2 = pis.read(); 721 722 while (Character.isDigit((char) c2)) { 723 tokenBuffer.append((char) c2); 724 c2 = pis.read(); 725 } 726 727 pis.mark(256); 728 if (log.isDebugEnabled()) { 729 System.out.println("(1) token=`" + tokenBuffer.toString() + 730 "' (c2:" + c2 + "<" + (char) c2 + ")"); 731 } 732 733 if (c2 == '.') { 734 tokenBuffer.append((char) c2); 735 c2 = pis.read(); 736 if (log.isDebugEnabled()) { 737 System.out.println("(2) token=`" + 738 tokenBuffer.toString() + "' (c2:" + c2 + 739 "<" + (char) c2 + ")"); 740 } 741 742 if (c2 == 'e' || c2 == 'E') { 743 tokenBuffer.append((char) c2); 744 c2 = pis.read(); 745 if (log.isDebugEnabled()) { 746 System.out.println("(3) token=`" + 747 tokenBuffer.toString() + 748 "' (c2:" + c2 + "<" + (char) c2 + 749 ")"); 750 } 751 } 752 753 System.out.println("(4) token=`" + 754 tokenBuffer.toString() + "' (c2:" + c2 + 755 "<" + (char) c2 + ")"); 756 757 if (c2 == '+' || c2 == '-') { 758 tokenBuffer.append((char) c2); 759 c2 = pis.read(); 760 } 761 if (Character.isDigit((char) c2)) { 762 while (Character.isDigit((char) c2)) { 763 tokenBuffer.append((char) c2); 764 c2 = pis.read(); 765 } 766 } else { 767 768 valid = false; 771 pis.reset(); 772 } 773 } 774 775 pis.unread(c2); 777 if (valid) { 778 out.print("<font color=\"" + decimalNumberColor + 779 "\" >"); 780 } 781 782 out.print(tokenBuffer.toString()); 783 784 if (valid) { 785 out.print("</font>"); 786 } 787 } else if (Character.isLetter((char) c1) && !cstyleComment && 788 !insideSQuote && !insideDQuote) { 789 790 StringBuffer tokenBuffer = new StringBuffer (); 792 tokenBuffer.append((char) c1); 793 794 int c2 = pis.read(); 795 796 while (Character.isLetter((char) c2)) { 797 tokenBuffer.append((char) c2); 798 c2 = pis.read(); 799 } 800 801 pis.unread(c2); 803 boolean wasMatched = false; 805 String token = tokenBuffer.toString(); 806 if (log.isDebugEnabled()) { 807 System.out.println("<" + token + ">(" + c2 + "/`" + 808 (char) c2 + "')"); 809 } 810 811 ReservedWord reservedWord = (ReservedWord) fast_keyword_map.get(token); 812 813 if (reservedWord != null) { 814 815 wasMatched = true; 817 } 818 if (wasMatched) { 819 out.print("<font color=\"" + reservedWord.htmlcolor + 820 "\" >"); 821 } 822 823 out.print(token); 824 825 if (wasMatched) { 826 out.print("</font>"); 827 } 828 } else { 829 out.print(substituteEntity((char) c1)); 830 } 831 832 c1 = pis.read(); 834 } 835 836 out.println("</font>"); 838 out.println("</pre>"); 839 } finally { 840 if (pis != null) { 841 pis.close(); 842 } 843 if (fis != null) { 844 fis.close(); 845 } 846 } 847 } 848 849 protected static final String substituteEntity(char c9) { 850 switch (c9) { 851 case '<': 852 return "<"; 853 854 case '>': 855 return ">"; 856 857 case '&': 858 return "&"; 859 860 case '\"': 861 return """; 862 } 863 864 return new String (new char[]{c9}); 865 } 866 867 public String getTitle() { 868 return "Serve Text File"; 869 } 870 871 872 } | Popular Tags |