Mercurial Hosting > luan
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 } |