Mercurial Hosting > luan
diff src/luan/host/WebHandler.java @ 1185:94cf2576a922
implement WebHandler for nginx
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 21 Feb 2018 21:22:16 -0700 |
parents | src/luan/host/jetty/WebHandler.java@0b55a1af5a44 |
children | 83c8a5a47f70 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/host/WebHandler.java Wed Feb 21 21:22:16 2018 -0700 @@ -0,0 +1,187 @@ +package luan.host; + +import java.io.File; +import java.io.IOException; +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 Site { + final Handler handler; + final LuanHandler luanHandler; + + Site(Handler handler,LuanHandler luanHandler) { + this.handler = handler; + this.luanHandler = luanHandler; + } + } + + public static String allowJavaFileName = "allow_java"; // change for security + private static final Map<String,Site> siteMap = new HashMap<String,Site>(); + private static String sitesDir = null; + public static Server server; + + 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(); + this.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); + Site site = getSite(domain); + return site==null ? null : site.handler.handle(request); + } + + public static Object runLuan(String domain,String sourceText,String sourceName) throws LuanException { + return getSite(domain).luanHandler.runLuan(sourceText,sourceName); + } + + public static Object callSite(String domain,String fnName,Object... args) throws LuanException { + return getSite(domain).luanHandler.call_rpc(fnName,args); + } + + private static Site getSite(String domain) { + synchronized(siteMap) { + Site site = siteMap.get(domain); + if( site == null ) { + if( sitesDir==null ) + throw new NullPointerException("sitesDir"); + File dir = new File(sitesDir,domain); + if( !dir.exists() /* && !recover(dir) */ ) + return null; + site = newSite(dir.toString(),domain); + siteMap.put(domain,site); + } + return site; + } + } +/* + 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 Site 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(); + + return new Site(handler,luanHandler); + } + + public static void removeHandler(String domain) throws Exception { + synchronized(siteMap) { + Site site = siteMap.remove(domain); + if( site != null ) { + site.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"); + } + }; +}