1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.example.httpserver.codec;
21
22 import java.io.BufferedReader;
23 import java.io.IOException;
24 import java.io.Reader;
25 import java.io.StringReader;
26 import java.nio.charset.CharacterCodingException;
27 import java.nio.charset.CharsetDecoder;
28 import java.nio.charset.Charset;
29 import java.util.HashMap;
30 import java.util.Map;
31
32 import org.apache.mina.common.ByteBuffer;
33 import org.apache.mina.common.IoSession;
34 import org.apache.mina.filter.codec.ProtocolDecoderOutput;
35 import org.apache.mina.filter.codec.demux.MessageDecoderAdapter;
36 import org.apache.mina.filter.codec.demux.MessageDecoderResult;
37
38
39
40
41
42
43
44 public class HttpRequestDecoder extends MessageDecoderAdapter {
45 private static final byte[] CONTENT_LENGTH = new String("Content-Length:")
46 .getBytes();
47
48 private CharsetDecoder decoder = Charset.defaultCharset().newDecoder();
49
50 private HttpRequestMessage request = null;
51
52 public HttpRequestDecoder() {
53 }
54
55 public MessageDecoderResult decodable(IoSession session, ByteBuffer in) {
56
57 try {
58 return messageComplete(in) ? MessageDecoderResult.OK
59 : MessageDecoderResult.NEED_DATA;
60 } catch (Exception ex) {
61 ex.printStackTrace();
62 }
63
64 return MessageDecoderResult.NOT_OK;
65 }
66
67 public MessageDecoderResult decode(IoSession session, ByteBuffer in,
68 ProtocolDecoderOutput out) throws Exception {
69
70 HttpRequestMessage m = decodeBody(in);
71
72
73 if (m == null)
74 return MessageDecoderResult.NEED_DATA;
75
76 out.write(m);
77
78 return MessageDecoderResult.OK;
79 }
80
81 private boolean messageComplete(ByteBuffer in) throws Exception {
82 int last = in.remaining() - 1;
83 if (in.remaining() < 4)
84 return false;
85
86
87 if (in.get(0) == (byte) 'G' && in.get(1) == (byte) 'E'
88 && in.get(2) == (byte) 'T') {
89
90 return (in.get(last) == (byte) 0x0A
91 && in.get(last - 1) == (byte) 0x0D
92 && in.get(last - 2) == (byte) 0x0A && in.get(last - 3) == (byte) 0x0D);
93 } else if (in.get(0) == (byte) 'P' && in.get(1) == (byte) 'O'
94 && in.get(2) == (byte) 'S' && in.get(3) == (byte) 'T') {
95
96
97 int eoh = -1;
98 for (int i = last; i > 2; i--) {
99 if (in.get(i) == (byte) 0x0A && in.get(i - 1) == (byte) 0x0D
100 && in.get(i - 2) == (byte) 0x0A
101 && in.get(i - 3) == (byte) 0x0D) {
102 eoh = i + 1;
103 break;
104 }
105 }
106 if (eoh == -1)
107 return false;
108 for (int i = 0; i < last; i++) {
109 boolean found = false;
110 for (int j = 0; j < CONTENT_LENGTH.length; j++) {
111 if (in.get(i + j) != CONTENT_LENGTH[j]) {
112 found = false;
113 break;
114 }
115 found = true;
116 }
117 if (found) {
118
119 StringBuilder contentLength = new StringBuilder();
120 for (int j = i + CONTENT_LENGTH.length; j < last; j++) {
121 if (in.get(j) == 0x0D)
122 break;
123 contentLength.append(new String(
124 new byte[] { in.get(j) }));
125 }
126
127 return (Integer.parseInt(contentLength.toString().trim())
128 + eoh == in.remaining());
129 }
130 }
131 }
132
133
134 return false;
135 }
136
137 private HttpRequestMessage decodeBody(ByteBuffer in) {
138 request = new HttpRequestMessage();
139 try {
140 request.setHeaders(parseRequest(new StringReader(in
141 .getString(decoder))));
142 return request;
143 } catch (CharacterCodingException ex) {
144 ex.printStackTrace();
145 }
146
147 return null;
148 }
149
150 private Map parseRequest(Reader is) {
151 Map<String, String[]> map = new HashMap<String, String[]>();
152 BufferedReader rdr = new BufferedReader(is);
153
154 try {
155
156 String line = rdr.readLine();
157 String[] url = line.split(" ");
158 if (url.length < 3)
159 return map;
160
161 map.put("URI", new String[] { line });
162 map.put("Method", new String[] { url[0].toUpperCase() });
163 map.put("Context", new String[] { url[1].substring(1) });
164 map.put("Protocol", new String[] { url[2] });
165
166 while ((line = rdr.readLine()) != null && line.length() > 0) {
167 String[] tokens = line.split(": ");
168 map.put(tokens[0], new String[] { tokens[1] });
169 }
170
171
172 if (url[0].equalsIgnoreCase("POST")) {
173 int len = Integer.parseInt(map.get("Content-Length")[0]);
174 char[] buf = new char[len];
175 if (rdr.read(buf) == len) {
176 line = String.copyValueOf(buf);
177 }
178 } else if (url[0].equalsIgnoreCase("GET")) {
179 int idx = url[1].indexOf('?');
180 if (idx != -1) {
181 map.put("Context",
182 new String[] { url[1].substring(1, idx) });
183 line = url[1].substring(idx + 1);
184 } else {
185 line = null;
186 }
187 }
188 if (line != null) {
189 String[] match = line.split("\\&");
190 for (int i = 0; i < match.length; i++) {
191 String[] params = new String[1];
192 String[] tokens = match[i].split("=");
193 switch (tokens.length) {
194 case 0:
195 map.put("@".concat(match[i]), new String[] {});
196 break;
197 case 1:
198 map.put("@".concat(tokens[0]), new String[] {});
199 break;
200 default:
201 String name = "@".concat(tokens[0]);
202 if (map.containsKey(name)) {
203 params = map.get(name);
204 String[] tmp = new String[params.length + 1];
205 for (int j = 0; j < params.length; j++)
206 tmp[j] = params[j];
207 params = null;
208 params = tmp;
209 }
210 params[params.length - 1] = tokens[1].trim();
211 map.put(name, params);
212 }
213 }
214 }
215 } catch (IOException ex) {
216 ex.printStackTrace();
217 }
218
219 return map;
220 }
221 }