comparison src/luan/host/jetty/WebHandler.java @ 1182:0b55a1af5a44

add luan/host/jetty
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 20 Feb 2018 21:08:04 -0700
parents src/luan/host/WebHandler.java@bdf27aa2a65c
children 94cf2576a922
comparison
equal deleted inserted replaced
1181:51d1342e25ad 1182:0b55a1af5a44
1 package luan.host.jetty;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.Map;
6 import java.util.HashMap;
7 import java.util.TimeZone;
8 import javax.servlet.ServletException;
9 import javax.servlet.http.HttpServlet;
10 import javax.servlet.http.HttpServletRequest;
11 import javax.servlet.http.HttpServletResponse;
12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory;
14 import org.eclipse.jetty.server.Request;
15 import org.eclipse.jetty.server.Handler;
16 import org.eclipse.jetty.server.Server;
17 import org.eclipse.jetty.server.NCSARequestLog;
18 import org.eclipse.jetty.server.handler.AbstractHandler;
19 import org.eclipse.jetty.server.handler.ResourceHandler;
20 import org.eclipse.jetty.server.handler.HandlerList;
21 import org.eclipse.jetty.server.handler.RequestLogHandler;
22 import org.eclipse.jetty.server.handler.DefaultHandler;
23 import org.eclipse.jetty.server.handler.HandlerCollection;
24 import luan.Luan;
25 import luan.LuanState;
26 import luan.LuanException;
27 import luan.LuanTable;
28 import luan.LuanFunction;
29 import luan.modules.IoLuan;
30 import luan.modules.JavaLuan;
31 import luan.modules.PackageLuan;
32 import luan.modules.http.jetty.LuanHandler;
33 import luan.modules.http.jetty.AuthenticationHandler;
34 import luan.modules.http.jetty.NotFound;
35
36
37 public class WebHandler extends AbstractHandler {
38 private static final Logger logger = LoggerFactory.getLogger(WebHandler.class);
39
40 private static class Site {
41 final Handler handler;
42 final LuanHandler luanHandler;
43
44 Site(Handler handler,LuanHandler luanHandler) {
45 this.handler = handler;
46 this.luanHandler = luanHandler;
47 }
48 }
49
50 public static String allowJavaFileName = "allow_java"; // change for security
51 private static final String tz = TimeZone.getDefault().getID();
52 private static final Map<String,Site> siteMap = new HashMap<String,Site>();
53 private static String sitesDir = null;
54 private static Server server = null;
55
56 public static boolean isServing() {
57 return sitesDir != null;
58 }
59
60 public WebHandler(String dir,Server server) {
61 if( sitesDir != null )
62 throw new RuntimeException("already set");
63 if( !new File(dir).exists() )
64 throw new RuntimeException();
65 this.sitesDir = dir;
66 this.server = server;
67 }
68
69 public void handle(String target,Request baseRequest,HttpServletRequest request,HttpServletResponse response)
70 throws IOException, ServletException
71 {
72 String domain = baseRequest.getServerName();
73 // System.out.println("handle "+domain);
74 Site site = getSite(domain);
75 if( site != null ) {
76 site.handler.handle(target,baseRequest,request,response);
77 }
78 }
79
80 public static Object runLuan(String domain,String sourceText,String sourceName) throws LuanException {
81 return getSite(domain).luanHandler.runLuan(sourceText,sourceName);
82 }
83
84 public static Object callSite(String domain,String fnName,Object... args) throws LuanException {
85 return getSite(domain).luanHandler.call_rpc(fnName,args);
86 }
87
88 private static Site getSite(String domain) {
89 synchronized(siteMap) {
90 Site site = siteMap.get(domain);
91 if( site == null ) {
92 if( sitesDir==null )
93 throw new NullPointerException("sitesDir");
94 File dir = new File(sitesDir,domain);
95 if( !dir.exists() /* && !recover(dir) */ )
96 return null;
97 site = newSite(dir.toString(),domain);
98 siteMap.put(domain,site);
99 }
100 return site;
101 }
102 }
103 /*
104 private static boolean recover(File dir) {
105 File backups = new File(dir.getParentFile().getParentFile(),"backups");
106 if( !backups.exists() )
107 return false;
108 String name = dir.getName();
109 File from = null;
110 for( File backup : backups.listFiles() ) {
111 File d = new File(backup,"current/"+name);
112 if( d.exists() && (from==null || from.lastModified() < d.lastModified()) )
113 from = d;
114 }
115 if( from == null )
116 return false;
117 if( !from.renameTo(dir) )
118 throw new RuntimeException("couldn't rename "+from+" to "+dir);
119 logger.info("recovered "+name+" from "+from);
120 return true;
121 }
122 */
123 static LuanTable initLuan(LuanState luan,String dir,String domain) {
124 LuanTable init;
125 try {
126 init = (LuanTable)luan.eval(
127 "local Luan = require 'luan:Luan.luan'\n"
128 +"local f = Luan.load_file 'classpath:luan/host/Init.luan'\n"
129 +"return f('"+dir+"','"+domain+"')\n"
130 );
131 } catch(LuanException e) {
132 throw new RuntimeException(e);
133 }
134 File allowJavaFile = new File(dir,"site/private/"+allowJavaFileName);
135 if( !allowJavaFile.exists() ) {
136 JavaLuan.setSecurity( luan, javaSecurity );
137 IoLuan.setSecurity( luan, ioSecurity(dir) );
138 }
139 return init;
140 }
141
142 private static Site newSite(String dir,String domain) {
143 LuanState luan = new LuanState();
144 LuanTable init = initLuan(luan,dir,domain);
145 String password = (String)init.rawGet("password");
146
147 AuthenticationHandler authenticationHandler = new AuthenticationHandler("/private/");
148 authenticationHandler.setPassword(password);
149 String loggerRoot = (String)init.rawGet("logger_root");
150 LuanHandler luanHandler = new LuanHandler(luan,loggerRoot);
151
152 ResourceHandler resourceHandler = new ResourceHandler();
153 resourceHandler.setResourceBase(dir+"/site");
154 resourceHandler.setDirectoriesListed(true);
155 resourceHandler.setAliases(true);
156
157 NotFound notFoundHandler = new NotFound(luanHandler);
158 DefaultHandler defaultHandler = new DefaultHandler();
159
160 HandlerList handlers = new HandlerList();
161 handlers.setHandlers(new Handler[]{authenticationHandler,luanHandler,resourceHandler,notFoundHandler,defaultHandler});
162
163 String logDir = dir+"/site/private/local/logs/web";
164 new File(logDir).mkdirs();
165 NCSARequestLog log = new NCSARequestLog(logDir+"/yyyy_mm_dd.log");
166 log.setExtended(false);
167 log.setLogTimeZone(tz);
168 RequestLogHandler logHandler = new RequestLogHandler();
169 logHandler.setRequestLog(log);
170
171 HandlerCollection hc = new HandlerCollection();
172 hc.setHandlers(new Handler[]{handlers,logHandler});
173 // hc.setServer(getServer());
174
175 try {
176 hc.start();
177 } catch(Exception e) {
178 throw new RuntimeException(e);
179 }
180 return new Site(hc,luanHandler);
181 }
182
183 public static void removeHandler(String domain) throws Exception {
184 synchronized(siteMap) {
185 Site site = siteMap.remove(domain);
186 if( site != null ) {
187 site.handler.stop();
188 site.handler.destroy();
189 }
190 }
191 }
192
193 public static void loadHandler(String domain) {
194 getSite(domain);
195 }
196
197 public static Server server() {
198 return server;
199 }
200
201 private static final IoLuan.Security ioSecurity(String dir) {
202 final String siteUri = "file:" + dir + "/site";
203 return new IoLuan.Security() {
204 public void check(LuanState luan,String name) throws LuanException {
205 if( name.startsWith("file:") ) {
206 if( name.contains("..") )
207 throw new LuanException("Security violation - '"+name+"' contains '..'");
208 if( !(name.equals(siteUri) || name.startsWith(siteUri+"/")) )
209 throw new LuanException("Security violation - '"+name+"' outside of site dir");
210 }
211 else if( name.startsWith("classpath:luan/host/") ) {
212 throw new LuanException("Security violation");
213 }
214 else if( name.startsWith("os:") || name.startsWith("bash:") ) {
215 throw new LuanException("Security violation");
216 }
217 }
218 };
219 }
220
221 private static final JavaLuan.Security javaSecurity = new JavaLuan.Security() {
222 public void check(LuanState luan,String name) throws LuanException {
223 if( !name.startsWith("luan:") )
224 throw new LuanException("Security violation - only luan:* modules can load Java");
225 if( name.equals("luan:logging/Logging") )
226 throw new LuanException("Security violation - cannot reload Logging");
227 }
228 };
229 }