Mercurial Hosting > luan
changeset 494:2b9bc97f0439
change luan:web to luan:http
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/http/src/luan/modules/http/AuthenticationHandler.java Fri May 15 17:43:13 2015 -0600 @@ -0,0 +1,53 @@ +package luan.modules.http; + +import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.util.B64Code; + + +public class AuthenticationHandler extends AbstractHandler { + private final String path; + private String password = "password"; + + public AuthenticationHandler(String path) { + this.path = path; + } + + public void setPassword(String password) { + this.password = password; + } + + public void handle(String target,Request baseRequest,HttpServletRequest request,HttpServletResponse response) + throws IOException + { + if( !target.startsWith(path) ) + return; + String pwd = getPassword(request); + if( password.equals(pwd) ) + return; + response.setHeader("WWW-Authenticate","Basic realm=\""+path+"\""); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + baseRequest.setHandled(true); + } + + private static String getPassword(HttpServletRequest request) { + String auth = request.getHeader("Authorization"); + if( auth==null ) + return null; + String[] a = auth.split(" +"); + if( a.length != 2 ) + throw new RuntimeException("auth = "+auth); + if( !a[0].equals("Basic") ) + throw new RuntimeException("auth = "+auth); + auth = new String(B64Code.decode(a[1])); + a = auth.split(":"); + if( a.length != 2 ) + throw new RuntimeException("auth = "+auth); + return a[1]; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/http/src/luan/modules/http/Http.luan Fri May 15 17:43:13 2015 -0600 @@ -0,0 +1,53 @@ +local Io = require "luan:Io" + + + + +function init_for_test() + + welcome_file = "index.html" + + function get_page(path) + if welcome_file ~= nil and path.matches ".*/" then + path = path .. welcome_file + end + local old_out = Io.stdout + local mod = require("site:"..path) + mod.service() + text_writer.close() + Io.stdout = old_out + return result.read_text() + end + + cookies = cookies or {} + + request = { + parameters = {}; + } + request.cookies = cookies + + response = { + + text_writer = function() + result = Io.uri "string:" + text_writer = result.text_writer() + return text_writer + end; + + set_cookie = function(name,value) + cookies[name] = value + end; + + remove_cookie = function(name) + cookies[name] = nil + end; + + send_redirect = function(url) + response.redirect = url + end; + + headers = {}; + + } + +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/http/src/luan/modules/http/HttpServicer.java Fri May 15 17:43:13 2015 -0600 @@ -0,0 +1,563 @@ +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() ); + module.put( luan, "session", lib.sessionTable() ); +/* + module.put( "write", new LuanJavaFunction( + HttpServicer.class.getMethod( "text_write", LuanState.class, new Object[0].getClass() ), lib + ) ); +*/ + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + + luan.call(fn,"<http>"); + return true; + } + + private static LuanFunction getService(LuanState luan,LuanTable tbl) + throws LuanException + { + Object service = tbl.get(luan,"service"); + if( service == null ) + throw luan.exception( "function 'service' is not defined" ); + if( !(service instanceof LuanFunction) ) + throw luan.exception( "'service' must be a function but is a " + Luan.type(service) ); + return (LuanFunction)service; + } + + + 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 LuanTable sessionTable() throws NoSuchMethodException { + LuanTable tbl = new LuanTable(); + LuanTable attributes = new NameMeta() { + + @Override Object get(String name) { + return request.getSession().getAttribute(name); + } + + @Override protected Iterator keys(LuanTable tbl) { + return new EnumerationIterator(request.getSession().getAttributeNames()); + } + + @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 session attributes table"); + String name = (String)key; + request.getSession().setAttribute(name,val); + } + + @Override protected String type(LuanTable tbl) { + return "session.attributes"; + } + + }.newTable(); + tbl.rawPut( "attributes", attributes ); + 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; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/http/src/luan/modules/http/LuanHandler.java Fri May 15 17:43:13 2015 -0600 @@ -0,0 +1,44 @@ +package luan.modules.http; + +import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import luan.LuanState; +import luan.LuanException; + + +public class LuanHandler extends AbstractHandler { + private static final Logger logger = LoggerFactory.getLogger(LuanHandler.class); + private final LuanState luan; + private String welcomeFile = "index.html"; + + public LuanHandler(LuanState luan) { + this.luan = luan; + } + + public void handle(String target,Request baseRequest,HttpServletRequest request,HttpServletResponse response) + throws IOException + { + if( target.endsWith("/") ) + target += welcomeFile; + try { + if( !HttpServicer.service(luan,request,response,"site:"+target) ) + return; + } catch(LuanException e) { + String err = e.getFullMessage(luan); + logger.error(err); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,err); + } + baseRequest.setHandled(true); + } + + public void setWelcomeFile(String welcomeFile) { + this.welcomeFile = welcomeFile; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/http/src/luan/modules/http/LuanServlet.java Fri May 15 17:43:13 2015 -0600 @@ -0,0 +1,46 @@ +package luan.modules.http; + +import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import luan.LuanState; +import luan.LuanException; + + +public class LuanServlet extends HttpServlet { + protected final String uriPrefix; + protected final LuanState luan; + + public LuanServlet(String uriPrefix,LuanState luan) { + this.uriPrefix = uriPrefix; + this.luan = luan; + } + + public LuanServlet(String uriPrefix) { + this(uriPrefix,LuanState.newInstance()); + } + + @Override protected void service(HttpServletRequest request,HttpServletResponse response) + throws IOException + { + String path = request.getRequestURI(); + service(request,response,path); + } + + public void service(HttpServletRequest request,HttpServletResponse response,String path) + throws IOException + { + if( !path.endsWith(".luan") ) + throw new RuntimeException("'"+path+"' doesn't end with '.luan'"); + String uri = uriPrefix + path.substring(0,path.length()-5); + try { + if( !HttpServicer.service(luan,request,response,uri) ) + response.sendError(HttpServletResponse.SC_NOT_FOUND); + } catch(LuanException e) { + throw new RuntimeException(e); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/http/src/luan/modules/http/NotFound.java Fri May 15 17:43:13 2015 -0600 @@ -0,0 +1,22 @@ +package luan.modules.http; + +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.server.Request; +import luan.LuanState; + + +public class NotFound extends LuanHandler { + + public NotFound(LuanState luan) { + super(luan); + } + + public void handle(String target,Request baseRequest,HttpServletRequest request,HttpServletResponse response) + throws IOException + { + super.handle("/not_found",baseRequest,request,response); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/http/src/luan/modules/http/Server.luan Fri May 15 17:43:13 2015 -0600 @@ -0,0 +1,100 @@ +require "luan:String" +local Io = require "luan:Io" +local Package = require "luan:Package" +local Http = require "luan:http/Http" +require "luan:logging/Logging" -- initialize logging + +java() +local Server = require "java:org.eclipse.jetty.server.Server" +local NCSARequestLog = require "java:org.eclipse.jetty.server.NCSARequestLog" +local DefaultHandler = require "java:org.eclipse.jetty.server.handler.DefaultHandler" +local HandlerList = require "java:org.eclipse.jetty.server.handler.HandlerList" +local HandlerCollection = require "java:org.eclipse.jetty.server.handler.HandlerCollection" +local ResourceHandler = require "java:org.eclipse.jetty.server.handler.ResourceHandler" +local RequestLogHandler = require "java:org.eclipse.jetty.server.handler.RequestLogHandler" +local ContextHandler = require "java:org.eclipse.jetty.server.handler.ContextHandler" +local GzipHandler = require "java:org.eclipse.jetty.server.handler.GzipHandler" +local HandlerWrapper = require "java:org.eclipse.jetty.server.handler.HandlerWrapper" +local SessionHandler = require "java:org.eclipse.jetty.server.session.SessionHandler" +local AuthenticationHandler = require "java:luan.modules.http.AuthenticationHandler" +local LuanHandler = require "java:luan.modules.http.LuanHandler" +local NotFound = require "java:luan.modules.http.NotFound" + + +port = 8080 + +private_password = "password" + +welcome_file = "index.html" + + +authentication_handler = AuthenticationHandler.new("/private/") + +luan_handler = LuanHandler.new() + +resource_handler = ResourceHandler.new() +resource_handler.setDirectoriesListed(true) + +handlers = HandlerList.new() +handlers.setHandlers { authentication_handler, luan_handler, resource_handler } + +function add_folder(context,dir) + local rh = ResourceHandler.new() + rh.setResourceBase(dir) + rh.setDirectoriesListed(true) + local ch = ContextHandler.new(context) + ch.setHandler(rh) + handlers.addHandler(ch) + return rh +end + +handler_wrapper = HandlerWrapper.new() +handler_wrapper.setHandler(handlers) + +function zip() + local h = GzipHandler.new() + h.setHandler(handler_wrapper.getHandler()) + handler_wrapper.setHandler(h) +end + +log = NCSARequestLog.new() +log.setExtended(false) +log_handler = RequestLogHandler.new() +log_handler.setRequestLog(log) + +function set_log_file(file_name) + log.setFilename(file_name) +end + +local hc = HandlerCollection.new() +hc.setHandlers { SessionHandler.new(), handler_wrapper, DefaultHandler.new(), log_handler } + + +function init(dir) + dir = dir.gsub("/$","") -- remove trailing '/' if any + Http.dir = dir + function Io.schemes.site(path,add_extension) + return Io.uri( dir..path, add_extension ) + end + authentication_handler.setPassword(private_password) + local base = dir + if base.match("^classpath:") ~= nil then + base = dir.."#"..welcome_file.."#"..welcome_file..".luan" + end + resource_handler.setResourceBase(Io.uri(base).to_string()) + resource_handler.setWelcomeFiles {welcome_file} + luan_handler.setWelcomeFile(welcome_file) + handlers.addHandler(NotFound.new()) + server = Server.new(port) + server.setHandler(hc) + Package.load("site:/init") +end + +function start() + server.start() +end + +function serve(dir) + init(dir) + start() +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/http/src/luan/modules/http/run.luan Fri May 15 17:43:13 2015 -0600 @@ -0,0 +1,78 @@ +local Luan = require "luan:Luan" +local load = Luan.load +local try = Luan.try +local Io = require "luan:Io" +local print = Io.print +local Http = require "luan:http/Http" +local String = require "luan:String" +local Html = require "luan:Html" + +local function lines(s) + local matcher = s.gmatch "([^\n]*)\n|([^\n])+$" + return function() + local m1, m2 = matcher() + return m1 or m2 + end +end + +local function print_with_line_numbers(s) + i = 1 + for line in lines(s) do + print(i,line) + i = i + 1 + end +end + +local function form() %> +<html> + <head> + <% Html.simply_html_head() %> + <title>Run Luan Code</title> + </head> + <body> + <center margin-top=10> + <h3>Run Luan Code</h3> + </center> + <form name="form0" method="post"> + <input type="hidden" name="content_type" value="text/plain" /> + <center> + <textarea name="code" rows="20" cols="90" wrap="off" autofocus></textarea> + </center> + <center margin-top=5> + <input type="submit" value="Execute Luan Code" textcolor="white" bgcolor="#337ab7"/> + </center> + </form> + <% Html.simply_html_body_bottom() %> + </body> +</html> +<% end + +function service() + Io.stdout = Http.response.text_writer() + local code = Http.request.parameters.code + if code == nil then + form() + return + end + local content_type = Http.request.parameters.content_type + if content_type ~= nil then + Http.response.content_type = content_type + end + local env = { + request = Http.request; + response = Http.response; + } + try { + function() + local run = load(code,"<web_run>",env) + run() + end; + catch = function(e) + Http.response.content_type = "text/plain" + print(e) + print() + print() + print_with_line_numbers(code) + end; + } +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/http/src/luan/modules/http/serve.luan Fri May 15 17:43:13 2015 -0600 @@ -0,0 +1,9 @@ +local Io = require "luan:Io" +local Server = require "luan:http/Server" + +if #{...} ~= 1 then + Io.stderr.write "usage: luan luan:http/serve dir-URI\n" + return +end + +Server.serve(...)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/http/src/luan/modules/http/shell.luan Fri May 15 17:43:13 2015 -0600 @@ -0,0 +1,68 @@ +local Luan = require "luan:Luan" +local ipairs = Luan.ipairs +local load = Luan.load +local try = Luan.try +local Io = require "luan:Io" +local print = Io.print +local Debug = require "luan:Debug" +local Http = require "luan:http/Http" +local Html = require "luan:Html" + +per_session = true + +local history = {} +env = {} + +function service() + if Http.request.parameters.clear ~= nil then + history = {} + else + local cmd = Http.request.parameters.cmd + if cmd ~= nil then + Io.stdout = {} + function Io.stdout.write(...) + for v in Luan.values(...) do + history[#history+1] = v + end + end + print( "% "..cmd ) + try { + function() + local line = load(cmd,"<web_shell>",env,true) + Debug.print_if_something( line() ) + end; + catch = function(e) + Io.print_to(Io.stderr,e) + print(e) + end; + } + end + end + + Io.stdout = Http.response.text_writer() +%> +<html> + <head> + <% Html.simply_html_head() %> + <title>Luan Shell</title> + </head> + <body> + <div container> + <h3>Luan Shell</h3> + <p>This is a command shell. Enter commands below.</p> + <pre><% + for _,v in ipairs(history) do + Io.stdout.write(v) + end + %></pre> + <form name='form0' method='post'> + % <input name='cmd' size="80" autofocus> + <input type="submit" value="run" textcolor="white" bgcolor="#337ab7"> + <input type="submit" name="clear" value="clear" textcolor="white" bgcolor="#337ab7"> + </form> + </div> + <% Html.simply_html_body_bottom() %> + </body> +</html> +<% +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/http/src/luan/modules/http/test.luan Fri May 15 17:43:13 2015 -0600 @@ -0,0 +1,11 @@ +local Io = require "luan:Io" +local Server = require "luan:http/Server" + +if #{...} ~= 2 then + Io.stderr.write "usage: luan luan:http/serve dir-URI test-URI\n" + return +end + +local dir, test = ... +Server.init(dir) +require(test)
--- a/http/src/luan/modules/web/AuthenticationHandler.java Fri May 15 17:29:59 2015 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -package luan.modules.web; - -import java.io.IOException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.util.B64Code; - - -public class AuthenticationHandler extends AbstractHandler { - private final String path; - private String password = "password"; - - public AuthenticationHandler(String path) { - this.path = path; - } - - public void setPassword(String password) { - this.password = password; - } - - public void handle(String target,Request baseRequest,HttpServletRequest request,HttpServletResponse response) - throws IOException - { - if( !target.startsWith(path) ) - return; - String pwd = getPassword(request); - if( password.equals(pwd) ) - return; - response.setHeader("WWW-Authenticate","Basic realm=\""+path+"\""); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED); - baseRequest.setHandled(true); - } - - private static String getPassword(HttpServletRequest request) { - String auth = request.getHeader("Authorization"); - if( auth==null ) - return null; - String[] a = auth.split(" +"); - if( a.length != 2 ) - throw new RuntimeException("auth = "+auth); - if( !a[0].equals("Basic") ) - throw new RuntimeException("auth = "+auth); - auth = new String(B64Code.decode(a[1])); - a = auth.split(":"); - if( a.length != 2 ) - throw new RuntimeException("auth = "+auth); - return a[1]; - } -}
--- a/http/src/luan/modules/web/Http.luan Fri May 15 17:29:59 2015 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -local Io = require "luan:Io" - - - - -function init_for_test() - - welcome_file = "index.html" - - function get_page(path) - if welcome_file ~= nil and path.matches ".*/" then - path = path .. welcome_file - end - local old_out = Io.stdout - local mod = require("site:"..path) - mod.service() - text_writer.close() - Io.stdout = old_out - return result.read_text() - end - - cookies = cookies or {} - - request = { - parameters = {}; - } - request.cookies = cookies - - response = { - - text_writer = function() - result = Io.uri "string:" - text_writer = result.text_writer() - return text_writer - end; - - set_cookie = function(name,value) - cookies[name] = value - end; - - remove_cookie = function(name) - cookies[name] = nil - end; - - send_redirect = function(url) - response.redirect = url - end; - - headers = {}; - - } - -end
--- a/http/src/luan/modules/web/HttpServicer.java Fri May 15 17:29:59 2015 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,563 +0,0 @@ -package luan.modules.web; - -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:web/Http"); - HttpServicer lib = new HttpServicer(request,response); - try { - module.put( luan, "request", lib.requestTable() ); - module.put( luan, "response", lib.responseTable() ); - module.put( luan, "session", lib.sessionTable() ); -/* - module.put( "write", new LuanJavaFunction( - HttpServicer.class.getMethod( "text_write", LuanState.class, new Object[0].getClass() ), lib - ) ); -*/ - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - - luan.call(fn,"<http>"); - return true; - } - - private static LuanFunction getService(LuanState luan,LuanTable tbl) - throws LuanException - { - Object service = tbl.get(luan,"service"); - if( service == null ) - throw luan.exception( "function 'service' is not defined" ); - if( !(service instanceof LuanFunction) ) - throw luan.exception( "'service' must be a function but is a " + Luan.type(service) ); - return (LuanFunction)service; - } - - - 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 LuanTable sessionTable() throws NoSuchMethodException { - LuanTable tbl = new LuanTable(); - LuanTable attributes = new NameMeta() { - - @Override Object get(String name) { - return request.getSession().getAttribute(name); - } - - @Override protected Iterator keys(LuanTable tbl) { - return new EnumerationIterator(request.getSession().getAttributeNames()); - } - - @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 session attributes table"); - String name = (String)key; - request.getSession().setAttribute(name,val); - } - - @Override protected String type(LuanTable tbl) { - return "session.attributes"; - } - - }.newTable(); - tbl.rawPut( "attributes", attributes ); - 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; - } -}
--- a/http/src/luan/modules/web/LuanHandler.java Fri May 15 17:29:59 2015 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -package luan.modules.web; - -import java.io.IOException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; -import luan.LuanState; -import luan.LuanException; - - -public class LuanHandler extends AbstractHandler { - private static final Logger logger = LoggerFactory.getLogger(LuanHandler.class); - private final LuanState luan; - private String welcomeFile = "index.html"; - - public LuanHandler(LuanState luan) { - this.luan = luan; - } - - public void handle(String target,Request baseRequest,HttpServletRequest request,HttpServletResponse response) - throws IOException - { - if( target.endsWith("/") ) - target += welcomeFile; - try { - if( !HttpServicer.service(luan,request,response,"site:"+target) ) - return; - } catch(LuanException e) { - String err = e.getFullMessage(luan); - logger.error(err); - response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,err); - } - baseRequest.setHandled(true); - } - - public void setWelcomeFile(String welcomeFile) { - this.welcomeFile = welcomeFile; - } -}
--- a/http/src/luan/modules/web/LuanServlet.java Fri May 15 17:29:59 2015 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -package luan.modules.web; - -import java.io.IOException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import luan.LuanState; -import luan.LuanException; - - -public class LuanServlet extends HttpServlet { - protected final String uriPrefix; - protected final LuanState luan; - - public LuanServlet(String uriPrefix,LuanState luan) { - this.uriPrefix = uriPrefix; - this.luan = luan; - } - - public LuanServlet(String uriPrefix) { - this(uriPrefix,LuanState.newInstance()); - } - - @Override protected void service(HttpServletRequest request,HttpServletResponse response) - throws IOException - { - String path = request.getRequestURI(); - service(request,response,path); - } - - public void service(HttpServletRequest request,HttpServletResponse response,String path) - throws IOException - { - if( !path.endsWith(".luan") ) - throw new RuntimeException("'"+path+"' doesn't end with '.luan'"); - String uri = uriPrefix + path.substring(0,path.length()-5); - try { - if( !HttpServicer.service(luan,request,response,uri) ) - response.sendError(HttpServletResponse.SC_NOT_FOUND); - } catch(LuanException e) { - throw new RuntimeException(e); - } - } - -}
--- a/http/src/luan/modules/web/NotFound.java Fri May 15 17:29:59 2015 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -package luan.modules.web; - -import java.io.IOException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.server.Request; -import luan.LuanState; - - -public class NotFound extends LuanHandler { - - public NotFound(LuanState luan) { - super(luan); - } - - public void handle(String target,Request baseRequest,HttpServletRequest request,HttpServletResponse response) - throws IOException - { - super.handle("/not_found",baseRequest,request,response); - } - -}
--- a/http/src/luan/modules/web/Server.luan Fri May 15 17:29:59 2015 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -require "luan:String" -local Io = require "luan:Io" -local Package = require "luan:Package" -local Http = require "luan:web/Http" -require "luan:logging/Logging" -- initialize logging - -java() -local Server = require "java:org.eclipse.jetty.server.Server" -local NCSARequestLog = require "java:org.eclipse.jetty.server.NCSARequestLog" -local DefaultHandler = require "java:org.eclipse.jetty.server.handler.DefaultHandler" -local HandlerList = require "java:org.eclipse.jetty.server.handler.HandlerList" -local HandlerCollection = require "java:org.eclipse.jetty.server.handler.HandlerCollection" -local ResourceHandler = require "java:org.eclipse.jetty.server.handler.ResourceHandler" -local RequestLogHandler = require "java:org.eclipse.jetty.server.handler.RequestLogHandler" -local ContextHandler = require "java:org.eclipse.jetty.server.handler.ContextHandler" -local GzipHandler = require "java:org.eclipse.jetty.server.handler.GzipHandler" -local HandlerWrapper = require "java:org.eclipse.jetty.server.handler.HandlerWrapper" -local SessionHandler = require "java:org.eclipse.jetty.server.session.SessionHandler" -local AuthenticationHandler = require "java:luan.modules.web.AuthenticationHandler" -local LuanHandler = require "java:luan.modules.web.LuanHandler" -local NotFound = require "java:luan.modules.web.NotFound" - - -port = 8080 - -private_password = "password" - -welcome_file = "index.html" - - -authentication_handler = AuthenticationHandler.new("/private/") - -luan_handler = LuanHandler.new() - -resource_handler = ResourceHandler.new() -resource_handler.setDirectoriesListed(true) - -handlers = HandlerList.new() -handlers.setHandlers { authentication_handler, luan_handler, resource_handler } - -function add_folder(context,dir) - local rh = ResourceHandler.new() - rh.setResourceBase(dir) - rh.setDirectoriesListed(true) - local ch = ContextHandler.new(context) - ch.setHandler(rh) - handlers.addHandler(ch) - return rh -end - -handler_wrapper = HandlerWrapper.new() -handler_wrapper.setHandler(handlers) - -function zip() - local h = GzipHandler.new() - h.setHandler(handler_wrapper.getHandler()) - handler_wrapper.setHandler(h) -end - -log = NCSARequestLog.new() -log.setExtended(false) -log_handler = RequestLogHandler.new() -log_handler.setRequestLog(log) - -function set_log_file(file_name) - log.setFilename(file_name) -end - -local hc = HandlerCollection.new() -hc.setHandlers { SessionHandler.new(), handler_wrapper, DefaultHandler.new(), log_handler } - - -function init(dir) - dir = dir.gsub("/$","") -- remove trailing '/' if any - Http.dir = dir - function Io.schemes.site(path,add_extension) - return Io.uri( dir..path, add_extension ) - end - authentication_handler.setPassword(private_password) - local base = dir - if base.match("^classpath:") ~= nil then - base = dir.."#"..welcome_file.."#"..welcome_file..".luan" - end - resource_handler.setResourceBase(Io.uri(base).to_string()) - resource_handler.setWelcomeFiles {welcome_file} - luan_handler.setWelcomeFile(welcome_file) - handlers.addHandler(NotFound.new()) - server = Server.new(port) - server.setHandler(hc) - Package.load("site:/init") -end - -function start() - server.start() -end - -function serve(dir) - init(dir) - start() -end
--- a/http/src/luan/modules/web/run.luan Fri May 15 17:29:59 2015 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -local Luan = require "luan:Luan" -local load = Luan.load -local try = Luan.try -local Io = require "luan:Io" -local print = Io.print -local Http = require "luan:web/Http" -local String = require "luan:String" -local Html = require "luan:Html" - -local function lines(s) - local matcher = s.gmatch "([^\n]*)\n|([^\n])+$" - return function() - local m1, m2 = matcher() - return m1 or m2 - end -end - -local function print_with_line_numbers(s) - i = 1 - for line in lines(s) do - print(i,line) - i = i + 1 - end -end - -local function form() %> -<html> - <head> - <% Html.simply_html_head() %> - <title>Run Luan Code</title> - </head> - <body> - <center margin-top=10> - <h3>Run Luan Code</h3> - </center> - <form name="form0" method="post"> - <input type="hidden" name="content_type" value="text/plain" /> - <center> - <textarea name="code" rows="20" cols="90" wrap="off" autofocus></textarea> - </center> - <center margin-top=5> - <input type="submit" value="Execute Luan Code" textcolor="white" bgcolor="#337ab7"/> - </center> - </form> - <% Html.simply_html_body_bottom() %> - </body> -</html> -<% end - -function service() - Io.stdout = Http.response.text_writer() - local code = Http.request.parameters.code - if code == nil then - form() - return - end - local content_type = Http.request.parameters.content_type - if content_type ~= nil then - Http.response.content_type = content_type - end - local env = { - request = Http.request; - response = Http.response; - } - try { - function() - local run = load(code,"<web_run>",env) - run() - end; - catch = function(e) - Http.response.content_type = "text/plain" - print(e) - print() - print() - print_with_line_numbers(code) - end; - } -end
--- a/http/src/luan/modules/web/serve.luan Fri May 15 17:29:59 2015 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -local Io = require "luan:Io" -local Server = require "luan:web/Server" - -if #{...} ~= 1 then - Io.stderr.write "usage: luan luan:web/serve dir-URI\n" - return -end - -Server.serve(...)
--- a/http/src/luan/modules/web/shell.luan Fri May 15 17:29:59 2015 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -local Luan = require "luan:Luan" -local ipairs = Luan.ipairs -local load = Luan.load -local try = Luan.try -local Io = require "luan:Io" -local print = Io.print -local Debug = require "luan:Debug" -local Http = require "luan:web/Http" -local Html = require "luan:Html" - -per_session = true - -local history = {} -env = {} - -function service() - if Http.request.parameters.clear ~= nil then - history = {} - else - local cmd = Http.request.parameters.cmd - if cmd ~= nil then - Io.stdout = {} - function Io.stdout.write(...) - for v in Luan.values(...) do - history[#history+1] = v - end - end - print( "% "..cmd ) - try { - function() - local line = load(cmd,"<web_shell>",env,true) - Debug.print_if_something( line() ) - end; - catch = function(e) - Io.print_to(Io.stderr,e) - print(e) - end; - } - end - end - - Io.stdout = Http.response.text_writer() -%> -<html> - <head> - <% Html.simply_html_head() %> - <title>Luan Shell</title> - </head> - <body> - <div container> - <h3>Luan Shell</h3> - <p>This is a command shell. Enter commands below.</p> - <pre><% - for _,v in ipairs(history) do - Io.stdout.write(v) - end - %></pre> - <form name='form0' method='post'> - % <input name='cmd' size="80" autofocus> - <input type="submit" value="run" textcolor="white" bgcolor="#337ab7"> - <input type="submit" name="clear" value="clear" textcolor="white" bgcolor="#337ab7"> - </form> - </div> - <% Html.simply_html_body_bottom() %> - </body> -</html> -<% -end
--- a/http/src/luan/modules/web/test.luan Fri May 15 17:29:59 2015 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -local Io = require "luan:Io" -local Server = require "luan:web/Server" - -if #{...} ~= 2 then - Io.stderr.write "usage: luan luan:web/serve dir-URI test-URI\n" - return -end - -local dir, test = ... -Server.init(dir) -require(test)
--- a/lucene/src/luan/modules/lucene/Ab_testing.luan Fri May 15 17:29:59 2015 -0600 +++ b/lucene/src/luan/modules/lucene/Ab_testing.luan Fri May 15 17:43:13 2015 -0600 @@ -6,7 +6,7 @@ local Math = require "luan:Math" local Table = require "luan:Table" local Io = require "luan:Io" -local Http = require "luan:web/Http" +local Http = require "luan:http/Http" local Logging = require "luan:logging/Logging"
--- a/lucene/src/luan/modules/lucene/Web_search.luan Fri May 15 17:29:59 2015 -0600 +++ b/lucene/src/luan/modules/lucene/Web_search.luan Fri May 15 17:43:13 2015 -0600 @@ -4,7 +4,7 @@ local ipairs = Luan.ipairs local range = Luan.range local Io = require "luan:Io" -local Http = require "luan:web/Http" +local Http = require "luan:http/Http" local String = require "luan:String" local Html = require "luan:Html"
--- a/scripts/test.luan Fri May 15 17:29:59 2015 -0600 +++ b/scripts/test.luan Fri May 15 17:43:13 2015 -0600 @@ -2,7 +2,7 @@ local assert = Luan.assert local range = Luan.range local Io = require "luan:Io" -local Http = require "luan:web/Http" +local Http = require "luan:http/Http" local Lucene = require "luan:lucene/Lucene" local Ab_testing = require "luan:lucene/Ab_testing" @@ -12,7 +12,7 @@ end function Io.schemes.site(path) - return Io.uri( "luan:web"..path ) + return Io.uri( "luan:http"..path ) end
--- a/website/serve.sh Fri May 15 17:29:59 2015 -0600 +++ b/website/serve.sh Fri May 15 17:43:13 2015 -0600 @@ -1,1 +1,1 @@ -luan luan:web/serve file:src 2>&1 | tee err +luan luan:http/serve file:src 2>&1 | tee err
--- a/website/src/diff.html.luan Fri May 15 17:29:59 2015 -0600 +++ b/website/src/diff.html.luan Fri May 15 17:43:13 2015 -0600 @@ -1,6 +1,6 @@ local Io = require "luan:Io" local Html = require "luan:Html" -local Http = require "luan:web/Http" +local Http = require "luan:http/Http" local Shared = require "site:/Shared" local Manual = require "site:/manual.html"
--- a/website/src/docs.html.luan Fri May 15 17:29:59 2015 -0600 +++ b/website/src/docs.html.luan Fri May 15 17:43:13 2015 -0600 @@ -1,6 +1,6 @@ local Io = require "luan:Io" local Html = require "luan:Html" -local Http = require "luan:web/Http" +local Http = require "luan:http/Http" local Shared = require "site:/Shared"
--- a/website/src/examples/hi.luan Fri May 15 17:29:59 2015 -0600 +++ b/website/src/examples/hi.luan Fri May 15 17:43:13 2015 -0600 @@ -1,5 +1,5 @@ local Io = require "luan:Io" -local Http = require "luan:web/Http" +local Http = require "luan:http/Http" function service()
--- a/website/src/examples/hi2.luan Fri May 15 17:29:59 2015 -0600 +++ b/website/src/examples/hi2.luan Fri May 15 17:43:13 2015 -0600 @@ -1,5 +1,5 @@ local Io = require "luan:Io" -local Http = require "luan:web/Http" +local Http = require "luan:http/Http" local function form()
--- a/website/src/examples/hi2_simply_html.luan Fri May 15 17:29:59 2015 -0600 +++ b/website/src/examples/hi2_simply_html.luan Fri May 15 17:43:13 2015 -0600 @@ -1,6 +1,6 @@ local Io = require "luan:Io" local Html = require "luan:Html" -local Http = require "luan:web/Http" +local Http = require "luan:http/Http" local function form() %>
--- a/website/src/examples/shell.luan Fri May 15 17:29:59 2015 -0600 +++ b/website/src/examples/shell.luan Fri May 15 17:43:13 2015 -0600 @@ -1,1 +1,1 @@ -return require "luan:web/shell" +return require "luan:http/shell"
--- a/website/src/index.html.luan Fri May 15 17:29:59 2015 -0600 +++ b/website/src/index.html.luan Fri May 15 17:43:13 2015 -0600 @@ -1,6 +1,6 @@ local Io = require "luan:Io" local Html = require "luan:Html" -local Http = require "luan:web/Http" +local Http = require "luan:http/Http" function service()
--- a/website/src/manual.html.luan Fri May 15 17:29:59 2015 -0600 +++ b/website/src/manual.html.luan Fri May 15 17:43:13 2015 -0600 @@ -1,7 +1,7 @@ local Luan = require "luan:Luan" local Io = require "luan:Io" local Html = require "luan:Html" -local Http = require "luan:web/Http" +local Http = require "luan:http/Http" local Shared = require "site:/Shared" heading_options = [[margin-top="2em" margin-bottom=".6em" textcolor="#233E93"]]
--- a/website/src/pil.html.luan Fri May 15 17:29:59 2015 -0600 +++ b/website/src/pil.html.luan Fri May 15 17:43:13 2015 -0600 @@ -1,6 +1,6 @@ local Io = require "luan:Io" local Html = require "luan:Html" -local Http = require "luan:web/Http" +local Http = require "luan:http/Http" local Shared = require "site:/Shared"
--- a/website/src/tutorial.html.luan Fri May 15 17:29:59 2015 -0600 +++ b/website/src/tutorial.html.luan Fri May 15 17:43:13 2015 -0600 @@ -1,6 +1,6 @@ local Io = require "luan:Io" local Html = require "luan:Html" -local Http = require "luan:web/Http" +local Http = require "luan:http/Http" local Shared = require "site:/Shared" @@ -72,7 +72,7 @@ <p><tt><pre><%=Html.encode[[ local Io = require "luan:Io" - local Http = require "luan:web/Http" + local Http = require "luan:http/Http" function service() Io.stdout = Http.response.text_writer() @@ -86,7 +86,7 @@ end ]]%></pre></tt></p> -<p>Now go back to the parent directory and do <b>luan luan:web/serve file:site</b>. This will run the Luan web server on port 8080. Try going to <a href="http://localhost:8080/">http://localhost:8080/</a>. You should see the directory. If you click on <b>hi.luan</b> you will see the source. But if you remove the <b>.luan</b> and just go to <a href="http://localhost:8080/hi">http://localhost:8080/hi</a> then you will run the program which will generate the web page.</p> +<p>Now go back to the parent directory and do <b>luan luan:http/serve file:site</b>. This will run the Luan web server on port 8080. Try going to <a href="http://localhost:8080/">http://localhost:8080/</a>. You should see the directory. If you click on <b>hi.luan</b> you will see the source. But if you remove the <b>.luan</b> and just go to <a href="http://localhost:8080/hi">http://localhost:8080/hi</a> then you will run the program which will generate the web page.</p> <p>The Luan webserver looks for function named <b>service</b> in the file and calls it to generate the page. Code of the form <b><%=Html.encode[[%>...<%]]%></b> writes its output to <b>Io.stdout</b> which by default is the standard output of the command line. So in <b>service</b> one usually starts by setting <b>Io.stdout</b> to a <tt>text_writer</tt> which writes its output to the HTTP response (to the web browser).</p>