001 package railo.runtime.config; 002 003 import java.io.IOException; 004 import java.io.InputStream; 005 import java.util.Iterator; 006 import java.util.Map; 007 import java.util.Map.Entry; 008 009 import javax.servlet.ServletConfig; 010 import javax.servlet.ServletContext; 011 012 import railo.commons.digest.MD5; 013 import railo.commons.io.IOUtil; 014 import railo.commons.io.SystemUtil; 015 import railo.commons.io.log.Log; 016 import railo.commons.io.log.LogAndSource; 017 import railo.commons.io.log.LogAndSourceImpl; 018 import railo.commons.io.log.LogConsole; 019 import railo.commons.io.log.LogResource; 020 import railo.commons.io.res.Resource; 021 import railo.commons.io.res.util.ResourceUtil; 022 import railo.commons.lang.StringUtil; 023 import railo.commons.lang.SystemOut; 024 import railo.runtime.Mapping; 025 import railo.runtime.exp.SecurityException; 026 import railo.runtime.listener.ApplicationListener; 027 import railo.runtime.listener.ClassicAppListener; 028 import railo.runtime.listener.MixedAppListener; 029 import railo.runtime.listener.ModernAppListener; 030 import railo.runtime.listener.NoneAppListener; 031 import railo.runtime.net.http.ReqRspUtil; 032 import railo.runtime.security.SecurityManager; 033 import railo.runtime.type.Collection.Key; 034 import railo.runtime.type.Struct; 035 036 037 /** 038 * 039 */ 040 public final class ConfigWebUtil { 041 042 /** 043 * touch a file object by the string definition 044 * @param config 045 * @param directory 046 * @param path 047 * @param type 048 * @return matching file 049 */ 050 public static Resource getFile(Config config, Resource directory,String path, short type) { 051 path=replacePlaceholder(path,config); 052 if(!StringUtil.isEmpty(path,true)) { 053 Resource file=getFile(directory.getRealResource(path),type); 054 if(file!=null) return file; 055 056 file=getFile(config.getResource(path),type); 057 058 if(file!=null) return file; 059 } 060 return null; 061 } 062 063 /** 064 * generate a file object by the string definition 065 * @param rootDir 066 * @param strDir 067 * @param defaultDir 068 * @param configDir 069 * @param type 070 * @param config 071 * @return file 072 */ 073 static Resource getFile(Resource rootDir,String strDir, String defaultDir,Resource configDir, short type, ConfigImpl config) { 074 strDir=replacePlaceholder(strDir,config); 075 if(!StringUtil.isEmpty(strDir,true)) { 076 Resource res; 077 if(strDir.indexOf("://")!=-1){ // TODO better impl. 078 res=getFile(config.getResource(strDir),type); 079 if(res!=null) return res; 080 } 081 res=getFile(rootDir.getRealResource(strDir),type); 082 if(res!=null) return res; 083 084 res=getFile(config.getResource(strDir),type); 085 if(res!=null) return res; 086 } 087 if(defaultDir==null) return null; 088 Resource file=getFile(configDir.getRealResource(defaultDir),type); 089 return file; 090 } 091 092 093 /*public static String replacePlaceholder(String str, Config config) { 094 if(StringUtil.isEmpty(str)) return str; 095 if(str.indexOf("railo-pcw-web")!=-1){ 096 print.out(str); 097 str=_replacePlaceholder(str, config); 098 print.out(str); 099 return str; 100 } 101 return _replacePlaceholder(str, config); 102 }*/ 103 104 public static String replacePlaceholder(String str, Config config) { 105 if(StringUtil.isEmpty(str)) return str; 106 107 if(StringUtil.startsWith(str,'{')){ 108 109 110 // Config Server 111 if(str.startsWith("{railo-config")) { 112 if(str.startsWith("}",13)) str=checkResult(str,config.getConfigDir().getReal(str.substring(14))); 113 else if(str.startsWith("-dir}",13)) str=checkResult(str,config.getConfigDir().getReal(str.substring(18))); 114 else if(str.startsWith("-directory}",13)) str=checkResult(str,config.getConfigDir().getReal(str.substring(24))); 115 } 116 117 118 else if(config!=null && str.startsWith("{railo-server")) { 119 Resource dir=config instanceof ConfigWeb?((ConfigWeb)config).getConfigServerDir():config.getConfigDir(); 120 //if(config instanceof ConfigServer && cs==null) cs=(ConfigServer) cw; 121 if(dir!=null) { 122 if(str.startsWith("}",13)) str=checkResult(str,dir.getReal(str.substring(14))); 123 else if(str.startsWith("-dir}",13)) str=checkResult(str,dir.getReal(str.substring(18))); 124 else if(str.startsWith("-directory}",13)) str=checkResult(str,dir.getReal(str.substring(24))); 125 } 126 } 127 // Config Web 128 else if(str.startsWith("{railo-web")) { 129 //if(cw instanceof ConfigServer) cw=null; 130 //if(config instanceof ConfigWeb) { 131 if(str.startsWith("}",10)) str=checkResult(str,config.getConfigDir().getReal(str.substring(11))); 132 else if(str.startsWith("-dir}",10)) str=checkResult(str,config.getConfigDir().getReal(str.substring(15))); 133 else if(str.startsWith("-directory}",10)) str=checkResult(str,config.getConfigDir().getReal(str.substring(21))); 134 //} 135 } 136 // Web Root 137 else if(str.startsWith("{web-root")) { 138 //if(cw instanceof ConfigServer) cw=null; 139 if(config instanceof ConfigWeb) { 140 if(str.startsWith("}",9)) str=checkResult(str,config.getRootDirectory().getReal(str.substring(10))); 141 else if(str.startsWith("-dir}",9)) str=checkResult(str,config.getRootDirectory().getReal(str.substring(14))); 142 else if(str.startsWith("-directory}",9)) str=checkResult(str,config.getRootDirectory().getReal(str.substring(20))); 143 } 144 } 145 // Temp 146 else if(str.startsWith("{temp")) { 147 if(str.startsWith("}",5)) str=checkResult(str,config.getTempDirectory().getRealResource(str.substring(6)).toString()); 148 else if(str.startsWith("-dir}",5)) str=checkResult(str,config.getTempDirectory().getRealResource(str.substring(10)).toString()); 149 else if(str.startsWith("-directory}",5)) str=checkResult(str,config.getTempDirectory().getRealResource(str.substring(16)).toString()); 150 } 151 else if(config instanceof ServletConfig){ 152 Map<String,String> labels=null; 153 // web 154 if(config instanceof ConfigWebImpl){ 155 labels=((ConfigWebImpl)config).getAllLabels(); 156 } 157 // server 158 else if(config instanceof ConfigServerImpl){ 159 labels=((ConfigServerImpl)config).getLabels(); 160 } 161 if(labels!=null)str=SystemUtil.parsePlaceHolder(str,((ServletConfig)config).getServletContext(),labels); 162 } 163 else str=SystemUtil.parsePlaceHolder(str); 164 165 if(StringUtil.startsWith(str,'{')){ 166 Struct constants = ((ConfigImpl)config).getConstants(); 167 //Collection.Key[] arr = constants.keys(); 168 Iterator<Entry<Key, Object>> it = constants.entryIterator(); 169 Entry<Key, Object> e; 170 while(it.hasNext()) { 171 e = it.next(); 172 if(StringUtil.startsWithIgnoreCase(str,"{"+e.getKey().getString()+"}")) { 173 String value=(String) e.getValue(); 174 str=checkResult(str,config.getResource( value) 175 .getReal(str.substring(e.getKey().getString().length()+2))); 176 break; 177 178 } 179 } 180 } 181 } 182 return str; 183 } 184 185 186 187 private static String checkResult(String src, String res) { 188 boolean srcEndWithSep=StringUtil.endsWith(src, ResourceUtil.FILE_SEPERATOR) || StringUtil.endsWith(src, '/') || StringUtil.endsWith(src, '\\'); 189 boolean resEndWithSep=StringUtil.endsWith(res, ResourceUtil.FILE_SEPERATOR) || StringUtil.endsWith(res, '/') || StringUtil.endsWith(res, '\\'); 190 if(srcEndWithSep && !resEndWithSep) return res+ResourceUtil.FILE_SEPERATOR; 191 if(!srcEndWithSep && resEndWithSep) return res.substring(0,res.length()-1); 192 193 return res; 194 } 195 196 /** 197 * get only a existing file, dont create it 198 * @param sc 199 * @param strDir 200 * @param defaultDir 201 * @param configDir 202 * @param type 203 * @param config 204 * @return existing file 205 */ 206 public static Resource getExistingResource(ServletContext sc,String strDir, String defaultDir,Resource configDir, short type, ConfigImpl config) { 207 //ARP 208 209 strDir=replacePlaceholder(strDir,config); 210 if(strDir!=null && strDir.trim().length()>0) { 211 Resource res=sc==null?null:_getExistingFile(config.getResource(ResourceUtil.merge(ReqRspUtil.getRootPath(sc),strDir)),type); 212 if(res!=null) return res; 213 214 res=_getExistingFile(config.getResource(strDir),type); 215 if(res!=null) return res; 216 } 217 if(defaultDir==null) return null; 218 return _getExistingFile(configDir.getRealResource(defaultDir),type); 219 220 } 221 222 private static Resource _getExistingFile(Resource file, short type) { 223 224 boolean asDir=type==ResourceUtil.TYPE_DIR; 225 // File 226 if(file.exists() && ((file.isDirectory() && asDir)||(file.isFile() && !asDir))) { 227 return ResourceUtil.getCanonicalResourceEL(file); 228 } 229 return null; 230 } 231 232 /** 233 * 234 * @param file 235 * @param type (FileUtil.TYPE_X) 236 * @return created file 237 */ 238 public static Resource getFile(Resource file, short type) { 239 return ResourceUtil.createResource(file,ResourceUtil.LEVEL_GRAND_PARENT_FILE,type); 240 } 241 /*public static File getFile(File file, int level, short type) { 242 243 boolean asDir=type==TYPE_DIR; 244 // File 245 if(level>=LEVEL_FILE && file.exists() && ((file.isDirectory() && asDir)||(file.isFile() && !asDir))) { 246 return FileUtil.getCanonicalFileEL(file); 247 } 248 249 // Parent 250 File parent=file.getParentFile(); 251 if(level>=LEVEL_PARENT && parent!=null && parent.exists() && FileUtil.canRW(parent)) { 252 if(asDir) { 253 if(file.mkdirs()) return FileUtil.getCanonicalFileEL(file); 254 } 255 else { 256 if(FileUtil.createNewFileEL(file))return FileUtil.getCanonicalFileEL(file); 257 } 258 return FileUtil.getCanonicalFileEL(file); 259 } 260 261 // Grand Parent 262 if(level>=LEVEL_GRAND_PARENT && parent!=null) { 263 File gparent=parent.getParentFile(); 264 if(gparent!=null && gparent.exists() && FileUtil.canRW(gparent)) { 265 if(asDir) { 266 if(file.mkdirs())return FileUtil.getCanonicalFileEL(file); 267 } 268 else { 269 if(parent.mkdirs() && FileUtil.createNewFileEL(file)) 270 return FileUtil.getCanonicalFileEL(file); 271 } 272 } 273 } 274 return null; 275 }*/ 276 277 /** 278 * checks if file is a directory or not, if directory doesn't exist, it will be created 279 * @param directory 280 * @return is directory or not 281 */ 282 public static boolean isDirectory(Resource directory) { 283 if(directory.exists()) return directory.isDirectory(); 284 return directory.mkdirs(); 285 } 286 287 /** 288 * checks if file is a file or not, if file doesn't exist, it will be created 289 * @param file 290 * @return is file or not 291 */ 292 public static boolean isFile(Resource file) { 293 if(file.exists()) return file.isFile(); 294 Resource parent=file.getParentResource(); 295 //try { 296 return parent.mkdirs() && file.createNewFile(); 297 /*} catch (IOException e) { 298 return false; 299 }*/ 300 } 301 302 /** 303 * has access checks if config object has access to given type 304 * @param config 305 * @param type 306 * @return has access 307 */ 308 public static boolean hasAccess(Config config, int type) { 309 310 boolean has=true; 311 if(config instanceof ConfigWeb) { 312 has=((ConfigWeb)config).getSecurityManager().getAccess(type)!=SecurityManager.VALUE_NO; 313 } 314 return has; 315 } 316 317 /** 318 * loads log 319 * @param configServer 320 * @param config 321 * @param strLogger 322 * @param hasAccess 323 * @param logLevel 324 * @return log 325 * @throws IOException 326 */ 327 public static LogAndSource getLogAndSource( ConfigServer configServer, Config config, String strLogger, boolean hasAccess, int logLevel) throws IOException { 328 if(logLevel==-1)logLevel=Log.LEVEL_ERROR; 329 //boolean isCS=config instanceof ConfigServer; 330 if(!StringUtil.isEmpty(strLogger) && hasAccess && !"console".equalsIgnoreCase(strLogger)) { 331 return ConfigWebUtil.getLogAndSource(config,strLogger,logLevel); 332 } 333 return new LogAndSourceImpl(LogConsole.getInstance(config,logLevel),strLogger); 334 } 335 private static LogAndSource getLogAndSource(Config config, String strLogger, int logLevel) { 336 if(strLogger==null) return new LogAndSourceImpl(LogConsole.getInstance(config,logLevel),""); 337 338 // File 339 strLogger=translateOldPath(strLogger); 340 Resource file=ConfigWebUtil.getFile(config, config.getConfigDir(),strLogger, ResourceUtil.TYPE_FILE); 341 if(file!=null && ResourceUtil.canRW(file)) { 342 try { 343 return new LogAndSourceImpl(new LogResource(file,logLevel,config.getResourceCharset()),strLogger); 344 } catch (IOException e) { 345 SystemOut.printDate(config.getErrWriter(),e.getMessage()); 346 } 347 } 348 349 if(file==null)SystemOut.printDate(config.getErrWriter(),"can't create logger from file ["+strLogger+"], invalid path"); 350 else SystemOut.printDate(config.getErrWriter(),"can't create logger from file ["+strLogger+"], no write access"); 351 352 return new LogAndSourceImpl(LogConsole.getInstance(config,logLevel),strLogger); 353 354 } 355 356 public static String translateOldPath(String path) { 357 if(path==null) return path; 358 if(path.startsWith("/WEB-INF/railo/")) { 359 path="{web-root}"+path; 360 } 361 //print.ln(path); 362 return path; 363 } 364 365 public static Object getIdMapping(Mapping m) { 366 StringBuffer id=new StringBuffer(m.getVirtualLowerCase()); 367 if(m.hasPhysical())id.append(m.getStrPhysical()); 368 if(m.hasArchive())id.append(m.getStrPhysical()); 369 return m.toString().toLowerCase(); 370 } 371 public static void checkGeneralReadAccess(ConfigImpl config, String password) throws SecurityException { 372 SecurityManager sm = config.getSecurityManager(); 373 short access = sm.getAccess(SecurityManager.TYPE_ACCESS_READ); 374 if(config instanceof ConfigServer)access=SecurityManager.ACCESS_PROTECTED; 375 if(access==SecurityManager.ACCESS_PROTECTED) { 376 checkPassword(config,"read",password); 377 } 378 else if(access==SecurityManager.ACCESS_CLOSE) { 379 throw new SecurityException("can't access, read access is disabled"); 380 } 381 } 382 383 public static void checkGeneralWriteAccess(ConfigImpl config, String password) throws SecurityException { 384 SecurityManager sm = config.getSecurityManager(); 385 short access = sm.getAccess(SecurityManager.TYPE_ACCESS_WRITE); 386 387 if(config instanceof ConfigServer)access=SecurityManager.ACCESS_PROTECTED; 388 if(access==SecurityManager.ACCESS_PROTECTED) { 389 checkPassword(config,"write",password); 390 } 391 else if(access==SecurityManager.ACCESS_CLOSE) { 392 throw new SecurityException("can't access, write access is disabled"); 393 } 394 } 395 396 public static void checkPassword(ConfigImpl config, String type,String password) throws SecurityException { 397 if(!config.hasPassword()) 398 throw new SecurityException("can't access, no password is defined"); 399 //print.ln(config.getPassword()+".equalsIgnoreCase("+password+")"); 400 if(!config.getPassword().equalsIgnoreCase(password)){ 401 if(StringUtil.isEmpty(password)){ 402 if(type==null) 403 throw new SecurityException("Access is protected", 404 "to access the configuration without a password, you need to change the access to [open] in the Server Administrator"); 405 throw new SecurityException(type +" access is protected", 406 "to access the configuration without a password, you need to change the "+type+" access to [open] in the Server Administrator"); 407 } 408 throw new SecurityException("No access, password is invalid"); 409 } 410 } 411 412 public static String createMD5FromResource(Resource resource) throws IOException { 413 InputStream is=null; 414 try{ 415 is=resource.getInputStream(); 416 byte[] barr = IOUtil.toBytes(is); 417 return MD5.getDigestAsString(barr); 418 } 419 finally{ 420 IOUtil.closeEL(is); 421 } 422 } 423 424 public static int toListenerMode(String strListenerMode, int defaultValue) { 425 if(StringUtil.isEmpty(strListenerMode,true)) return defaultValue; 426 strListenerMode=strListenerMode.trim(); 427 428 if("current".equalsIgnoreCase(strListenerMode) || "curr".equalsIgnoreCase(strListenerMode)) 429 return ApplicationListener.MODE_CURRENT; 430 else if("current2root".equalsIgnoreCase(strListenerMode) || "curr2root".equalsIgnoreCase(strListenerMode)) 431 return ApplicationListener.MODE_CURRENT2ROOT; 432 else if("root".equalsIgnoreCase(strListenerMode)) 433 return ApplicationListener.MODE_ROOT; 434 435 return defaultValue; 436 } 437 438 public static ApplicationListener loadListener(String type, ApplicationListener defaultValue) { 439 if(StringUtil.isEmpty(type,true)) return defaultValue; 440 type=type.trim(); 441 442 // none 443 if("none".equalsIgnoreCase(type)) 444 return new NoneAppListener(); 445 // classic 446 if("classic".equalsIgnoreCase(type)) 447 return new ClassicAppListener(); 448 // modern 449 if("modern".equalsIgnoreCase(type)) 450 return new ModernAppListener(); 451 // mixed 452 if("mixed".equalsIgnoreCase(type)) 453 return new MixedAppListener(); 454 455 return defaultValue; 456 } 457 458 public static short inspectTemplate(String str, short defaultValue) { 459 if(str==null) return defaultValue; 460 str = str.trim().toLowerCase(); 461 if (str.equals("always")) return ConfigImpl.INSPECT_ALWAYS; 462 else if (str.equals("never"))return ConfigImpl.INSPECT_NEVER; 463 else if (str.equals("once"))return ConfigImpl.INSPECT_ONCE; 464 return defaultValue; 465 } 466 467 468 public static String inspectTemplate(short s,String defaultValue) { 469 switch(s){ 470 case ConfigImpl.INSPECT_ALWAYS: return "always"; 471 case ConfigImpl.INSPECT_NEVER: return "never"; 472 case ConfigImpl.INSPECT_ONCE: return "once"; 473 default: return defaultValue; 474 } 475 } 476 477 }