You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by mw...@apache.org on 2007/08/28 02:00:46 UTC

svn commit: r570271 - /mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/

Author: mwebb
Date: Mon Aug 27 17:00:46 2007
New Revision: 570271

URL: http://svn.apache.org/viewvc?rev=570271&view=rev
Log:
initial check-in.  much is left to do in the commenting section.  This will at least get the ball rolling and allow others to make updates.

Added:
    mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/Cookie.java
    mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpDecoder.java
    mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpMessage.java
    mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpProtocolCodecFactory.java
    mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpRequestEncoder.java
    mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpRequestMessage.java
    mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpResponseDecoder.java
    mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpResponseMessage.java

Added: mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/Cookie.java
URL: http://svn.apache.org/viewvc/mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/Cookie.java?rev=570271&view=auto
==============================================================================
--- mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/Cookie.java (added)
+++ mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/Cookie.java Mon Aug 27 17:00:46 2007
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.http.codec;
+
+
+import java.util.Date;
+
+
+/**
+ * TODO Cookie.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class Cookie
+{
+
+    private String comment;
+    private String domain;
+    private String name;
+    private String value;
+    private String path;
+    private boolean secure;
+    private int version = 0;
+    private Date expires;
+
+
+    public Cookie( String name, String value )
+    {
+        this.name = name;
+        this.value = value;
+    }
+
+
+    public String getComment()
+    {
+        return comment;
+    }
+
+
+    public void setComment( String comment )
+    {
+        this.comment = comment;
+    }
+
+
+    public String getDomain()
+    {
+        return domain;
+    }
+
+
+    public void setDomain( String domain )
+    {
+        this.domain = domain;
+    }
+
+
+    public String getName()
+    {
+        return name;
+    }
+
+
+    public void setName( String name )
+    {
+        this.name = name;
+    }
+
+
+    public String getValue()
+    {
+        return value;
+    }
+
+
+    public void setValue( String value )
+    {
+        this.value = value;
+    }
+
+
+    public String getPath()
+    {
+        return path;
+    }
+
+
+    public void setPath( String path )
+    {
+        this.path = path;
+    }
+
+
+    public boolean isSecure()
+    {
+        return secure;
+    }
+
+
+    public void setSecure( boolean secure )
+    {
+        this.secure = secure;
+    }
+
+
+    public int getVersion()
+    {
+        return version;
+    }
+
+
+    public void setVersion( int version )
+    {
+        this.version = version;
+    }
+
+
+    public Date getExpires()
+    {
+        return expires;
+    }
+
+
+    public void setExpires( Date expires )
+    {
+        this.expires = expires;
+    }
+}

Added: mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpDecoder.java
URL: http://svn.apache.org/viewvc/mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpDecoder.java?rev=570271&view=auto
==============================================================================
--- mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpDecoder.java (added)
+++ mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpDecoder.java Mon Aug 27 17:00:46 2007
@@ -0,0 +1,250 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.http.codec;
+
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.util.Date;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.http.util.DateUtil;
+
+
+/**
+ * TODO HttpDecoder.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class HttpDecoder
+{
+    /**
+     * Carriage return character
+     */
+    private static final byte CR = 13;
+
+    /**
+     * Line feed character
+     */
+    private static final byte LF = 10;
+
+    public final static String COOKIE_COMMENT = "comment";
+    public final static String COOKIE_DOMAIN = "domain";
+    public final static String COOKIE_EXPIRES = "expires";
+    public final static String COOKIE_MAX_AGE = "max-age";
+    public final static String COOKIE_PATH = "path";
+    public final static String COOKIE_SECURE = "secure";
+    public final static String COOKIE_VERSION = "version";
+
+    public final static String SET_COOKIE = "Set-Cookie";
+    public final static String TRANSFER_ENCODING = "Transfer-Encoding";
+    public final static String CHUNKED = "chunked";
+
+    private CharsetDecoder decoder = Charset.defaultCharset().newDecoder();
+
+
+    public String decodeLine( ByteBuffer in ) throws Exception
+    {
+        int beginPos = in.position();
+        int limit = in.limit();
+        boolean lastIsCR = false;
+        int terminatorPos = -1;
+
+        for ( int i = beginPos; i < limit; i++ )
+        {
+            byte b = in.get( i );
+            if ( b == CR )
+            {
+                lastIsCR = true;
+            }
+            else
+            {
+                if ( b == LF && lastIsCR )
+                {
+                    terminatorPos = i;
+                    break;
+                }
+                lastIsCR = false;
+            }
+        }
+
+        //Check if we don't have enough data to process or found a full readable line
+        if ( terminatorPos == -1 )
+            return null;
+
+        String result = null;
+        if ( terminatorPos > 1 )
+        {
+            ByteBuffer line = in.slice();
+            line.limit( terminatorPos - beginPos - 1 );
+            result = line.getString( decoder );
+        }
+
+        in.position( terminatorPos + 1 );
+
+        return result;
+    }
+
+
+    public void decodeStatus( String line, HttpResponseMessage msg ) throws Exception
+    {
+        String magic = line.substring( 0, 8 );
+        if ( !magic.equals( "HTTP/1.1" ) && !magic.equals( "HTTP/1.0" ) )
+            throw new IOException( "Invalid HTTP response" );
+
+        String status = line.substring( 9, 12 );
+        msg.setStatusCode( Integer.parseInt( status ) );
+        msg.setStatusMessage( line.substring( 13 ) );
+    }
+
+
+    public void decodeHeader( String line, HttpResponseMessage msg ) throws Exception
+    {
+        int pos = line.indexOf( ": " );
+        String name = line.substring( 0, pos );
+        String value = line.substring( pos + 2 );
+        msg.addHeader( name, value );
+
+        if ( name.equalsIgnoreCase( SET_COOKIE ) )
+        {
+            Cookie cookie = decodeCookie( value );
+            if ( cookie != null )
+                msg.addCookie( cookie );
+        }
+
+        if ( name.equalsIgnoreCase( HttpMessage.CONTENT_TYPE ) )
+        {
+            msg.setContentType( value );
+        }
+
+        if ( name.equalsIgnoreCase( HttpMessage.CONTENT_LENGTH ) )
+        {
+            msg.setContentLength( Integer.parseInt( value ) );
+        }
+
+        if ( name.equalsIgnoreCase( TRANSFER_ENCODING ) && value != null && value.equalsIgnoreCase( CHUNKED ) )
+        {
+            msg.setChunked( true );
+        }
+
+    }
+
+
+    public int decodeSize( String line ) throws Exception
+    {
+        String strippedLine = line.trim().toLowerCase();
+        for ( int i = 0; i < strippedLine.length(); i++ )
+        {
+            char ch = strippedLine.charAt( i );
+            //Once we hit a non-numeric character, parse the number we have
+            if ( ( ch < '0' || ( ch > '9' && ch < 'a' ) || ch > 'f' ) )
+            {
+                return Integer.parseInt( strippedLine.substring( 0, i ), 16 );
+            }
+        }
+
+        //We got here, so the entire line passes
+        return Integer.parseInt( strippedLine, 16 );
+    }
+
+
+    public void decodeContent( ByteBuffer in, HttpResponseMessage msg ) throws Exception
+    {
+        byte content[] = new byte[msg.getContentLength()];
+        in.get( content );
+        msg.addContent( content );
+    }
+
+
+    public void decodeChunkedContent( ByteBuffer in, HttpResponseMessage msg ) throws Exception
+    {
+        int toRead = msg.getExpectedToRead();
+        if ( ( in.get( in.position() + toRead ) != CR ) && ( in.get( in.position() + toRead + 1 ) != LF ) )
+        {
+            throw new IOException( "Invalid HTTP response - chunk does not end with CRLF" );
+
+        }
+        byte content[] = new byte[toRead];
+        in.get( content );
+        msg.addContent( content );
+
+        //Pop the CRLF
+        in.get();
+        in.get();
+    }
+
+
+    public Cookie decodeCookie( String cookieStr ) throws Exception
+    {
+
+        Cookie cookie = null;
+
+        String pairs[] = cookieStr.split( ";" );
+        for ( int i = 0; i < pairs.length; i++ )
+        {
+            String nameValue[] = pairs[i].trim().split( "=" );
+            String name = nameValue[0].trim();
+
+            //First one is the cookie name/value pair
+            if ( i == 0 )
+            {
+                cookie = new Cookie( name, nameValue[1].trim() );
+                continue;
+            }
+
+            if ( name.equalsIgnoreCase( COOKIE_COMMENT ) )
+            {
+                cookie.setComment( nameValue[1].trim() );
+                continue;
+            }
+
+            if ( name.equalsIgnoreCase( COOKIE_PATH ) )
+            {
+                cookie.setPath( nameValue[1].trim() );
+            }
+
+            if ( name.equalsIgnoreCase( COOKIE_SECURE ) )
+            {
+                cookie.setSecure( true );
+            }
+
+            if ( name.equalsIgnoreCase( COOKIE_VERSION ) )
+            {
+                cookie.setVersion( Integer.parseInt( nameValue[1] ) );
+            }
+
+            if ( name.equalsIgnoreCase( COOKIE_MAX_AGE ) )
+            {
+                int age = Integer.parseInt( nameValue[1] );
+                cookie.setExpires( new Date( System.currentTimeMillis() + age * 1000L ) );
+            }
+
+            if ( name.equalsIgnoreCase( COOKIE_EXPIRES ) )
+            {
+                cookie.setExpires( DateUtil.parseDate( nameValue[1] ) );
+            }
+
+        }
+
+        return cookie;
+    }
+}

Added: mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpMessage.java
URL: http://svn.apache.org/viewvc/mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpMessage.java?rev=570271&view=auto
==============================================================================
--- mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpMessage.java (added)
+++ mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpMessage.java Mon Aug 27 17:00:46 2007
@@ -0,0 +1,142 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.mina.http.codec;
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.mina.http.util.NameValuePair;
+
+
+/**
+ * TODO HttpMessage.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class HttpMessage
+{
+
+    public final static String CONTENT_TYPE = "Content-Type";
+    public final static String CONTENT_LENGTH = "Content-Length";
+
+    protected List<NameValuePair> headers = new ArrayList<NameValuePair>();
+    protected List<Cookie> cookies = new ArrayList<Cookie>();
+    protected String contentType;
+    protected int contentLength;
+    protected ByteArrayOutputStream content;
+
+
+    public String getStringContent()
+    {
+        if ( content == null )
+            return null;
+
+        return new String( content.toByteArray() );
+    }
+
+
+    public byte[] getContent()
+    {
+        if ( content == null )
+            return null;
+
+        return content.toByteArray();
+    }
+
+
+    public void addContent( byte[] content ) throws IOException
+    {
+        if ( this.content == null )
+            this.content = new ByteArrayOutputStream();
+
+        this.content.write( content );
+    }
+
+
+    public List<Cookie> getCookies()
+    {
+        return cookies;
+    }
+
+
+    public void setCookies( List<Cookie> cookies )
+    {
+        this.cookies = cookies;
+    }
+
+
+    public void addCookie( Cookie cookie )
+    {
+        this.cookies.add( cookie );
+    }
+
+
+    public List<NameValuePair> getHeaders()
+    {
+        return headers;
+    }
+
+
+    public void setHeaders( List<NameValuePair> headers )
+    {
+        this.headers = headers;
+    }
+
+
+    public void addHeader( NameValuePair header )
+    {
+        headers.add( header );
+    }
+
+
+    public void addHeader( String name, String value )
+    {
+        headers.add( new NameValuePair( name, value ) );
+    }
+
+
+    public String getContentType()
+    {
+        return contentType;
+    }
+
+
+    public void setContentType( String contentType )
+    {
+        this.contentType = contentType;
+    }
+
+
+    public int getContentLength()
+    {
+        return contentLength;
+    }
+
+
+    public void setContentLength( int contentLength )
+    {
+        this.contentLength = contentLength;
+    }
+
+}

Added: mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpProtocolCodecFactory.java
URL: http://svn.apache.org/viewvc/mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpProtocolCodecFactory.java?rev=570271&view=auto
==============================================================================
--- mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpProtocolCodecFactory.java (added)
+++ mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpProtocolCodecFactory.java Mon Aug 27 17:00:46 2007
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.mina.http.codec;
+
+
+import org.apache.mina.filter.codec.ProtocolCodecFactory;
+import org.apache.mina.filter.codec.ProtocolEncoder;
+import org.apache.mina.filter.codec.ProtocolDecoder;
+
+import java.net.URL;
+
+
+/**
+ * TODO HttpProtocolCodecFactory.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class HttpProtocolCodecFactory implements ProtocolCodecFactory
+{
+
+    private final ProtocolEncoder encoder;
+    private final ProtocolDecoder decoder;
+
+
+    public HttpProtocolCodecFactory( URL url )
+    {
+        encoder = new HttpRequestEncoder( url );
+        decoder = new HttpResponseDecoder();
+    }
+
+
+    public ProtocolEncoder getEncoder() throws Exception
+    {
+        return encoder;
+    }
+
+
+    public ProtocolDecoder getDecoder() throws Exception
+    {
+        return decoder;
+    }
+}

Added: mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpRequestEncoder.java
URL: http://svn.apache.org/viewvc/mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpRequestEncoder.java?rev=570271&view=auto
==============================================================================
--- mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpRequestEncoder.java (added)
+++ mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpRequestEncoder.java Mon Aug 27 17:00:46 2007
@@ -0,0 +1,200 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.mina.http.codec;
+
+
+import java.net.URL;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
+import org.apache.mina.filter.codec.ProtocolEncoderOutput;
+import org.apache.mina.http.util.EncodingUtil;
+import org.apache.mina.http.util.NameValuePair;
+
+
+/**
+ * TODO HttpRequestEncoder.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class HttpRequestEncoder extends ProtocolEncoderAdapter
+{
+    private static final Set<Class<HttpRequestMessage>> TYPES;
+    private static final byte[] CRLF = new byte[]
+        { 0x0D, 0x0A };
+    private static final String POST_CONTENT_TYPE = "application/x-www-form-urlencoded";
+    private URL url;
+
+    static
+    {
+        Set<Class<HttpRequestMessage>> types = new HashSet<Class<HttpRequestMessage>>();
+        types.add( HttpRequestMessage.class );
+        TYPES = Collections.unmodifiableSet( types );
+    }
+
+
+    public HttpRequestEncoder( URL url )
+    {
+        this.url = url;
+    }
+
+
+    Set<Class<HttpRequestMessage>> getMessageTypes()
+    {
+        return TYPES;
+    }
+
+
+    public void encode( IoSession ioSession, Object message, ProtocolEncoderOutput out ) throws Exception
+    {
+        HttpRequestMessage msg = ( HttpRequestMessage ) message;
+
+        ByteBuffer buf = ByteBuffer.allocate( 256 );
+
+        // Enable auto-expand for easier encoding
+        buf.setAutoExpand( true );
+
+        try
+        {
+            //If we have content, lets create the query string
+            int attrCount = msg.getParameters().size();
+            String urlAttrs = "";
+            if ( attrCount > 0 )
+            {
+                NameValuePair attrs[] = new NameValuePair[attrCount];
+                Set<Map.Entry<String, String>> set = msg.getParameters().entrySet();
+                int i = 0;
+                for ( Map.Entry<String, String> entry : set )
+                {
+                    attrs[i++] = new NameValuePair( entry.getKey(), entry.getValue() );
+                }
+                urlAttrs = EncodingUtil.formUrlEncode( attrs, Charset.defaultCharset().toString() );
+            }
+
+            CharsetEncoder encoder = Charset.defaultCharset().newEncoder();
+            buf.putString( msg.getRequestMethod(), encoder );
+            buf.putString( " ", encoder );
+            buf.putString( msg.getPath(), encoder );
+            //If its a GET, append the attributes
+            if ( msg.getRequestMethod().equals( HttpRequestMessage.REQUEST_GET ) && attrCount > 0 )
+            {
+                //If there is not already a ? in the query, append one, otherwise append a &
+                if ( !msg.getPath().contains( "?" ) )
+                {
+                    buf.putString( "?", encoder );
+                }
+                else
+                {
+                    buf.putString( "&", encoder );
+                }
+                buf.putString( urlAttrs, encoder );
+            }
+            buf.putString( " HTTP/1.1", encoder );
+            buf.put( CRLF );
+
+            //This header is required for HTTP/1.1
+            buf.putString( "Host: ", encoder );
+            buf.putString( url.getHost(), encoder );
+            buf.putString( ":", encoder );
+            buf.putString( url.getPort() + "", encoder );
+            buf.put( CRLF );
+
+            //Process any headers we have
+            List<NameValuePair> headers = msg.getHeaders();
+            for ( NameValuePair header : headers )
+            {
+                String name = header.getName();
+                String value = header.getValue();
+
+                buf.putString( name, encoder );
+                buf.putString( ": ", encoder );
+                buf.putString( value, encoder );
+                buf.put( CRLF );
+            }
+
+            //Process cookies
+            //NOTE: I am just passing the name value pairs and not doing management of the expiration or path
+            //As that will be left up to the user.  A possible enhancement is to make use of a CookieManager
+            //to handle these issues for the request
+            List<Cookie> cookies = msg.getCookies();
+            if ( cookies.size() > 0 )
+            {
+                buf.putString( "Cookie: ", encoder );
+                for ( Cookie cookie : cookies )
+                {
+                    String name = cookie.getName();
+                    String value = cookie.getValue();
+
+                    buf.putString( name, encoder );
+                    buf.putString( "=", encoder );
+                    buf.putString( value, encoder );
+                    buf.putString( "; ", encoder );
+                }
+                buf.put( CRLF );
+            }
+
+            //If this is a POST, then we need a content length and type
+            if ( msg.getRequestMethod().equals( HttpRequestMessage.REQUEST_POST ) )
+            {
+                byte content[] = urlAttrs.getBytes();
+
+                //Type
+                buf.putString( HttpMessage.CONTENT_TYPE, encoder );
+                buf.putString( ": ", encoder );
+                buf.putString( POST_CONTENT_TYPE, encoder );
+                buf.put( CRLF );
+
+                //Length
+                buf.putString( HttpMessage.CONTENT_LENGTH, encoder );
+                buf.putString( ": ", encoder );
+                buf.putString( content.length + "", encoder );
+                buf.put( CRLF );
+                //Blank line
+                buf.put( CRLF );
+                buf.put( content );
+            }
+            else
+            {
+                //Blank line
+                buf.put( CRLF );
+            }
+
+        }
+        catch ( CharacterCodingException ex )
+        {
+            ex.printStackTrace();
+        }
+
+        buf.flip();
+        out.write( buf );
+
+    }
+
+}

Added: mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpRequestMessage.java
URL: http://svn.apache.org/viewvc/mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpRequestMessage.java?rev=570271&view=auto
==============================================================================
--- mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpRequestMessage.java (added)
+++ mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpRequestMessage.java Mon Aug 27 17:00:46 2007
@@ -0,0 +1,113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.mina.http.codec;
+
+
+import java.net.ProtocolException;
+import java.util.Map;
+import java.util.HashMap;
+
+
+/**
+ * TODO HttpRequestMessage.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class HttpRequestMessage extends HttpMessage
+{
+
+    public static String REQUEST_GET = "GET";
+    public static String REQUEST_POST = "POST";
+    public static String REQUEST_HEAD = "HEAD";
+    public static String REQUEST_OPTIONS = "OPTIONS";
+    public static String REQUEST_PUT = "PUT";
+    public static String REQUEST_DELETE = "DELETE";
+    public static String REQUEST_TRACE = "TRACE";
+
+    private String requestMethod = REQUEST_GET;
+    private String path;
+    private Map<String, String> parameters = new HashMap<String, String>();
+
+
+    public HttpRequestMessage( String path )
+    {
+        this.path = path;
+    }
+
+
+    public String getRequestMethod()
+    {
+        return requestMethod;
+    }
+
+
+    public void setRequestMethod( String requestMethod ) throws ProtocolException
+    {
+        if ( requestMethod.equals( REQUEST_GET ) || requestMethod.equals( REQUEST_POST )
+            || requestMethod.equals( REQUEST_HEAD ) || requestMethod.equals( REQUEST_OPTIONS )
+            || requestMethod.equals( REQUEST_PUT ) || requestMethod.equals( REQUEST_DELETE )
+            || requestMethod.equals( REQUEST_TRACE ) )
+        {
+            this.requestMethod = requestMethod;
+            return;
+        }
+
+        throw new ProtocolException( "Invalid request method type." );
+    }
+
+
+    public String getPath()
+    {
+        return path;
+    }
+
+
+    public void setPath( String path )
+    {
+        if ( path == null || path.trim().length() == 0 )
+            path = "/";
+        this.path = path;
+    }
+
+
+    public String getParameter( String name )
+    {
+        return parameters.get( name );
+    }
+
+
+    public Map<String, String> getParameters()
+    {
+        return parameters;
+    }
+
+
+    public void setParameters( Map<String, String> parameters )
+    {
+        this.parameters.putAll( parameters );
+    }
+
+
+    public void setParameter( String name, String value )
+    {
+        parameters.put( name, value );
+    }
+}

Added: mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpResponseDecoder.java
URL: http://svn.apache.org/viewvc/mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpResponseDecoder.java?rev=570271&view=auto
==============================================================================
--- mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpResponseDecoder.java (added)
+++ mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpResponseDecoder.java Mon Aug 27 17:00:46 2007
@@ -0,0 +1,242 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.mina.http.codec;
+
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolDecoderOutput;
+
+
+/**
+ * TODO HttpResponseDecoder.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class HttpResponseDecoder extends CumulativeProtocolDecoder
+{
+
+    public final static String CURRENT_RESPONSE = "CURRENT_RESPONSE";
+
+    private HttpDecoder httpDecoder = new HttpDecoder();
+
+
+    protected boolean doDecode( IoSession ioSession, ByteBuffer in, ProtocolDecoderOutput out ) throws Exception
+    {
+
+        HttpResponseMessage response = ( HttpResponseMessage ) ioSession.getAttribute( CURRENT_RESPONSE );
+        if ( response == null )
+        {
+            response = new HttpResponseMessage();
+            ioSession.setAttribute( CURRENT_RESPONSE, response );
+        }
+
+        //Test if we need the response...
+        if ( response.getState() == HttpResponseMessage.STATE_START )
+        {
+
+            if ( !processStatus( response, in ) )
+            {
+                return false;
+            }
+
+            //Handle HTTP/1.1 100 Continue
+            if ( response.getStatusCode() == 100 )
+            {
+                response.setState( HttpResponseMessage.STATE_STATUS_CONTINUE );
+            }
+            else
+            {
+                response.setState( HttpResponseMessage.STATE_STATUS_READ );
+            }
+        }
+
+        //If we are in a 100 Continue, read until we get the real header
+        if ( response.getState() == HttpResponseMessage.STATE_STATUS_CONTINUE )
+        {
+            //Continue reading until we get a blank line
+            while ( true )
+            {
+                String line = httpDecoder.decodeLine( in );
+
+                //Check if the entire response has been read
+                if ( line == null )
+                    return false;
+
+                //Check if the entire response headers have been read
+                if ( line.length() == 0 )
+                {
+                    response.setState( HttpResponseMessage.STATE_STATUS_READ );
+
+                    //The next line should be a header
+                    if ( !processStatus( response, in ) )
+                    {
+                        return false;
+                    }
+                    break;
+                }
+            }
+        }
+
+        //Are we reading headers?
+        if ( response.getState() == HttpResponseMessage.STATE_STATUS_READ )
+        {
+            if ( processHeaders( response, in ) == false )
+                return false;
+        }
+
+        //Are we reading content?
+        if ( response.getState() == HttpResponseMessage.STATE_HEADERS_READ )
+        {
+            if ( processContent( response, in ) == false )
+                return false;
+        }
+
+        //If we are chunked and we have read all the content, then read the footers if there are any
+        if ( response.isChunked() && response.getState() == HttpResponseMessage.STATE_CONTENT_READ )
+        {
+            if ( processFooters( response, in ) == false )
+                return false;
+        }
+
+        response.setState( HttpResponseMessage.STATE_FINISHED );
+
+        out.write( response );
+
+        ioSession.removeAttribute( CURRENT_RESPONSE );
+
+        return true;
+    }
+
+
+    private boolean processHeaders( HttpResponseMessage response, ByteBuffer in ) throws Exception
+    {
+        if ( !findHeaders( response, in ) )
+            return false;
+
+        response.setState( HttpResponseMessage.STATE_HEADERS_READ );
+        return true;
+    }
+
+
+    private boolean processFooters( HttpResponseMessage response, ByteBuffer in ) throws Exception
+    {
+        if ( !findHeaders( response, in ) )
+            return false;
+
+        response.setState( HttpResponseMessage.STATE_FOOTERS_READ );
+        return true;
+    }
+
+
+    private boolean findHeaders( HttpResponseMessage response, ByteBuffer in ) throws Exception
+    {
+        //Read the headers and process them
+        while ( true )
+        {
+            String line = httpDecoder.decodeLine( in );
+
+            //Check if the entire response has been read
+            if ( line == null )
+                return false;
+
+            //Check if the entire response headers have been read
+            if ( line.length() == 0 )
+            {
+                break;
+            }
+
+            httpDecoder.decodeHeader( line, response );
+        }
+        return true;
+    }
+
+
+    private boolean processContent( HttpResponseMessage response, ByteBuffer in ) throws Exception
+    {
+        if ( response.isChunked() )
+        {
+            while ( true )
+            {
+                //Check what kind of record we are reading (content or size)
+                if ( response.getExpectedToRead() == HttpResponseMessage.EXPECTED_NOT_READ )
+                {
+                    //We haven't read the size, so we are expecting a size
+                    String line = httpDecoder.decodeLine( in );
+
+                    //Check if the entire line has been read
+                    if ( line == null )
+                        return false;
+
+                    response.setExpectedToRead( httpDecoder.decodeSize( line ) );
+
+                    //Are we done reading the chunked content? (A zero means we are done)
+                    if ( response.getExpectedToRead() == 0 )
+                    {
+                        break;
+                    }
+                }
+
+                //Now read the content chunk
+
+                //Be sure all of the data is there for us to retrieve + the CRLF...
+                if ( response.getExpectedToRead() + 2 > in.remaining() )
+                {
+                    //Need more data
+                    return false;
+                }
+
+                //Read the content
+                httpDecoder.decodeChunkedContent( in, response );
+
+                //Flag that it's time to read a size record
+                response.setExpectedToRead( HttpResponseMessage.EXPECTED_NOT_READ );
+
+            }
+
+        }
+        else if ( response.getContentLength() > 0 )
+        {
+            //Do we have enough data?
+            if ( ( response.getContentLength() ) > in.remaining() )
+                return false;
+            httpDecoder.decodeContent( in, response );
+        }
+
+        response.setState( HttpResponseMessage.STATE_CONTENT_READ );
+
+        return true;
+    }
+
+
+    private boolean processStatus( HttpResponseMessage response, ByteBuffer in ) throws Exception
+    {
+        //Read the status header
+        String header = httpDecoder.decodeLine( in );
+        if ( header == null )
+            return false;
+
+        httpDecoder.decodeStatus( header, response );
+
+        return true;
+    }
+}

Added: mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpResponseMessage.java
URL: http://svn.apache.org/viewvc/mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpResponseMessage.java?rev=570271&view=auto
==============================================================================
--- mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpResponseMessage.java (added)
+++ mina/trunk/mina-filter-codec-http/src/main/java/org/apache/mina/http/codec/HttpResponseMessage.java Mon Aug 27 17:00:46 2007
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.mina.http.codec;
+
+
+/**
+ * TODO HttpResponseMessage.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class HttpResponseMessage extends HttpMessage
+{
+
+    static final int EXPECTED_NOT_READ = -1;
+
+    static final int STATE_START = 0;
+    static final int STATE_STATUS_CONTINUE = 1;
+    static final int STATE_STATUS_READ = 2;
+    static final int STATE_HEADERS_READ = 3;
+    static final int STATE_CONTENT_READ = 4;
+    static final int STATE_FOOTERS_READ = 5;
+    static final int STATE_FINISHED = 6;
+
+    private int statusCode;
+    private String statusMessage;
+
+    private boolean chunked = false;
+    private int expectedToRead = -1;
+    private int state = STATE_START;
+
+
+    public int getStatusCode()
+    {
+        return statusCode;
+    }
+
+
+    public void setStatusCode( int statusCode )
+    {
+        this.statusCode = statusCode;
+    }
+
+
+    public String getStatusMessage()
+    {
+        return statusMessage;
+    }
+
+
+    public void setStatusMessage( String statusMessage )
+    {
+        this.statusMessage = statusMessage;
+    }
+
+
+    boolean isChunked()
+    {
+        return chunked;
+    }
+
+
+    void setChunked( boolean chunked )
+    {
+        this.chunked = chunked;
+    }
+
+
+    int getExpectedToRead()
+    {
+        return expectedToRead;
+    }
+
+
+    void setExpectedToRead( int expectedToRead )
+    {
+        this.expectedToRead = expectedToRead;
+    }
+
+
+    int getState()
+    {
+        return state;
+    }
+
+
+    void setState( int state )
+    {
+        this.state = state;
+    }
+
+}