comparison http/src/luan/modules/http/HttpServicer.java @ 497:55f9f74f1e55

Http.request is now pure luan
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 17 May 2015 19:25:47 -0600
parents c65df5b25932
children ee55be414a34
comparison
equal deleted inserted replaced
496:c65df5b25932 497:55f9f74f1e55
72 fn = (LuanFunction)cloner.get(fn); 72 fn = (LuanFunction)cloner.get(fn);
73 } 73 }
74 } 74 }
75 75
76 LuanTable module = (LuanTable)PackageLuan.require(luan,"luan:http/Http"); 76 LuanTable module = (LuanTable)PackageLuan.require(luan,"luan:http/Http");
77 HttpServicer lib = new HttpServicer(request,response); 77
78 try { 78 // request
79 module.put( luan, "request", lib.requestTable() ); 79 LuanTable requestTbl = (LuanTable)luan.call( (LuanFunction)module.rawGet("new_request") );
80 module.put( luan, "response", lib.responseTable() ); 80 module.rawPut("request",requestTbl);
81 } catch(NoSuchMethodException e) { 81 requestTbl.rawPut("java",request);
82 throw new RuntimeException(e); 82 requestTbl.rawPut("method",request.getMethod());
83 } 83 requestTbl.rawPut("path",request.getRequestURI());
84 84 requestTbl.rawPut("protocol",request.getProtocol());
85 luan.call(fn,"<http>"); 85 requestTbl.rawPut("scheme",request.getScheme());
86 return true; 86
87 } 87 LuanTable headersTbl = (LuanTable)requestTbl.rawGet("headers");
88 88 for( Enumeration<String> enKeys = request.getHeaderNames(); enKeys.hasMoreElements(); ) {
89 private static LuanFunction getService(LuanState luan,LuanTable tbl) 89 String key = enKeys.nextElement();
90 throws LuanException 90 key = key.toLowerCase().replace('-','_');
91 { 91 LuanTable values = new LuanTable();
92 Object respond = tbl.get(luan,"respond"); 92 for( Enumeration<String> en = request.getHeaders(key); en.hasMoreElements(); ) {
93 if( respond == null ) 93 values.rawPut(values.rawLength()+1,en.nextElement());
94 throw luan.exception( "function 'respond' is not defined" ); 94 }
95 if( !(respond instanceof LuanFunction) ) 95 headersTbl.rawPut(key,values);
96 throw luan.exception( "'respond' must be a function but is a " + Luan.type(respond) ); 96 }
97 return (LuanFunction)respond; 97
98 } 98 LuanTable parametersTbl = (LuanTable)requestTbl.rawGet("parameters");
99
100
101 private final HttpServletRequest request;
102 private final HttpServletResponse response;
103 // private PrintWriter writer = null;
104 // private ServletOutputStream sos = null;
105
106 private HttpServicer(HttpServletRequest request,HttpServletResponse response) {
107 this.request = request;
108 this.response = response;
109 }
110
111 private LuanTable requestTable() throws NoSuchMethodException {
112 LuanTable tbl = LuanPropertyMeta.INSTANCE.newTable();
113 LuanTable getters = LuanPropertyMeta.INSTANCE.getters(tbl);
114 tbl.rawPut("java",request);
115 LuanTable parameters = new NameMeta() {
116
117 @Override Object get(String name) {
118 return request.getParameter(name);
119 }
120
121 @Override protected Iterator keys(LuanTable tbl) {
122 return new EnumerationIterator(request.getParameterNames());
123 }
124
125 @Override protected String type(LuanTable tbl) {
126 return "request.parameters";
127 }
128
129 }.newTable();
130 tbl.rawPut( "parameters", parameters );
131 add( tbl, "get_parameter_values", String.class );
132 LuanTable headers = new NameMeta() {
133
134 @Override Object get(String name) {
135 return request.getHeader(name);
136 }
137
138 @Override protected Iterator keys(LuanTable tbl) {
139 return new EnumerationIterator(request.getHeaderNames());
140 }
141
142 @Override protected String type(LuanTable tbl) {
143 return "request.headers";
144 }
145
146 }.newTable();
147 tbl.rawPut( "headers", headers );
148 getters.rawPut( "method", new LuanJavaFunction(
149 HttpServletRequest.class.getMethod( "getMethod" ), request
150 ) );
151 getters.rawPut( "path", new LuanJavaFunction(
152 HttpServletRequest.class.getMethod( "getRequestURI" ), request
153 ) );
154 getters.rawPut( "server_name", new LuanJavaFunction(
155 HttpServletRequest.class.getMethod( "getServerName" ), request
156 ) );
157 getters.rawPut( "url", new LuanJavaFunction(
158 HttpServicer.class.getMethod( "getURL" ), this
159 ) );
160 getters.rawPut( "query_string", new LuanJavaFunction(
161 HttpServicer.class.getMethod( "getQueryString" ), this
162 ) );
163 getters.rawPut( "remote_address", new LuanJavaFunction(
164 HttpServletRequest.class.getMethod( "getRemoteAddr" ), request
165 ) );
166 getters.rawPut( "protocol", new LuanJavaFunction(
167 HttpServletRequest.class.getMethod( "getProtocol" ), request
168 ) );
169 getters.rawPut( "scheme", new LuanJavaFunction(
170 HttpServletRequest.class.getMethod( "getScheme" ), request
171 ) );
172 getters.rawPut( "is_secure", new LuanJavaFunction(
173 HttpServletRequest.class.getMethod( "isSecure" ), request
174 ) );
175 LuanTable cookies = new LuanMeta() {
176
177 @Override public Object __index(LuanState luan,LuanTable tbl,Object key) {
178 if( !(key instanceof String) )
179 return null;
180 String name = (String)key;
181 return getCookieValue(request,name);
182 }
183
184 @Override protected Iterator<Object> keys(LuanTable tbl) {
185 return new Iterator<Object>() {
186 final Cookie[] cookies = request.getCookies();
187 int i = 0;
188
189 @Override public boolean hasNext() {
190 return i < cookies.length;
191 }
192 @Override public Object next() {
193 return cookies[i++].getName();
194 }
195 @Override public void remove() {
196 throw new UnsupportedOperationException();
197 }
198 };
199 }
200
201 @Override protected String type(LuanTable tbl) {
202 return "request.cookies";
203 }
204
205 }.newTable();
206 tbl.rawPut( "cookies", cookies );
207
208 String contentType = request.getContentType(); 99 String contentType = request.getContentType();
209 if( contentType!=null && contentType.startsWith("multipart/form-data") ) { 100 if( contentType==null || !contentType.startsWith("multipart/form-data") ) {
101 for( Map.Entry<String,String[]> entry : request.getParameterMap().entrySet() ) {
102 parametersTbl.rawPut(entry.getKey(),new LuanTable(Arrays.asList(entry.getValue())));
103 }
104 } else { // multipart
210 try { 105 try {
211 InputStream in = new BufferedInputStream(request.getInputStream()); 106 InputStream in = new BufferedInputStream(request.getInputStream());
212 final MultiPartInputStream mpis = new MultiPartInputStream(in,contentType,null,null); 107 final MultiPartInputStream mpis = new MultiPartInputStream(in,contentType,null,null);
213 mpis.setDeleteOnExit(true); 108 mpis.setDeleteOnExit(true);
214 parameters = new LuanTable();
215 final Map map = new HashMap();
216 for( Part p : mpis.getParts() ) { 109 for( Part p : mpis.getParts() ) {
217 final MultiPartInputStream.MultiPart part = (MultiPartInputStream.MultiPart)p; 110 final MultiPartInputStream.MultiPart part = (MultiPartInputStream.MultiPart)p;
218 String name = part.getName(); 111 String name = part.getName();
219 Object value; 112 Object value;
220 String filename = part.getContentDispositionFilename(); 113 String filename = part.getContentDispositionFilename();
236 } 129 }
237 } 130 }
238 } ); 131 } );
239 value = partTbl; 132 value = partTbl;
240 } 133 }
241 parameters.rawPut(name,value); 134 LuanTable list = (LuanTable)parametersTbl.rawGet(name);
242 Object old = map.get(name); 135 if( list == null ) {
243 if( old == null ) { 136 list = new LuanTable();
244 map.put(name,value); 137 parametersTbl.rawPut(name,list);
245 } else if( old instanceof Object[] ) {
246 Object[] aOld = (Object[])old;
247 Object[] aNew = new Object[aOld.length+1];
248 System.arraycopy(aOld,0,aNew,0,aOld.length);
249 aNew[aOld.length] = value;
250 map.put(name,aNew);
251 } else {
252 map.put(name,new Object[]{old,value});
253 } 138 }
139 parametersTbl.rawPut(parametersTbl.rawLength()+1,value);
254 } 140 }
255 tbl.rawPut( "parameters", parameters );
256 tbl.rawPut( "get_parameter_values", new LuanFunction() {
257 @Override public Object call(LuanState luan,Object[] args) throws LuanException {
258 return args.length==0 ? null : map.get(args[0]);
259 }
260 } );
261 } catch(IOException e) { 141 } catch(IOException e) {
262 throw new RuntimeException(e); 142 throw new RuntimeException(e);
263 } catch(ServletException e) { 143 } catch(ServletException e) {
264 throw new RuntimeException(e); 144 throw new RuntimeException(e);
265 } 145 }
266 } 146 }
267 147
268 return tbl; 148 LuanTable cookieTbl = (LuanTable)requestTbl.rawGet("cookie");
149 for( Cookie cookie : request.getCookies() ) {
150 cookieTbl.rawPut( cookie.getName(), unescape(cookie.getValue()) );
151 }
152
153 HttpServicer lib = new HttpServicer(request,response);
154 try {
155 module.put( luan, "response", lib.responseTable() );
156 } catch(NoSuchMethodException e) {
157 throw new RuntimeException(e);
158 }
159
160 luan.call(fn,"<http>");
161 return true;
162 }
163
164 private static LuanFunction getService(LuanState luan,LuanTable tbl)
165 throws LuanException
166 {
167 Object respond = tbl.get(luan,"respond");
168 if( respond == null )
169 throw luan.exception( "function 'respond' is not defined" );
170 if( !(respond instanceof LuanFunction) )
171 throw luan.exception( "'respond' must be a function but is a " + Luan.type(respond) );
172 return (LuanFunction)respond;
173 }
174
175
176 private final HttpServletRequest request;
177 private final HttpServletResponse response;
178
179 private HttpServicer(HttpServletRequest request,HttpServletResponse response) {
180 this.request = request;
181 this.response = response;
269 } 182 }
270 183
271 private LuanTable responseTable() throws NoSuchMethodException { 184 private LuanTable responseTable() throws NoSuchMethodException {
272 LuanTable tbl = LuanPropertyMeta.INSTANCE.newTable(); 185 LuanTable tbl = LuanPropertyMeta.INSTANCE.newTable();
273 LuanTable getters = LuanPropertyMeta.INSTANCE.getters(tbl); 186 LuanTable getters = LuanPropertyMeta.INSTANCE.getters(tbl);
344 } 257 }
345 258
346 private void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { 259 private void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException {
347 t.rawPut( method, new LuanJavaFunction(HttpServicer.class.getMethod(method,parameterTypes),this) ); 260 t.rawPut( method, new LuanJavaFunction(HttpServicer.class.getMethod(method,parameterTypes),this) );
348 } 261 }
349 /* 262
350 public void text_write(LuanState luan,Object... args) throws LuanException, IOException {
351 if( writer == null )
352 writer = response.getWriter();
353 for( Object obj : args ) {
354 writer.print( luan.toString(obj) );
355 }
356 }
357 */
358 public LuanTable text_writer() throws IOException { 263 public LuanTable text_writer() throws IOException {
359 return IoLuan.textWriter(response.getWriter()); 264 return IoLuan.textWriter(response.getWriter());
360 } 265 }
361 266
362 public Object[] get_parameter_values(String name) {
363 return request.getParameterValues(name);
364 }
365
366 public void set_cookie(String name,String value,boolean isPersistent, String domain) { 267 public void set_cookie(String name,String value,boolean isPersistent, String domain) {
367 setCookie(request,response,name,value,isPersistent,domain); 268 setCookie(request,response,name,value,isPersistent,domain);
368 } 269 }
369 270
370 public void remove_cookie(String name, String domain) { 271 public void remove_cookie(String name, String domain) {
371 removeCookie(request,response,name,domain); 272 removeCookie(request,response,name,domain);
372 } 273 }
373 274
374 275
375 // static utils 276 // static utils
376
377 public String getQueryString() {
378 return getQueryString(request);
379 }
380
381 public static String getQueryString(HttpServletRequest request) {
382 return getQueryString(request,0);
383 }
384
385 public static String getQueryString(HttpServletRequest request,int maxValueLen) {
386 String method = request.getMethod();
387 if( method.equals("GET") )
388 return request.getQueryString();
389 if( !method.equals("POST") && !method.equals("HEAD") )
390 throw new RuntimeException(method);
391 Enumeration en = request.getParameterNames();
392 StringBuilder queryBuf = new StringBuilder();
393 if( !en.hasMoreElements() )
394 return null;
395 do {
396 String param = (String)en.nextElement();
397 String value = request.getParameter(param);
398 if( maxValueLen > 0 ) {
399 int len = value.length();
400 if( len > maxValueLen )
401 value = value.substring(0,maxValueLen) + "..." + (len-maxValueLen);
402 }
403 queryBuf.append(param);
404 queryBuf.append('=');
405 queryBuf.append(value);
406 queryBuf.append('&');
407 } while( en.hasMoreElements() );
408 queryBuf.deleteCharAt(queryBuf.length() - 1);
409 return queryBuf.toString();
410 }
411
412 public String getURL() {
413 return getURL(request);
414 }
415
416 public static String getURL(HttpServletRequest request) {
417 return getURL(request,0);
418 }
419
420 public static String getURL(HttpServletRequest request,int maxValueLen) {
421 // StringBuffer buf = HttpUtils.getRequestURL(request);
422 StringBuffer buf = request.getRequestURL();
423 String qStr = getQueryString(request,maxValueLen);
424 if(qStr != null && qStr.length() > 0) {
425 buf.append('?');
426 buf.append(qStr);
427 }
428 return buf.toString();
429 }
430 277
431 private static String escape(String value) { 278 private static String escape(String value) {
432 return value.replaceAll(";", "%3B"); 279 return value.replaceAll(";", "%3B");
433 } 280 }
434 281
443 for (Cookie cookie : cookies) { 290 for (Cookie cookie : cookies) {
444 if (cookie.getName().equals(name)) 291 if (cookie.getName().equals(name))
445 return cookie; 292 return cookie;
446 } 293 }
447 return null; 294 return null;
448 }
449
450 public static String getCookieValue(HttpServletRequest request,String name) {
451 Cookie cookie = getCookie(request,name);
452 return cookie==null ? null : unescape(cookie.getValue());
453 } 295 }
454 296
455 public static void setCookie(HttpServletRequest request,HttpServletResponse response,String name,String value,boolean isPersistent, String domain) { 297 public static void setCookie(HttpServletRequest request,HttpServletResponse response,String name,String value,boolean isPersistent, String domain) {
456 Cookie cookie = getCookie(request,name); 298 Cookie cookie = getCookie(request,name);
457 if( cookie==null || !cookie.getValue().equals(value) ) { 299 if( cookie==null || !cookie.getValue().equals(value) ) {
483 325
484 326
485 327
486 // util classes 328 // util classes
487 329
488 static final class EnumerationIterator implements Iterator {
489 private final Enumeration en;
490
491 EnumerationIterator(Enumeration en) {
492 this.en = en;
493 }
494
495 @Override public boolean hasNext() {
496 return en.hasMoreElements();
497 }
498
499 @Override public Object next() {
500 return en.nextElement();
501 }
502
503 @Override public void remove() {
504 throw new UnsupportedOperationException();
505 }
506 }
507
508 private static abstract class NameMeta extends LuanMeta { 330 private static abstract class NameMeta extends LuanMeta {
509 abstract Object get(String name); 331 abstract Object get(String name);
510 332
511 @Override public Object __index(LuanState luan,LuanTable tbl,Object key) { 333 @Override public Object __index(LuanState luan,LuanTable tbl,Object key) {
512 if( !(key instanceof String) ) 334 if( !(key instanceof String) )
515 return get(name); 337 return get(name);
516 } 338 }
517 339
518 }; 340 };
519 341
520 private static String string(Object value) {
521 if( !(value instanceof String) )
522 throw new IllegalArgumentException("value must be string");
523 return (String)value;
524 }
525 } 342 }