Mercurial Hosting > luan
view http/src/luan/modules/http/HttpServicer.java @ 496:c65df5b25932
remove Http.session
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Sat, 16 May 2015 20:19:05 -0600 |
parents | 598123096772 |
children | 55f9f74f1e55 |
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"); HttpServicer lib = new HttpServicer(request,response); try { module.put( luan, "request", lib.requestTable() ); 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 PrintWriter writer = null; // private ServletOutputStream sos = null; private HttpServicer(HttpServletRequest request,HttpServletResponse response) { this.request = request; this.response = response; } private LuanTable requestTable() throws NoSuchMethodException { LuanTable tbl = LuanPropertyMeta.INSTANCE.newTable(); LuanTable getters = LuanPropertyMeta.INSTANCE.getters(tbl); tbl.rawPut("java",request); LuanTable parameters = new NameMeta() { @Override Object get(String name) { return request.getParameter(name); } @Override protected Iterator keys(LuanTable tbl) { return new EnumerationIterator(request.getParameterNames()); } @Override protected String type(LuanTable tbl) { return "request.parameters"; } }.newTable(); tbl.rawPut( "parameters", parameters ); add( tbl, "get_parameter_values", String.class ); LuanTable headers = new NameMeta() { @Override Object get(String name) { return request.getHeader(name); } @Override protected Iterator keys(LuanTable tbl) { return new EnumerationIterator(request.getHeaderNames()); } @Override protected String type(LuanTable tbl) { return "request.headers"; } }.newTable(); tbl.rawPut( "headers", headers ); getters.rawPut( "method", new LuanJavaFunction( HttpServletRequest.class.getMethod( "getMethod" ), request ) ); getters.rawPut( "path", new LuanJavaFunction( HttpServletRequest.class.getMethod( "getRequestURI" ), request ) ); getters.rawPut( "server_name", new LuanJavaFunction( HttpServletRequest.class.getMethod( "getServerName" ), request ) ); getters.rawPut( "url", new LuanJavaFunction( HttpServicer.class.getMethod( "getURL" ), this ) ); getters.rawPut( "query_string", new LuanJavaFunction( HttpServicer.class.getMethod( "getQueryString" ), this ) ); getters.rawPut( "remote_address", new LuanJavaFunction( HttpServletRequest.class.getMethod( "getRemoteAddr" ), request ) ); getters.rawPut( "protocol", new LuanJavaFunction( HttpServletRequest.class.getMethod( "getProtocol" ), request ) ); getters.rawPut( "scheme", new LuanJavaFunction( HttpServletRequest.class.getMethod( "getScheme" ), request ) ); getters.rawPut( "is_secure", new LuanJavaFunction( HttpServletRequest.class.getMethod( "isSecure" ), request ) ); LuanTable cookies = new LuanMeta() { @Override public Object __index(LuanState luan,LuanTable tbl,Object key) { if( !(key instanceof String) ) return null; String name = (String)key; return getCookieValue(request,name); } @Override protected Iterator<Object> keys(LuanTable tbl) { return new Iterator<Object>() { final Cookie[] cookies = request.getCookies(); int i = 0; @Override public boolean hasNext() { return i < cookies.length; } @Override public Object next() { return cookies[i++].getName(); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } @Override protected String type(LuanTable tbl) { return "request.cookies"; } }.newTable(); tbl.rawPut( "cookies", cookies ); String contentType = request.getContentType(); if( contentType!=null && contentType.startsWith("multipart/form-data") ) { try { InputStream in = new BufferedInputStream(request.getInputStream()); final MultiPartInputStream mpis = new MultiPartInputStream(in,contentType,null,null); mpis.setDeleteOnExit(true); parameters = new LuanTable(); final Map map = new HashMap(); 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; } parameters.rawPut(name,value); Object old = map.get(name); if( old == null ) { map.put(name,value); } else if( old instanceof Object[] ) { Object[] aOld = (Object[])old; Object[] aNew = new Object[aOld.length+1]; System.arraycopy(aOld,0,aNew,0,aOld.length); aNew[aOld.length] = value; map.put(name,aNew); } else { map.put(name,new Object[]{old,value}); } } tbl.rawPut( "parameters", parameters ); tbl.rawPut( "get_parameter_values", new LuanFunction() { @Override public Object call(LuanState luan,Object[] args) throws LuanException { return args.length==0 ? null : map.get(args[0]); } } ); } catch(IOException e) { throw new RuntimeException(e); } catch(ServletException e) { throw new RuntimeException(e); } } return tbl; } 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 void text_write(LuanState luan,Object... args) throws LuanException, IOException { if( writer == null ) writer = response.getWriter(); for( Object obj : args ) { writer.print( luan.toString(obj) ); } } */ public LuanTable text_writer() throws IOException { return IoLuan.textWriter(response.getWriter()); } public Object[] get_parameter_values(String name) { return request.getParameterValues(name); } 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 public String getQueryString() { return getQueryString(request); } public static String getQueryString(HttpServletRequest request) { return getQueryString(request,0); } public static String getQueryString(HttpServletRequest request,int maxValueLen) { String method = request.getMethod(); if( method.equals("GET") ) return request.getQueryString(); if( !method.equals("POST") && !method.equals("HEAD") ) throw new RuntimeException(method); Enumeration en = request.getParameterNames(); StringBuilder queryBuf = new StringBuilder(); if( !en.hasMoreElements() ) return null; do { String param = (String)en.nextElement(); String value = request.getParameter(param); if( maxValueLen > 0 ) { int len = value.length(); if( len > maxValueLen ) value = value.substring(0,maxValueLen) + "..." + (len-maxValueLen); } queryBuf.append(param); queryBuf.append('='); queryBuf.append(value); queryBuf.append('&'); } while( en.hasMoreElements() ); queryBuf.deleteCharAt(queryBuf.length() - 1); return queryBuf.toString(); } public String getURL() { return getURL(request); } public static String getURL(HttpServletRequest request) { return getURL(request,0); } public static String getURL(HttpServletRequest request,int maxValueLen) { // StringBuffer buf = HttpUtils.getRequestURL(request); StringBuffer buf = request.getRequestURL(); String qStr = getQueryString(request,maxValueLen); if(qStr != null && qStr.length() > 0) { buf.append('?'); buf.append(qStr); } return buf.toString(); } 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 String getCookieValue(HttpServletRequest request,String name) { Cookie cookie = getCookie(request,name); return cookie==null ? null : unescape(cookie.getValue()); } 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 static final class EnumerationIterator implements Iterator { private final Enumeration en; EnumerationIterator(Enumeration en) { this.en = en; } @Override public boolean hasNext() { return en.hasMoreElements(); } @Override public Object next() { return en.nextElement(); } @Override public void remove() { throw new UnsupportedOperationException(); } } 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); } }; private static String string(Object value) { if( !(value instanceof String) ) throw new IllegalArgumentException("value must be string"); return (String)value; } }