Mercurial Hosting > luan
view src/luan/host/WebHandler.java @ 1230:034f2a0b3915
better gc
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 04 Apr 2018 14:54:29 -0600 |
parents | 7e6d132904fd |
children | 0b75337bb91a |
line wrap: on
line source
package luan.host; import java.io.File; import java.io.IOException; import java.lang.ref.Reference; import java.lang.ref.SoftReference; //import java.lang.ref.WeakReference; import java.lang.ref.ReferenceQueue; import java.util.Map; import java.util.HashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import luan.webserver.Handler; import luan.webserver.Server; import luan.webserver.Request; import luan.webserver.Response; import luan.webserver.handlers.IndexHandler; import luan.webserver.handlers.ListHandler; import luan.Luan; import luan.LuanState; import luan.LuanException; import luan.LuanTable; import luan.LuanFunction; import luan.modules.IoLuan; import luan.modules.JavaLuan; import luan.modules.PackageLuan; import luan.modules.http.LuanHandler; import luan.modules.http.NotFound; public class WebHandler implements Handler { private static final Logger logger = LoggerFactory.getLogger(WebHandler.class); private static class LuanRef { private final LuanState luan; private LuanRef(LuanState luan) { this.luan = luan; } } private static final ReferenceQueue<LuanRef> queue = new ReferenceQueue<LuanRef>(); private static class MyReference extends SoftReference<LuanRef> { private final LuanState luan; private MyReference(LuanRef lr) { super(lr,queue); this.luan = lr.luan; } } private static void sweep() { while(true) { MyReference ref = (MyReference)queue.poll(); if( ref == null ) return; logger.info("sweep"); ref.luan.close(); } } public static String allowJavaFileName = "allow_java"; // change for security private static final Map<String,MyReference> siteMap = new HashMap<String,MyReference>(); private static String sitesDir = null; private static final String HANDLER = "WebHandler.handler"; private static final String LUAN_HANDLER = "WebHandler.luanHandler"; public static boolean isServing() { return sitesDir != null; } public WebHandler(String dir) { if( sitesDir != null ) throw new RuntimeException("already set"); if( !new File(dir).exists() ) throw new RuntimeException(); sitesDir = dir; } public Response handle(Request request) { String host = (String)request.headers.get("host"); int i = host.indexOf(':'); String domain = i == -1 ? host : host.substring(0,i); // System.out.println("handle "+domain); LuanRef lr = getSite(domain); if( lr == null ) return null; LuanState luan = lr.luan; Handler handler = (Handler)luan.registry().get(HANDLER); return handler.handle(request); } public static Object runLuan(String domain,String sourceText,String sourceName) throws LuanException { LuanRef lr = getSite(domain); LuanState luan = lr.luan; LuanHandler luanHandler = (LuanHandler)luan.registry().get(LUAN_HANDLER); return luanHandler.runLuan(sourceText,sourceName); } public static Object callSite(String domain,String fnName,Object... args) throws LuanException { LuanRef lr = getSite(domain); LuanState luan = lr.luan; LuanHandler luanHandler = (LuanHandler)luan.registry().get(LUAN_HANDLER); return luanHandler.call_rpc(fnName,args); } private static LuanRef getSite(String domain) { synchronized(siteMap) { Reference<LuanRef> ref = siteMap.get(domain); LuanRef lr = ref==null ? null : ref.get(); if( lr == null ) { //if(ref!=null) logger.info("gc "+domain); if( sitesDir==null ) throw new NullPointerException("sitesDir"); File dir = new File(sitesDir,domain); if( !dir.exists() /* && !recover(dir) */ ) return null; sweep(); LuanState luan = newSite(dir.toString(),domain); lr = new LuanRef(luan); siteMap.put(domain,new MyReference(lr)); } return lr; } } /* private static boolean recover(File dir) { File backups = new File(dir.getParentFile().getParentFile(),"backups"); if( !backups.exists() ) return false; String name = dir.getName(); File from = null; for( File backup : backups.listFiles() ) { File d = new File(backup,"current/"+name); if( d.exists() && (from==null || from.lastModified() < d.lastModified()) ) from = d; } if( from == null ) return false; if( !from.renameTo(dir) ) throw new RuntimeException("couldn't rename "+from+" to "+dir); logger.info("recovered "+name+" from "+from); return true; } */ static LuanTable initLuan(LuanState luan,String dir,String domain) { LuanTable init; try { init = (LuanTable)luan.eval( "local Luan = require 'luan:Luan.luan'\n" +"local f = Luan.load_file 'classpath:luan/host/Init.luan'\n" +"return f('"+dir+"','"+domain+"')\n" ); } catch(LuanException e) { throw new RuntimeException(e); } File allowJavaFile = new File(dir,"site/private/"+allowJavaFileName); if( !allowJavaFile.exists() ) { JavaLuan.setSecurity( luan, javaSecurity ); IoLuan.setSecurity( luan, ioSecurity(dir) ); } return init; } private static LuanState newSite(String dir,String domain) { LuanState luan = new LuanState(); LuanTable init = initLuan(luan,dir,domain); String loggerRoot = (String)init.rawGet("logger_root"); LuanHandler luanHandler = new LuanHandler(luan,loggerRoot); NotFound notFoundHandler = new NotFound(luanHandler); Handler handler = luanHandler; handler = new IndexHandler(handler); handler = new ListHandler( handler, notFoundHandler ); String logDir = dir + "/site/private/local/logs/web"; new File(logDir).mkdirs(); luan.registry().put(HANDLER,handler); luan.registry().put(LUAN_HANDLER,luanHandler); return luan; } public static void removeHandler(String domain) throws Exception { synchronized(siteMap) { Reference<LuanRef> ref = siteMap.remove(domain); LuanRef lr = ref==null ? null : ref.get(); if( lr != null ) { LuanState luan = lr.luan; LuanHandler luanHandler = (LuanHandler)luan.registry().get(LUAN_HANDLER); luanHandler.close(); } } } public static void loadHandler(String domain) { getSite(domain); } private static final IoLuan.Security ioSecurity(String dir) { final String siteUri = "file:" + dir + "/site"; return new IoLuan.Security() { public void check(LuanState luan,String name) throws LuanException { if( name.startsWith("file:") ) { if( name.contains("..") ) throw new LuanException("Security violation - '"+name+"' contains '..'"); if( !(name.equals(siteUri) || name.startsWith(siteUri+"/")) ) throw new LuanException("Security violation - '"+name+"' outside of site dir"); } else if( name.startsWith("classpath:luan/host/") ) { throw new LuanException("Security violation"); } else if( name.startsWith("os:") || name.startsWith("bash:") ) { throw new LuanException("Security violation"); } } }; } private static final JavaLuan.Security javaSecurity = new JavaLuan.Security() { public void check(LuanState luan,String name) throws LuanException { if( !name.startsWith("luan:") ) throw new LuanException("Security violation - only luan:* modules can load Java"); if( name.equals("luan:logging/Logging") ) throw new LuanException("Security violation - cannot reload Logging"); } }; }