changeset 1143:3bf5190b3c77

webserver - handle GET params
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 30 Jan 2018 23:53:28 -0700
parents 0f59eab45f3d
children ae0a048f3bc7
files src/luan/modules/http/tools/Dump_mod.luan src/luan/webserver/Request.java src/luan/webserver/RequestHeadParser.java src/luan/webserver/examples/Example.java src/luan/webserver/examples/Params.java
diffstat 5 files changed, 111 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/luan/modules/http/tools/Dump_mod.luan	Tue Jan 30 18:02:47 2018 -0700
+++ b/src/luan/modules/http/tools/Dump_mod.luan	Tue Jan 30 23:53:28 2018 -0700
@@ -1,6 +1,7 @@
 local Luan = require "luan:Luan.luan"
-local pairs = Luan.pairs
-local ipairs = Luan.ipairs
+local error = Luan.error
+local pairs = Luan.pairs or error()
+local ipairs = Luan.ipairs or error()
 local Io = require "luan:Io.luan"
 local Http = require "luan:http/Http.luan"
 java()
--- a/src/luan/webserver/Request.java	Tue Jan 30 18:02:47 2018 -0700
+++ b/src/luan/webserver/Request.java	Tue Jan 30 23:53:28 2018 -0700
@@ -8,6 +8,7 @@
 public class Request {
 	public volatile String rawHead;
 	public volatile String method;
+	public volatile String rawPath;
 	public volatile String path;
 	public volatile String protocol;  // only HTTP/1.1 is accepted
 	public final Map<String,String> headers = Collections.synchronizedMap(new LinkedHashMap<String,String>());
--- a/src/luan/webserver/RequestHeadParser.java	Tue Jan 30 18:02:47 2018 -0700
+++ b/src/luan/webserver/RequestHeadParser.java	Tue Jan 30 23:53:28 2018 -0700
@@ -1,5 +1,9 @@
 package luan.webserver;
 
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.List;
+import java.util.ArrayList;
 import luan.lib.parser.Parser;
 import luan.lib.parser.ParseException;
 
@@ -31,7 +35,7 @@
 	private void parseRequestLine() throws ParseException {
 		parseMethod();
 		require( parser.match(' ') );
-		parsePath();
+		parseRawPath();
 		require( parser.match(' ') );
 		parseProtocol();
 		require( parser.match("\r\n") );
@@ -49,17 +53,64 @@
 		return parser.inCharRange('A','Z');
 	}
 
+	private void parseRawPath() throws ParseException {
+		int start = parser.currentIndex();
+		parsePath();
+		if( parser.match('?') )
+			parseQuery();
+		request.rawPath = parser.textFrom(start);
+	}
+
 	private void parsePath() throws ParseException {
 		int start = parser.currentIndex();
 		if( !parser.match('/') )
 			throw new ParseException(parser,"bad path");
-		while(
-			parser.inCharRange('A','Z')
+		while( safePathChar() || parser.anyOf("&=") );
+		request.path = decode( parser.textFrom(start) );
+	}
+
+	private void parseQuery() throws ParseException {
+		while(true) {
+			while( parser.match('&') );
+			int start = parser.currentIndex();
+			if( !queryChar() )
+				return;
+			while( queryChar() );
+			String name = decode( parser.textFrom(start) );
+			String value;
+			if( parser.match('=') ) {
+				start = parser.currentIndex();
+				while( queryChar() );
+				value = decode( parser.textFrom(start) );
+			} else {
+				value = "";
+			}
+			Object current = request.parameters.get(name);
+			if( current == null ) {
+				request.parameters.put(name,value);
+			} else if( current instanceof List ) {
+				List list = (List)current;
+				list.add(value);
+			} else {
+				List list = new ArrayList();
+				list.add(current);
+				list.add(value);
+				request.parameters.put(name,list);
+			}
+		}
+	}
+
+	private boolean queryChar() {
+		return safePathChar() || parser.anyOf("?");
+	}
+
+	// where did I get this?
+	private boolean safePathChar() {
+		return parser.inCharRange('A','Z')
 			|| parser.inCharRange('a','z')
 			|| parser.inCharRange('0','9')
-			|| parser.anyOf("-._~:/?#[]@!$&'()*+,;=`.")
-		);
-		request.path = parser.textFrom(start);
+			|| parser.anyOf("-._~:/[]@!$'()*+,;`.%")
+		;
 	}
 
 	private void parseProtocol() throws ParseException {
@@ -135,4 +186,12 @@
 			return false;
 		}
 	}
+
+	private static String decode(String s) {
+		try {
+			return URLDecoder.decode(s,"UTF-8");
+		} catch(UnsupportedEncodingException e) {
+			throw new RuntimeException(e);
+		}
+	}
 }
--- a/src/luan/webserver/examples/Example.java	Tue Jan 30 18:02:47 2018 -0700
+++ b/src/luan/webserver/examples/Example.java	Tue Jan 30 23:53:28 2018 -0700
@@ -5,7 +5,9 @@
 import java.io.IOException;
 import java.util.Map;
 import java.util.HashMap;
-import org.apache.log4j.BasicConfigurator;
+import org.apache.log4j.EnhancedPatternLayout;
+import org.apache.log4j.ConsoleAppender;
+import org.apache.log4j.Logger;
 import luan.webserver.Handler;
 import luan.webserver.Request;
 import luan.webserver.Response;
@@ -42,6 +44,7 @@
 		Map<String,Handler> map = new HashMap<String,Handler>();
 		map.put( "/hello", new Example() );
 		map.put( "/headers", new Headers() );
+		map.put( "/params", new Params() );
 		Handler handler = new MapHandler(map);
 		handler = new ListHandler( handler, new FileHandler() );
 		handler = new SafeHandler(handler);
@@ -49,8 +52,15 @@
 		new Server(8080,handler).start();
 	}
 
+	public static void initLogging() {
+//		Logger.getRootLogger().setLevel(Level.INFO);
+		EnhancedPatternLayout layout = new EnhancedPatternLayout("%d{HH:mm:ss} %-5p %c - %m%n");
+		ConsoleAppender appender = new ConsoleAppender(layout,"System.err");
+		Logger.getRootLogger().addAppender(appender);
+	}
+
 	public static void main(String[] args) throws Exception {
-		BasicConfigurator.configure();
+		initLogging();
 		fancy();
 	}
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/webserver/examples/Params.java	Tue Jan 30 23:53:28 2018 -0700
@@ -0,0 +1,30 @@
+package luan.webserver.examples;
+
+import java.io.Writer;
+import java.io.OutputStreamWriter;
+import java.io.IOException;
+import java.util.Map;
+import luan.webserver.Handler;
+import luan.webserver.Request;
+import luan.webserver.Response;
+import luan.webserver.ResponseOutputStream;
+
+
+public final class Params implements Handler {
+
+	public Response handle(Request request) {
+		Response response = new Response();
+		response.headers.put( "Content-Type", "text/plain; charset=UTF-8" );
+		try {
+			Writer writer = new OutputStreamWriter( new ResponseOutputStream(response) );
+			for( Map.Entry<String,Object> entry : request.parameters.entrySet() ) {
+				writer.write(entry.getKey()+" = "+entry.getValue()+"\n");
+			}
+			writer.close();
+		} catch(IOException e) {
+			throw new RuntimeException(e);
+		}
+		return response;
+	}
+
+}