KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > mina > example > httpserver > codec > HttpRequestDecoder


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  *
19  */

20 package org.apache.mina.example.httpserver.codec;
21
22 import java.io.BufferedReader JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.Reader JavaDoc;
25 import java.io.StringReader JavaDoc;
26 import java.nio.charset.CharacterCodingException JavaDoc;
27 import java.nio.charset.CharsetDecoder JavaDoc;
28 import java.nio.charset.Charset JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.Map JavaDoc;
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  * A {@link org.apache.mina.filter.codec.demux.MessageDecoder} that decodes {@link HttpRequest}.
40  *
41  * @author The Apache Directory Project (mina-dev@directory.apache.org)
42  * @version $Rev: 555855 $, $Date: 2007-07-13 12:19:00 +0900 (금, 13 7월 2007) $
43  */

44 public class HttpRequestDecoder extends MessageDecoderAdapter {
45     private static final byte[] CONTENT_LENGTH = new String JavaDoc("Content-Length:")
46             .getBytes();
47
48     private CharsetDecoder JavaDoc 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         // Return NEED_DATA if the whole header is not read yet.
57
try {
58             return messageComplete(in) ? MessageDecoderResult.OK
59                     : MessageDecoderResult.NEED_DATA;
60         } catch (Exception JavaDoc 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 JavaDoc {
69         // Try to decode body
70
HttpRequestMessage m = decodeBody(in);
71
72         // Return NEED_DATA if the body is not fully read.
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 JavaDoc {
82         int last = in.remaining() - 1;
83         if (in.remaining() < 4)
84             return false;
85
86         // to speed up things we check if the Http request is a GET or POST
87
if (in.get(0) == (byte) 'G' && in.get(1) == (byte) 'E'
88                 && in.get(2) == (byte) 'T') {
89             // Http GET request therefore the last 4 bytes should be 0x0D 0x0A 0x0D 0x0A
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             // Http POST request
96
// first the position of the 0x0D 0x0A 0x0D 0x0A bytes
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                     // retrieve value from this position till next 0x0D 0x0A
119
StringBuilder JavaDoc contentLength = new StringBuilder JavaDoc();
120                     for (int j = i + CONTENT_LENGTH.length; j < last; j++) {
121                         if (in.get(j) == 0x0D)
122                             break;
123                         contentLength.append(new String JavaDoc(
124                                 new byte[] { in.get(j) }));
125                     }
126                     // if content-length worth of data has been received then the message is complete
127
return (Integer.parseInt(contentLength.toString().trim())
128                             + eoh == in.remaining());
129                 }
130             }
131         }
132
133         // the message is not complete and we need more data
134
return false;
135     }
136
137     private HttpRequestMessage decodeBody(ByteBuffer in) {
138         request = new HttpRequestMessage();
139         try {
140             request.setHeaders(parseRequest(new StringReader JavaDoc(in
141                     .getString(decoder))));
142             return request;
143         } catch (CharacterCodingException JavaDoc ex) {
144             ex.printStackTrace();
145         }
146
147         return null;
148     }
149
150     private Map JavaDoc parseRequest(Reader JavaDoc is) {
151         Map JavaDoc<String JavaDoc, String JavaDoc[]> map = new HashMap JavaDoc<String JavaDoc, String JavaDoc[]>();
152         BufferedReader JavaDoc rdr = new BufferedReader JavaDoc(is);
153
154         try {
155             // Get request URL.
156
String JavaDoc line = rdr.readLine();
157             String JavaDoc[] url = line.split(" ");
158             if (url.length < 3)
159                 return map;
160
161             map.put("URI", new String JavaDoc[] { line });
162             map.put("Method", new String JavaDoc[] { url[0].toUpperCase() });
163             map.put("Context", new String JavaDoc[] { url[1].substring(1) });
164             map.put("Protocol", new String JavaDoc[] { url[2] });
165             // Read header
166
while ((line = rdr.readLine()) != null && line.length() > 0) {
167                 String JavaDoc[] tokens = line.split(": ");
168                 map.put(tokens[0], new String JavaDoc[] { tokens[1] });
169             }
170
171             // If method 'POST' then read Content-Length worth of data
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 JavaDoc[] { 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 JavaDoc[] match = line.split("\\&");
190                 for (int i = 0; i < match.length; i++) {
191                     String JavaDoc[] params = new String JavaDoc[1];
192                     String JavaDoc[] tokens = match[i].split("=");
193                     switch (tokens.length) {
194                     case 0:
195                         map.put("@".concat(match[i]), new String JavaDoc[] {});
196                         break;
197                     case 1:
198                         map.put("@".concat(tokens[0]), new String JavaDoc[] {});
199                         break;
200                     default:
201                         String JavaDoc name = "@".concat(tokens[0]);
202                         if (map.containsKey(name)) {
203                             params = map.get(name);
204                             String JavaDoc[] tmp = new String JavaDoc[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 JavaDoc ex) {
216             ex.printStackTrace();
217         }
218
219         return map;
220     }
221 }
222
Popular Tags