001: /* ====================================================================
002: The Jicarilla Software License
003:
004: Copyright (c) 2003 Leo Simons.
005: All rights reserved.
006:
007: Permission is hereby granted, free of charge, to any person obtaining
008: a copy of this software and associated documentation files (the
009: "Software"), to deal in the Software without restriction, including
010: without limitation the rights to use, copy, modify, merge, publish,
011: distribute, sublicense, and/or sell copies of the Software, and to
012: permit persons to whom the Software is furnished to do so, subject to
013: the following conditions:
014:
015: The above copyright notice and this permission notice shall be
016: included in all copies or substantial portions of the Software.
017:
018: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
019: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
020: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
021: IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
022: CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
023: TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
024: SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
025: ==================================================================== */
026: package org.jicarilla.http;
027:
028: import org.apache.commons.pool.ObjectPool;
029: import org.jicarilla.http.util.NioUtil;
030: import org.jicarilla.lang.Assert;
031: import org.jicarilla.lang.ExceptionListener;
032:
033: import java.nio.ByteBuffer;
034: import java.util.ArrayList;
035: import java.util.Iterator;
036: import java.util.List;
037:
038: /**
039: * Will populateContainer a HTTPMessage instance based on the events
040: * fired by a HTTPParser. Not Threadsafe.
041: *
042: * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
043: * @version $Id: HTTPMessageGenerator.java,v 1.8 2004/04/03 10:13:24 lsimons Exp $
044: */
045: public class HTTPMessageGenerator implements HTTPHandler,
046: HTTPErrorHandler {
047: // ----------------------------------------------------------------------
048: // Properties
049: // ----------------------------------------------------------------------
050: protected HTTPMessage m_message = null;
051: protected ByteBuffer m_headerNameCache = null;
052:
053: protected ExceptionListener m_exceptionListener;
054: protected MessageReceivedListener m_messageListener;
055: protected ObjectPool m_messagePool;
056:
057: // ----------------------------------------------------------------------
058: // Constructors
059: // ----------------------------------------------------------------------
060: public HTTPMessageGenerator(
061: final ExceptionListener exceptionListener,
062: final MessageReceivedListener messageListener,
063: final ObjectPool messagePool) {
064: Assert.assertNotNull(
065: "exceptionListener argument may not be null",
066: exceptionListener);
067: Assert.assertNotNull(
068: "messageListener argument may not be null",
069: messageListener);
070: Assert.assertNotNull("messagePool argument may not be null",
071: messagePool);
072:
073: m_exceptionListener = exceptionListener;
074: m_messageListener = messageListener;
075: m_messagePool = messagePool;
076: }
077:
078: // ----------------------------------------------------------------------
079: // Getters/Setters
080: // ----------------------------------------------------------------------
081: public void setMessage(final HTTPMessage message) {
082: m_message = message;
083: }
084:
085: public HTTPMessage getMessage() {
086: return m_message;
087: }
088:
089: public void setMessageType(final boolean isRequest) {
090: checkState();
091: m_message.setMessageType(isRequest);
092: }
093:
094: public boolean getMessageType() {
095: checkState();
096: return m_message.getMessageType();
097: }
098:
099: protected ByteBuffer getHeaderNameCache() {
100: return m_headerNameCache;
101: }
102:
103: protected void setHeaderNameCache(final ByteBuffer headerNameCache) {
104: m_headerNameCache = headerNameCache;
105: }
106:
107: protected ExceptionListener getExceptionListener() {
108: return m_exceptionListener;
109: }
110:
111: protected void setExceptionListener(
112: final ExceptionListener exceptionListener) {
113: m_exceptionListener = exceptionListener;
114: }
115:
116: protected MessageReceivedListener getMessageListener() {
117: return m_messageListener;
118: }
119:
120: protected void setMessageListener(
121: final MessageReceivedListener messageListener) {
122: m_messageListener = messageListener;
123: }
124:
125: protected ObjectPool getMessagePool() {
126: return m_messagePool;
127: }
128:
129: protected void setMessagePool(final ObjectPool messagePool) {
130: m_messagePool = messagePool;
131: }
132:
133: // ----------------------------------------------------------------------
134: // Work Interface: HTTPHandler
135: // ----------------------------------------------------------------------
136:
137: public int getBodyType() {
138: checkState();
139: // default
140: int type = HTTPParser.BODY_TYPE_NORMAL;
141:
142: /* the spec says we should forward and ignore...
143:
144: if( HTTPEncoding.METHOD_GET.equals( m_message.getField1() ) )
145: type = HTTPParser.BODY_TYPE_NONE;*/
146:
147: // decide based on spec basics
148: type = getTypeFromMessageProperties(type);
149:
150: // modify decision based on headers
151: type = getTypeFromHeaders(type);
152:
153: return type;
154: }
155:
156: public int getBodySize() {
157: checkState();
158: final int type = getBodyType();
159: switch (type) {
160: case HTTPParser.BODY_TYPE_NONE:
161: return 0;
162: case HTTPParser.BODY_TYPE_CHUNKING:
163: return -1; // unknown
164: case HTTPParser.BODY_TYPE_NORMAL:
165: return getNormalBodySize();
166:
167: default:
168: return 0;
169: //throw new IllegalStateException( "Parsing error: bad body type!" );
170: }
171: }
172:
173: public void newMessage() {
174: try {
175: setMessage((HTTPMessage) getMessagePool().borrowObject());
176: } catch (Exception e) {
177: setMessage(new HTTPMessage());
178: }
179: }
180:
181: public void foundStartLineFirstField(final ByteBuffer firstField) {
182: checkState();
183: getMessage().setField1(firstField);
184: }
185:
186: public void foundStartLineSecondField(final ByteBuffer secondField) {
187: checkState();
188: getMessage().setField2(secondField);
189: }
190:
191: public void foundStartLineThirdField(final ByteBuffer thirdField) {
192: checkState();
193: getMessage().setField3(thirdField);
194: }
195:
196: public void foundHeaderName(final ByteBuffer header) {
197: checkState();
198: setHeaderNameCache(header);
199: }
200:
201: public void foundHeaderValue(final ByteBuffer value) {
202: checkState();
203: getMessage().addHeader(getHeaderNameCache(), value);
204: setHeaderNameCache(null);
205: }
206:
207: public void foundBody(final ByteBuffer buffer) {
208: checkState();
209: getMessage().addBodyPart(buffer);
210: }
211:
212: public boolean hasTrailers() {
213: checkState();
214: Iterator it = getMessage().getHeaders().iterator();
215: while (it.hasNext()) {
216: HTTPField field = (HTTPField) it.next();
217: if (HTTPEncoding.HEADER_TRAILER.equalsIgnoreCase(field
218: .getNameString())) {
219: return true;
220: }
221: }
222: return false;
223: }
224:
225: public String[] getTrailerNames() {
226: checkState();
227: Iterator it = getMessage().getHeaders().iterator();
228: List nameList = new ArrayList();
229: while (it.hasNext()) {
230: HTTPField field = (HTTPField) it.next();
231: if (HTTPEncoding.HEADER_TRAILER.equalsIgnoreCase(field
232: .getNameString())) {
233: String[] names = field.getValueString().split(",");
234: for (int i = 0; i < names.length; i++) {
235: nameList.add(names[i].trim());
236: }
237: }
238: }
239: return (String[]) nameList.toArray(new String[nameList.size()]);
240: }
241:
242: public void foundTrailerName(final ByteBuffer trailer) {
243: checkState();
244: final String trailerString = NioUtil.toString(trailer);
245: Assert.assertFalse("Illegal trailer",
246: HTTPEncoding.HEADER_TRANSFER_ENCODING
247: .equalsIgnoreCase(trailerString)
248: || HTTPEncoding.HEADER_TRAILER
249: .equalsIgnoreCase(trailerString)
250: || HTTPEncoding.HEADER_CONTENT_LENGTH
251: .equalsIgnoreCase(trailerString));
252: foundHeaderName(trailer);
253: }
254:
255: public void foundTrailerValue(final ByteBuffer value) {
256: checkState();
257: foundHeaderValue(value);
258: }
259:
260: public void endMessage() {
261: checkState();
262: getMessageListener().messageReceived(getMessage());
263: getMessage().setComplete(true);
264: }
265:
266: // ----------------------------------------------------------------------
267: // Work Interface: HTTPErrorHandler
268: // ----------------------------------------------------------------------
269:
270: public void exceptionOccurred(final HTTPException he)
271: throws HTTPException {
272: m_exceptionListener.exceptionOccurred(he);
273: throw he;
274: }
275:
276: // ----------------------------------------------------------------------
277: // Helper Methods
278: // ----------------------------------------------------------------------
279:
280: protected void checkState() {
281: Assert.assertNotNull("setMessage() must be called first!",
282: getMessage());
283: }
284:
285: protected int getTypeFromMessageProperties(final int fallbackType) {
286: int type = fallbackType;
287: if (!getMessage().getMessageType()) {
288: // handle response defaults
289: final int statuscode = getMessage().getStatusCode();
290: if ((statuscode >= HTTPEncoding.STATUS_100_Continue && statuscode < HTTPEncoding.STATUS_200_OK)
291: || statuscode == HTTPEncoding.STATUS_204_No_Content
292: || statuscode == HTTPEncoding.STATUS_304_Not_Modified)
293: type = HTTPParser.BODY_TYPE_NONE;
294: } else {
295: // handle request defaults
296: final String method = getMessage().getField1String();
297: if (HTTPEncoding.METHOD_GET.equals(method)
298: || HTTPEncoding.METHOD_HEAD.equals(method)
299: || HTTPEncoding.METHOD_OPTIONS.equals(method)
300: || HTTPEncoding.METHOD_CONNECT.equals(method)
301: || HTTPEncoding.METHOD_DELETE.equals(method)
302: || HTTPEncoding.METHOD_TRACE.equals(method))
303: type = HTTPParser.BODY_TYPE_NONE;
304: }
305: return type;
306: }
307:
308: protected int getTypeFromHeaders(final int fallbackType) {
309: int type = fallbackType;
310: final Iterator it = getMessage().getHeaders().iterator();
311: while (it.hasNext()) {
312: // modify based on headers
313: final HTTPField h = (HTTPField) it.next();
314: final String name = NioUtil.toString(h.getName());
315: final String value = NioUtil.toString(h.getValue());
316:
317: if (name == null || value == null)
318: continue;
319:
320: if (name.equalsIgnoreCase(HTTPEncoding.TRANSFER_CODING)
321: && value
322: .equalsIgnoreCase(HTTPEncoding.TRANSFER_CODING_CHUNKED)) {
323: type = HTTPParser.BODY_TYPE_CHUNKING;
324: }
325: }
326: return type;
327: }
328:
329: protected int getNormalBodySize() {
330: // -1 will result in exception!
331: final Iterator it = getMessage().getHeaders().iterator();
332:
333: while (it.hasNext()) {
334: final HTTPField h = (HTTPField) it.next();
335: final String name = NioUtil.toString(h.getName());
336: final String value = NioUtil.toString(h.getValue());
337:
338: if (name == null) // ignore
339: continue;
340:
341: if (name
342: .equalsIgnoreCase(HTTPEncoding.HEADER_CONTENT_LENGTH)) {
343: if (value == null)
344: //throw new IllegalStateException(
345: // "Parsing error: no value for content-length header given!" );
346: return 0;
347: return new Integer(value).intValue();
348: }
349: }
350:
351: //throw new IllegalStateException( "Parsing error: no content-length given!" );
352: return 0;
353: }
354: }
|