comparison src/luan/webserver/RequestHeadParser.java @ 1137:c123ee15f99b

add webserver
author Franklin Schmidt <fschmidt@gmail.com>
date Mon, 29 Jan 2018 18:49:59 -0700
parents
children 3bf5190b3c77
comparison
equal deleted inserted replaced
1136:d30d400fd43d 1137:c123ee15f99b
1 package luan.webserver;
2
3 import luan.lib.parser.Parser;
4 import luan.lib.parser.ParseException;
5
6
7 final class RequestHeadParser {
8
9 static Request parse(String text) throws ParseException {
10 RequestHeadParser rhp = new RequestHeadParser(text);
11 rhp.parse();
12 return rhp.request;
13 }
14
15 private final Request request = new Request();
16 private final Parser parser;
17
18 private RequestHeadParser(String text) {
19 this.parser = new Parser(text);
20 request.rawHead = text;
21 }
22
23 private void parse() throws ParseException {
24 parseRequestLine();
25 while( !parser.match("\r\n") ) {
26 parserHeaderField();
27 }
28 }
29
30
31 private void parseRequestLine() throws ParseException {
32 parseMethod();
33 require( parser.match(' ') );
34 parsePath();
35 require( parser.match(' ') );
36 parseProtocol();
37 require( parser.match("\r\n") );
38 }
39
40 private void parseMethod() throws ParseException {
41 int start = parser.currentIndex();
42 if( !methodChar() )
43 throw new ParseException(parser,"no method");
44 while( methodChar() );
45 request.method = parser.textFrom(start);
46 }
47
48 private boolean methodChar() {
49 return parser.inCharRange('A','Z');
50 }
51
52 private void parsePath() throws ParseException {
53 int start = parser.currentIndex();
54 if( !parser.match('/') )
55 throw new ParseException(parser,"bad path");
56 while(
57 parser.inCharRange('A','Z')
58 || parser.inCharRange('a','z')
59 || parser.inCharRange('0','9')
60 || parser.anyOf("-._~:/?#[]@!$&'()*+,;=`.")
61 );
62 request.path = parser.textFrom(start);
63 }
64
65 private void parseProtocol() throws ParseException {
66 int start = parser.currentIndex();
67 if( !(
68 parser.match("HTTP/")
69 && parser.inCharRange('0','9')
70 && parser.match('.')
71 && parser.inCharRange('0','9')
72 ) )
73 throw new ParseException(parser,"bad protocol");
74 request.protocol = parser.textFrom(start);
75 }
76
77
78 private void parserHeaderField() throws ParseException {
79 String name = parseName();
80 require( parser.match(':') );
81 while( parser.anyOf(" \t") );
82 String value = parseValue();
83 while( parser.anyOf(" \t") );
84 require( parser.match("\r\n") );
85 request.headers.put(name,value);
86 }
87
88 private String parseName() throws ParseException {
89 StringBuilder buf = new StringBuilder();
90 boolean cap = true;
91 require( tokenChar() );
92 do {
93 char c = parser.lastChar();
94 if( c == '-' ) {
95 cap = true;
96 } else if( cap ) {
97 c = Character.toUpperCase(c);
98 cap = false;
99 } else {
100 c = Character.toLowerCase(c);
101 }
102 buf.append(c);
103 } while( tokenChar() );
104 return buf.toString();
105 }
106
107 private String parseValue() {
108 int start = parser.currentIndex();
109 while( !testEndOfValue() )
110 parser.anyChar();
111 return parser.textFrom(start);
112 }
113
114 private boolean testEndOfValue() {
115 parser.begin();
116 while( parser.anyOf(" \t") );
117 boolean b = parser.endOfInput() || parser.anyOf("\r\n");
118 parser.failure(); // rollback
119 return b;
120 }
121
122 private void require(boolean b) throws ParseException {
123 if( !b )
124 throw new ParseException(parser,"failed");
125 }
126
127 boolean tokenChar() {
128 if( parser.endOfInput() )
129 return false;
130 char c = parser.currentChar();
131 if( 32 <= c && c <= 126 && "()<>@,;:\\\"/[]?={} \t\r\n".indexOf(c) == -1 ) {
132 parser.anyChar();
133 return true;
134 } else {
135 return false;
136 }
137 }
138 }