package railo.runtime.config; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import railo.commons.digest.MD5; import railo.commons.io.IOUtil; import railo.commons.io.SystemUtil; import railo.commons.io.log.Log; import railo.commons.io.log.LogAndSource; import railo.commons.io.log.LogAndSourceImpl; import railo.commons.io.log.LogConsole; import railo.commons.io.log.LogResource; import railo.commons.io.res.Resource; import railo.commons.io.res.util.ResourceUtil; import railo.commons.lang.StringUtil; import railo.commons.lang.SystemOut; import railo.runtime.Mapping; import railo.runtime.exp.SecurityException; import railo.runtime.listener.ApplicationListener; import railo.runtime.listener.ClassicAppListener; import railo.runtime.listener.MixedAppListener; import railo.runtime.listener.ModernAppListener; import railo.runtime.listener.NoneAppListener; import railo.runtime.net.http.ReqRspUtil; import railo.runtime.security.SecurityManager; import railo.runtime.type.Collection.Key; import railo.runtime.type.Struct; /** * */ public final class ConfigWebUtil { /** * touch a file object by the string definition * @param config * @param directory * @param path * @param type * @return matching file */ public static Resource getFile(Config config, Resource directory,String path, short type) { path=replacePlaceholder(path,config); if(!StringUtil.isEmpty(path,true)) { Resource file=getFile(directory.getRealResource(path),type); if(file!=null) return file; file=getFile(config.getResource(path),type); if(file!=null) return file; } return null; } /** * generate a file object by the string definition * @param rootDir * @param strDir * @param defaultDir * @param configDir * @param type * @param config * @return file */ static Resource getFile(Resource rootDir,String strDir, String defaultDir,Resource configDir, short type, ConfigImpl config) { strDir=replacePlaceholder(strDir,config); if(!StringUtil.isEmpty(strDir,true)) { Resource res; if(strDir.indexOf("://")!=-1){ // TODO better impl. res=getFile(config.getResource(strDir),type); if(res!=null) return res; } res=getFile(rootDir.getRealResource(strDir),type); if(res!=null) return res; res=getFile(config.getResource(strDir),type); if(res!=null) return res; } if(defaultDir==null) return null; Resource file=getFile(configDir.getRealResource(defaultDir),type); return file; } /*public static String replacePlaceholder(String str, Config config) { if(StringUtil.isEmpty(str)) return str; if(str.indexOf("railo-pcw-web")!=-1){ print.out(str); str=_replacePlaceholder(str, config); print.out(str); return str; } return _replacePlaceholder(str, config); }*/ public static String replacePlaceholder(String str, Config config) { if(StringUtil.isEmpty(str)) return str; if(StringUtil.startsWith(str,'{')){ // Config Server if(str.startsWith("{railo-config")) { if(str.startsWith("}",13)) str=checkResult(str,config.getConfigDir().getReal(str.substring(14))); else if(str.startsWith("-dir}",13)) str=checkResult(str,config.getConfigDir().getReal(str.substring(18))); else if(str.startsWith("-directory}",13)) str=checkResult(str,config.getConfigDir().getReal(str.substring(24))); } else if(config!=null && str.startsWith("{railo-server")) { Resource dir=config instanceof ConfigWeb?((ConfigWeb)config).getConfigServerDir():config.getConfigDir(); //if(config instanceof ConfigServer && cs==null) cs=(ConfigServer) cw; if(dir!=null) { if(str.startsWith("}",13)) str=checkResult(str,dir.getReal(str.substring(14))); else if(str.startsWith("-dir}",13)) str=checkResult(str,dir.getReal(str.substring(18))); else if(str.startsWith("-directory}",13)) str=checkResult(str,dir.getReal(str.substring(24))); } } // Config Web else if(str.startsWith("{railo-web")) { //if(cw instanceof ConfigServer) cw=null; //if(config instanceof ConfigWeb) { if(str.startsWith("}",10)) str=checkResult(str,config.getConfigDir().getReal(str.substring(11))); else if(str.startsWith("-dir}",10)) str=checkResult(str,config.getConfigDir().getReal(str.substring(15))); else if(str.startsWith("-directory}",10)) str=checkResult(str,config.getConfigDir().getReal(str.substring(21))); //} } // Web Root else if(str.startsWith("{web-root")) { //if(cw instanceof ConfigServer) cw=null; if(config instanceof ConfigWeb) { if(str.startsWith("}",9)) str=checkResult(str,config.getRootDirectory().getReal(str.substring(10))); else if(str.startsWith("-dir}",9)) str=checkResult(str,config.getRootDirectory().getReal(str.substring(14))); else if(str.startsWith("-directory}",9)) str=checkResult(str,config.getRootDirectory().getReal(str.substring(20))); } } // Temp else if(str.startsWith("{temp")) { if(str.startsWith("}",5)) str=checkResult(str,config.getTempDirectory().getRealResource(str.substring(6)).toString()); else if(str.startsWith("-dir}",5)) str=checkResult(str,config.getTempDirectory().getRealResource(str.substring(10)).toString()); else if(str.startsWith("-directory}",5)) str=checkResult(str,config.getTempDirectory().getRealResource(str.substring(16)).toString()); } else if(config instanceof ServletConfig){ Map<String,String> labels=null; // web if(config instanceof ConfigWebImpl){ labels=((ConfigWebImpl)config).getAllLabels(); } // server else if(config instanceof ConfigServerImpl){ labels=((ConfigServerImpl)config).getLabels(); } if(labels!=null)str=SystemUtil.parsePlaceHolder(str,((ServletConfig)config).getServletContext(),labels); } else str=SystemUtil.parsePlaceHolder(str); if(StringUtil.startsWith(str,'{')){ Struct constants = ((ConfigImpl)config).getConstants(); //Collection.Key[] arr = constants.keys(); Iterator<Entry<Key, Object>> it = constants.entryIterator(); Entry<Key, Object> e; while(it.hasNext()) { e = it.next(); if(StringUtil.startsWithIgnoreCase(str,"{"+e.getKey().getString()+"}")) { String value=(String) e.getValue(); str=checkResult(str,config.getResource( value) .getReal(str.substring(e.getKey().getString().length()+2))); break; } } } } return str; } private static String checkResult(String src, String res) { boolean srcEndWithSep=StringUtil.endsWith(src, ResourceUtil.FILE_SEPERATOR) || StringUtil.endsWith(src, '/') || StringUtil.endsWith(src, '\\'); boolean resEndWithSep=StringUtil.endsWith(res, ResourceUtil.FILE_SEPERATOR) || StringUtil.endsWith(res, '/') || StringUtil.endsWith(res, '\\'); if(srcEndWithSep && !resEndWithSep) return res+ResourceUtil.FILE_SEPERATOR; if(!srcEndWithSep && resEndWithSep) return res.substring(0,res.length()-1); return res; } /** * get only a existing file, dont create it * @param sc * @param strDir * @param defaultDir * @param configDir * @param type * @param config * @return existing file */ public static Resource getExistingResource(ServletContext sc,String strDir, String defaultDir,Resource configDir, short type, Config config) { //ARP strDir=replacePlaceholder(strDir,config); if(strDir!=null && strDir.trim().length()>0) { Resource res=sc==null?null:_getExistingFile(config.getResource(ResourceUtil.merge(ReqRspUtil.getRootPath(sc),strDir)),type); if(res!=null) return res; res=_getExistingFile(config.getResource(strDir),type); if(res!=null) return res; } if(defaultDir==null) return null; return _getExistingFile(configDir.getRealResource(defaultDir),type); } private static Resource _getExistingFile(Resource file, short type) { boolean asDir=type==ResourceUtil.TYPE_DIR; // File if(file.exists() && ((file.isDirectory() && asDir)||(file.isFile() && !asDir))) { return ResourceUtil.getCanonicalResourceEL(file); } return null; } /** * * @param file * @param type (FileUtil.TYPE_X) * @return created file */ public static Resource getFile(Resource file, short type) { return ResourceUtil.createResource(file,ResourceUtil.LEVEL_GRAND_PARENT_FILE,type); } /*public static File getFile(File file, int level, short type) { boolean asDir=type==TYPE_DIR; // File if(level>=LEVEL_FILE && file.exists() && ((file.isDirectory() && asDir)||(file.isFile() && !asDir))) { return FileUtil.getCanonicalFileEL(file); } // Parent File parent=file.getParentFile(); if(level>=LEVEL_PARENT && parent!=null && parent.exists() && FileUtil.canRW(parent)) { if(asDir) { if(file.mkdirs()) return FileUtil.getCanonicalFileEL(file); } else { if(FileUtil.createNewFileEL(file))return FileUtil.getCanonicalFileEL(file); } return FileUtil.getCanonicalFileEL(file); } // Grand Parent if(level>=LEVEL_GRAND_PARENT && parent!=null) { File gparent=parent.getParentFile(); if(gparent!=null && gparent.exists() && FileUtil.canRW(gparent)) { if(asDir) { if(file.mkdirs())return FileUtil.getCanonicalFileEL(file); } else { if(parent.mkdirs() && FileUtil.createNewFileEL(file)) return FileUtil.getCanonicalFileEL(file); } } } return null; }*/ /** * checks if file is a directory or not, if directory doesn't exist, it will be created * @param directory * @return is directory or not */ public static boolean isDirectory(Resource directory) { if(directory.exists()) return directory.isDirectory(); return directory.mkdirs(); } /** * checks if file is a file or not, if file doesn't exist, it will be created * @param file * @return is file or not */ public static boolean isFile(Resource file) { if(file.exists()) return file.isFile(); Resource parent=file.getParentResource(); //try { return parent.mkdirs() && file.createNewFile(); /*} catch (IOException e) { return false; }*/ } /** * has access checks if config object has access to given type * @param config * @param type * @return has access */ public static boolean hasAccess(Config config, int type) { boolean has=true; if(config instanceof ConfigWeb) { has=((ConfigWeb)config).getSecurityManager().getAccess(type)!=SecurityManager.VALUE_NO; } return has; } /** * loads log * @param configServer * @param config * @param strLogger * @param hasAccess * @param logLevel * @return log * @throws IOException */ public static LogAndSource getLogAndSource( ConfigServer configServer, Config config, String strLogger, boolean hasAccess, int logLevel) throws IOException { if(logLevel==-1)logLevel=Log.LEVEL_ERROR; //boolean isCS=config instanceof ConfigServer; if(!StringUtil.isEmpty(strLogger) && hasAccess && !"console".equalsIgnoreCase(strLogger)) { return ConfigWebUtil.getLogAndSource(config,strLogger,logLevel); } return new LogAndSourceImpl(LogConsole.getInstance(config,logLevel),strLogger); } private static LogAndSource getLogAndSource(Config config, String strLogger, int logLevel) { if(strLogger==null) return new LogAndSourceImpl(LogConsole.getInstance(config,logLevel),""); // File strLogger=translateOldPath(strLogger); Resource file=ConfigWebUtil.getFile(config, config.getConfigDir(),strLogger, ResourceUtil.TYPE_FILE); if(file!=null && ResourceUtil.canRW(file)) { try { return new LogAndSourceImpl(new LogResource(file,logLevel,config.getResourceCharset()),strLogger); } catch (IOException e) { SystemOut.printDate(config.getErrWriter(),e.getMessage()); } } if(file==null)SystemOut.printDate(config.getErrWriter(),"can't create logger from file ["+strLogger+"], invalid path"); else SystemOut.printDate(config.getErrWriter(),"can't create logger from file ["+strLogger+"], no write access"); return new LogAndSourceImpl(LogConsole.getInstance(config,logLevel),strLogger); } public static String translateOldPath(String path) { if(path==null) return path; if(path.startsWith("/WEB-INF/railo/")) { path="{web-root}"+path; } //print.ln(path); return path; } public static Object getIdMapping(Mapping m) { StringBuffer id=new StringBuffer(m.getVirtualLowerCase()); if(m.hasPhysical())id.append(m.getStrPhysical()); if(m.hasArchive())id.append(m.getStrPhysical()); return m.toString().toLowerCase(); } public static void checkGeneralReadAccess(ConfigImpl config, String password) throws SecurityException { SecurityManager sm = config.getSecurityManager(); short access = sm.getAccess(SecurityManager.TYPE_ACCESS_READ); if(config instanceof ConfigServer)access=SecurityManager.ACCESS_PROTECTED; if(access==SecurityManager.ACCESS_PROTECTED) { checkPassword(config,"read",password); } else if(access==SecurityManager.ACCESS_CLOSE) { throw new SecurityException("can't access, read access is disabled"); } } public static void checkGeneralWriteAccess(ConfigImpl config, String password) throws SecurityException { SecurityManager sm = config.getSecurityManager(); short access = sm.getAccess(SecurityManager.TYPE_ACCESS_WRITE); if(config instanceof ConfigServer)access=SecurityManager.ACCESS_PROTECTED; if(access==SecurityManager.ACCESS_PROTECTED) { checkPassword(config,"write",password); } else if(access==SecurityManager.ACCESS_CLOSE) { throw new SecurityException("can't access, write access is disabled"); } } public static void checkPassword(ConfigImpl config, String type,String password) throws SecurityException { if(!config.hasPassword()) throw new SecurityException("can't access, no password is defined"); //print.ln(config.getPassword()+".equalsIgnoreCase("+password+")"); if(!config.isPasswordEqual(password,true)){ if(StringUtil.isEmpty(password)){ if(type==null) throw new SecurityException("Access is protected", "to access the configuration without a password, you need to change the access to [open] in the Server Administrator"); throw new SecurityException(type +" access is protected", "to access the configuration without a password, you need to change the "+type+" access to [open] in the Server Administrator"); } throw new SecurityException("No access, password is invalid"); } } public static String createMD5FromResource(Resource resource) throws IOException { InputStream is=null; try{ is=resource.getInputStream(); byte[] barr = IOUtil.toBytes(is); return MD5.getDigestAsString(barr); } finally{ IOUtil.closeEL(is); } } public static int toListenerMode(String strListenerMode, int defaultValue) { if(StringUtil.isEmpty(strListenerMode,true)) return defaultValue; strListenerMode=strListenerMode.trim(); if("current".equalsIgnoreCase(strListenerMode) || "curr".equalsIgnoreCase(strListenerMode)) return ApplicationListener.MODE_CURRENT; else if("current2root".equalsIgnoreCase(strListenerMode) || "curr2root".equalsIgnoreCase(strListenerMode)) return ApplicationListener.MODE_CURRENT2ROOT; else if("root".equalsIgnoreCase(strListenerMode)) return ApplicationListener.MODE_ROOT; return defaultValue; } public static ApplicationListener loadListener(String type, ApplicationListener defaultValue) { if(StringUtil.isEmpty(type,true)) return defaultValue; type=type.trim(); // none if("none".equalsIgnoreCase(type)) return new NoneAppListener(); // classic if("classic".equalsIgnoreCase(type)) return new ClassicAppListener(); // modern if("modern".equalsIgnoreCase(type)) return new ModernAppListener(); // mixed if("mixed".equalsIgnoreCase(type)) return new MixedAppListener(); return defaultValue; } public static short inspectTemplate(String str, short defaultValue) { if(str==null) return defaultValue; str = str.trim().toLowerCase(); if (str.equals("always")) return ConfigImpl.INSPECT_ALWAYS; else if (str.equals("never"))return ConfigImpl.INSPECT_NEVER; else if (str.equals("once"))return ConfigImpl.INSPECT_ONCE; return defaultValue; } public static String inspectTemplate(short s,String defaultValue) { switch(s){ case ConfigImpl.INSPECT_ALWAYS: return "always"; case ConfigImpl.INSPECT_NEVER: return "never"; case ConfigImpl.INSPECT_ONCE: return "once"; default: return defaultValue; } } }