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