Mercurial Hosting > luan
annotate 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 |
rev | line source |
---|---|
1185
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
1 package luan.host; |
1135 | 2 |
3 import java.io.File; | |
4 import java.io.IOException; | |
1202 | 5 import java.lang.ref.Reference; |
6 import java.lang.ref.SoftReference; | |
7 //import java.lang.ref.WeakReference; | |
1230 | 8 import java.lang.ref.ReferenceQueue; |
1135 | 9 import java.util.Map; |
10 import java.util.HashMap; | |
11 import org.slf4j.Logger; | |
12 import org.slf4j.LoggerFactory; | |
1185
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
13 import luan.webserver.Handler; |
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
14 import luan.webserver.Server; |
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
15 import luan.webserver.Request; |
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
16 import luan.webserver.Response; |
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
17 import luan.webserver.handlers.IndexHandler; |
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
18 import luan.webserver.handlers.ListHandler; |
1135 | 19 import luan.Luan; |
20 import luan.LuanState; | |
21 import luan.LuanException; | |
22 import luan.LuanTable; | |
23 import luan.LuanFunction; | |
24 import luan.modules.IoLuan; | |
25 import luan.modules.JavaLuan; | |
26 import luan.modules.PackageLuan; | |
1185
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
27 import luan.modules.http.LuanHandler; |
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
28 import luan.modules.http.NotFound; |
1135 | 29 |
30 | |
1185
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
31 public class WebHandler implements Handler { |
1135 | 32 private static final Logger logger = LoggerFactory.getLogger(WebHandler.class); |
33 | |
1230 | 34 private static class LuanRef { |
35 private final LuanState luan; | |
36 | |
37 private LuanRef(LuanState luan) { | |
38 this.luan = luan; | |
39 } | |
40 } | |
41 | |
42 private static final ReferenceQueue<LuanRef> queue = new ReferenceQueue<LuanRef>(); | |
43 | |
44 private static class MyReference extends SoftReference<LuanRef> { | |
45 private final LuanState luan; | |
46 | |
47 private MyReference(LuanRef lr) { | |
48 super(lr,queue); | |
49 this.luan = lr.luan; | |
50 } | |
51 } | |
52 | |
53 private static void sweep() { | |
54 while(true) { | |
55 MyReference ref = (MyReference)queue.poll(); | |
56 if( ref == null ) | |
57 return; | |
58 logger.info("sweep"); | |
59 ref.luan.close(); | |
60 } | |
61 } | |
62 | |
63 | |
1202 | 64 public static String allowJavaFileName = "allow_java"; // change for security |
1230 | 65 private static final Map<String,MyReference> siteMap = new HashMap<String,MyReference>(); |
1202 | 66 private static String sitesDir = null; |
1135 | 67 |
1202 | 68 private static final String HANDLER = "WebHandler.handler"; |
69 private static final String LUAN_HANDLER = "WebHandler.luanHandler"; | |
1135 | 70 |
71 public static boolean isServing() { | |
72 return sitesDir != null; | |
73 } | |
74 | |
1185
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
75 public WebHandler(String dir) { |
1135 | 76 if( sitesDir != null ) |
77 throw new RuntimeException("already set"); | |
78 if( !new File(dir).exists() ) | |
79 throw new RuntimeException(); | |
1230 | 80 sitesDir = dir; |
1135 | 81 } |
82 | |
1185
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
83 public Response handle(Request request) { |
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
84 String host = (String)request.headers.get("host"); |
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
85 int i = host.indexOf(':'); |
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
86 String domain = i == -1 ? host : host.substring(0,i); |
1135 | 87 // System.out.println("handle "+domain); |
1230 | 88 LuanRef lr = getSite(domain); |
89 if( lr == null ) | |
1202 | 90 return null; |
1230 | 91 LuanState luan = lr.luan; |
1202 | 92 Handler handler = (Handler)luan.registry().get(HANDLER); |
93 return handler.handle(request); | |
1135 | 94 } |
95 | |
96 public static Object runLuan(String domain,String sourceText,String sourceName) throws LuanException { | |
1230 | 97 LuanRef lr = getSite(domain); |
98 LuanState luan = lr.luan; | |
1202 | 99 LuanHandler luanHandler = (LuanHandler)luan.registry().get(LUAN_HANDLER); |
100 return luanHandler.runLuan(sourceText,sourceName); | |
1135 | 101 } |
102 | |
103 public static Object callSite(String domain,String fnName,Object... args) throws LuanException { | |
1230 | 104 LuanRef lr = getSite(domain); |
105 LuanState luan = lr.luan; | |
1202 | 106 LuanHandler luanHandler = (LuanHandler)luan.registry().get(LUAN_HANDLER); |
107 return luanHandler.call_rpc(fnName,args); | |
1135 | 108 } |
109 | |
1230 | 110 private static LuanRef getSite(String domain) { |
1135 | 111 synchronized(siteMap) { |
1230 | 112 Reference<LuanRef> ref = siteMap.get(domain); |
113 LuanRef lr = ref==null ? null : ref.get(); | |
114 if( lr == null ) { | |
1203 | 115 //if(ref!=null) logger.info("gc "+domain); |
1135 | 116 if( sitesDir==null ) |
117 throw new NullPointerException("sitesDir"); | |
118 File dir = new File(sitesDir,domain); | |
119 if( !dir.exists() /* && !recover(dir) */ ) | |
120 return null; | |
1230 | 121 sweep(); |
122 LuanState luan = newSite(dir.toString(),domain); | |
123 lr = new LuanRef(luan); | |
124 siteMap.put(domain,new MyReference(lr)); | |
1135 | 125 } |
1230 | 126 return lr; |
1135 | 127 } |
128 } | |
129 /* | |
130 private static boolean recover(File dir) { | |
131 File backups = new File(dir.getParentFile().getParentFile(),"backups"); | |
132 if( !backups.exists() ) | |
133 return false; | |
134 String name = dir.getName(); | |
135 File from = null; | |
136 for( File backup : backups.listFiles() ) { | |
137 File d = new File(backup,"current/"+name); | |
138 if( d.exists() && (from==null || from.lastModified() < d.lastModified()) ) | |
139 from = d; | |
140 } | |
141 if( from == null ) | |
142 return false; | |
143 if( !from.renameTo(dir) ) | |
144 throw new RuntimeException("couldn't rename "+from+" to "+dir); | |
145 logger.info("recovered "+name+" from "+from); | |
146 return true; | |
147 } | |
148 */ | |
149 static LuanTable initLuan(LuanState luan,String dir,String domain) { | |
150 LuanTable init; | |
151 try { | |
152 init = (LuanTable)luan.eval( | |
153 "local Luan = require 'luan:Luan.luan'\n" | |
154 +"local f = Luan.load_file 'classpath:luan/host/Init.luan'\n" | |
155 +"return f('"+dir+"','"+domain+"')\n" | |
156 ); | |
157 } catch(LuanException e) { | |
158 throw new RuntimeException(e); | |
159 } | |
160 File allowJavaFile = new File(dir,"site/private/"+allowJavaFileName); | |
161 if( !allowJavaFile.exists() ) { | |
162 JavaLuan.setSecurity( luan, javaSecurity ); | |
163 IoLuan.setSecurity( luan, ioSecurity(dir) ); | |
164 } | |
165 return init; | |
166 } | |
167 | |
1202 | 168 private static LuanState newSite(String dir,String domain) { |
1135 | 169 LuanState luan = new LuanState(); |
170 LuanTable init = initLuan(luan,dir,domain); | |
171 | |
172 String loggerRoot = (String)init.rawGet("logger_root"); | |
173 LuanHandler luanHandler = new LuanHandler(luan,loggerRoot); | |
1185
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
174 NotFound notFoundHandler = new NotFound(luanHandler); |
1135 | 175 |
1185
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
176 Handler handler = luanHandler; |
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
177 handler = new IndexHandler(handler); |
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
178 handler = new ListHandler( handler, notFoundHandler ); |
1135 | 179 |
1202 | 180 String logDir = dir + "/site/private/local/logs/web"; |
1135 | 181 new File(logDir).mkdirs(); |
182 | |
1202 | 183 luan.registry().put(HANDLER,handler); |
184 luan.registry().put(LUAN_HANDLER,luanHandler); | |
185 | |
186 return luan; | |
1135 | 187 } |
188 | |
189 public static void removeHandler(String domain) throws Exception { | |
190 synchronized(siteMap) { | |
1230 | 191 Reference<LuanRef> ref = siteMap.remove(domain); |
192 LuanRef lr = ref==null ? null : ref.get(); | |
193 if( lr != null ) { | |
194 LuanState luan = lr.luan; | |
1202 | 195 LuanHandler luanHandler = (LuanHandler)luan.registry().get(LUAN_HANDLER); |
196 luanHandler.close(); | |
1135 | 197 } |
198 } | |
199 } | |
200 | |
201 public static void loadHandler(String domain) { | |
202 getSite(domain); | |
203 } | |
204 | |
205 private static final IoLuan.Security ioSecurity(String dir) { | |
1174
bdf27aa2a65c
fix luanhost security bug
Franklin Schmidt <fschmidt@gmail.com>
parents:
1136
diff
changeset
|
206 final String siteUri = "file:" + dir + "/site"; |
1135 | 207 return new IoLuan.Security() { |
208 public void check(LuanState luan,String name) throws LuanException { | |
209 if( name.startsWith("file:") ) { | |
210 if( name.contains("..") ) | |
211 throw new LuanException("Security violation - '"+name+"' contains '..'"); | |
1174
bdf27aa2a65c
fix luanhost security bug
Franklin Schmidt <fschmidt@gmail.com>
parents:
1136
diff
changeset
|
212 if( !(name.equals(siteUri) || name.startsWith(siteUri+"/")) ) |
1135 | 213 throw new LuanException("Security violation - '"+name+"' outside of site dir"); |
214 } | |
215 else if( name.startsWith("classpath:luan/host/") ) { | |
216 throw new LuanException("Security violation"); | |
217 } | |
218 else if( name.startsWith("os:") || name.startsWith("bash:") ) { | |
219 throw new LuanException("Security violation"); | |
220 } | |
221 } | |
222 }; | |
223 } | |
224 | |
225 private static final JavaLuan.Security javaSecurity = new JavaLuan.Security() { | |
226 public void check(LuanState luan,String name) throws LuanException { | |
227 if( !name.startsWith("luan:") ) | |
228 throw new LuanException("Security violation - only luan:* modules can load Java"); | |
229 if( name.equals("luan:logging/Logging") ) | |
230 throw new LuanException("Security violation - cannot reload Logging"); | |
231 } | |
232 }; | |
233 } |