Mercurial Hosting > luan
changeset 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 |
files | .hgignore core/src/luan/LuanTable.java core/src/luan/impl/ForStmt.java core/src/luan/modules/Html.luan core/src/luan/modules/Table.luan http/src/luan/modules/http/Http.luan http/src/luan/modules/http/HttpServicer.java http/src/luan/modules/http/run.luan http/src/luan/modules/http/shell.luan lucene/src/luan/modules/lucene/Web_search.luan scripts/test.luan website/src/examples/hi2.luan website/src/examples/hi2_simply_html.luan |
diffstat | 13 files changed, 227 insertions(+), 283 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Sat May 16 20:19:05 2015 -0600 +++ b/.hgignore Sun May 17 19:25:47 2015 -0600 @@ -8,3 +8,4 @@ mine *.bck *.n +go
--- a/core/src/luan/LuanTable.java Sat May 16 20:19:05 2015 -0600 +++ b/core/src/luan/LuanTable.java Sun May 17 19:25:47 2015 -0600 @@ -282,7 +282,7 @@ if( obj==null ) return null; Object[] a = (Object[])obj; - if( a.length == 0 ) + if( a.length == 0 || a[0]==null ) return null; return new AbstractMap.SimpleEntry<Object,Object>(a[0],a[1]); } catch(LuanException e) { @@ -416,9 +416,6 @@ hasJava = true; } - - // from AbstractLuanTable - private Map<Object,Object> newMap() { return new LinkedHashMap<Object,Object>(); } @@ -447,4 +444,9 @@ return map; } + public void rawClear() { + map = null; + list = null; + } + }
--- a/core/src/luan/impl/ForStmt.java Sat May 16 20:19:05 2015 -0600 +++ b/core/src/luan/impl/ForStmt.java Sun May 17 19:25:47 2015 -0600 @@ -32,7 +32,7 @@ break; if( vals instanceof Object[] ) { Object[] a = (Object[])vals; - if( a.length==0 ) + if( a.length==0 || a[0]==null ) break; for( int i=0; i<nVars; i++ ) { luan.stackSet( iVars+i, i < a.length ? a[i] : null );
--- a/core/src/luan/modules/Html.luan Sat May 16 20:19:05 2015 -0600 +++ b/core/src/luan/modules/Html.luan Sun May 17 19:25:47 2015 -0600 @@ -13,6 +13,11 @@ local ipairs = Luan.ipairs local type = Luan.type local Io = require "luan:Io" +local URLEncoder = require "java:java.net.URLEncoder" + +function url_encode(s) + return URLEncoder.encode(s,"UTF-8") +end function process_url_tags(html) for i, v in ipairs(html) do
--- a/core/src/luan/modules/Table.luan Sat May 16 20:19:05 2015 -0600 +++ b/core/src/luan/modules/Table.luan Sun May 17 19:25:47 2015 -0600 @@ -10,3 +10,11 @@ sort = TableLuan.sort sub_list = TableLuan.sub_list unpack = TableLuan.unpack + + +local Luan = require "luan:Luan" +local pairs = Luan.pairs + +function is_empty(t) + return pairs(t)() == nil +end
--- a/http/src/luan/modules/http/Http.luan Sat May 16 20:19:05 2015 -0600 +++ b/http/src/luan/modules/http/Http.luan Sun May 17 19:25:47 2015 -0600 @@ -1,15 +1,87 @@ +local Luan = require "luan:Luan" +local ipairs = Luan.ipairs +local pairs = Luan.pairs +local set_metatable = Luan.set_metatable local Io = require "luan:Io" +local Html = require "luan:Html" +local url_encode = Html.url_encode +local singular_metatable = {} + +function singular_metatable.__index(table,key) + local list = table.__plural[key] + return list and list[1] +end + +function singular_metatable.__new_index(table,key,value) + table.__plural[key] = {value} +end + +function singular_metatable.__pairs(table) + local iter = pairs(table.__plural) + return function() + local key, value = iter() + return key, value and value[1] + end +end + + +local function new_common(this) + this = this or {} + this.headers = {} + this.header = {__plural=this.headers} + set_metatable(this.header,singular_metatable) + return this +end + + +function new_request(this) + this = new_common(this) + this.method = "GET" -- default + -- this.path + -- this.protocol + this.scheme = "http" -- default + this.parameters = {} + this.parameter = {__plural=this.parameters} + set_metatable(this.parameter,singular_metatable) + this.cookie = {} + + function this.url() + local string_uri = Io.uri "string:" + local out = string_uri.text_writer() + + out.write( this.scheme, "://", this.header.host, this.path ) + if this.method ~= "POST" then + local and_char = "?" + for name, values in pairs(this.parameters) do + for _, value in ipairs(values) do + out.write( and_char, url_encode(name), "=", url_encode(value) ) + and_char = "&" + end + end + end + + out.close() + return string_uri.read_text() + end + + return this +end + +-- request = new_request{} -- filled in by HttpServicer + function init_for_test() - welcome_file = "index.html" + test = test or {} + + test.welcome_file = "index.html" function get_page(path) - if welcome_file ~= nil and path.matches ".*/" then - path = path .. welcome_file + if test.welcome_file ~= nil and path.matches ".*/" then + path = path .. test.welcome_file end local old_out = Io.stdout local mod = require("site:"..path) @@ -19,12 +91,10 @@ return result.read_text() end - cookies = cookies or {} + test.cookies = test.cookies or {} - request = { - parameters = {}; - } - request.cookies = cookies + request = new_request{} + request.cookies = test.cookies response = { @@ -35,11 +105,11 @@ end; set_cookie = function(name,value) - cookies[name] = value + test.cookies[name] = value end; remove_cookie = function(name) - cookies[name] = nil + test.cookies[name] = nil end; send_redirect = function(url)
--- a/http/src/luan/modules/http/HttpServicer.java Sat May 16 20:19:05 2015 -0600 +++ b/http/src/luan/modules/http/HttpServicer.java Sun May 17 19:25:47 2015 -0600 @@ -74,145 +74,38 @@ } 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); + + // 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); } - 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"; + 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()))); } - - }.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") ) { + } else { // multipart 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(); @@ -238,26 +131,13 @@ } ); 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}); + LuanTable list = (LuanTable)parametersTbl.rawGet(name); + if( list == null ) { + list = new LuanTable(); + parametersTbl.rawPut(name,list); } + parametersTbl.rawPut(parametersTbl.rawLength()+1,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) { @@ -265,7 +145,40 @@ } } - return tbl; + 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 { @@ -346,23 +259,11 @@ 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); } @@ -374,60 +275,6 @@ // 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"); } @@ -447,11 +294,6 @@ 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) ) { @@ -485,26 +327,6 @@ // 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); @@ -517,9 +339,4 @@ }; - 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/http/run.luan Sat May 16 20:19:05 2015 -0600 +++ b/http/src/luan/modules/http/run.luan Sun May 17 19:25:47 2015 -0600 @@ -49,12 +49,12 @@ function respond() Io.stdout = Http.response.text_writer() - local code = Http.request.parameters.code + local code = Http.request.parameter.code if code == nil then form() return end - local content_type = Http.request.parameters.content_type + local content_type = Http.request.parameter.content_type if content_type ~= nil then Http.response.content_type = content_type end
--- a/http/src/luan/modules/http/shell.luan Sat May 16 20:19:05 2015 -0600 +++ b/http/src/luan/modules/http/shell.luan Sun May 17 19:25:47 2015 -0600 @@ -14,10 +14,10 @@ env = {} function respond() - if Http.request.parameters.clear ~= nil then + if Http.request.parameter.clear ~= nil then history = {} else - local cmd = Http.request.parameters.cmd + local cmd = Http.request.parameter.cmd if cmd ~= nil then Io.stdout = {} function Io.stdout.write(...)
--- a/lucene/src/luan/modules/lucene/Web_search.luan Sat May 16 20:19:05 2015 -0600 +++ b/lucene/src/luan/modules/lucene/Web_search.luan Sun May 17 19:25:47 2015 -0600 @@ -121,16 +121,16 @@ function of(index) - return { service = function() + return { respond = function() Io.stdout = Http.response.text_writer() - local query_string = Http.request.parameters.query + local query_string = Http.request.parameter.query if query_string == nil then form() return end local query = load(query_string,"<query>",{Query=index.query},true)() - local rows = Http.request.parameters.rows.to_number() - local sort = load(Http.request.parameters.sort,"<sort>",{Query=index.query},true)() + local rows = Http.request.parameter.rows.to_number() + local sort = load(Http.request.parameter.sort,"<sort>",{Query=index.query},true)() index.Searcher( function(searcher) local results, length, total_hits = searcher.search(query,rows,sort) local headers = {}
--- a/scripts/test.luan Sat May 16 20:19:05 2015 -0600 +++ b/scripts/test.luan Sun May 17 19:25:47 2015 -0600 @@ -1,8 +1,9 @@ local Luan = require "luan:Luan" -local assert = Luan.assert +local error = Luan.error local range = Luan.range local Io = require "luan:Io" local Http = require "luan:http/Http" +local init_for_test = Http.init_for_test local Lucene = require "luan:lucene/Lucene" local Ab_testing = require "luan:lucene/Ab_testing" @@ -16,15 +17,15 @@ end -Http.init_for_test() -Http.request.parameters.code = "require('luan:Io').print 'hi'" +init_for_test() +Http.request.parameter.code = "require('luan:Io').print 'hi'" page = Http.get_page "/run" -assert( page.trim() == "hi" ) +page.trim() == "hi" or error "failed" -Http.init_for_test() -Http.request.parameters.cmd = "'ab'..'cd'" +init_for_test() +Http.request.parameter.cmd = "'ab'..'cd'" page = Http.get_page "/shell" -assert( page.find "abcd" ) +page.find "abcd" or error "failed" -- lucene @@ -50,8 +51,48 @@ db.save_document(doc) end -Http.init_for_test() +init_for_test() ab_testing.web_page{"All","null"}.respond() +local Web_search = require "luan:lucene/Web_search" +local web_search = Web_search.of(db) + +init_for_test() +web_search.respond() + +init_for_test() +Http.request.parameter.query = "Query.all_docs" +Http.request.parameter.rows = "100" +Http.request.parameter.sort = "" +web_search.respond() + + +-- website + +function Io.schemes.site(path,add_extension) + return Io.uri( "file:../website/src"..path, add_extension ) +end + +init_for_test(); Http.get_page "/" +init_for_test(); Http.get_page "/docs.html" +init_for_test(); Http.get_page "/tutorial.html" +init_for_test(); Http.get_page "/pil.html" +init_for_test(); Http.get_page "/manual.html" +init_for_test(); Http.get_page "/diff.html" +init_for_test(); Http.get_page "/examples/hi" +init_for_test(); Http.get_page "/examples/hi2" +init_for_test(); Http.get_page "/examples/hi2_simply_html" +init_for_test(); Http.get_page "/examples/shell" + +init_for_test() +Http.request.parameter.name = "bob" +page = Http.get_page "/examples/hi2" +page.find "bob" or error "failed" + +init_for_test() +Http.request.parameter.name = "bob" +page = Http.get_page "/examples/hi2_simply_html" +page.find "bob" or error "failed" + print "done"
--- a/website/src/examples/hi2.luan Sat May 16 20:19:05 2015 -0600 +++ b/website/src/examples/hi2.luan Sun May 17 19:25:47 2015 -0600 @@ -8,7 +8,7 @@ <body> <h1>Hello</h1> <form> - What is you name? + What is your name? <input name="name"> <input type=submit> </form> @@ -30,7 +30,7 @@ function respond() Io.stdout = Http.response.text_writer() - name = Http.request.parameters.name + name = Http.request.parameter.name if name == nil then form() else
--- a/website/src/examples/hi2_simply_html.luan Sat May 16 20:19:05 2015 -0600 +++ b/website/src/examples/hi2_simply_html.luan Sun May 17 19:25:47 2015 -0600 @@ -5,7 +5,7 @@ local function form() %> <form> - <label>What is you name?</label> + <label>What is your name?</label> <input name="name" margin-bottom="1em"> <input type=submit> </form> @@ -19,7 +19,7 @@ function respond() Io.stdout = Http.response.text_writer() - name = Http.request.parameters.name + name = Http.request.parameter.name %> <html> <head>