Mercurial Hosting > luan
view src/luan/webserver/RequestParser.java @ 1145:12ececf30597
webserver - minor
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 31 Jan 2018 01:43:50 -0700 |
parents | ae0a048f3bc7 |
children | 2dda3c92a473 |
line wrap: on
line source
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; final class RequestParser { private final Request request; private Parser parser; RequestParser(Request request) { this.request = request; } void parseUrlencoded() throws ParseException { this.parser = new Parser(request.body); parseQuery(); require( parser.endOfInput() ); } void parseHead() throws ParseException { this.parser = new Parser(request.rawHead); parseRequestLine(); while( !parser.match("\r\n") ) { parserHeaderField(); } } private void parseRequestLine() throws ParseException { parseMethod(); require( parser.match(' ') ); parseRawPath(); require( parser.match(' ') ); parseProtocol(); require( parser.match("\r\n") ); } private void parseMethod() throws ParseException { int start = parser.currentIndex(); if( !methodChar() ) throw new ParseException(parser,"no method"); while( methodChar() ); request.method = parser.textFrom(start); } private boolean methodChar() { 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( 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("-._~:/[]@!$'()*+,;`.%") ; } private void parseProtocol() throws ParseException { int start = parser.currentIndex(); if( !( parser.match("HTTP/") && parser.inCharRange('0','9') && parser.match('.') && parser.inCharRange('0','9') ) ) throw new ParseException(parser,"bad protocol"); request.protocol = parser.textFrom(start); } private void parserHeaderField() throws ParseException { String name = parseName(); require( parser.match(':') ); while( parser.anyOf(" \t") ); String value = parseValue(); while( parser.anyOf(" \t") ); require( parser.match("\r\n") ); request.headers.put(name,value); } private String parseName() throws ParseException { StringBuilder buf = new StringBuilder(); boolean cap = true; require( tokenChar() ); do { char c = parser.lastChar(); if( c == '-' ) { cap = true; } else if( cap ) { c = Character.toUpperCase(c); cap = false; } else { c = Character.toLowerCase(c); } buf.append(c); } while( tokenChar() ); return buf.toString(); } private String parseValue() { int start = parser.currentIndex(); while( !testEndOfValue() ) parser.anyChar(); return parser.textFrom(start); } private boolean testEndOfValue() { parser.begin(); while( parser.anyOf(" \t") ); boolean b = parser.endOfInput() || parser.anyOf("\r\n"); parser.failure(); // rollback return b; } private void require(boolean b) throws ParseException { if( !b ) throw new ParseException(parser,"failed"); } boolean tokenChar() { if( parser.endOfInput() ) return false; char c = parser.currentChar(); if( 32 <= c && c <= 126 && "()<>@,;:\\\"/[]?={} \t\r\n".indexOf(c) == -1 ) { parser.anyChar(); return true; } else { return false; } } private static String decode(String s) { try { return URLDecoder.decode(s,"UTF-8"); } catch(UnsupportedEncodingException e) { throw new RuntimeException(e); } } }