Mercurial Hosting > luan
changeset 1146:2dda3c92a473
webserver - implement cookies
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 01 Feb 2018 03:08:21 -0700 |
parents | 12ececf30597 |
children | 30d87b7d1d62 |
files | src/luan/webserver/Connection.java src/luan/webserver/Request.java src/luan/webserver/RequestParser.java src/luan/webserver/Response.java src/luan/webserver/Util.java src/luan/webserver/examples/Cookies.java src/luan/webserver/examples/Example.java src/luan/webserver/examples/Headers.java |
diffstat | 8 files changed, 151 insertions(+), 31 deletions(-) [+] |
line wrap: on
line diff
--- a/src/luan/webserver/Connection.java Wed Jan 31 01:43:50 2018 -0700 +++ b/src/luan/webserver/Connection.java Thu Feb 01 03:08:21 2018 -0700 @@ -63,7 +63,7 @@ RequestParser parser = new RequestParser(request); parser.parseHead(); - String lenStr = request.headers.get("Content-Length"); + String lenStr = (String)request.headers.get("Content-Length"); if( lenStr != null ) { int len = Integer.parseInt(lenStr); byte[] body = new byte[len]; @@ -80,7 +80,7 @@ //System.out.println(request.body); } - String contentType = request.headers.get("Content-Type"); + String contentType = (String)request.headers.get("Content-Type"); if( contentType != null ) { if( request.body == null ) { logger.error("body is null");
--- a/src/luan/webserver/Request.java Wed Jan 31 01:43:50 2018 -0700 +++ b/src/luan/webserver/Request.java Thu Feb 01 03:08:21 2018 -0700 @@ -11,7 +11,8 @@ 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>()); + public final Map<String,Object> headers = Collections.synchronizedMap(new LinkedHashMap<String,Object>()); public final Map<String,Object> parameters = Collections.synchronizedMap(new LinkedHashMap<String,Object>()); + public final Map<String,String> cookies = Collections.synchronizedMap(new LinkedHashMap<String,String>()); public volatile String body; }
--- a/src/luan/webserver/RequestParser.java Wed Jan 31 01:43:50 2018 -0700 +++ b/src/luan/webserver/RequestParser.java Thu Feb 01 03:08:21 2018 -0700 @@ -1,7 +1,5 @@ package luan.webserver; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; import java.util.List; import java.util.ArrayList; import luan.lib.parser.Parser; @@ -28,6 +26,7 @@ while( !parser.match("\r\n") ) { parserHeaderField(); } + parseCookies(); } private void parseRequestLine() throws ParseException { @@ -64,7 +63,7 @@ if( !parser.match('/') ) throw new ParseException(parser,"bad path"); while( safePathChar() || parser.anyOf("&=") ); - request.path = decode( parser.textFrom(start) ); + request.path = Util.urlDecode( parser.textFrom(start) ); } private void parseQuery() throws ParseException { @@ -74,27 +73,16 @@ if( !queryChar() ) return; while( queryChar() ); - String name = decode( parser.textFrom(start) ); + String name = Util.urlDecode( parser.textFrom(start) ); String value; if( parser.match('=') ) { start = parser.currentIndex(); while( queryChar() ); - value = decode( parser.textFrom(start) ); + value = Util.urlDecode( 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); - } + Util.add(request.parameters,name,value); } } @@ -131,7 +119,7 @@ String value = parseValue(); while( parser.anyOf(" \t") ); require( parser.match("\r\n") ); - request.headers.put(name,value); + Util.add(request.headers,name,value); } private String parseName() throws ParseException { @@ -185,11 +173,26 @@ } } - private static String decode(String s) { - try { - return URLDecoder.decode(s,"UTF-8"); - } catch(UnsupportedEncodingException e) { - throw new RuntimeException(e); + + private void parseCookies() throws ParseException { + String text = (String)request.headers.get("Cookie"); + if( text == null ) + return; + this.parser = new Parser(text); + while(true) { + int start = parser.currentIndex(); + while( parser.noneOf("=;") ); + String name = Util.urlDecode( parser.textFrom(start) ); + if( parser.match('=') ) { + start = parser.currentIndex(); + while( parser.noneOf(";") ); + String value = Util.urlDecode( parser.textFrom(start) ); + request.cookies.put(name,value); + } + if( parser.endOfInput() ) + return; + require( parser.match("; ") ); } } + }
--- a/src/luan/webserver/Response.java Wed Jan 31 01:43:50 2018 -0700 +++ b/src/luan/webserver/Response.java Thu Feb 01 03:08:21 2018 -0700 @@ -4,12 +4,13 @@ import java.util.Map; import java.util.LinkedHashMap; import java.util.Collections; +import java.util.List; public class Response { public final String protocol = "HTTP/1.1"; public volatile Status status = Status.OK; - public final Map<String,String> headers = Collections.synchronizedMap(new LinkedHashMap<String,String>()); + public final Map<String,Object> headers = Collections.synchronizedMap(new LinkedHashMap<String,Object>()); { headers.put("Server","ThreeBody"); } @@ -26,6 +27,25 @@ } + public void addHeader(String name,String value) { + Util.add(headers,name,value); + } + + public void setCookie(String name,String value,Map<String,String> attributes) { + StringBuilder buf = new StringBuilder(); + buf.append( Util.urlEncode(name) ); + buf.append( '=' ); + buf.append( Util.urlEncode(value) ); + for( Map.Entry<String,String> entry : attributes.entrySet() ) { + buf.append( "; " ); + buf.append( entry.getKey() ); + buf.append( '=' ); + buf.append( entry.getValue() ); + } + addHeader( "Set-Cookie", buf.toString() ); + } + + public String toHeaderString() { StringBuilder sb = new StringBuilder(); sb.append( protocol ) @@ -33,10 +53,16 @@ .append( ' ' ).append( status.reason ) .append( "\r\n" ) ; - for( Map.Entry<String,String> entry : headers.entrySet() ) { + for( Map.Entry<String,Object> entry : headers.entrySet() ) { String name = entry.getKey(); - String value = entry.getValue(); - sb.append( name ).append( ": " ).append( value ).append( "\r\n" ); + Object value = entry.getValue(); + if( value instanceof List ) { + for( Object v : (List)value ) { + sb.append( name ).append( ": " ).append( v ).append( "\r\n" ); + } + } else { + sb.append( name ).append( ": " ).append( value ).append( "\r\n" ); + } } sb.append( "\r\n" ); return sb.toString();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/webserver/Util.java Thu Feb 01 03:08:21 2018 -0700 @@ -0,0 +1,45 @@ +package luan.webserver; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.Map; +import java.util.List; +import java.util.ArrayList; + + +final class Util { + + static String urlDecode(String s) { + try { + return URLDecoder.decode(s,"UTF-8"); + } catch(UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + static String urlEncode(String s) { + try { + return URLEncoder.encode(s,"UTF-8"); + } catch(UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + static void add(Map<String,Object> map,String name,String value) { + Object current = map.get(name); + if( current == null ) { + map.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); + map.put(name,list); + } + } + + private Util() {} // never +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/webserver/examples/Cookies.java Thu Feb 01 03:08:21 2018 -0700 @@ -0,0 +1,42 @@ +package luan.webserver.examples; + +import java.io.Writer; +import java.io.OutputStreamWriter; +import java.io.IOException; +import java.util.Map; +import java.util.HashMap; +import luan.webserver.Handler; +import luan.webserver.Request; +import luan.webserver.Response; +import luan.webserver.ResponseOutputStream; + + +public final class Cookies implements Handler { + + public Response handle(Request request) { + Response response = new Response(); + String name = (String)request.parameters.get("name"); + if( name != null ) { + Map<String,String> attributes = new HashMap<String,String>(); + String value = (String)request.parameters.get("value"); + if( value != null ) { + response.setCookie(name,value,attributes); + } else { + attributes.put("Max-Age","0"); + response.setCookie(name,"delete",attributes); + } + } + response.headers.put( "Content-Type", "text/plain; charset=UTF-8" ); + try { + Writer writer = new OutputStreamWriter( new ResponseOutputStream(response) ); + for( Map.Entry<String,String> entry : request.cookies.entrySet() ) { + writer.write(entry.getKey()+" = "+entry.getValue()+"\n"); + } + writer.close(); + } catch(IOException e) { + throw new RuntimeException(e); + } + return response; + } + +}
--- a/src/luan/webserver/examples/Example.java Wed Jan 31 01:43:50 2018 -0700 +++ b/src/luan/webserver/examples/Example.java Thu Feb 01 03:08:21 2018 -0700 @@ -18,6 +18,7 @@ import luan.webserver.handlers.LogHandler; import luan.webserver.handlers.FileHandler; import luan.webserver.handlers.ListHandler; +import luan.webserver.handlers.ContentTypeHandler; public class Example implements Handler { @@ -45,8 +46,10 @@ map.put( "/hello", new Example() ); map.put( "/headers", new Headers() ); map.put( "/params", new Params() ); + map.put( "/cookies", new Cookies() ); Handler handler = new MapHandler(map); handler = new ListHandler( handler, new FileHandler() ); + handler = new ContentTypeHandler(handler); handler = new SafeHandler(handler); handler = new LogHandler(handler); new Server(8080,handler).start();
--- a/src/luan/webserver/examples/Headers.java Wed Jan 31 01:43:50 2018 -0700 +++ b/src/luan/webserver/examples/Headers.java Thu Feb 01 03:08:21 2018 -0700 @@ -17,7 +17,7 @@ response.headers.put( "Content-Type", "text/plain; charset=UTF-8" ); try { Writer writer = new OutputStreamWriter( new ResponseOutputStream(response) ); - for( Map.Entry<String,String> entry : request.headers.entrySet() ) { + for( Map.Entry<String,Object> entry : request.headers.entrySet() ) { writer.write(entry.getKey()+": "+entry.getValue()+"\n"); } writer.close();