Mercurial Hosting > luan
annotate src/luan/webserver/RequestParser.java @ 1144:ae0a048f3bc7
webserver - handle POST params
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 31 Jan 2018 00:29:50 -0700 |
parents | src/luan/webserver/RequestHeadParser.java@3bf5190b3c77 |
children | 12ececf30597 |
rev | line source |
---|---|
1137 | 1 package luan.webserver; |
2 | |
1143
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
3 import java.io.UnsupportedEncodingException; |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
4 import java.net.URLDecoder; |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
5 import java.util.List; |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
6 import java.util.ArrayList; |
1137 | 7 import luan.lib.parser.Parser; |
8 import luan.lib.parser.ParseException; | |
9 | |
10 | |
1144
ae0a048f3bc7
webserver - handle POST params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1143
diff
changeset
|
11 final class RequestParser { |
ae0a048f3bc7
webserver - handle POST params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1143
diff
changeset
|
12 private final Request request; |
ae0a048f3bc7
webserver - handle POST params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1143
diff
changeset
|
13 private Parser parser; |
1137 | 14 |
1144
ae0a048f3bc7
webserver - handle POST params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1143
diff
changeset
|
15 RequestParser(Request request) { |
ae0a048f3bc7
webserver - handle POST params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1143
diff
changeset
|
16 this.request = request; |
1137 | 17 } |
18 | |
1144
ae0a048f3bc7
webserver - handle POST params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1143
diff
changeset
|
19 void parsePost() throws ParseException { |
ae0a048f3bc7
webserver - handle POST params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1143
diff
changeset
|
20 this.parser = new Parser(request.body); |
ae0a048f3bc7
webserver - handle POST params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1143
diff
changeset
|
21 parseQuery(); |
ae0a048f3bc7
webserver - handle POST params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1143
diff
changeset
|
22 require( parser.endOfInput() ); |
1137 | 23 } |
24 | |
1144
ae0a048f3bc7
webserver - handle POST params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1143
diff
changeset
|
25 void parseHead() throws ParseException { |
ae0a048f3bc7
webserver - handle POST params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1143
diff
changeset
|
26 this.parser = new Parser(request.rawHead); |
1137 | 27 parseRequestLine(); |
28 while( !parser.match("\r\n") ) { | |
29 parserHeaderField(); | |
30 } | |
31 } | |
32 | |
33 private void parseRequestLine() throws ParseException { | |
34 parseMethod(); | |
35 require( parser.match(' ') ); | |
1143
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
36 parseRawPath(); |
1137 | 37 require( parser.match(' ') ); |
38 parseProtocol(); | |
39 require( parser.match("\r\n") ); | |
40 } | |
41 | |
42 private void parseMethod() throws ParseException { | |
43 int start = parser.currentIndex(); | |
44 if( !methodChar() ) | |
45 throw new ParseException(parser,"no method"); | |
46 while( methodChar() ); | |
47 request.method = parser.textFrom(start); | |
48 } | |
49 | |
50 private boolean methodChar() { | |
51 return parser.inCharRange('A','Z'); | |
52 } | |
53 | |
1143
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
54 private void parseRawPath() throws ParseException { |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
55 int start = parser.currentIndex(); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
56 parsePath(); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
57 if( parser.match('?') ) |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
58 parseQuery(); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
59 request.rawPath = parser.textFrom(start); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
60 } |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
61 |
1137 | 62 private void parsePath() throws ParseException { |
63 int start = parser.currentIndex(); | |
64 if( !parser.match('/') ) | |
65 throw new ParseException(parser,"bad path"); | |
1143
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
66 while( safePathChar() || parser.anyOf("&=") ); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
67 request.path = decode( parser.textFrom(start) ); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
68 } |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
69 |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
70 private void parseQuery() throws ParseException { |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
71 while(true) { |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
72 while( parser.match('&') ); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
73 int start = parser.currentIndex(); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
74 if( !queryChar() ) |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
75 return; |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
76 while( queryChar() ); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
77 String name = decode( parser.textFrom(start) ); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
78 String value; |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
79 if( parser.match('=') ) { |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
80 start = parser.currentIndex(); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
81 while( queryChar() ); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
82 value = decode( parser.textFrom(start) ); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
83 } else { |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
84 value = ""; |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
85 } |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
86 Object current = request.parameters.get(name); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
87 if( current == null ) { |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
88 request.parameters.put(name,value); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
89 } else if( current instanceof List ) { |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
90 List list = (List)current; |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
91 list.add(value); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
92 } else { |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
93 List list = new ArrayList(); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
94 list.add(current); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
95 list.add(value); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
96 request.parameters.put(name,list); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
97 } |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
98 } |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
99 } |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
100 |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
101 private boolean queryChar() { |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
102 return safePathChar() || parser.anyOf("?"); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
103 } |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
104 |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
105 // where did I get this? |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
106 private boolean safePathChar() { |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
107 return parser.inCharRange('A','Z') |
1137 | 108 || parser.inCharRange('a','z') |
109 || parser.inCharRange('0','9') | |
1143
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
110 || parser.anyOf("-._~:/[]@!$'()*+,;`.%") |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
111 ; |
1137 | 112 } |
113 | |
114 private void parseProtocol() throws ParseException { | |
115 int start = parser.currentIndex(); | |
116 if( !( | |
117 parser.match("HTTP/") | |
118 && parser.inCharRange('0','9') | |
119 && parser.match('.') | |
120 && parser.inCharRange('0','9') | |
121 ) ) | |
122 throw new ParseException(parser,"bad protocol"); | |
123 request.protocol = parser.textFrom(start); | |
124 } | |
125 | |
126 | |
127 private void parserHeaderField() throws ParseException { | |
128 String name = parseName(); | |
129 require( parser.match(':') ); | |
130 while( parser.anyOf(" \t") ); | |
131 String value = parseValue(); | |
132 while( parser.anyOf(" \t") ); | |
133 require( parser.match("\r\n") ); | |
134 request.headers.put(name,value); | |
135 } | |
136 | |
137 private String parseName() throws ParseException { | |
138 StringBuilder buf = new StringBuilder(); | |
139 boolean cap = true; | |
140 require( tokenChar() ); | |
141 do { | |
142 char c = parser.lastChar(); | |
143 if( c == '-' ) { | |
144 cap = true; | |
145 } else if( cap ) { | |
146 c = Character.toUpperCase(c); | |
147 cap = false; | |
148 } else { | |
149 c = Character.toLowerCase(c); | |
150 } | |
151 buf.append(c); | |
152 } while( tokenChar() ); | |
153 return buf.toString(); | |
154 } | |
155 | |
156 private String parseValue() { | |
157 int start = parser.currentIndex(); | |
158 while( !testEndOfValue() ) | |
159 parser.anyChar(); | |
160 return parser.textFrom(start); | |
161 } | |
162 | |
163 private boolean testEndOfValue() { | |
164 parser.begin(); | |
165 while( parser.anyOf(" \t") ); | |
166 boolean b = parser.endOfInput() || parser.anyOf("\r\n"); | |
167 parser.failure(); // rollback | |
168 return b; | |
169 } | |
170 | |
171 private void require(boolean b) throws ParseException { | |
172 if( !b ) | |
173 throw new ParseException(parser,"failed"); | |
174 } | |
175 | |
176 boolean tokenChar() { | |
177 if( parser.endOfInput() ) | |
178 return false; | |
179 char c = parser.currentChar(); | |
180 if( 32 <= c && c <= 126 && "()<>@,;:\\\"/[]?={} \t\r\n".indexOf(c) == -1 ) { | |
181 parser.anyChar(); | |
182 return true; | |
183 } else { | |
184 return false; | |
185 } | |
186 } | |
1143
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
187 |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
188 private static String decode(String s) { |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
189 try { |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
190 return URLDecoder.decode(s,"UTF-8"); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
191 } catch(UnsupportedEncodingException e) { |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
192 throw new RuntimeException(e); |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
193 } |
3bf5190b3c77
webserver - handle GET params
Franklin Schmidt <fschmidt@gmail.com>
parents:
1137
diff
changeset
|
194 } |
1137 | 195 } |