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    }