Mercurial Hosting > luan
view 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 |
line wrap: on
line source
package luan.modules.http; import java.io.InputStream; import java.io.BufferedInputStream; import java.io.PrintWriter; import java.io.IOException; import java.util.Map; import java.util.HashMap; import java.util.AbstractMap; import java.util.Set; import java.util.List; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.Enumeration; import javax.servlet.ServletOutputStream; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.http.Part; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.eclipse.jetty.util.MultiPartInputStream; import luan.Luan; import luan.LuanState; import luan.LuanFunction; import luan.LuanElement; import luan.LuanException; import luan.LuanTable; import luan.LuanMeta; import luan.LuanJavaFunction; import luan.LuanPropertyMeta; import luan.DeepCloner; import luan.modules.PackageLuan; import luan.modules.IoLuan; import luan.modules.TableLuan; import luan.modules.Utils; public final class HttpServicer { private static final Logger logger = LoggerFactory.getLogger(HttpServicer.class); public static boolean service(LuanState luan,HttpServletRequest request,HttpServletResponse response,String modName) throws LuanException { LuanFunction fn; synchronized(luan) { Object mod = PackageLuan.load(luan,modName); if( mod==null ) return false; if( !(mod instanceof LuanTable) ) throw luan.exception( "module '"+modName+"' must return a table" ); LuanTable tbl = (LuanTable)mod; if( Boolean.TRUE.equals(tbl.get(luan,"per_session")) ) { HttpSession session = request.getSession(); LuanState sessionLuan = (LuanState)session.getValue("luan"); if( sessionLuan!=null ) { luan = sessionLuan; } else { DeepCloner cloner = new DeepCloner(); luan = (LuanState)cloner.deepClone(luan); session.putValue("luan",luan); } tbl = (LuanTable)PackageLuan.require(luan,modName); fn = getService(luan,tbl); } else { fn = getService(luan,tbl); DeepCloner cloner = new DeepCloner(); luan = (LuanState)cloner.deepClone(luan); fn = (LuanFunction)cloner.get(fn); } } LuanTable module = (LuanTable)PackageLuan.require(luan,"luan:http/Http"); // request LuanTable requestTbl = (LuanTable)luan.call( (LuanFunction)module.rawGet("new_request") ); module.rawPut("request",requestTbl); requestTbl.rawPut("java",request); requestTbl.rawPut("method",request.getMethod()); requestTbl.rawPut("path",request.getRequestURI()); requestTbl.rawPut("protocol",request.getProtocol()); requestTbl.rawPut("scheme",request.getScheme()); LuanTable headersTbl = (LuanTable)requestTbl.rawGet("headers"); for( Enumeration<String> enKeys = request.getHeaderNames(); enKeys.hasMoreElements(); ) { String key = enKeys.nextElement(); key = key.toLowerCase().replace('-','_'); LuanTable values = new LuanTable(); for( Enumeration<String> en = request.getHeaders(key); en.hasMoreElements(); ) { values.rawPut(values.rawLength()+1,en.nextElement()); } headersTbl.rawPut(key,values); } LuanTable parametersTbl = (LuanTable)requestTbl.rawGet("parameters"); String contentType = request.getContentType(); if( contentType==null || !contentType.startsWith("multipart/form-data") ) { for( Map.Entry<String,String[]> entry : request.getParameterMap().entrySet() ) { parametersTbl.rawPut(entry.getKey(),new LuanTable(Arrays.asList(entry.getValue()))); } } else { // multipart try { InputStream in = new BufferedInputStream(request.getInputStream()); final MultiPartInputStream mpis = new MultiPartInputStream(in,contentType,null,null); mpis.setDeleteOnExit(true); for( Part p : mpis.getParts() ) { final MultiPartInputStream.MultiPart part = (MultiPartInputStream.MultiPart)p; String name = part.getName(); Object value; String filename = part.getContentDispositionFilename(); if( filename == null ) { value = new String(part.getBytes()); } else { LuanTable partTbl = LuanPropertyMeta.INSTANCE.newTable(); partTbl.rawPut("filename",filename); partTbl.rawPut("content_type",part.getContentType()); LuanPropertyMeta.INSTANCE.getters(partTbl).rawPut( "content", new LuanFunction() { @Override public Object call(LuanState luan,Object[] args) throws LuanException { try { InputStream in = part.getInputStream(); byte[] content = Utils.readAll(in); in.close(); return content; } catch(IOException e) { throw new RuntimeException(e); } } } ); value = partTbl; } LuanTable list = (LuanTable)parametersTbl.rawGet(name); if( list == null ) { list = new LuanTable(); parametersTbl.rawPut(name,list); } parametersTbl.rawPut(parametersTbl.rawLength()+1,value); } } catch(IOException e) { throw new RuntimeException(e); } catch(ServletException e) { throw new RuntimeException(e); } } LuanTable cookieTbl = (LuanTable)requestTbl.rawGet("cookie"); for( Cookie cookie : request.getCookies() ) { cookieTbl.rawPut( cookie.getName(), unescape(cookie.getValue()) ); } HttpServicer lib = new HttpServicer(request,response); try { module.put( luan, "response", lib.responseTable() ); } catch(NoSuchMethodException e) { throw new RuntimeException(e); } luan.call(fn,"<http>"); return true; } private static LuanFunction getService(LuanState luan,LuanTable tbl) throws LuanException { Object respond = tbl.get(luan,"respond"); if( respond == null ) throw luan.exception( "function 'respond' is not defined" ); if( !(respond instanceof LuanFunction) ) throw luan.exception( "'respond' must be a function but is a " + Luan.type(respond) ); return (LuanFunction)respond; } private final HttpServletRequest request; private final HttpServletResponse response; private HttpServicer(HttpServletRequest request,HttpServletResponse response) { this.request = request; this.response = response; } private LuanTable responseTable() throws NoSuchMethodException { LuanTable tbl = LuanPropertyMeta.INSTANCE.newTable(); LuanTable getters = LuanPropertyMeta.INSTANCE.getters(tbl); LuanTable setters = LuanPropertyMeta.INSTANCE.setters(tbl); tbl.rawPut("java",response); tbl.rawPut( "send_redirect", new LuanJavaFunction( HttpServletResponse.class.getMethod( "sendRedirect", String.class ), response ) ); tbl.rawPut( "send_error", new LuanJavaFunction( HttpServletResponse.class.getMethod( "sendError", Integer.TYPE, String.class ), response ) ); LuanTable headers = new NameMeta() { @Override Object get(String name) { return response.getHeader(name); } @Override protected Iterator keys(LuanTable tbl) { return response.getHeaderNames().iterator(); } @Override public boolean canNewindex() { return true; } @Override public void __new_index(LuanState luan,LuanTable tbl,Object key,Object val) { if( !(key instanceof String) ) throw new IllegalArgumentException("key must be string for headers table"); String name = (String)key; if( val instanceof String ) { response.setHeader(name,(String)val); return; } Integer i = Luan.asInteger(val); if( i != null ) { response.setIntHeader(name,i); return; } throw new IllegalArgumentException("value must be string or integer for headers table"); } @Override protected String type(LuanTable tbl) { return "response.headers"; } }.newTable(); tbl.rawPut( "headers", headers ); getters.rawPut( "content_type", new LuanJavaFunction( HttpServletResponse.class.getMethod( "getContentType" ), response ) ); setters.rawPut( "content_type", new LuanJavaFunction( HttpServletResponse.class.getMethod( "setContentType", String.class ), response ) ); getters.rawPut( "character_encoding", new LuanJavaFunction( HttpServletResponse.class.getMethod( "getCharacterEncoding" ), response ) ); setters.rawPut( "character_encoding", new LuanJavaFunction( HttpServletResponse.class.getMethod( "setCharacterEncoding", String.class ), response ) ); add( tbl, "text_writer" ); add( tbl, "set_cookie", String.class, String.class, Boolean.TYPE, String.class ); add( tbl, "remove_cookie", String.class, String.class ); try { getters.rawPut( "status", new LuanJavaFunction( HttpServletResponse.class.getMethod( "getStatus" ), response ) ); } catch(NoSuchMethodException e) { logger.info("please upgrade jetty"); } setters.rawPut( "status", new LuanJavaFunction( HttpServletResponse.class.getMethod( "setStatus", Integer.TYPE ), response ) ); return tbl; } private void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { t.rawPut( method, new LuanJavaFunction(HttpServicer.class.getMethod(method,parameterTypes),this) ); } public LuanTable text_writer() throws IOException { return IoLuan.textWriter(response.getWriter()); } public void set_cookie(String name,String value,boolean isPersistent, String domain) { setCookie(request,response,name,value,isPersistent,domain); } public void remove_cookie(String name, String domain) { removeCookie(request,response,name,domain); } // static utils private static String escape(String value) { return value.replaceAll(";", "%3B"); } private static String unescape(String value) { return value.replaceAll("%3B", ";"); } private static Cookie getCookie(HttpServletRequest request,String name) { Cookie[] cookies = request.getCookies(); if( cookies == null ) return null; for (Cookie cookie : cookies) { if (cookie.getName().equals(name)) return cookie; } return null; } public static void setCookie(HttpServletRequest request,HttpServletResponse response,String name,String value,boolean isPersistent, String domain) { Cookie cookie = getCookie(request,name); if( cookie==null || !cookie.getValue().equals(value) ) { cookie = new Cookie(name, escape(value)); cookie.setPath("/"); if (domain != null && domain.length() > 0) cookie.setDomain(domain); if( isPersistent ) cookie.setMaxAge(10000000); response.addCookie(cookie); } } public static void removeCookie(HttpServletRequest request, HttpServletResponse response, String name, String domain ) { Cookie cookie = getCookie(request, name); if(cookie != null) { Cookie delCookie = new Cookie(name, "delete"); delCookie.setPath("/"); delCookie.setMaxAge(0); if (domain != null && domain.length() > 0) delCookie.setDomain(domain); response.addCookie(delCookie); } } // util classes private static abstract class NameMeta extends LuanMeta { abstract Object get(String name); @Override public Object __index(LuanState luan,LuanTable tbl,Object key) { if( !(key instanceof String) ) return null; String name = (String)key; return get(name); } }; }