Mercurial Hosting > luan
annotate src/luan/host/WebHandler.java @ 1264:d41997776788
fix onClose issues
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Tue, 25 Sep 2018 17:03:57 -0600 |
parents | 382c444a6c77 |
children | 51a1987b55a3 |
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 { |
1231 | 35 private final Handler handler; |
36 private final LuanHandler luanHandler; | |
1230 | 37 |
1264 | 38 private LuanRef(Handler handler,LuanHandler luanHandler) { |
1231 | 39 this.handler = handler; |
40 this.luanHandler = luanHandler; | |
1230 | 41 } |
42 } | |
43 | |
44 private static final ReferenceQueue<LuanRef> queue = new ReferenceQueue<LuanRef>(); | |
45 | |
46 private static class MyReference extends SoftReference<LuanRef> { | |
1264 | 47 private LuanHandler luanHandler; |
1230 | 48 |
49 private MyReference(LuanRef lr) { | |
50 super(lr,queue); | |
1264 | 51 this.luanHandler = lr.luanHandler; |
1230 | 52 } |
53 } | |
54 | |
55 private static void sweep() { | |
56 while(true) { | |
57 MyReference ref = (MyReference)queue.poll(); | |
58 if( ref == null ) | |
59 return; | |
1232 | 60 //logger.info("sweep"); |
1264 | 61 ref.luanHandler.close(); |
62 ref.luanHandler = null; | |
1230 | 63 } |
64 } | |
65 | |
66 | |
1202 | 67 public static String allowJavaFileName = "allow_java"; // change for security |
1230 | 68 private static final Map<String,MyReference> siteMap = new HashMap<String,MyReference>(); |
1202 | 69 private static String sitesDir = null; |
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; |
1231 | 91 return lr.handler.handle(request); |
1135 | 92 } |
93 | |
94 public static Object runLuan(String domain,String sourceText,String sourceName) throws LuanException { | |
1230 | 95 LuanRef lr = getSite(domain); |
1231 | 96 return lr.luanHandler.runLuan(sourceText,sourceName); |
1135 | 97 } |
98 | |
99 public static Object callSite(String domain,String fnName,Object... args) throws LuanException { | |
1230 | 100 LuanRef lr = getSite(domain); |
1231 | 101 return lr.luanHandler.call_rpc(fnName,args); |
1135 | 102 } |
103 | |
1230 | 104 private static LuanRef getSite(String domain) { |
1135 | 105 synchronized(siteMap) { |
1230 | 106 Reference<LuanRef> ref = siteMap.get(domain); |
107 LuanRef lr = ref==null ? null : ref.get(); | |
108 if( lr == null ) { | |
1203 | 109 //if(ref!=null) logger.info("gc "+domain); |
1135 | 110 if( sitesDir==null ) |
111 throw new NullPointerException("sitesDir"); | |
112 File dir = new File(sitesDir,domain); | |
113 if( !dir.exists() /* && !recover(dir) */ ) | |
114 return null; | |
1230 | 115 sweep(); |
1231 | 116 lr = newSite(dir.toString(),domain); |
1230 | 117 siteMap.put(domain,new MyReference(lr)); |
1135 | 118 } |
1230 | 119 return lr; |
1135 | 120 } |
121 } | |
122 /* | |
123 private static boolean recover(File dir) { | |
124 File backups = new File(dir.getParentFile().getParentFile(),"backups"); | |
125 if( !backups.exists() ) | |
126 return false; | |
127 String name = dir.getName(); | |
128 File from = null; | |
129 for( File backup : backups.listFiles() ) { | |
130 File d = new File(backup,"current/"+name); | |
131 if( d.exists() && (from==null || from.lastModified() < d.lastModified()) ) | |
132 from = d; | |
133 } | |
134 if( from == null ) | |
135 return false; | |
136 if( !from.renameTo(dir) ) | |
137 throw new RuntimeException("couldn't rename "+from+" to "+dir); | |
138 logger.info("recovered "+name+" from "+from); | |
139 return true; | |
140 } | |
141 */ | |
142 static LuanTable initLuan(LuanState luan,String dir,String domain) { | |
143 LuanTable init; | |
144 try { | |
145 init = (LuanTable)luan.eval( | |
146 "local Luan = require 'luan:Luan.luan'\n" | |
147 +"local f = Luan.load_file 'classpath:luan/host/Init.luan'\n" | |
148 +"return f('"+dir+"','"+domain+"')\n" | |
149 ); | |
150 } catch(LuanException e) { | |
151 throw new RuntimeException(e); | |
152 } | |
153 File allowJavaFile = new File(dir,"site/private/"+allowJavaFileName); | |
154 if( !allowJavaFile.exists() ) { | |
155 JavaLuan.setSecurity( luan, javaSecurity ); | |
156 IoLuan.setSecurity( luan, ioSecurity(dir) ); | |
157 } | |
158 return init; | |
159 } | |
160 | |
1231 | 161 private static LuanRef newSite(String dir,String domain) { |
1135 | 162 LuanState luan = new LuanState(); |
163 LuanTable init = initLuan(luan,dir,domain); | |
164 | |
165 String loggerRoot = (String)init.rawGet("logger_root"); | |
1263
382c444a6c77
add Http.eval_in_root and Http.handle_error
Franklin Schmidt <fschmidt@gmail.com>
parents:
1256
diff
changeset
|
166 LuanHandler luanHandler = new LuanHandler(luan,loggerRoot); |
1185
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
167 NotFound notFoundHandler = new NotFound(luanHandler); |
1135 | 168 |
1185
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
169 Handler handler = luanHandler; |
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
170 handler = new IndexHandler(handler); |
94cf2576a922
implement WebHandler for nginx
Franklin Schmidt <fschmidt@gmail.com>
parents:
1182
diff
changeset
|
171 handler = new ListHandler( handler, notFoundHandler ); |
1135 | 172 |
1202 | 173 String logDir = dir + "/site/private/local/logs/web"; |
1135 | 174 new File(logDir).mkdirs(); |
175 | |
1264 | 176 return new LuanRef(handler,luanHandler); |
1135 | 177 } |
178 | |
179 public static void removeHandler(String domain) throws Exception { | |
180 synchronized(siteMap) { | |
1230 | 181 Reference<LuanRef> ref = siteMap.remove(domain); |
182 LuanRef lr = ref==null ? null : ref.get(); | |
183 if( lr != null ) { | |
1264 | 184 lr.luanHandler.close(); |
1135 | 185 } |
186 } | |
187 } | |
188 | |
189 public static void loadHandler(String domain) { | |
190 getSite(domain); | |
191 } | |
192 | |
193 private static final IoLuan.Security ioSecurity(String dir) { | |
1174
bdf27aa2a65c
fix luanhost security bug
Franklin Schmidt <fschmidt@gmail.com>
parents:
1136
diff
changeset
|
194 final String siteUri = "file:" + dir + "/site"; |
1135 | 195 return new IoLuan.Security() { |
196 public void check(LuanState luan,String name) throws LuanException { | |
197 if( name.startsWith("file:") ) { | |
198 if( name.contains("..") ) | |
199 throw new LuanException("Security violation - '"+name+"' contains '..'"); | |
1174
bdf27aa2a65c
fix luanhost security bug
Franklin Schmidt <fschmidt@gmail.com>
parents:
1136
diff
changeset
|
200 if( !(name.equals(siteUri) || name.startsWith(siteUri+"/")) ) |
1135 | 201 throw new LuanException("Security violation - '"+name+"' outside of site dir"); |
202 } | |
203 else if( name.startsWith("classpath:luan/host/") ) { | |
204 throw new LuanException("Security violation"); | |
205 } | |
206 else if( name.startsWith("os:") || name.startsWith("bash:") ) { | |
207 throw new LuanException("Security violation"); | |
208 } | |
209 } | |
210 }; | |
211 } | |
212 | |
213 private static final JavaLuan.Security javaSecurity = new JavaLuan.Security() { | |
214 public void check(LuanState luan,String name) throws LuanException { | |
1238 | 215 if( !(name.startsWith("luan:") || name.matches("^file:[^/]+$")) ) |
1135 | 216 throw new LuanException("Security violation - only luan:* modules can load Java"); |
217 if( name.equals("luan:logging/Logging") ) | |
218 throw new LuanException("Security violation - cannot reload Logging"); | |
219 } | |
220 }; | |
221 } |