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