From f698484d64b432e37be12c134771098ed64ebbe6 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 16 Oct 2020 16:47:06 -0500 Subject: [PATCH 01/11] Implement static ext whitelist --- gradle/version | 2 +- src/main/java/runwar/RunwarConfigurer.java | 70 ++++++++++++++++++- .../runwar/options/CommandLineHandler.java | 13 +++- .../java/runwar/options/ServerOptions.java | 7 +- .../runwar/options/ServerOptionsImpl.java | 21 +++++- 5 files changed, 108 insertions(+), 5 deletions(-) diff --git a/gradle/version b/gradle/version index 9f7be106..8363d4dd 100644 --- a/gradle/version +++ b/gradle/version @@ -1 +1 @@ -4.3.8-b7a54e666cee480f6145bed79c6b3f7062f156fa-da454ea547dcae2592feedc25198527264f06e3b \ No newline at end of file +4.3.9-949be4358db1368e821d3f1ed69e9fea80e4512f-7378622296451aea80c3ced3009313d4e2c604da \ No newline at end of file diff --git a/src/main/java/runwar/RunwarConfigurer.java b/src/main/java/runwar/RunwarConfigurer.java index 1f99a6f0..87a2be80 100644 --- a/src/main/java/runwar/RunwarConfigurer.java +++ b/src/main/java/runwar/RunwarConfigurer.java @@ -21,6 +21,7 @@ import java.nio.file.Paths; import java.security.GeneralSecurityException; import java.util.*; +import java.util.BitSet; import static io.undertow.Handlers.predicate; import static io.undertow.servlet.Servlets.servlet; @@ -414,10 +415,31 @@ public void handleChanges(Collection changes) { }); */ + // Default list of what the default servlet will serve + String allowedExt = "aif,aiff,au,avi,bmp,btm,btm,css,csv,doc,docx,eps,font,gif,gif,htm,html,ico,ini,jpeg,jpg,js,json,map,mid,midi,mov,mp3,mp4,mpeg4,pdf,png,ppt,pptx,psd,ra,rtf,tar,tif,ttf,txt,wav,wmf,xls,xlsx,xml,zip,woff,woff2,eot"; + // Add any custom additions by our users + if( serverOptions.defaultServletAllowedExt().length() > 0 ) { + allowedExt += "," + serverOptions.defaultServletAllowedExt(); + } + + LOG.info("Extensions allowed by the default servlet for static files: " + allowedExt); + + allowedExt = allowedExt.toLowerCase(); + StringBuilder allowedExtBuilder = new StringBuilder(); + for( String ext : allowedExt.split(",") ) { + expandExtension( ext, allowedExtBuilder ); + } + allowedExt = allowedExtBuilder.toString(); + if( allowedExt.endsWith(",") ) { + allowedExt = allowedExt.substring(0, allowedExt.length()-1); + } + // this prevents us from having to use our own ResourceHandler (directory listing, welcome files, see below) and error handler for now servletBuilder.addServlet( new ServletInfo(io.undertow.servlet.handlers.ServletPathMatches.DEFAULT_SERVLET_NAME, DefaultServlet.class) .addInitParam("directory-listing", Boolean.toString(serverOptions.directoryListingEnable())) - .addInitParam("disallowed-extensions", "CFC,cfc,Cfc,CFc,cFc,cfC,CfC,cFC,CFM,cfm,Cfm,CFm,cFm,cfM,CfM,cFM,CFML,cfmL,CfmL,CFmL,cFmL,cfML,CfML,cFML,CFMl,cfml,Cfml,CFml,cFml,cfMl,CfMl,cFMl") + .addInitParam("default-allowed", "false") + .addInitParam("allowed-extensions", allowedExt) + //.addInitParam("disallowed-extensions", "CFC,cfc,Cfc,CFc,cFc,cfC,CfC,cFC,CFM,cfm,Cfm,CFm,cFm,cfM,CfM,cFM,CFML,cfmL,CfmL,CFmL,cFmL,cfML,CfML,cFML,CFMl,cfml,Cfml,CFml,cFml,cfMl,CfMl,cFMl") .addInitParam("allow-post", "true") ); List welcomePages = servletBuilder.getWelcomePages(); @@ -447,6 +469,52 @@ public void handleChanges(Collection changes) { } } + + void expandExtension(String input, StringBuilder allowedExtBuilder) { + char[] currentCombo = input.toCharArray(); + + // Create a bit vector the same length as the input, and set all of the bits to 1 + BitSet bv = new BitSet(input.length()); + bv.set(0, currentCombo.length); + + // While the bit vector still has some bits set + while(!bv.isEmpty()) { + // Loop through the array of characters and set each one to uppercase or lowercase, + // depending on whether its corresponding bit is set + for(int i = 0; i < currentCombo.length; ++i) { + if(bv.get(i)) // If the bit is set + currentCombo[i] = Character.toUpperCase(currentCombo[i]); + else + currentCombo[i] = Character.toLowerCase(currentCombo[i]); + } + + // append the current combination + allowedExtBuilder.append(currentCombo); + allowedExtBuilder.append(","); + + // Decrement the bit vector + DecrementBitVector(bv, currentCombo.length); + } + + // Now the bit vector contains all zeroes, which corresponds to all of the letters being lowercase. + // Simply append the input as lowercase for the final combination + allowedExtBuilder.append(input.toLowerCase()); + allowedExtBuilder.append(","); + } + + + public void DecrementBitVector(BitSet bv, int numberOfBits) { + int currentBit = numberOfBits - 1; + while(currentBit >= 0) { + bv.flip(currentBit); + + // If the bit became a 0 when we flipped it, then we're done. + // Otherwise we have to continue flipping bits + if(!bv.get(currentBit)) + break; + currentBit--; + } + } void generateSelfSignedCertificate() throws GeneralSecurityException, IOException { Path defaultCertPath, defaultKeyPath; diff --git a/src/main/java/runwar/options/CommandLineHandler.java b/src/main/java/runwar/options/CommandLineHandler.java index 1696ebe8..fb56890b 100644 --- a/src/main/java/runwar/options/CommandLineHandler.java +++ b/src/main/java/runwar/options/CommandLineHandler.java @@ -584,6 +584,12 @@ private static Options getOptions() { .hasArg().withArgName("firefox, chrome, opera, konqueror, epiphany, mozilla, netscape") .create(Keys.BROWSER)); + options.addOption(OptionBuilder + .withLongOpt("default-servlet-allowed-ext") + .withDescription("Additional allowed extensions to add to the default list.") + .hasArg().withArgName("log,foo,bar") + .create(Keys.DEFAULTSERVLETALLOWEDEXT)); + options.addOption(new Option("h", Keys.HELP, false, "print this message")); options.addOption(new Option("v", "version", false, "print runwar version and undertow version")); @@ -866,10 +872,15 @@ public static ServerOptions parseArguments(String[] args, ServerOptions serverOp if (hasOptionValue(line, Keys.LOGACCESS)) { serverOptions.logAccessEnable(Boolean.valueOf(line.getOptionValue(Keys.LOGACCESS))); } - + if (hasOptionValue(line, Keys.OPENBROWSER)) { serverOptions.openbrowser(Boolean.valueOf(line.getOptionValue("open"))); } + + if (hasOptionValue(line, Keys.DEFAULTSERVLETALLOWEDEXT)) { + serverOptions.defaultServletAllowedExt(line.getOptionValue(Keys.DEFAULTSERVLETALLOWEDEXT)); + } + if (line.hasOption(Keys.OPENURL)) { serverOptions.openbrowserURL(line.getOptionValue(Keys.OPENURL)); if (!line.hasOption(Keys.OPENBROWSER)) { diff --git a/src/main/java/runwar/options/ServerOptions.java b/src/main/java/runwar/options/ServerOptions.java index a14ba78d..91d866af 100644 --- a/src/main/java/runwar/options/ServerOptions.java +++ b/src/main/java/runwar/options/ServerOptions.java @@ -112,6 +112,7 @@ public static final class Keys { final static String UNDERTOWOPTIONS = "undertowOptions"; final static String XNIOOPTIONS = "xnioOptions"; final static String BROWSER = "browser"; + final static String DEFAULTSERVLETALLOWEDEXT = ""; } String defaultShell(); @@ -359,7 +360,11 @@ public static final class Keys { String browser(); ServerOptions browser(String browser); - + + String defaultServletAllowedExt(); + + ServerOptions defaultServletAllowedExt(String defaultServletAllowedExt); + ServerOptions sslCertificate(File file); File sslCertificate(); diff --git a/src/main/java/runwar/options/ServerOptionsImpl.java b/src/main/java/runwar/options/ServerOptionsImpl.java index 9f0a7004..97dcdc1e 100644 --- a/src/main/java/runwar/options/ServerOptionsImpl.java +++ b/src/main/java/runwar/options/ServerOptionsImpl.java @@ -68,7 +68,7 @@ public class ServerOptionsImpl implements ServerOptions { private String action = "start"; private String browser = ""; - + private String cfengineName = ""; private boolean customHTTPStatusEnable = true; @@ -127,6 +127,8 @@ public class ServerOptionsImpl implements ServerOptions { public String logPattern = "[%-5p] %c: %m%n"; + private String defaultServletAllowedExt = ""; + private final Map aliases = new HashMap<>(); private Set contentDirectories = new HashSet<>(); @@ -2133,6 +2135,23 @@ public ServerOptions service(boolean enable) { return this; } + /* + * @see runwar.options.ServerOptions#defaultServletAllowedExt() + */ + @Override + public String defaultServletAllowedExt() { + return defaultServletAllowedExt; + } + + /* + * @see runwar.options.ServerOptions#defaultServletAllowedExt(boolean) + */ + @Override + public ServerOptions defaultServletAllowedExt(String defaultServletAllowedExt) { + this.defaultServletAllowedExt = defaultServletAllowedExt; + return this; + } + /** * @see runwar.options.ServerOptions#xnioOptions(java.lang.String) */ From d0b741085ad4ca3cfc55ebb50041009f965727ad Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 20 Oct 2020 17:07:03 -0500 Subject: [PATCH 02/11] Additional ext --- src/main/java/runwar/RunwarConfigurer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/runwar/RunwarConfigurer.java b/src/main/java/runwar/RunwarConfigurer.java index 87a2be80..b6db3ac1 100644 --- a/src/main/java/runwar/RunwarConfigurer.java +++ b/src/main/java/runwar/RunwarConfigurer.java @@ -416,7 +416,7 @@ public void handleChanges(Collection changes) { */ // Default list of what the default servlet will serve - String allowedExt = "aif,aiff,au,avi,bmp,btm,btm,css,csv,doc,docx,eps,font,gif,gif,htm,html,ico,ini,jpeg,jpg,js,json,map,mid,midi,mov,mp3,mp4,mpeg4,pdf,png,ppt,pptx,psd,ra,rtf,tar,tif,ttf,txt,wav,wmf,xls,xlsx,xml,zip,woff,woff2,eot"; + String allowedExt = "aif,aiff,au,avi,bmp,btm,btm,css,csv,doc,docx,eps,font,gif,gif,htm,html,ico,ini,jpeg,jpg,js,json,map,mid,midi,mov,mp3,mp4,mpeg4,pdf,png,ppt,pptx,psd,ra,rtf,tar,tif,ttf,txt,wav,wmf,xls,xlsx,xml,zip,woff,woff2,eot,svgz"; // Add any custom additions by our users if( serverOptions.defaultServletAllowedExt().length() > 0 ) { allowedExt += "," + serverOptions.defaultServletAllowedExt(); From cd9d477c36146a2e4309c97419ec26d4ded07636 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 20 Oct 2020 17:12:16 -0500 Subject: [PATCH 03/11] one more extensions --- src/main/java/runwar/RunwarConfigurer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/runwar/RunwarConfigurer.java b/src/main/java/runwar/RunwarConfigurer.java index b6db3ac1..7479de79 100644 --- a/src/main/java/runwar/RunwarConfigurer.java +++ b/src/main/java/runwar/RunwarConfigurer.java @@ -416,7 +416,7 @@ public void handleChanges(Collection changes) { */ // Default list of what the default servlet will serve - String allowedExt = "aif,aiff,au,avi,bmp,btm,btm,css,csv,doc,docx,eps,font,gif,gif,htm,html,ico,ini,jpeg,jpg,js,json,map,mid,midi,mov,mp3,mp4,mpeg4,pdf,png,ppt,pptx,psd,ra,rtf,tar,tif,ttf,txt,wav,wmf,xls,xlsx,xml,zip,woff,woff2,eot,svgz"; + String allowedExt = "aif,aiff,au,avi,bmp,btm,btm,css,csv,doc,docx,eps,font,gif,gif,htm,html,ico,ini,jpeg,jpg,js,json,map,mid,midi,mov,mp3,mp4,mpeg4,pdf,png,ppt,pptx,psd,ra,rtf,tar,tif,ttf,txt,wav,wmf,xls,xlsx,xml,zip,woff,woff2,eot,svg,svgz"; // Add any custom additions by our users if( serverOptions.defaultServletAllowedExt().length() > 0 ) { allowedExt += "," + serverOptions.defaultServletAllowedExt(); From 7508f452e8a04cae5ef90ccccacd4db48e0f2586 Mon Sep 17 00:00:00 2001 From: Miguel Mathus Date: Wed, 21 Oct 2020 00:19:58 -0600 Subject: [PATCH 04/11] adding extensions --- src/main/java/runwar/RunwarConfigurer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/runwar/RunwarConfigurer.java b/src/main/java/runwar/RunwarConfigurer.java index 87a2be80..31f4dc5e 100644 --- a/src/main/java/runwar/RunwarConfigurer.java +++ b/src/main/java/runwar/RunwarConfigurer.java @@ -416,7 +416,7 @@ public void handleChanges(Collection changes) { */ // Default list of what the default servlet will serve - String allowedExt = "aif,aiff,au,avi,bmp,btm,btm,css,csv,doc,docx,eps,font,gif,gif,htm,html,ico,ini,jpeg,jpg,js,json,map,mid,midi,mov,mp3,mp4,mpeg4,pdf,png,ppt,pptx,psd,ra,rtf,tar,tif,ttf,txt,wav,wmf,xls,xlsx,xml,zip,woff,woff2,eot"; + String allowedExt = "3gp,7z,aif,aiff,aifc,aac,apk,asf,au,atom,avi,bak,bk,bz2,bin,bmp,btm,btm,css,csv,cdr,cmx,dat,deb,dtd,dll,dmg,doc,docx,eml,eps,exe,flv,fla,font,gif,gz,gzip,htm,html,iso,ico,ipa,img,ini,ia,indd,jar,jpeg,jpg,js,json,hey,lz,m4v,map,maf,markdown,md,mid,midi,mkv,mov,mp1,mp2,mp3,mp4,mpg,mpe,mpeg,mpeg4,msi,odt,ott,odg,odf,ots,ogg,pdf,png,pps,ppt,pptx,pot,psd,pmd,pub,ra,rar,raw,rpm,rtf,rss,svg,sdd,swf,tar,tif,tiff,ttf,tsv,txt,wav,wmv,wmf,xcf,xls,xlsx,xhtml,xml,yml,yaml,zip,woff,woff2,eot,webm"; // Add any custom additions by our users if( serverOptions.defaultServletAllowedExt().length() > 0 ) { allowedExt += "," + serverOptions.defaultServletAllowedExt(); From c73eb35bb79a8eee41989888e674d502cfcc3588 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 23 Oct 2020 13:07:29 -0500 Subject: [PATCH 05/11] Even more extensions --- src/main/java/runwar/RunwarConfigurer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/runwar/RunwarConfigurer.java b/src/main/java/runwar/RunwarConfigurer.java index 7a4193ab..1cc8b994 100644 --- a/src/main/java/runwar/RunwarConfigurer.java +++ b/src/main/java/runwar/RunwarConfigurer.java @@ -416,7 +416,7 @@ public void handleChanges(Collection changes) { */ // Default list of what the default servlet will serve - String allowedExt = "3gp,7z,aif,aiff,aifc,aac,apk,asf,au,atom,avi,bak,bk,bz2,bin,bmp,btm,css,csv,cdr,cmx,dat,deb,dtd,dll,dmg,doc,docx,eml,eps,exe,flv,fla,font,gif,gz,gzip,htm,html,iso,ico,ipa,img,ini,ia,indd,jar,jpeg,jpg,js,json,hey,lz,m4v,map,maf,markdown,md,mid,midi,mkv,mov,mp1,mp2,mp3,mp4,mpg,mpe,mpeg,mpeg4,msi,odt,ott,odg,odf,ots,ogg,pdf,png,pps,ppt,pptx,pot,psd,pmd,pub,ra,rar,raw,rpm,rtf,rss,svg,svgz,sdd,swf,tar,tif,tiff,ttf,tsv,txt,wav,wmv,wmf,xcf,xls,xlsx,xhtml,xml,yml,yaml,zip,woff,woff2,eot,webm"; + String allowedExt = "3gp,3gpp,7z,ai,aif,aiff,asf,asx,atom,au,avi,bin,bmp,btm,cco,crt,css,csv,deb,der,dmg,doc,docx,eot,eps,flv,font,gif,hqx,htc,htm,html,ico,img,ini,iso,jad,jng,jnlp,jpeg,jpg,js,json,kar,kml,kmz,m3u8,m4a,m4v,map,mid,midi,mml,mng,mov,mp3,mp4,mpeg,mpeg4,mpg,msi,msm,msp,ogg,otf,pdb,pdf,pem,pl,pm,png,ppt,pptx,prc,ps,psd,ra,rar,rpm,rss,rtf,run,sea,shtml,sit,svg,svgz,swf,tar,tcl,tif,tiff,tk,ts,ttf,txt,wav,wbmp,webm,webp,wmf,wml,wmlc,wmv,woff,woff2,xhtml,xls,xlsx,xml,xpi,xspf,zip,aifc,aac,apk,bak,bk,bz2,cdr,cmx,dat,dtd,eml,fla,gz,gzip,ipa,ia,indd,hey,lz,maf,markdown,md,mkv,mp1,mp2,mpe,odt,ott,odg,odf,ots,pps,pot,pmd,pub,raw,sdd,tsv,xcf,yml,yaml"; // Add any custom additions by our users if( serverOptions.defaultServletAllowedExt().length() > 0 ) { allowedExt += "," + serverOptions.defaultServletAllowedExt(); From ff62de0faf9e8ca4b31669ea4a2685708643c79b Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 24 Oct 2020 00:48:11 -0500 Subject: [PATCH 06/11] Experimental features for case sensitivity --- gradle/version | 2 +- src/main/java/runwar/RunwarConfigurer.java | 1 - src/main/java/runwar/Server.java | 2 +- .../java/runwar/logging/LoggerFactory.java | 4 +- .../runwar/options/CommandLineHandler.java | 21 +++ .../java/runwar/options/ServerOptions.java | 12 +- .../runwar/options/ServerOptionsImpl.java | 41 +++++- .../undertow/MappedResourceManager.java | 139 ++++++++++++++++-- 8 files changed, 204 insertions(+), 18 deletions(-) diff --git a/gradle/version b/gradle/version index 8363d4dd..4d66b10f 100644 --- a/gradle/version +++ b/gradle/version @@ -1 +1 @@ -4.3.9-949be4358db1368e821d3f1ed69e9fea80e4512f-7378622296451aea80c3ced3009313d4e2c604da \ No newline at end of file +4.3.10-c73eb35bb79a8eee41989888e674d502cfcc3588-7378622296451aea80c3ced3009313d4e2c604da \ No newline at end of file diff --git a/src/main/java/runwar/RunwarConfigurer.java b/src/main/java/runwar/RunwarConfigurer.java index 1cc8b994..1f30b335 100644 --- a/src/main/java/runwar/RunwarConfigurer.java +++ b/src/main/java/runwar/RunwarConfigurer.java @@ -439,7 +439,6 @@ public void handleChanges(Collection changes) { .addInitParam("directory-listing", Boolean.toString(serverOptions.directoryListingEnable())) .addInitParam("default-allowed", "false") .addInitParam("allowed-extensions", allowedExt) - //.addInitParam("disallowed-extensions", "CFC,cfc,Cfc,CFc,cFc,cfC,CfC,cFC,CFM,cfm,Cfm,CFm,cFm,cfM,CfM,cFM,CFML,cfmL,CfmL,CFmL,cFmL,cfML,CfML,cFML,CFMl,cfml,Cfml,CFml,cFml,cfMl,CfMl,cFMl") .addInitParam("allow-post", "true") ); List welcomePages = servletBuilder.getWelcomePages(); diff --git a/src/main/java/runwar/Server.java b/src/main/java/runwar/Server.java index 33530036..0eecce02 100644 --- a/src/main/java/runwar/Server.java +++ b/src/main/java/runwar/Server.java @@ -932,7 +932,7 @@ public void stopServer() { } ResourceManager getResourceManager(File warFile, Long transferMinSize, Set contentDirs, Map aliases, File internalCFMLServerRoot) { - MappedResourceManager mappedResourceManager = new MappedResourceManager(warFile, transferMinSize, contentDirs, aliases, internalCFMLServerRoot); + MappedResourceManager mappedResourceManager = new MappedResourceManager(warFile, transferMinSize, contentDirs, aliases, internalCFMLServerRoot,serverOptions); if (serverOptions.directoryListingRefreshEnable() || !serverOptions.bufferEnable()) { return mappedResourceManager; } diff --git a/src/main/java/runwar/logging/LoggerFactory.java b/src/main/java/runwar/logging/LoggerFactory.java index 45d593bd..b982fc10 100644 --- a/src/main/java/runwar/logging/LoggerFactory.java +++ b/src/main/java/runwar/logging/LoggerFactory.java @@ -125,7 +125,9 @@ public static synchronized void configure(ServerOptions options) { // This logger is only used in the resource mapper and is really chatty // Consider a setting to enable it only when troubleshooting file system mapping issues - //RUNWAR_REQUEST.setLevel(level); + if( serverOptions.resourceManagerLogging() ) { + RUNWAR_REQUEST.setLevel(level); + } Logger.getRootLogger().setLevel(level); configureUrlRewriteLoggers(true); diff --git a/src/main/java/runwar/options/CommandLineHandler.java b/src/main/java/runwar/options/CommandLineHandler.java index fb56890b..c3773d68 100644 --- a/src/main/java/runwar/options/CommandLineHandler.java +++ b/src/main/java/runwar/options/CommandLineHandler.java @@ -590,6 +590,19 @@ private static Options getOptions() { .hasArg().withArgName("log,foo,bar") .create(Keys.DEFAULTSERVLETALLOWEDEXT)); + options.addOption(OptionBuilder + .withLongOpt("case-sensitive-web-server") + .withDescription("Experimental- force case sensitive or insensitive checks on web server") + .hasArg().withArgName("true|false") + .create(Keys.CASESENSITIVEWEBSERVER)); + + options.addOption(OptionBuilder + .withLongOpt("resource-manager-logging") + .withDescription("Enable low level file system logging in resource manager") + .hasArg().withArgName("true|false") + .create(Keys.RESOURCEMANAGERLOGGING)); + + options.addOption(new Option("h", Keys.HELP, false, "print this message")); options.addOption(new Option("v", "version", false, "print runwar version and undertow version")); @@ -881,6 +894,14 @@ public static ServerOptions parseArguments(String[] args, ServerOptions serverOp serverOptions.defaultServletAllowedExt(line.getOptionValue(Keys.DEFAULTSERVLETALLOWEDEXT)); } + if (hasOptionValue(line, Keys.CASESENSITIVEWEBSERVER)) { + serverOptions.caseSensitiveWebServer(Boolean.valueOf(line.getOptionValue(Keys.CASESENSITIVEWEBSERVER))); + } + + if (hasOptionValue(line, Keys.RESOURCEMANAGERLOGGING)) { + serverOptions.resourceManagerLogging(Boolean.valueOf(line.getOptionValue(Keys.RESOURCEMANAGERLOGGING))); + } + if (line.hasOption(Keys.OPENURL)) { serverOptions.openbrowserURL(line.getOptionValue(Keys.OPENURL)); if (!line.hasOption(Keys.OPENBROWSER)) { diff --git a/src/main/java/runwar/options/ServerOptions.java b/src/main/java/runwar/options/ServerOptions.java index 91d866af..3b14d39f 100644 --- a/src/main/java/runwar/options/ServerOptions.java +++ b/src/main/java/runwar/options/ServerOptions.java @@ -112,7 +112,9 @@ public static final class Keys { final static String UNDERTOWOPTIONS = "undertowOptions"; final static String XNIOOPTIONS = "xnioOptions"; final static String BROWSER = "browser"; - final static String DEFAULTSERVLETALLOWEDEXT = ""; + final static String DEFAULTSERVLETALLOWEDEXT = "defaultServletAllowedExt"; + final static String CASESENSITIVEWEBSERVER="caseSensitiveWebServer"; + final static String RESOURCEMANAGERLOGGING="resourceManagerLogging"; } String defaultShell(); @@ -364,6 +366,14 @@ public static final class Keys { String defaultServletAllowedExt(); ServerOptions defaultServletAllowedExt(String defaultServletAllowedExt); + + Boolean caseSensitiveWebServer(); + + ServerOptions caseSensitiveWebServer(Boolean caseSensitiveWebServer); + + Boolean resourceManagerLogging(); + + ServerOptions resourceManagerLogging(Boolean resourceManagerLogging); ServerOptions sslCertificate(File file); diff --git a/src/main/java/runwar/options/ServerOptionsImpl.java b/src/main/java/runwar/options/ServerOptionsImpl.java index 97dcdc1e..6b75037c 100644 --- a/src/main/java/runwar/options/ServerOptionsImpl.java +++ b/src/main/java/runwar/options/ServerOptionsImpl.java @@ -128,6 +128,11 @@ public class ServerOptionsImpl implements ServerOptions { public String logPattern = "[%-5p] %c: %m%n"; private String defaultServletAllowedExt = ""; + + private Boolean caseSensitiveWebServer= false; + + private Boolean resourceManagerLogging= false; + private final Map aliases = new HashMap<>(); @@ -2144,13 +2149,47 @@ public String defaultServletAllowedExt() { } /* - * @see runwar.options.ServerOptions#defaultServletAllowedExt(boolean) + * @see runwar.options.ServerOptions#defaultServletAllowedExt(String) */ @Override public ServerOptions defaultServletAllowedExt(String defaultServletAllowedExt) { this.defaultServletAllowedExt = defaultServletAllowedExt; return this; } + + /* + * @see runwar.options.ServerOptions#resourceManagerLogging() + */ + @Override + public Boolean resourceManagerLogging() { + return resourceManagerLogging; + } + + /* + * @see runwar.options.ServerOptions#resourceManagerLogging(boolean) + */ + @Override + public ServerOptions resourceManagerLogging(Boolean resourceManagerLogging) { + this.resourceManagerLogging = resourceManagerLogging; + return this; + } + + /* + * @see runwar.options.ServerOptions#caseSensitiveWebServer() + */ + @Override + public Boolean caseSensitiveWebServer() { + return caseSensitiveWebServer; + } + + /* + * @see runwar.options.ServerOptions#caseSensitiveWebServer(boolean) + */ + @Override + public ServerOptions caseSensitiveWebServer(Boolean caseSensitiveWebServer) { + this.caseSensitiveWebServer = caseSensitiveWebServer; + return this; + } /** * @see runwar.options.ServerOptions#xnioOptions(java.lang.String) diff --git a/src/main/java/runwar/undertow/MappedResourceManager.java b/src/main/java/runwar/undertow/MappedResourceManager.java index ac4b76a9..7113340a 100644 --- a/src/main/java/runwar/undertow/MappedResourceManager.java +++ b/src/main/java/runwar/undertow/MappedResourceManager.java @@ -1,6 +1,7 @@ package runwar.undertow; import java.io.File; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -16,29 +17,38 @@ import io.undertow.server.handlers.resource.FileResource; import io.undertow.server.handlers.resource.FileResourceManager; import io.undertow.server.handlers.resource.Resource; +import runwar.options.ServerOptions; import static runwar.logging.RunwarLogger.MAPPER_LOG; public class MappedResourceManager extends FileResourceManager { + private ServerOptions serverOptions; + private Boolean forceCaseSensitiveWebServer; + private Boolean forceCaseInsensitiveWebServer; private HashMap aliases; private HashSet contentDirs; private File WEBINF = null, CFIDE = null; + private static boolean isCaseSensitiveFS = caseSensitivityCheck(); private static final Pattern CFIDE_REGEX_PATTERN; private static final Pattern WEBINF_REGEX_PATTERN; static { CFIDE_REGEX_PATTERN = Pattern.compile("(?i)^.*[\\\\/]?CFIDE([\\\\/].*)?"); WEBINF_REGEX_PATTERN = Pattern.compile("(?i)^.*[\\\\/]?WEB-INF([\\\\/].*)?"); - } + } private final boolean allowResourceChangeListeners; - public MappedResourceManager(File base, long transferMinSize, Set contentDirs, Map aliases, File webinfDir) { + public MappedResourceManager(File base, long transferMinSize, Set contentDirs, Map aliases, File webinfDir, ServerOptions serverOptions) { super(base, transferMinSize); this.allowResourceChangeListeners = false; this.contentDirs = (HashSet) contentDirs; this.aliases = (HashMap) aliases; + this.serverOptions = serverOptions; + this.forceCaseSensitiveWebServer = serverOptions.caseSensitiveWebServer() != null && serverOptions.caseSensitiveWebServer(); + this.forceCaseInsensitiveWebServer = serverOptions.caseSensitiveWebServer() != null && !serverOptions.caseSensitiveWebServer(); + if(webinfDir != null){ WEBINF = webinfDir; CFIDE = new File(WEBINF.getParentFile(),"CFIDE"); @@ -92,18 +102,54 @@ public Resource getResource(String path) { } } } - if (reqFile != null && Files.exists(reqFile)) { - if(reqFile.toString().indexOf('\\') > 0) { - reqFile = Paths.get(reqFile.toString().replace('/', '\\')); - } - MAPPER_LOG.debugf("** path mapped to: '%s'", reqFile); - return new FileResource(reqFile.toFile(), this, path); - } else { - MAPPER_LOG.debugf("** No mapped resource for: '%s' (reqFile was: '%s')",path,reqFile != null ? reqFile.toString() : "null"); - return super.getResource(path); - } + + reqFile = pathExists(reqFile); + + if (reqFile == null ) { + MAPPER_LOG.debugf("** No mapped resource for: '%s' (reqFile was: '%s')",path,reqFile != null ? reqFile.toString() : "null"); + return super.getResource(path); + } + + if(reqFile.toString().indexOf('\\') > 0) { + reqFile = Paths.get(reqFile.toString().replace('/', '\\')); + } + + // Check for Windows doing silly things with file canonicalization + String originalPath = reqFile.toString(); + // The real path will return the actual file on the file system that is matched + // the original path may be in the wrong case and may have extra junk on the end that Windows removes when it canonicalizes + String realPath = reqFile.toRealPath().toString(); + String originalPathCase; + String realPathCase; + + // If this is a case insensitive file system like Windows and we're not forcing the web server to be case sensitive + // then compare the paths regardless of case. Or if this is a case sensitive file system like Linux + // and we're forcing it to be case insensitive + if( (!isCaseSensitiveFS && !forceCaseSensitiveWebServer) || ( isCaseSensitiveFS && forceCaseInsensitiveWebServer ) ) { + originalPathCase = originalPath.toLowerCase(); + realPathCase = realPath.toLowerCase(); + // For case sensitive file systems like Linux OR if we're forcing the web server to be case sensitive + // compare the real path exactly + } else { + originalPathCase = originalPath; + realPathCase = realPath; + } + + // make sure the path we found on the file system matches what was asked for. + if( !originalPathCase.equals( realPathCase ) ) { + throw new InvalidPathException( "Real file path [" + realPath + "] doesn't match [" + originalPath + "]", "" ); + } + + MAPPER_LOG.debugf("** path mapped to: '%s'", reqFile); + return new FileResource(reqFile.toFile(), this, path); + } catch( InvalidPathException e ){ MAPPER_LOG.debugf("** InvalidPathException for: '%s'",path != null ? path : "null"); + MAPPER_LOG.debug("** " + e.getMessage()); + return null; + } catch( IOException e ){ + MAPPER_LOG.debugf("** IOException for: '%s'",path != null ? path : "null"); + MAPPER_LOG.debug("** " + e.getMessage()); return null; } } @@ -137,6 +183,50 @@ static Path getAliasedFile(HashMap aliasMap, String path) { return null; } + Path pathExists(Path path) { + Boolean defaultCheck = Files.exists( path ); + if( defaultCheck ) { + return path; + } + if( isCaseSensitiveFS && forceCaseInsensitiveWebServer ) { + MAPPER_LOG.debugf("*** Case insensitive check for %s",path); + String realPath = ""; + String[] pathSegments = path.toString().replace('\\', '/').split( "/" ); + if( pathSegments.length > 0 && pathSegments[0].contains(":") ){ + realPath = pathSegments[0]; + } + Boolean first = true; + for( String thisSegment : pathSegments ) { + // Skip windows drive letter + if( realPath == pathSegments[0] && pathSegments[0].contains(":") && first ) { + first = false; + continue; + } + // Skip empty segments + if( thisSegment.length() == 0 ) { + continue; + } + + Boolean found = false; + for( String thisChild : new File( realPath + "/" ).list() ) { + // We're taking the FIRST MATCH. Buyer beware + if( thisSegment.equalsIgnoreCase(thisChild)) { + realPath += "/" + thisChild; + found = true; + break; + } + } + // If we made it through the inner loop without a match, we've hit a dead end + if( !found ) { + return null; + } + } + // If we made it through the outer loop, we've found a match + return Paths.get( realPath ); + } + return null; + } + private void processMappings(String cfmlDirList) { HashSet dirs = new HashSet<>(); // Stream.of(cfmlDirList.split(",")) @@ -198,5 +288,30 @@ private static String getRecentSteps() { return recentSteps.toString(); } + + private static boolean caseSensitivityCheck() { + return true; + /*try { + File currentWorkingDir = new File(System.getProperty("user.dir")); + File case1 = new File(currentWorkingDir, "case1"); + File case2 = new File(currentWorkingDir, "Case1"); + case1.createNewFile(); + if (case2.createNewFile()) { + MAPPER_LOG.debug("FileSystem of working directory is case sensitive"); + case1.delete(); + case2.delete(); + return true; + } else { + MAPPER_LOG.debug("FileSystem of working directory is NOT case sensitive"); + case1.delete(); + return false; + } + } catch (Throwable e) { + MAPPER_LOG.debug("Error detecting case sensitivity of file system."); + e.printStackTrace(); + } + return true; + */ + } } From 3b4aec354285588569dc18923d19c0c649471d99 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sun, 25 Oct 2020 17:08:12 -0500 Subject: [PATCH 07/11] Adobe needs null check --- src/main/java/runwar/undertow/MappedResourceManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/runwar/undertow/MappedResourceManager.java b/src/main/java/runwar/undertow/MappedResourceManager.java index 7113340a..51ef5f23 100644 --- a/src/main/java/runwar/undertow/MappedResourceManager.java +++ b/src/main/java/runwar/undertow/MappedResourceManager.java @@ -103,7 +103,9 @@ public Resource getResource(String path) { } } - reqFile = pathExists(reqFile); + if (reqFile != null ) { + reqFile = pathExists(reqFile); + } if (reqFile == null ) { MAPPER_LOG.debugf("** No mapped resource for: '%s' (reqFile was: '%s')",path,reqFile != null ? reqFile.toString() : "null"); From 218c5f631882406898a1e36c1ed3aaa0d10f1678 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sun, 25 Oct 2020 17:09:06 -0500 Subject: [PATCH 08/11] version bump --- gradle/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version b/gradle/version index 4d66b10f..4174964f 100644 --- a/gradle/version +++ b/gradle/version @@ -1 +1 @@ -4.3.10-c73eb35bb79a8eee41989888e674d502cfcc3588-7378622296451aea80c3ced3009313d4e2c604da \ No newline at end of file +4.3.11-ff62de0faf9e8ca4b31669ea4a2685708643c79b-7378622296451aea80c3ced3009313d4e2c604da \ No newline at end of file From a596ae135e1eea95ea80b56290e0536ba6a74759 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 30 Oct 2020 01:39:29 -0500 Subject: [PATCH 09/11] Fixes for symlinks --- gradle/version | 2 +- .../runwar/options/ServerOptionsImpl.java | 2 +- .../undertow/MappedResourceManager.java | 41 +++++++++++++------ 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/gradle/version b/gradle/version index 4174964f..38cfccd1 100644 --- a/gradle/version +++ b/gradle/version @@ -1 +1 @@ -4.3.11-ff62de0faf9e8ca4b31669ea4a2685708643c79b-7378622296451aea80c3ced3009313d4e2c604da \ No newline at end of file +4.3.12-218c5f631882406898a1e36c1ed3aaa0d10f1678-7378622296451aea80c3ced3009313d4e2c604da \ No newline at end of file diff --git a/src/main/java/runwar/options/ServerOptionsImpl.java b/src/main/java/runwar/options/ServerOptionsImpl.java index 6b75037c..f0f7ca56 100644 --- a/src/main/java/runwar/options/ServerOptionsImpl.java +++ b/src/main/java/runwar/options/ServerOptionsImpl.java @@ -129,7 +129,7 @@ public class ServerOptionsImpl implements ServerOptions { private String defaultServletAllowedExt = ""; - private Boolean caseSensitiveWebServer= false; + private Boolean caseSensitiveWebServer= null; private Boolean resourceManagerLogging= false; diff --git a/src/main/java/runwar/undertow/MappedResourceManager.java b/src/main/java/runwar/undertow/MappedResourceManager.java index 51ef5f23..3ef12de3 100644 --- a/src/main/java/runwar/undertow/MappedResourceManager.java +++ b/src/main/java/runwar/undertow/MappedResourceManager.java @@ -6,6 +6,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.InvalidPathException; +import java.nio.file.LinkOption; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -27,6 +28,7 @@ public class MappedResourceManager extends FileResourceManager { private Boolean forceCaseSensitiveWebServer; private Boolean forceCaseInsensitiveWebServer; private HashMap aliases; + private HashMap caseInsensitiveCache = new HashMap(); private HashSet contentDirs; private File WEBINF = null, CFIDE = null; private static boolean isCaseSensitiveFS = caseSensitivityCheck(); @@ -118,9 +120,10 @@ public Resource getResource(String path) { // Check for Windows doing silly things with file canonicalization String originalPath = reqFile.toString(); + // The real path will return the actual file on the file system that is matched // the original path may be in the wrong case and may have extra junk on the end that Windows removes when it canonicalizes - String realPath = reqFile.toRealPath().toString(); + String realPath = reqFile.toRealPath(LinkOption.NOFOLLOW_LINKS).toString(); String originalPathCase; String realPathCase; @@ -186,12 +189,22 @@ static Path getAliasedFile(HashMap aliasMap, String path) { } Path pathExists(Path path) { - Boolean defaultCheck = Files.exists( path ); - if( defaultCheck ) { - return path; - } - if( isCaseSensitiveFS && forceCaseInsensitiveWebServer ) { + Boolean defaultCheck = Files.exists( path ); + if( defaultCheck ) { + return path; + } + if( isCaseSensitiveFS && forceCaseInsensitiveWebServer ) { MAPPER_LOG.debugf("*** Case insensitive check for %s",path); + + Path cacheLookup = caseInsensitiveCache.get(path.toString()); + if( cacheLookup != null && Files.exists( cacheLookup ) ) { + MAPPER_LOG.tracef("*** Case insensitive lookup found in cache %s -> %s",path, cacheLookup); + return cacheLookup; + } else if( cacheLookup != null ) { + MAPPER_LOG.tracef("*** Case insensitive lookup removed from cache %s",path); + caseInsensitiveCache.remove(path.toString()); + } + String realPath = ""; String[] pathSegments = path.toString().replace('\\', '/').split( "/" ); if( pathSegments.length > 0 && pathSegments[0].contains(":") ){ @@ -209,7 +222,7 @@ Path pathExists(Path path) { continue; } - Boolean found = false; + Boolean found = false; for( String thisChild : new File( realPath + "/" ).list() ) { // We're taking the FIRST MATCH. Buyer beware if( thisSegment.equalsIgnoreCase(thisChild)) { @@ -224,9 +237,13 @@ Path pathExists(Path path) { } } // If we made it through the outer loop, we've found a match - return Paths.get( realPath ); - } - return null; + Path realPathFinal = Paths.get( realPath ); + + MAPPER_LOG.tracef("*** Case insensitive lookup put in cache %s -> %s",path,realPathFinal); + caseInsensitiveCache.put(path.toString(), realPathFinal ); + return realPathFinal; + } + return null; } private void processMappings(String cfmlDirList) { @@ -292,8 +309,7 @@ private static String getRecentSteps() { } private static boolean caseSensitivityCheck() { - return true; - /*try { + try { File currentWorkingDir = new File(System.getProperty("user.dir")); File case1 = new File(currentWorkingDir, "case1"); File case2 = new File(currentWorkingDir, "Case1"); @@ -313,7 +329,6 @@ private static boolean caseSensitivityCheck() { e.printStackTrace(); } return true; - */ } } From d9fcd26b256b9b15031616a3bf9d7badaf9a8c79 Mon Sep 17 00:00:00 2001 From: Miguel Mathus Date: Wed, 11 Nov 2020 14:52:56 -0600 Subject: [PATCH 10/11] renaming console appender --- .../java/runwar/logging/LoggerFactory.java | 518 +++++++++--------- 1 file changed, 259 insertions(+), 259 deletions(-) diff --git a/src/main/java/runwar/logging/LoggerFactory.java b/src/main/java/runwar/logging/LoggerFactory.java index b982fc10..14694775 100644 --- a/src/main/java/runwar/logging/LoggerFactory.java +++ b/src/main/java/runwar/logging/LoggerFactory.java @@ -1,259 +1,259 @@ -package runwar.logging; - -import runwar.options.ServerOptions; -import runwar.options.ServerOptionsImpl; - -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import org.apache.log4j.Appender; -import org.apache.log4j.ConsoleAppender; -import org.apache.log4j.Level; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; -import org.apache.log4j.PatternLayout; -import org.apache.log4j.RollingFileAppender; - -public class LoggerFactory { - - private static volatile boolean initialized = false; - private static volatile String logFile; - private static volatile String logLevel; - private static volatile String logPattern; - private static volatile List appenders; - private static volatile List loggers; - private static volatile List urlrewriteLoggers; - private static volatile RollingFileAppender rewriteLogAppender; - private static volatile ConsoleAppender consoleAppender; - private static ServerOptions serverOptions; - - public static synchronized void configure(ServerOptions options) { - - Logger.getRootLogger().getLoggerRepository().resetConfiguration(); - serverOptions = options; - logLevel = serverOptions.logLevel().toUpperCase(); - appenders = new ArrayList<>(); - loggers = new ArrayList<>(); - Level level = Level.toLevel(logLevel); - consoleAppender = consoleAppender(serverOptions.getLogPattern()); - appenders.add(consoleAppender); - Logger.getRootLogger().setLevel(Level.WARN); - Logger.getRootLogger().addAppender(consoleAppender); - - Logger DORKBOX_LOG = Logger.getLogger("dorkbox.systemTray.SystemTray"); - loggers.add(DORKBOX_LOG); - - Logger OSCACHE_LOG = Logger.getLogger("com.opensymphony.oscache.base.Config"); - loggers.add(OSCACHE_LOG); - - Logger JBOSS_LOG = Logger.getLogger("org.jboss.logging"); - loggers.add(JBOSS_LOG); - - Logger UNDERTOW_LOG = Logger.getLogger("io.undertow.servlet"); - loggers.add(UNDERTOW_LOG); - - Logger UNDERTOW_PREDICATE_LOG = Logger.getLogger("io.undertow.predicate"); - loggers.add(UNDERTOW_PREDICATE_LOG); - - Logger UNDERTOW_IO_LOG = Logger.getLogger("io.undertow"); - loggers.add(UNDERTOW_IO_LOG); - - Logger XNIO_LOG = Logger.getLogger("org.xnio"); - loggers.add(XNIO_LOG); - - Logger HTTP_CLIENT_LOG = Logger.getLogger("org.apache.http.client.protocol"); - loggers.add(HTTP_CLIENT_LOG); - - Logger RUNWAR_SERVER = Logger.getLogger("runwar.server"); - loggers.add(RUNWAR_SERVER); - - Logger RUNWAR_CONTEXT = Logger.getLogger("runwar.context"); - loggers.add(RUNWAR_CONTEXT); - - Logger RUNWAR_CONFIG = Logger.getLogger("runwar.config"); - loggers.add(RUNWAR_CONFIG); - - Logger RUNWAR_SECURITY = Logger.getLogger("runwar.security"); - loggers.add(RUNWAR_SECURITY); - - Logger RUNWAR_REQUEST = Logger.getLogger("runwar.request"); - loggers.add(RUNWAR_REQUEST); - - - Logger RUNWAR_BACKGROUND = Logger.getLogger("runwar.background"); - RUNWAR_BACKGROUND.addAppender(consoleAppender("%m%n")); - RUNWAR_BACKGROUND.setLevel(Level.TRACE); - RUNWAR_BACKGROUND.setAdditivity(false); - - if (serverOptions.urlRewriteLog() != null) { - rewriteLogAppender = new RollingFileAppender(); - rewriteLogAppender.setName("URLRewriteFileLogger"); - rewriteLogAppender.setFile(serverOptions.urlRewriteLog().getAbsolutePath()); - rewriteLogAppender.setLayout(new PatternLayout(serverOptions.getLogPattern())); - rewriteLogAppender.setThreshold(Level.toLevel(logLevel)); - rewriteLogAppender.setAppend(true); - rewriteLogAppender.setMaxFileSize("10MB"); - rewriteLogAppender.setMaxBackupIndex(3); - rewriteLogAppender.activateOptions(); - } - - RUNWAR_SERVER.setLevel(level); - RUNWAR_CONTEXT.setLevel(level); - RUNWAR_CONFIG.setLevel(Level.INFO); - RUNWAR_SECURITY.setLevel(Level.WARN); - RUNWAR_REQUEST.setLevel(Level.WARN); - DORKBOX_LOG.setLevel(Level.ERROR); - UNDERTOW_LOG.setLevel(Level.WARN); - UNDERTOW_IO_LOG.setLevel(Level.WARN); - XNIO_LOG.setLevel(Level.WARN); - HTTP_CLIENT_LOG.setLevel(Level.WARN); - System.setProperty("org.eclipse.jetty.LEVEL", "WARN"); - - - if (serverOptions.debug() || !logLevel.equalsIgnoreCase("info")) { - - if (logLevel.equalsIgnoreCase("trace")) { - DORKBOX_LOG.setLevel(level); - appenders.forEach(DORKBOX_LOG::addAppender); - UNDERTOW_LOG.setLevel(level); - UNDERTOW_PREDICATE_LOG.setLevel(level); - HTTP_CLIENT_LOG.setLevel(level); - RUNWAR_CONFIG.setLevel(level); - RUNWAR_SERVER.setLevel(level); - RUNWAR_CONTEXT.setLevel(level); - RUNWAR_SECURITY.setLevel(level); - - // This logger is only used in the resource mapper and is really chatty - // Consider a setting to enable it only when troubleshooting file system mapping issues - if( serverOptions.resourceManagerLogging() ) { - RUNWAR_REQUEST.setLevel(level); - } - - Logger.getRootLogger().setLevel(level); - configureUrlRewriteLoggers(true); - } else { - RUNWAR_REQUEST.setLevel(Level.INFO); - RUNWAR_SECURITY.setLevel(Level.DEBUG); - UNDERTOW_PREDICATE_LOG.setLevel(Level.DEBUG); - configureUrlRewriteLoggers(false); - } - } - - if (serverOptions.hasLogDir()) { - logFile = serverOptions.logDir().getPath() + '/' + serverOptions.logFileName() + ".out.txt"; - RollingFileAppender fa = new RollingFileAppender(); - fa.setName("FileLogger"); - fa.setFile(logFile); - fa.setLayout(new PatternLayout(serverOptions.logPattern())); - fa.setThreshold(Level.toLevel(logLevel)); - fa.setAppend(true); - fa.setMaxFileSize("10MB"); - fa.setMaxBackupIndex(10); - fa.activateOptions(); - appenders.add(fa); - Logger.getRootLogger().addAppender(fa); - } - Logger.getRootLogger().addAppender(consoleAppender); - - loggers.forEach(logger -> appenders.forEach(appender -> { - logger.addAppender(appender); - logger.setAdditivity(false); - })); - - initialized = true; - - if (System.getProperty("runwar.dumploggerstyles") != null) { - RunwarLogger.LOG.trace("This is a TRACE message"); - RunwarLogger.LOG.debug("This is a DEBUG message"); - RunwarLogger.LOG.warn("This is a WARN message"); - RunwarLogger.LOG.error("This is an ERROR message"); - } - } - - private static ConsoleAppender consoleAppender(String pattern) { - ConsoleAppender appender = new ConsoleAppender(); - PatternLayout layout = new PatternLayout(); - layout.setConversionPattern(pattern); - appender.setLayout(layout); - appender.setName("CONSOLE"); - appender.setThreshold(Level.toLevel(logLevel)); - appender.activateOptions(); - return appender; - } - - public static boolean isInitialized() { - return initialized; - } - - public static synchronized boolean initialize() { - return initialize(false); - } - - public static synchronized boolean initialize(boolean force) { - if (!initialized || force) - configure(new ServerOptionsImpl().logDir("")); - return initialized; - } - - public static void configureUrlRewriteLoggers(boolean isTrace) { - boolean hadLoggers = urlrewriteLoggers == null; - Logger REWRITE_CONDITION_LOG = Logger.getLogger("org.tuckey.web.filters.urlrewrite.Condition"); - Logger REWRITE_RULE_LOG = Logger.getLogger("org.tuckey.web.filters.urlrewrite.RuleBase"); - Logger REWRITE_SUBSTITUTION_LOG = Logger - .getLogger("org.tuckey.web.filters.urlrewrite.substitution.VariableReplacer"); - Logger REWRITE_EXECUTION_LOG = Logger.getLogger("org.tuckey.web.filters.urlrewrite.RuleExecutionOutput"); - Logger REWRITE_WRITER_LOG = Logger.getLogger("org.tuckey.web.filters.urlrewrite.UrlRewriter"); - Logger REWRITE_URL_LOG = Logger.getLogger("org.tuckey.web.filters.urlrewrite"); - Logger REWRITE_FILTER = Logger.getLogger("runwar.util.UrlRewriteFilter"); - Logger REWRITE_LOG = Logger.getLogger("org.tuckey.web.filters.urlrewrite.utils.Log"); - urlrewriteLoggers = new ArrayList<>(); - urlrewriteLoggers.add(REWRITE_CONDITION_LOG); - urlrewriteLoggers.add(REWRITE_RULE_LOG); - urlrewriteLoggers.add(REWRITE_SUBSTITUTION_LOG); - urlrewriteLoggers.add(REWRITE_EXECUTION_LOG); - urlrewriteLoggers.add(REWRITE_WRITER_LOG); - urlrewriteLoggers.add(REWRITE_URL_LOG); - urlrewriteLoggers.add(REWRITE_FILTER); - urlrewriteLoggers.add(REWRITE_LOG); - - if (rewriteLogAppender != null) { - RunwarLogger.CONF_LOG.infof("Enabling URL rewrite log: %s", rewriteLogAppender.getFile()); - urlrewriteLoggers.forEach(logger -> { - logger.addAppender(rewriteLogAppender); - logger.setAdditivity(false); - }); - } - - if (isTrace) { - RunwarLogger.CONF_LOG.infof("Enabling URL rewrite log level: %s", "TRACE"); - urlrewriteLoggers.forEach(logger -> { - logger.setLevel(Level.TRACE); - logger.addAppender(consoleAppender(serverOptions.getLogPattern())); - logger.setAdditivity(false); - }); - } else { - if(!hadLoggers){ - RunwarLogger.CONF_LOG.infof("Enabling URL rewrite log level: %s", "DEBUG"); - } - urlrewriteLoggers.forEach(logger -> { - logger.setLevel(Level.WARN); - logger.addAppender(consoleAppender(serverOptions.getLogPattern())); - logger.setAdditivity(false); - }); - REWRITE_EXECUTION_LOG.setLevel(Level.DEBUG); - REWRITE_WRITER_LOG.setLevel(Level.DEBUG); - } - } - - public static void listLoggers() { - for (Enumeration loggers = LogManager.getCurrentLoggers(); loggers.hasMoreElements();) { - Logger logger = (Logger) loggers.nextElement(); - System.out.println("Logger: " + logger.getName()); - for (Enumeration appenders = logger.getAllAppenders(); appenders.hasMoreElements();) { - Appender appender = (Appender) appenders.nextElement(); - System.out.println(" appender: " + appender.getName()); - } - } - } - -} +package runwar.logging; + +import runwar.options.ServerOptions; +import runwar.options.ServerOptionsImpl; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import org.apache.log4j.Appender; +import org.apache.log4j.ConsoleAppender; +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.log4j.PatternLayout; +import org.apache.log4j.RollingFileAppender; + +public class LoggerFactory { + + private static volatile boolean initialized = false; + private static volatile String logFile; + private static volatile String logLevel; + private static volatile String logPattern; + private static volatile List appenders; + private static volatile List loggers; + private static volatile List urlrewriteLoggers; + private static volatile RollingFileAppender rewriteLogAppender; + private static volatile ConsoleAppender consoleAppender; + private static ServerOptions serverOptions; + + public static synchronized void configure(ServerOptions options) { + + Logger.getRootLogger().getLoggerRepository().resetConfiguration(); + serverOptions = options; + logLevel = serverOptions.logLevel().toUpperCase(); + appenders = new ArrayList<>(); + loggers = new ArrayList<>(); + Level level = Level.toLevel(logLevel); + consoleAppender = consoleAppender(serverOptions.getLogPattern()); + appenders.add(consoleAppender); + Logger.getRootLogger().setLevel(Level.WARN); + Logger.getRootLogger().addAppender(consoleAppender); + + Logger DORKBOX_LOG = Logger.getLogger("dorkbox.systemTray.SystemTray"); + loggers.add(DORKBOX_LOG); + + Logger OSCACHE_LOG = Logger.getLogger("com.opensymphony.oscache.base.Config"); + loggers.add(OSCACHE_LOG); + + Logger JBOSS_LOG = Logger.getLogger("org.jboss.logging"); + loggers.add(JBOSS_LOG); + + Logger UNDERTOW_LOG = Logger.getLogger("io.undertow.servlet"); + loggers.add(UNDERTOW_LOG); + + Logger UNDERTOW_PREDICATE_LOG = Logger.getLogger("io.undertow.predicate"); + loggers.add(UNDERTOW_PREDICATE_LOG); + + Logger UNDERTOW_IO_LOG = Logger.getLogger("io.undertow"); + loggers.add(UNDERTOW_IO_LOG); + + Logger XNIO_LOG = Logger.getLogger("org.xnio"); + loggers.add(XNIO_LOG); + + Logger HTTP_CLIENT_LOG = Logger.getLogger("org.apache.http.client.protocol"); + loggers.add(HTTP_CLIENT_LOG); + + Logger RUNWAR_SERVER = Logger.getLogger("runwar.server"); + loggers.add(RUNWAR_SERVER); + + Logger RUNWAR_CONTEXT = Logger.getLogger("runwar.context"); + loggers.add(RUNWAR_CONTEXT); + + Logger RUNWAR_CONFIG = Logger.getLogger("runwar.config"); + loggers.add(RUNWAR_CONFIG); + + Logger RUNWAR_SECURITY = Logger.getLogger("runwar.security"); + loggers.add(RUNWAR_SECURITY); + + Logger RUNWAR_REQUEST = Logger.getLogger("runwar.request"); + loggers.add(RUNWAR_REQUEST); + + + Logger RUNWAR_BACKGROUND = Logger.getLogger("runwar.background"); + RUNWAR_BACKGROUND.addAppender(consoleAppender("%m%n")); + RUNWAR_BACKGROUND.setLevel(Level.TRACE); + RUNWAR_BACKGROUND.setAdditivity(false); + + if (serverOptions.urlRewriteLog() != null) { + rewriteLogAppender = new RollingFileAppender(); + rewriteLogAppender.setName("URLRewriteFileLogger"); + rewriteLogAppender.setFile(serverOptions.urlRewriteLog().getAbsolutePath()); + rewriteLogAppender.setLayout(new PatternLayout(serverOptions.getLogPattern())); + rewriteLogAppender.setThreshold(Level.toLevel(logLevel)); + rewriteLogAppender.setAppend(true); + rewriteLogAppender.setMaxFileSize("10MB"); + rewriteLogAppender.setMaxBackupIndex(3); + rewriteLogAppender.activateOptions(); + } + + RUNWAR_SERVER.setLevel(level); + RUNWAR_CONTEXT.setLevel(level); + RUNWAR_CONFIG.setLevel(Level.INFO); + RUNWAR_SECURITY.setLevel(Level.WARN); + RUNWAR_REQUEST.setLevel(Level.WARN); + DORKBOX_LOG.setLevel(Level.ERROR); + UNDERTOW_LOG.setLevel(Level.WARN); + UNDERTOW_IO_LOG.setLevel(Level.WARN); + XNIO_LOG.setLevel(Level.WARN); + HTTP_CLIENT_LOG.setLevel(Level.WARN); + System.setProperty("org.eclipse.jetty.LEVEL", "WARN"); + + + if (serverOptions.debug() || !logLevel.equalsIgnoreCase("info")) { + + if (logLevel.equalsIgnoreCase("trace")) { + DORKBOX_LOG.setLevel(level); + appenders.forEach(DORKBOX_LOG::addAppender); + UNDERTOW_LOG.setLevel(level); + UNDERTOW_PREDICATE_LOG.setLevel(level); + HTTP_CLIENT_LOG.setLevel(level); + RUNWAR_CONFIG.setLevel(level); + RUNWAR_SERVER.setLevel(level); + RUNWAR_CONTEXT.setLevel(level); + RUNWAR_SECURITY.setLevel(level); + + // This logger is only used in the resource mapper and is really chatty + // Consider a setting to enable it only when troubleshooting file system mapping issues + if( serverOptions.resourceManagerLogging() ) { + RUNWAR_REQUEST.setLevel(level); + } + + Logger.getRootLogger().setLevel(level); + configureUrlRewriteLoggers(true); + } else { + RUNWAR_REQUEST.setLevel(Level.INFO); + RUNWAR_SECURITY.setLevel(Level.DEBUG); + UNDERTOW_PREDICATE_LOG.setLevel(Level.DEBUG); + configureUrlRewriteLoggers(false); + } + } + + if (serverOptions.hasLogDir()) { + logFile = serverOptions.logDir().getPath() + '/' + serverOptions.logFileName() + ".out.txt"; + RollingFileAppender fa = new RollingFileAppender(); + fa.setName("FileLogger"); + fa.setFile(logFile); + fa.setLayout(new PatternLayout(serverOptions.logPattern())); + fa.setThreshold(Level.toLevel(logLevel)); + fa.setAppend(true); + fa.setMaxFileSize("10MB"); + fa.setMaxBackupIndex(10); + fa.activateOptions(); + appenders.add(fa); + Logger.getRootLogger().addAppender(fa); + } + Logger.getRootLogger().addAppender(consoleAppender); + + loggers.forEach(logger -> appenders.forEach(appender -> { + logger.addAppender(appender); + logger.setAdditivity(false); + })); + + initialized = true; + + if (System.getProperty("runwar.dumploggerstyles") != null) { + RunwarLogger.LOG.trace("This is a TRACE message"); + RunwarLogger.LOG.debug("This is a DEBUG message"); + RunwarLogger.LOG.warn("This is a WARN message"); + RunwarLogger.LOG.error("This is an ERROR message"); + } + } + + private static ConsoleAppender consoleAppender(String pattern) { + ConsoleAppender appender = new ConsoleAppender(); + PatternLayout layout = new PatternLayout(); + layout.setConversionPattern(pattern); + appender.setLayout(layout); + appender.setName("rw.console"); + appender.setThreshold(Level.toLevel(logLevel)); + appender.activateOptions(); + return appender; + } + + public static boolean isInitialized() { + return initialized; + } + + public static synchronized boolean initialize() { + return initialize(false); + } + + public static synchronized boolean initialize(boolean force) { + if (!initialized || force) + configure(new ServerOptionsImpl().logDir("")); + return initialized; + } + + public static void configureUrlRewriteLoggers(boolean isTrace) { + boolean hadLoggers = urlrewriteLoggers == null; + Logger REWRITE_CONDITION_LOG = Logger.getLogger("org.tuckey.web.filters.urlrewrite.Condition"); + Logger REWRITE_RULE_LOG = Logger.getLogger("org.tuckey.web.filters.urlrewrite.RuleBase"); + Logger REWRITE_SUBSTITUTION_LOG = Logger + .getLogger("org.tuckey.web.filters.urlrewrite.substitution.VariableReplacer"); + Logger REWRITE_EXECUTION_LOG = Logger.getLogger("org.tuckey.web.filters.urlrewrite.RuleExecutionOutput"); + Logger REWRITE_WRITER_LOG = Logger.getLogger("org.tuckey.web.filters.urlrewrite.UrlRewriter"); + Logger REWRITE_URL_LOG = Logger.getLogger("org.tuckey.web.filters.urlrewrite"); + Logger REWRITE_FILTER = Logger.getLogger("runwar.util.UrlRewriteFilter"); + Logger REWRITE_LOG = Logger.getLogger("org.tuckey.web.filters.urlrewrite.utils.Log"); + urlrewriteLoggers = new ArrayList<>(); + urlrewriteLoggers.add(REWRITE_CONDITION_LOG); + urlrewriteLoggers.add(REWRITE_RULE_LOG); + urlrewriteLoggers.add(REWRITE_SUBSTITUTION_LOG); + urlrewriteLoggers.add(REWRITE_EXECUTION_LOG); + urlrewriteLoggers.add(REWRITE_WRITER_LOG); + urlrewriteLoggers.add(REWRITE_URL_LOG); + urlrewriteLoggers.add(REWRITE_FILTER); + urlrewriteLoggers.add(REWRITE_LOG); + + if (rewriteLogAppender != null) { + RunwarLogger.CONF_LOG.infof("Enabling URL rewrite log: %s", rewriteLogAppender.getFile()); + urlrewriteLoggers.forEach(logger -> { + logger.addAppender(rewriteLogAppender); + logger.setAdditivity(false); + }); + } + + if (isTrace) { + RunwarLogger.CONF_LOG.infof("Enabling URL rewrite log level: %s", "TRACE"); + urlrewriteLoggers.forEach(logger -> { + logger.setLevel(Level.TRACE); + logger.addAppender(consoleAppender(serverOptions.getLogPattern())); + logger.setAdditivity(false); + }); + } else { + if(!hadLoggers){ + RunwarLogger.CONF_LOG.infof("Enabling URL rewrite log level: %s", "DEBUG"); + } + urlrewriteLoggers.forEach(logger -> { + logger.setLevel(Level.WARN); + logger.addAppender(consoleAppender(serverOptions.getLogPattern())); + logger.setAdditivity(false); + }); + REWRITE_EXECUTION_LOG.setLevel(Level.DEBUG); + REWRITE_WRITER_LOG.setLevel(Level.DEBUG); + } + } + + public static void listLoggers() { + for (Enumeration loggers = LogManager.getCurrentLoggers(); loggers.hasMoreElements();) { + Logger logger = (Logger) loggers.nextElement(); + System.out.println("Logger: " + logger.getName()); + for (Enumeration appenders = logger.getAllAppenders(); appenders.hasMoreElements();) { + Appender appender = (Appender) appenders.nextElement(); + System.out.println(" appender: " + appender.getName()); + } + } + } + +} From f0d351999b46b3f63777e5204464093f71da4adb Mon Sep 17 00:00:00 2001 From: Miguel Mathus Date: Thu, 12 Nov 2020 14:24:58 -0600 Subject: [PATCH 11/11] bumping version --- gradle/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version b/gradle/version index 38cfccd1..cf0c2124 100644 --- a/gradle/version +++ b/gradle/version @@ -1 +1 @@ -4.3.12-218c5f631882406898a1e36c1ed3aaa0d10f1678-7378622296451aea80c3ced3009313d4e2c604da \ No newline at end of file +4.3.13-218c5f631882406898a1e36c1ed3aaa0d10f1678-7378622296451aea80c3ced3009313d4e2c604da \ No newline at end of file