You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by ed...@apache.org on 2008/08/13 02:05:43 UTC

svn commit: r685389 [1/4] - in /mina/trunk/core/src/main/java/org/apache/mina/proxy: ./ event/ filter/ handlers/ handlers/http/ handlers/http/basic/ handlers/http/digest/ handlers/http/ntlm/ handlers/socks/ session/ utils/

Author: edeoliveira
Date: Tue Aug 12 17:05:41 2008
New Revision: 685389

URL: http://svn.apache.org/viewvc?rev=685389&view=rev
Log:
DIRMINA-415 initial commit

Added:
    mina/trunk/core/src/main/java/org/apache/mina/proxy/
    mina/trunk/core/src/main/java/org/apache/mina/proxy/AbstractProxyIoHandler.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/AbstractProxyLogicHandler.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyAuthException.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyConnector.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyLogicHandler.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/event/
    mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEvent.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEventQueue.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEventType.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/filter/
    mina/trunk/core/src/main/java/org/apache/mina/proxy/filter/ProxyFilter.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/filter/ProxyHandshakeIoBuffer.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/ProxyRequest.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/AbstractAuthLogicHandler.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/AbstractHttpLogicHandler.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpAuthenticationMethods.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpProxyConstants.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpProxyRequest.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpProxyResponse.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpSmartProxyHandler.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/basic/
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/basic/HttpBasicAuthLogicHandler.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/basic/HttpNoAuthLogicHandler.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/digest/
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/digest/DigestUtilities.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/digest/HttpDigestAuthLogicHandler.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/ntlm/
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/ntlm/HttpNTLMAuthLogicHandler.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/ntlm/NTLMConstants.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/ntlm/NTLMResponses.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/ntlm/NTLMUtilities.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/socks/
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/socks/AbstractSocksLogicHandler.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/socks/Socks4LogicHandler.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/socks/Socks5LogicHandler.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/socks/SocksProxyConstants.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/socks/SocksProxyRequest.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/session/
    mina/trunk/core/src/main/java/org/apache/mina/proxy/session/ProxyIoSession.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/session/ProxyIoSessionInitializer.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/
    mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/ByteUtilities.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/IoBufferDecoder.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/StringUtilities.java   (with props)

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/AbstractProxyIoHandler.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/AbstractProxyIoHandler.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/AbstractProxyIoHandler.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/AbstractProxyIoHandler.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,61 @@
+/*
+ *  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.proxy;
+
+import org.apache.mina.core.service.IoHandler;
+import org.apache.mina.core.service.IoHandlerAdapter;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.proxy.handlers.socks.SocksProxyRequest;
+import org.apache.mina.proxy.session.ProxyIoSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * AbstractProxyIoHandler.java - {@link IoHandler} that intercepts events until handshake is complete.
+ * 
+ * @author Edouard De Oliveira <a href="mailto:doe_wanted@yahoo.fr">doe_wanted@yahoo.fr</a> 
+ * @version	$Id: $
+ */
+public abstract class AbstractProxyIoHandler extends IoHandlerAdapter {
+    private final static Logger logger = LoggerFactory
+            .getLogger(AbstractProxyIoHandler.class);
+
+    /**
+     * Method called only when handshake has completed.
+     */
+    public abstract void proxySessionOpened(IoSession session) throws Exception;
+
+    /**
+     * Hooked session opened event.
+     */
+    @Override
+    public final void sessionOpened(IoSession session) throws Exception {
+        ProxyIoSession proxyIoSession = (ProxyIoSession) session
+                .getAttribute(ProxyIoSession.PROXY_SESSION);
+
+        if (proxyIoSession.getRequest() instanceof SocksProxyRequest
+                || proxyIoSession.isAuthenticationFailed()
+                || proxyIoSession.getHandler().isHandshakeComplete()) {
+            proxySessionOpened(session);
+        } else {
+            logger.debug("Filtered session opened event !");
+        }
+    }
+}
\ No newline at end of file

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/AbstractProxyIoHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/AbstractProxyIoHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/AbstractProxyLogicHandler.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/AbstractProxyLogicHandler.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/AbstractProxyLogicHandler.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/AbstractProxyLogicHandler.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,231 @@
+/*
+ *  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.proxy;
+
+import java.io.UnsupportedEncodingException;
+import java.util.LinkedList;
+import java.util.Queue;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.filterchain.IoFilter.NextFilter;
+import org.apache.mina.core.future.DefaultWriteFuture;
+import org.apache.mina.core.future.WriteFuture;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.core.write.DefaultWriteRequest;
+import org.apache.mina.core.write.WriteRequest;
+import org.apache.mina.proxy.filter.ProxyFilter;
+import org.apache.mina.proxy.filter.ProxyHandshakeIoBuffer;
+import org.apache.mina.proxy.session.ProxyIoSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * AbstractProxyLogicHandler.java - Helper class to handle proxy handshaking logic. Derived classes 
+ * implement proxy type specific logic.
+ * <p>
+ * Based upon SSLHandler from mina-filter-ssl.
+ * 
+ * @author James Furness <a href="mailto:james.furness@lehman.com">james.furness@lehman.com</a>
+ * @author Edouard De Oliveira <a href="mailto:doe_wanted@yahoo.fr">doe_wanted@yahoo.fr</a>
+ * @version $Id: $
+ */
+public abstract class AbstractProxyLogicHandler implements ProxyLogicHandler {
+
+    private final static Logger logger = LoggerFactory
+            .getLogger(AbstractProxyLogicHandler.class);
+
+    /**
+     * Object that contains all the proxy authentication session informations.
+     */
+    private ProxyIoSession proxyIoSession;
+
+    /**
+     * Queue of write events which occurred before the proxy handshake had completed.
+     */
+    private Queue<Event> writeRequestQueue = null;
+
+    /**
+     * Has the handshake been completed.
+     */
+    private boolean handshakeComplete = false;
+
+    /**
+     * Creates a new {@link AbstractProxyLogicHandler}.
+     * 
+     * @param proxyIoSession	 {@link ProxyIoSession} in use.
+     */
+    public AbstractProxyLogicHandler(ProxyIoSession proxyIoSession) {
+        this.proxyIoSession = proxyIoSession;
+    }
+
+    /**
+     * Returns the proxyFilter {@link ProxyFilter}.
+     */
+    protected ProxyFilter getProxyFilter() {
+        return proxyIoSession.getProxyFilter();
+    }
+
+    /**
+     * Returns the session.
+     */
+    protected IoSession getSession() {
+        return proxyIoSession.getSession();
+    }
+
+    /**
+     * Returns the {@link ProxyIoSession} object.
+     */
+    public ProxyIoSession getProxyIoSession() {
+        return proxyIoSession;
+    }
+
+    public void setProxySession(ProxyIoSession proxyIoSession) {
+        this.proxyIoSession = proxyIoSession;
+    }
+
+    /**
+     * Write data to the proxy server.
+     * 
+     * @param nextFilter	Downstream filter to receive data.
+     * @param data			Data buffer to be written.
+     */
+    protected WriteFuture writeData(final NextFilter nextFilter,
+            final IoBuffer data) throws UnsupportedEncodingException {
+        // write net data
+        ProxyHandshakeIoBuffer writeBuffer = new ProxyHandshakeIoBuffer(data);
+
+        logger.debug("   session write: {}", writeBuffer);
+
+        WriteFuture writeFuture = new DefaultWriteFuture(getSession());
+        getProxyFilter().writeData(nextFilter, getSession(),
+                new DefaultWriteRequest(writeBuffer, writeFuture), true);
+
+        return writeFuture;
+    }
+
+    /**
+     * Returns <code>true</code> if handshaking is complete and
+     * data can be sent through the proxy.
+     */
+    public boolean isHandshakeComplete() {
+        synchronized (this) {
+            return handshakeComplete;
+        }
+    }
+
+    /**
+     * Signals that the shake has finished.
+     */
+    protected final void setHandshakeComplete() {
+        synchronized (this) {
+            handshakeComplete = true;
+        }
+
+        ProxyIoSession proxyIoSession = getProxyIoSession();
+        proxyIoSession.getConnector()
+                .fireConnected(proxyIoSession.getSession())
+                .awaitUninterruptibly();
+
+        logger.debug("  handshake completed");
+
+        // Connected OK
+        try {
+            proxyIoSession.getEventQueue().flushPendingSessionEvents();
+            flushPendingWriteRequests();
+        } catch (Exception ex) {
+            logger.error("Unable to flush pending write requests", ex);
+        }
+    }
+
+    /**
+     * Send any write requests which were queued whilst waiting for handshaking to complete.
+     */
+    protected synchronized void flushPendingWriteRequests() throws Exception {
+        logger.debug(" flushPendingWriteRequests()");
+
+        if (writeRequestQueue == null) {
+            return;
+        }
+
+        Event scheduledWrite;
+        while ((scheduledWrite = writeRequestQueue.poll()) != null) {
+            logger.debug(" Flushing buffered write request: {}",
+                    scheduledWrite.data);
+
+            getProxyFilter().filterWrite(scheduledWrite.nextFilter,
+                    getSession(), (WriteRequest) scheduledWrite.data);
+        }
+
+        // Free queue
+        writeRequestQueue = null;
+    }
+
+    /**
+     * Enqueue a message to be written once handshaking is complete.
+     */
+    public synchronized void enqueueWriteRequest(final NextFilter nextFilter,
+            final WriteRequest writeRequest) {
+        if (writeRequestQueue == null) {
+            writeRequestQueue = new LinkedList<Event>();
+        }
+
+        writeRequestQueue.offer(new Event(nextFilter, writeRequest));
+    }
+
+    /**
+     * Close the session.
+     */
+    protected void closeSession(final String message, final Throwable t) {
+        if (t != null) {
+            logger.error(message, t);
+            proxyIoSession.setAuthenticationFailed(true);
+        } else {
+            logger.error(message);
+        }
+
+        getSession().close();
+    }
+
+    protected void closeSession(final String message) {
+        closeSession(message, null);
+    }
+
+    /**
+     * Event wrapper class for enqueued events.
+     */
+    private final static class Event {
+        private final NextFilter nextFilter;
+
+        private final Object data;
+
+        Event(final NextFilter nextFilter, final Object data) {
+            this.nextFilter = nextFilter;
+            this.data = data;
+        }
+
+        public Object getData() {
+            return data;
+        }
+
+        public NextFilter getNextFilter() {
+            return nextFilter;
+        }
+    }
+}
\ No newline at end of file

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/AbstractProxyLogicHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/AbstractProxyLogicHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyAuthException.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyAuthException.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyAuthException.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyAuthException.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,41 @@
+/*
+ *  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.proxy;
+
+import javax.security.sasl.SaslException;
+
+/**
+ * ProxyAuthException.java - This class extends {@link SaslException} and represents an
+ * authentication failure to the proxy.
+ * 
+ * @author Edouard De Oliveira <a href="mailto:doe_wanted@yahoo.fr">doe_wanted@yahoo.fr</a>
+ * @version $Id: $
+ */
+public class ProxyAuthException extends SaslException {
+    private static final long serialVersionUID = -6511596809517532988L;
+
+    public ProxyAuthException(String message) {
+        super(message);
+    }
+
+    public ProxyAuthException(String message, Throwable ex) {
+        super(message, ex);
+    }
+}
\ No newline at end of file

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyAuthException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyAuthException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyConnector.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyConnector.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyConnector.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyConnector.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,234 @@
+/*
+ *  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.proxy;
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.concurrent.Executor;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.file.FileRegion;
+import org.apache.mina.core.filterchain.IoFilter;
+import org.apache.mina.core.future.ConnectFuture;
+import org.apache.mina.core.future.DefaultConnectFuture;
+import org.apache.mina.core.future.IoFuture;
+import org.apache.mina.core.service.AbstractIoConnector;
+import org.apache.mina.core.service.DefaultTransportMetadata;
+import org.apache.mina.core.service.IoHandler;
+import org.apache.mina.core.service.TransportMetadata;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.core.session.IoSessionConfig;
+import org.apache.mina.core.session.IoSessionInitializer;
+import org.apache.mina.proxy.filter.ProxyFilter;
+import org.apache.mina.proxy.handlers.socks.SocksProxyRequest;
+import org.apache.mina.proxy.session.ProxyIoSession;
+import org.apache.mina.proxy.session.ProxyIoSessionInitializer;
+import org.apache.mina.transport.socket.DefaultSocketSessionConfig;
+import org.apache.mina.transport.socket.SocketConnector;
+import org.apache.mina.transport.socket.SocketSessionConfig;
+
+/**
+ * ProxyConnector.java - Decorator for {@link SocketConnector} to provide proxy support, as suggested by MINA list discussions.
+ * <p>
+ * Operates by intercepting connect requests and replacing the endpoint address with the proxy address,
+ * then adding a {@link ProxyFilter} as the first {@link IoFilter} which performs any necessary
+ * handshaking with the proxy before allowing data to flow normally. During the handshake, any outgoing
+ * write requests are buffered.
+ * 
+ * @see		http://www.nabble.com/Meta-Transport%3A-an-idea-on-implementing-reconnection-and-proxy-td12969001.html
+ * @see		http://issues.apache.org/jira/browse/DIRMINA-415
+ * 
+ * @author Edouard De Oliveira <a href="mailto:doe_wanted@yahoo.fr">doe_wanted@yahoo.fr</a>
+ * @author	James Furness <a href="mailto:james.furness@lehman.com">james.furness@lehman.com</a>  
+ * @version	$Id: $
+ */
+public class ProxyConnector extends AbstractIoConnector {
+    static final TransportMetadata METADATA = new DefaultTransportMetadata(
+            "proxy", "proxyconnector", false, true, InetSocketAddress.class,
+            SocketSessionConfig.class, IoBuffer.class, FileRegion.class);
+
+    /**
+     * Wrapped connector to use for outgoing TCP connections.
+     */
+    private SocketConnector connector = null;
+
+    /**
+     * Proxy filter instance.
+     */
+    private final ProxyFilter proxyFilter = new ProxyFilter();
+
+    /**
+     * The {@link ProxyIoSession} in use.
+     */
+    private ProxyIoSession proxyIoSession;
+
+    /**
+     * This future will notify it's listeners when really connected to the target
+     */
+    private DefaultConnectFuture future;
+
+    /**
+     * Creates a new proxy connector.
+     */
+    public ProxyConnector() {
+        super(new DefaultSocketSessionConfig(), null);
+    }
+
+    /**
+     * Creates a new proxy connector.
+     * 
+     * @param connector         Connector used to establish proxy connections.
+     */
+    public ProxyConnector(final SocketConnector connector) {        
+        this(connector, new DefaultSocketSessionConfig(), null);
+    }
+
+    /**
+     * Creates a new proxy connector. 
+     * @see AbstractIoConnector(IoSessionConfig, Executor).
+     */
+    public ProxyConnector(final SocketConnector connector, IoSessionConfig config, Executor executor) {
+        super(config, executor);
+        setConnector(connector);
+    }    
+        
+    @Override
+    public IoSessionConfig getSessionConfig() {
+        return connector.getSessionConfig();
+    }
+
+    public ProxyIoSession getProxyIoSession() {
+        return proxyIoSession;
+    }
+
+    public void setProxyIoSession(ProxyIoSession proxyIoSession) {
+        if (proxyIoSession == null) {
+            throw new NullPointerException("proxySession cannot be null");
+        }
+
+        if (proxyIoSession.getProxyAddress() == null) {
+            throw new NullPointerException(
+                    "proxySession.proxyAddress cannot be null");
+        }
+
+        proxyIoSession.setConnector(this);
+        setDefaultRemoteAddress(proxyIoSession.getProxyAddress());
+        this.proxyIoSession = proxyIoSession;
+    }
+
+    /**
+     * Connects to the specified <code>address</code>.  If communication starts
+     * successfully, events are fired to the specified
+     * <code>handler</code>.
+     * 
+     * @return {@link ConnectFuture} that will tell the result of the connection attempt
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    protected ConnectFuture connect0(
+            final SocketAddress remoteAddress,
+            final SocketAddress localAddress,
+            final IoSessionInitializer<? extends ConnectFuture> sessionInitializer) {
+        if (!proxyIoSession.isReconnectionNeeded()) {
+            // First connection
+            IoHandler handler = getHandler();
+            if (!(handler instanceof AbstractProxyIoHandler)) {
+                throw new IllegalArgumentException(
+                        "IoHandler must be an instance of AbstractProxyIoHandler");
+            }
+
+            connector.setHandler(handler);
+            future = new DefaultConnectFuture();
+        }
+
+        ConnectFuture conFuture = connector.connect(proxyIoSession
+                .getProxyAddress(), new ProxyIoSessionInitializer(
+                sessionInitializer, proxyIoSession));
+
+        if (proxyIoSession.getRequest() instanceof SocksProxyRequest
+                || proxyIoSession.isReconnectionNeeded()) {
+            return conFuture;
+        } else {
+            return future;
+        }
+    }
+
+    public void cancelConnectFuture() {
+        future.cancel();
+    }
+
+    protected ConnectFuture fireConnected(final IoSession session) {
+        future.setSession(session);
+        return future;
+    }
+
+    /**
+     * Get the {@link SocketConnector} to be used for connections
+     * to the proxy server.
+     */
+    public final SocketConnector getConnector() {
+        return connector;
+    }
+
+    /**
+     * Set the {@link SocketConnector} to be used for connections
+     * to the proxy server.
+     */
+    public final void setConnector(final SocketConnector newConnector) {
+        if (newConnector == null) {
+            throw new NullPointerException("connector cannot be null");
+        }
+
+        SocketConnector oldConnector = this.connector;
+
+        // Remove the ProxyFilter from the old filter chain builder
+        if (oldConnector != null) {
+            oldConnector.getFilterChain().remove(ProxyFilter.class.getName());
+        }
+
+        this.connector = newConnector;
+
+        // Insert the ProxyFilter as the first filter in the filter chain builder
+        if (newConnector.getFilterChain().contains(ProxyFilter.class.getName())) {
+            newConnector.getFilterChain().remove(ProxyFilter.class.getName());
+        }
+
+        newConnector.getFilterChain().addFirst(ProxyFilter.class.getName(),
+                proxyFilter);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.mina.common.AbstractIoService#dispose0()
+     */
+    @Override
+    protected IoFuture dispose0() throws Exception {
+        if (connector != null) {
+            connector.dispose();
+        }
+        return null;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.mina.common.IoService#getTransportMetadata()
+     */
+    public TransportMetadata getTransportMetadata() {
+        return METADATA;
+    }
+}
\ No newline at end of file

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyConnector.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyConnector.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyLogicHandler.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyLogicHandler.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyLogicHandler.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyLogicHandler.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,64 @@
+/*
+ *  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.proxy;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.filterchain.IoFilter.NextFilter;
+import org.apache.mina.core.write.WriteRequest;
+import org.apache.mina.proxy.session.ProxyIoSession;
+
+/**
+ * ProxyLogicHandler.java - Interface implemented by classes containing proxy type specific logic.
+ * 
+ * @author James Furness <a href="mailto:james.furness@lehman.com">james.furness@lehman.com</a>
+ * @author Edouard De Oliveira <a href="mailto:doe_wanted@yahoo.fr">doe_wanted@yahoo.fr</a>
+ * @version $Id: $
+ */
+public interface ProxyLogicHandler {
+    /**
+     * Returns <code>true</code> if handshaking is complete and
+     * data can be sent through the proxy.
+     */
+    public abstract boolean isHandshakeComplete();
+
+    /**
+     * Handle incoming data during the handshake process. Should consume only the
+     * handshake data from the buffer, leaving any extra data in place.
+     */
+    public abstract void messageReceived(NextFilter nextFilter, IoBuffer buf)
+            throws ProxyAuthException;
+
+    /**
+     * Called at each step of the handshake procedure.
+     */
+    public abstract void doHandshake(NextFilter nextFilter)
+            throws ProxyAuthException;
+
+    /**
+     * Returns the {@link ProxyIoSession}.
+     */
+    public abstract ProxyIoSession getProxyIoSession();
+
+    /**
+     * Enqueue a message to be written once handshaking is complete.
+     */
+    public abstract void enqueueWriteRequest(final NextFilter nextFilter,
+            final WriteRequest writeRequest);
+}
\ No newline at end of file

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyLogicHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/ProxyLogicHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEvent.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEvent.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEvent.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEvent.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,108 @@
+/*
+ *  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.proxy.event;
+
+import org.apache.mina.core.filterchain.IoFilter.NextFilter;
+import org.apache.mina.core.session.IdleStatus;
+import org.apache.mina.core.session.IoSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * IoSessionEvent.java - Wrapper Class for enqueued events.
+ * 
+ * @author Edouard De Oliveira <a href="mailto:doe_wanted@yahoo.fr">doe_wanted@yahoo.fr</a>
+ * @version $Id: $
+ */
+public class IoSessionEvent {
+    private final static Logger logger = LoggerFactory
+            .getLogger(IoSessionEvent.class);
+
+    private final NextFilter nextFilter;
+
+    private final IoSession session;
+
+    private final IoSessionEventType type;
+
+    private IdleStatus status = null;
+
+    public IoSessionEvent(final NextFilter nextFilter, final IoSession session,
+            final IoSessionEventType type) {
+        this.nextFilter = nextFilter;
+        this.session = session;
+        this.type = type;
+    }
+
+    public void deliverEvent() {
+        logger.debug("Delivering event {}", this);
+        deliverEvent(this.nextFilter, this.session, this.type, this.status);
+    }
+
+    private static void deliverEvent(final NextFilter nextFilter,
+            final IoSession session, final IoSessionEventType type,
+            final IdleStatus status) {
+        switch (type) {
+        case CREATED:
+            nextFilter.sessionCreated(session);
+            break;
+        case OPENED:
+            nextFilter.sessionOpened(session);
+            break;
+        case IDLE:
+            nextFilter.sessionIdle(session, status);
+            break;
+        case CLOSED:
+            nextFilter.sessionClosed(session);
+            break;
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(IoSessionEvent.class
+                .getSimpleName());
+        sb.append('@');
+        sb.append(Integer.toHexString(hashCode()));
+        sb.append(" - [ ").append(session);
+        sb.append(", ").append(type);
+        sb.append(']');
+        return sb.toString();
+    }
+
+    public IdleStatus getStatus() {
+        return status;
+    }
+
+    public void setStatus(IdleStatus status) {
+        this.status = status;
+    }
+
+    public NextFilter getNextFilter() {
+        return nextFilter;
+    }
+
+    public IoSession getSession() {
+        return session;
+    }
+
+    public IoSessionEventType getType() {
+        return type;
+    }
+}
\ No newline at end of file

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEvent.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEvent.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEventQueue.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEventQueue.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEventQueue.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEventQueue.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,127 @@
+/*
+ *  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.proxy.event;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+import org.apache.mina.proxy.handlers.socks.SocksProxyRequest;
+import org.apache.mina.proxy.session.ProxyIoSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * IoSessionEventQueue.java - Queue that contains filtered session events while handshake isn't done.
+ * 
+ * @author Edouard De Oliveira <a href="mailto:doe_wanted@yahoo.fr">doe_wanted@yahoo.fr</a>
+ * @version $Id: $
+ */
+public class IoSessionEventQueue {
+    private final static Logger logger = LoggerFactory
+            .getLogger(IoSessionEventQueue.class);
+
+    private ProxyIoSession proxyIoSession;
+
+    /**
+     * Queue of session events which occurred before the proxy handshake had completed.
+     */
+    private Queue<IoSessionEvent> sessionEventsQueue = null;
+
+    public IoSessionEventQueue(ProxyIoSession proxyIoSession) {
+        this.proxyIoSession = proxyIoSession;
+    }
+
+    private void freeSessionQueue() {
+        logger.debug("Event queue CLEARED");
+
+        // Free queue
+        sessionEventsQueue = null;
+    }
+
+    /**
+     * Event is enqueued only if necessary.
+     */
+    public synchronized void enqueueEventIfNecessary(final IoSessionEvent evt) {
+        logger.debug("??? >> Enqueue {}", evt);
+
+        if (proxyIoSession.getRequest() instanceof SocksProxyRequest) {
+            // No reconnection used
+            evt.deliverEvent();
+            return;
+        }
+
+        if (proxyIoSession.getHandler().isHandshakeComplete()) {
+            evt.deliverEvent();
+        } else {
+            if (evt.getType() == IoSessionEventType.CLOSED) {
+                if (proxyIoSession.isAuthenticationFailed()) {
+                    proxyIoSession.getConnector().cancelConnectFuture();
+                    freeSessionQueue();
+                    evt.deliverEvent();
+                } else {
+                    freeSessionQueue();
+                }
+            } else if (evt.getType() == IoSessionEventType.OPENED) {
+                // Enqueue event cause it will not reach IoHandler but deliver it to enable session creation.
+                enqueueSessionEvent(evt);
+                evt.deliverEvent();
+            } else {
+                enqueueSessionEvent(evt);
+            }
+        }
+    }
+
+    /**
+     * Send any session event which were queued whilst waiting for handshaking to complete.
+     * 
+     * Please note this is an internal method. DO NOT USE it in your code.
+     */
+    public synchronized void flushPendingSessionEvents() throws Exception {
+        IoSessionEvent evt;
+
+        logger.debug(" flushPendingSessionEvents()");
+
+        if (sessionEventsQueue == null) {
+            return;
+        }
+
+        while ((evt = sessionEventsQueue.poll()) != null) {
+            logger.debug(" Flushing buffered event: {}", evt);
+
+            evt.deliverEvent();
+        }
+
+        // Free queue
+        sessionEventsQueue = null;
+    }
+
+    /**
+     * Enqueue an event to be delivered once handshaking is complete.
+     */
+    private void enqueueSessionEvent(final IoSessionEvent evt) {
+        if (sessionEventsQueue == null) {
+            sessionEventsQueue = new LinkedList<IoSessionEvent>();
+        }
+
+        logger.debug("Enqueuing event: {}", evt);
+
+        sessionEventsQueue.offer(evt);
+    }
+}
\ No newline at end of file

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEventQueue.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEventQueue.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEventType.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEventType.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEventType.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEventType.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,56 @@
+/*
+ *  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.proxy.event;
+
+/**
+ * IoSessionEventType.java - Enumerates session event types.
+ * 
+ * @author Edouard De Oliveira <a href="mailto:doe_wanted@yahoo.fr">doe_wanted@yahoo.fr</a>
+ * @version $Id: $
+ */
+public enum IoSessionEventType {
+    CREATED(1), OPENED(2), IDLE(3), CLOSED(4);
+
+    private final int id;
+    
+    private IoSessionEventType(int id) {
+    	this.id = id;
+    }
+    
+    public int getId() {
+		return id;
+	}
+
+	@Override
+    public String toString() {
+        switch (this) {
+        case CREATED:
+            return "- CREATED event -";
+        case OPENED:
+            return "- OPENED event -";
+        case IDLE:
+            return "- IDLE event -";
+        case CLOSED:
+            return "- CLOSED event -";
+        default:
+            return "- Event Id="+id+" -";
+        }
+    }
+}
\ No newline at end of file

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEventType.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/event/IoSessionEventType.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/filter/ProxyFilter.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/filter/ProxyFilter.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/filter/ProxyFilter.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/filter/ProxyFilter.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,285 @@
+/*
+ *  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.proxy.filter;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.filterchain.IoFilter;
+import org.apache.mina.core.filterchain.IoFilterAdapter;
+import org.apache.mina.core.filterchain.IoFilterChain;
+import org.apache.mina.core.session.IdleStatus;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.core.write.WriteRequest;
+import org.apache.mina.proxy.ProxyAuthException;
+import org.apache.mina.proxy.ProxyConnector;
+import org.apache.mina.proxy.ProxyLogicHandler;
+import org.apache.mina.proxy.event.IoSessionEvent;
+import org.apache.mina.proxy.event.IoSessionEventType;
+import org.apache.mina.proxy.handlers.ProxyRequest;
+import org.apache.mina.proxy.handlers.http.HttpSmartProxyHandler;
+import org.apache.mina.proxy.handlers.socks.Socks4LogicHandler;
+import org.apache.mina.proxy.handlers.socks.Socks5LogicHandler;
+import org.apache.mina.proxy.handlers.socks.SocksProxyConstants;
+import org.apache.mina.proxy.handlers.socks.SocksProxyRequest;
+import org.apache.mina.proxy.session.ProxyIoSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ProxyFilter.java - Proxy {@link IoFilter}. Automatically inserted into the {@link IoFilter} chain by {@link ProxyConnector}.
+ * Sends the initial handshake message to the proxy and handles any response
+ * to the handshake. Once the handshake has completed and the proxied connection has been
+ * established this filter becomes transparent to data flowing through the connection.
+ * <p>
+ * Based upon SSLFilter from mina-filter-ssl.
+ * 
+ * @author Edouard De Oliveira <a href="mailto:doe_wanted@yahoo.fr">doe_wanted@yahoo.fr</a>
+ * @author James Furness <a href="mailto:james.furness@lehman.com">james.furness@lehman.com</a> 
+ * @version $Id: $
+ */
+public class ProxyFilter extends IoFilterAdapter {
+    private final static Logger logger = LoggerFactory
+            .getLogger(ProxyFilter.class);
+
+    /**
+     * Create a new {@link ProxyFilter}.
+     */
+    public ProxyFilter() {
+    }
+
+    /**
+     * Called before the filter is added into the filter chain, creates the {@link ProxyLogicHandler} instance
+     * which will handle this session.
+     */
+    @Override
+    public void onPreAdd(final IoFilterChain chain, final String name,
+            final NextFilter nextFilter) {
+        if (chain.contains(ProxyFilter.class)) {
+            throw new IllegalStateException(
+                    "A filter chain cannot contain more than one ProxyFilter.");
+        }
+    }
+
+    /**
+     * Called when the filter is removed from the filter chain - cleans up the {@link ProxyIoSession} instance.
+     */
+    @Override
+    public void onPreRemove(final IoFilterChain chain, final String name,
+            final NextFilter nextFilter) {
+        IoSession session = chain.getSession();
+        session.removeAttribute(ProxyIoSession.PROXY_SESSION);
+    }
+
+    @Override
+    public void exceptionCaught(NextFilter nextFilter, IoSession session,
+            Throwable cause) throws Exception {
+        ProxyIoSession proxyIoSession = (ProxyIoSession) session
+                .getAttribute(ProxyIoSession.PROXY_SESSION);
+        proxyIoSession.setAuthenticationFailed(true);
+        super.exceptionCaught(nextFilter, session, cause);
+    }
+
+    /**
+     * Get the {@link ProxyLogicHandler} for a given session.
+     */
+    private ProxyLogicHandler getProxyHandler(final IoSession session) {
+        ProxyLogicHandler handler = ((ProxyIoSession) session
+                .getAttribute(ProxyIoSession.PROXY_SESSION)).getHandler();
+
+        if (handler == null) {
+            throw new IllegalStateException();
+        }
+
+        if (handler.getProxyIoSession().getProxyFilter() != this) {
+            throw new IllegalArgumentException("Not managed by this filter.");
+        }
+
+        return handler;
+    }
+
+    /**
+     * Receives data from the remote host, passes to the handler if a handshake is in progress, otherwise
+     * passes on transparently.
+     */
+    @Override
+    public void messageReceived(final NextFilter nextFilter,
+            final IoSession session, final Object message)
+            throws ProxyAuthException {
+        ProxyLogicHandler handler = getProxyHandler(session);
+
+        synchronized (handler) {
+            IoBuffer buf = (IoBuffer) message;
+
+            if (handler.isHandshakeComplete()) {
+                // Handshake done - pass data on as-is
+                nextFilter.messageReceived(session, buf);
+
+            } else {
+                logger.debug(" Data Read: {} ({})", handler, buf);
+
+                // Keep sending handshake data to the handler until we run out
+                // of data or the handshake is finished
+                while (buf.hasRemaining() && !handler.isHandshakeComplete()) {
+                    logger.debug(" Pre-handshake - passing to handler");
+
+                    int pos = buf.position();
+                    handler.messageReceived(nextFilter, buf);
+
+                    // Data not consumed or session closing
+                    if (buf.position() == pos || session.isClosing()) {
+                        return;
+                    }
+                }
+
+                // Pass on any remaining data to the next filter
+                if (buf.hasRemaining()) {
+                    logger.debug(" Passing remaining data to next filter");
+
+                    nextFilter.messageReceived(session, buf);
+                }
+            }
+        }
+    }
+
+    /**
+     * Filters outgoing writes, queueing them up if necessary whilst a handshake is ongoing.
+     */
+    @Override
+    public void filterWrite(final NextFilter nextFilter,
+            final IoSession session, final WriteRequest writeRequest) {
+        writeData(nextFilter, session, writeRequest, false);
+    }
+
+    /**
+     * Actually write data. Queues the data up unless it relates to the handshake or the handshake is done.
+     */
+    public void writeData(final NextFilter nextFilter, final IoSession session,
+            final WriteRequest writeRequest, final boolean isHandshakeData) {
+        ProxyLogicHandler handler = getProxyHandler(session);
+
+        synchronized (handler) {
+            if (handler.isHandshakeComplete()) {
+                // Handshake is done - write data as normal
+                nextFilter.filterWrite(session, writeRequest);
+            } else if (isHandshakeData) {
+                IoBuffer buf = (IoBuffer) writeRequest.getMessage();
+
+                // Writing handshake data - write
+                logger.debug("   handshake data: {}", buf);
+
+                nextFilter.filterWrite(session, writeRequest);
+            } else {
+                // Writing non-handshake data before the handshake finished
+                if (!session.isConnected()) {
+                    // Not even connected - ignore
+                    logger
+                            .debug(" Write request on closed session. Request ignored.");
+                } else {
+                    // Queue the data to be sent as soon as the handshake completes
+                    logger
+                            .debug(" Handshaking is not complete yet. Buffering write request.");
+
+                    handler.enqueueWriteRequest(nextFilter, writeRequest);
+                }
+            }
+        }
+    }
+
+    /**
+     * Filter handshake-related messages from reaching the messageSent callbacks of downstream filters.
+     */
+    @Override
+    public void messageSent(final NextFilter nextFilter,
+            final IoSession session, final WriteRequest writeRequest)
+            throws Exception {
+        if (writeRequest.getMessage() != null
+                && writeRequest.getMessage() instanceof ProxyHandshakeIoBuffer) {
+            // Ignore buffers used in handshaking
+            return;
+        }
+
+        nextFilter.messageSent(session, writeRequest);
+    }
+
+    @Override
+    public void sessionCreated(NextFilter nextFilter, IoSession session)
+            throws Exception {
+        logger.debug("Session created: " + session);
+        ProxyIoSession proxyIoSession = (ProxyIoSession) session
+                .getAttribute(ProxyIoSession.PROXY_SESSION);
+        logger.debug("  get proxyIoSession: " + proxyIoSession);
+        proxyIoSession.setProxyFilter(this);
+
+        // Create a HTTP proxy handler and start handshake.		
+        ProxyLogicHandler handler = proxyIoSession.getHandler();
+
+        if (handler == null) {
+            ProxyRequest request = proxyIoSession.getRequest();
+
+            if (request instanceof SocksProxyRequest) {
+                SocksProxyRequest req = (SocksProxyRequest) request;
+                if (req.getProtocolVersion() == SocksProxyConstants.SOCKS_VERSION_4) {
+                    handler = new Socks4LogicHandler(proxyIoSession);
+                } else {
+                    handler = new Socks5LogicHandler(proxyIoSession);
+                }
+            } else {
+                handler = new HttpSmartProxyHandler(proxyIoSession);
+            }
+
+            proxyIoSession.setHandler(handler);
+            handler.doHandshake(nextFilter);
+        }
+
+        proxyIoSession.getEventQueue().enqueueEventIfNecessary(
+                new IoSessionEvent(nextFilter, session,
+                        IoSessionEventType.CREATED));
+    }
+
+    @Override
+    public void sessionOpened(NextFilter nextFilter, IoSession session)
+            throws Exception {
+        ProxyIoSession proxyIoSession = (ProxyIoSession) session
+                .getAttribute(ProxyIoSession.PROXY_SESSION);
+        proxyIoSession.getEventQueue().enqueueEventIfNecessary(
+                new IoSessionEvent(nextFilter, session,
+                        IoSessionEventType.OPENED));
+    }
+
+    @Override
+    public void sessionIdle(NextFilter nextFilter, IoSession session,
+            IdleStatus status) throws Exception {
+        ProxyIoSession proxyIoSession = (ProxyIoSession) session
+                .getAttribute(ProxyIoSession.PROXY_SESSION);
+        IoSessionEvent evt = new IoSessionEvent(nextFilter, session,
+                IoSessionEventType.IDLE);
+        evt.setStatus(status);
+        proxyIoSession.getEventQueue().enqueueEventIfNecessary(evt);
+    }
+
+    @Override
+    public void sessionClosed(NextFilter nextFilter, IoSession session)
+            throws Exception {
+        ProxyIoSession proxyIoSession = (ProxyIoSession) session
+                .getAttribute(ProxyIoSession.PROXY_SESSION);
+        proxyIoSession.getEventQueue().enqueueEventIfNecessary(
+                new IoSessionEvent(nextFilter, session,
+                        IoSessionEventType.CLOSED));
+    }
+}
\ No newline at end of file

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/filter/ProxyFilter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/filter/ProxyFilter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/filter/ProxyHandshakeIoBuffer.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/filter/ProxyHandshakeIoBuffer.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/filter/ProxyHandshakeIoBuffer.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/filter/ProxyHandshakeIoBuffer.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,36 @@
+/*
+ *  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.proxy.filter;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.buffer.IoBufferWrapper;
+
+/**
+ * ProxyHandshakeIoBuffer.java - {@link IoBuffer} wrapper to indicate handshake 
+ * related messages which should not be passed upstream of the {@link ProxyFilter}.
+ * 
+ * @author James Furness <a href="mailto:james.furness@lehman.com">james.furness@lehman.com</a>
+ * @version $Id: $
+ */
+public class ProxyHandshakeIoBuffer extends IoBufferWrapper {
+    public ProxyHandshakeIoBuffer(final IoBuffer buf) {
+        super(buf);
+    }
+}
\ No newline at end of file

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/filter/ProxyHandshakeIoBuffer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/filter/ProxyHandshakeIoBuffer.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/ProxyRequest.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/ProxyRequest.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/ProxyRequest.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/ProxyRequest.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,54 @@
+/*
+ *  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.proxy.handlers;
+
+import java.net.InetSocketAddress;
+
+/**
+ * ProxyRequest.java - Wrapper class for proxy requests.
+ * 
+ * @author Edouard De Oliveira <a href="mailto:doe_wanted@yahoo.fr">doe_wanted@yahoo.fr</a>
+ * @version $Id: $
+ */
+public abstract class ProxyRequest {
+
+    private InetSocketAddress endpointAddress = null;
+
+    public ProxyRequest() {
+    }
+
+    public ProxyRequest(final InetSocketAddress endpointAddress) {
+        this.endpointAddress = endpointAddress;
+    }
+
+    /**
+     * The request endpoint.
+     */
+    public InetSocketAddress getEndpointAddress() {
+        return endpointAddress;
+    }
+
+    /**
+     * Sets the request endpoint.
+     */
+    public void setEndpointAddress(InetSocketAddress endpointAddress) {
+        this.endpointAddress = endpointAddress;
+    }
+}
\ No newline at end of file

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/ProxyRequest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/ProxyRequest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/AbstractAuthLogicHandler.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/AbstractAuthLogicHandler.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/AbstractAuthLogicHandler.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/AbstractAuthLogicHandler.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,81 @@
+/*
+ *  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.proxy.handlers.http;
+
+import org.apache.mina.core.filterchain.IoFilter.NextFilter;
+import org.apache.mina.proxy.ProxyAuthException;
+import org.apache.mina.proxy.handlers.ProxyRequest;
+import org.apache.mina.proxy.session.ProxyIoSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * AbstractAuthLogicHandler.java - Abstract class that handles an authentication mechanism logic.
+ * 
+ * @author Edouard De Oliveira <a href="mailto:doe_wanted@yahoo.fr">doe_wanted@yahoo.fr</a>
+ * @version $Id: $
+ */
+public abstract class AbstractAuthLogicHandler {
+    private final static Logger logger = LoggerFactory
+            .getLogger(AbstractAuthLogicHandler.class);
+
+    /**
+     * The request the proxy has to handle.
+     */
+    protected ProxyRequest request;
+
+    /**
+     * Object that contains all the proxy authentication session informations.
+     */
+    protected ProxyIoSession proxyIoSession;
+
+    /**
+     * The current step in the handshake.
+     */
+    protected int step = 0;
+
+    protected AbstractAuthLogicHandler(final ProxyIoSession proxyIoSession)
+            throws ProxyAuthException {
+        this.proxyIoSession = proxyIoSession;
+        this.request = proxyIoSession.getRequest();
+    }
+
+    /**
+     * Called on each step of the handshaking process.
+     */
+    public abstract void doHandshake(final NextFilter nextFilter)
+            throws ProxyAuthException;
+
+    /**
+     * Handles a HTTP response from the proxy server.
+     * 
+     * @param response The response.
+     */
+    public abstract void handleResponse(final HttpProxyResponse response)
+            throws ProxyAuthException;
+
+    protected void writeRequest(final NextFilter nextFilter,
+            final HttpProxyRequest request) throws ProxyAuthException {
+        logger.debug("  sending HTTP request");
+
+        ((AbstractHttpLogicHandler) proxyIoSession.getHandler()).writeRequest(
+                nextFilter, request);
+    }
+}
\ No newline at end of file

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/AbstractAuthLogicHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/AbstractAuthLogicHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/AbstractHttpLogicHandler.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/AbstractHttpLogicHandler.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/AbstractHttpLogicHandler.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/AbstractHttpLogicHandler.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,405 @@
+/*
+ *  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.proxy.handlers.http;
+
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.filterchain.IoFilter.NextFilter;
+import org.apache.mina.core.future.ConnectFuture;
+import org.apache.mina.core.future.IoFutureListener;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.core.session.IoSessionInitializer;
+import org.apache.mina.proxy.AbstractProxyLogicHandler;
+import org.apache.mina.proxy.ProxyAuthException;
+import org.apache.mina.proxy.ProxyConnector;
+import org.apache.mina.proxy.session.ProxyIoSession;
+import org.apache.mina.proxy.utils.IoBufferDecoder;
+import org.apache.mina.proxy.utils.StringUtilities;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * AbstractHttpLogicHandler.java - Base class for HTTP proxy {@link AbstractProxyLogicHandler} implementations. 
+ * Provides HTTP request encoding/response decoding functionality.
+ * 
+ * @author Edouard De Oliveira <a href="mailto:doe_wanted@yahoo.fr">doe_wanted@yahoo.fr</a>
+ * @version $Id: $
+ */
+public abstract class AbstractHttpLogicHandler extends
+        AbstractProxyLogicHandler {
+    private final static Logger logger = LoggerFactory
+            .getLogger(AbstractHttpLogicHandler.class);
+
+    private final static String DECODER = AbstractHttpLogicHandler.class
+            .getName()
+            + ".Decoder";
+
+    private final static byte[] HTTP_DELIMITER = new byte[] { '\r', '\n', '\r',
+            '\n' };
+
+    private final static byte[] CRLF_DELIMITER = new byte[] { '\r', '\n' };
+
+    // Parsing vars
+
+    /**
+     * Temporary buffer to accumulate the HTTP response from the proxy.
+     */
+    private IoBuffer responseData = null;
+
+    /**
+     * The parsed http proxy response
+     */
+    private HttpProxyResponse parsedResponse = null;
+
+    /**
+     * The content length of the proxy response.
+     */
+    private int contentLength = -1;
+
+    // HTTP/1.1 vars
+
+    /**
+     * A flag that indicates that this is a HTTP/1.1 response with chunked data.and that some chunks are missing.   
+     */
+    private boolean hasChunkedData;
+
+    /**
+     * A flag that indicates that some chunks of data are missing to complete the HTTP/1.1 response.   
+     */
+    private boolean waitingChunkedData;
+
+    /**
+     * A flag that indicates that chunked data has been read and that we're now reading the footers.   
+     */
+    private boolean waitingFooters;
+
+    /**
+     * Contains the position of the entity body start in the <code>responseData</code> {@link IoBuffer}.
+     */
+    private int entityBodyStartPosition;
+
+    /**
+     * Contains the limit of the entity body start in the <code>responseData</code> {@link IoBuffer}.
+     */
+    private int entityBodyLimitPosition;
+
+    /**
+     * Creates a new {@link AbstractHttpLogicHandler}.
+     * 
+     * @param proxyIoSession	 {@link ProxyIoSession} in use.
+     * @param request the requested url to negotiate with the proxy.
+     */
+    public AbstractHttpLogicHandler(final ProxyIoSession proxyIoSession) {
+        super(proxyIoSession);
+    }
+
+    /**
+     * Handle incoming data during the handshake process. Should consume only the
+     * handshake data from the buffer, leaving any extra data in place.
+     */
+    public synchronized void messageReceived(final NextFilter nextFilter,
+            final IoBuffer buf) throws ProxyAuthException {
+        logger.debug(" messageReceived()");
+
+        IoBufferDecoder decoder = (IoBufferDecoder) getSession().getAttribute(
+                DECODER);
+        if (decoder == null) {
+            decoder = new IoBufferDecoder(HTTP_DELIMITER);
+            getSession().setAttribute(DECODER, decoder);
+        }
+
+        try {
+            if (parsedResponse == null) {
+
+                responseData = decoder.decodeFully(buf);
+                if (responseData == null) {
+                    return;
+                }
+
+                // Handle the response								
+                String responseHeader = responseData
+                        .getString(getProxyIoSession().getCharset()
+                                .newDecoder());
+                entityBodyStartPosition = responseData.position();
+
+                logger.debug("  response header received:\n{}", responseHeader
+                        .replace("\r", "\\r").replace("\n", "\\n\n"));
+
+                // Parse the response
+                parsedResponse = decodeResponse(responseHeader);
+
+                // Is handshake complete ?
+                if (parsedResponse.getStatusCode() == 200
+                        || (parsedResponse.getStatusCode() >= 300 && parsedResponse
+                                .getStatusCode() <= 307)) {
+                    buf.position(0);
+                    setHandshakeComplete();
+                    return;
+                }
+
+                String contentLengthHeader = StringUtilities
+                        .getSingleValuedHeader(parsedResponse.getHeaders(),
+                                "Content-Length");
+
+                if (contentLengthHeader == null) {
+                    contentLength = 0;
+                } else {
+                    contentLength = Integer
+                            .parseInt(contentLengthHeader.trim());
+                    decoder.setContentLength(contentLength, true);
+                }
+            }
+
+            if (!hasChunkedData) {
+                if (contentLength > 0) {
+                    IoBuffer tmp = decoder.decodeFully(buf);
+                    if (tmp == null) {
+                        return;
+                    }
+                    responseData.setAutoExpand(true);
+                    responseData.put(tmp);
+                    contentLength = 0;
+                }
+
+                if ("chunked".equalsIgnoreCase(StringUtilities
+                        .getSingleValuedHeader(parsedResponse.getHeaders(),
+                                "Transfer-Encoding"))) {
+                    // Handle Transfer-Encoding: Chunked
+                    logger.debug("Retrieving additional http response chunks");
+                    hasChunkedData = true;
+                    waitingChunkedData = true;
+                }
+            }
+
+            if (hasChunkedData) {
+                // Read chunks
+                while (waitingChunkedData) {
+                    if (contentLength == 0) {
+                        decoder.setDelimiter(CRLF_DELIMITER, false);
+                        IoBuffer tmp = decoder.decodeFully(buf);
+                        if (tmp == null) {
+                            return;
+                        }
+
+                        String chunkSize = tmp.getString(getProxyIoSession()
+                                .getCharset().newDecoder());
+                        int pos = chunkSize.indexOf(';');
+                        if (pos >= 0) {
+                            chunkSize = chunkSize.substring(0, pos);
+                        } else {
+                            chunkSize = chunkSize.substring(0, chunkSize
+                                    .length() - 2);
+                        }
+                        contentLength = Integer.decode("0x" + chunkSize);
+                        if (contentLength > 0) {
+                            contentLength += 2; // also read chunk's trailing CRLF
+                            decoder.setContentLength(contentLength, true);
+                        }
+                    }
+
+                    if (contentLength == 0) {
+                        waitingChunkedData = false;
+                        waitingFooters = true;
+                        entityBodyLimitPosition = responseData.position();
+                        break;
+                    }
+
+                    IoBuffer tmp = decoder.decodeFully(buf);
+                    if (tmp == null) {
+                        return;
+                    }
+                    contentLength = 0;
+                    responseData.put(tmp);
+                    buf.position(buf.position());
+                }
+
+                // Read footers
+                while (waitingFooters) {
+                    decoder.setDelimiter(CRLF_DELIMITER, false);
+                    IoBuffer tmp = decoder.decodeFully(buf);
+                    if (tmp == null) {
+                        return;
+                    }
+
+                    if (tmp.remaining() == 2) {
+                        waitingFooters = false;
+                        break;
+                    }
+
+                    // add footer to headers					
+                    String footer = tmp.getString(getProxyIoSession()
+                            .getCharset().newDecoder());
+                    String[] f = footer.split(":\\s?", 2);
+                    StringUtilities.addValueToHeader(parsedResponse
+                            .getHeaders(), f[0], f[1], false);
+                    responseData.put(tmp);
+                    responseData.put(CRLF_DELIMITER);
+                }
+            }
+
+            responseData.flip();
+
+            logger.debug("  end of response received:\n{}",
+                    responseData.getString(getProxyIoSession().getCharset()
+                            .newDecoder()));
+
+            // Retrieve entity body content
+            responseData.position(entityBodyStartPosition);
+            responseData.limit(entityBodyLimitPosition);
+            parsedResponse.setBody(responseData.getString(getProxyIoSession()
+                    .getCharset().newDecoder()));
+
+            // Free the response buffer
+            responseData.free();
+            responseData = null;
+
+            handleResponse(parsedResponse);
+
+            parsedResponse = null;
+            hasChunkedData = false;
+            contentLength = -1;
+            decoder.setDelimiter(HTTP_DELIMITER, true);
+
+            if (!isHandshakeComplete()) {
+                doHandshake(nextFilter);
+            }
+        } catch (Exception ex) {
+            if (ex instanceof ProxyAuthException) {
+                throw ((ProxyAuthException) ex);
+            } else {
+                throw new ProxyAuthException("Handshake failed", ex);
+            }
+        }
+    }
+
+    /**
+     * Handle a HTTP response from the proxy server.
+     * 
+     * @param response The response.
+     */
+    public abstract void handleResponse(final HttpProxyResponse response)
+            throws ProxyAuthException;
+
+    /**
+     * Calls{@link #writeRequest0(NextFilter, HttpProxyRequest)} to write the request. 
+     * If needed a reconnection to the proxy is done previously.
+     */
+    public void writeRequest(final NextFilter nextFilter,
+            final HttpProxyRequest request) throws ProxyAuthException {
+        ProxyIoSession proxyIoSession = getProxyIoSession();
+
+        if (proxyIoSession.isReconnectionNeeded()) {
+            reconnect(nextFilter, request);
+        } else {
+            writeRequest0(nextFilter, request);
+        }
+    }
+
+    /**
+     * Encode a HTTP request and send it to the proxy server.
+     */
+    private void writeRequest0(final NextFilter nextFilter,
+            final HttpProxyRequest request) {
+        try {
+            String data = request.toHttpString();
+            IoBuffer buf = IoBuffer.wrap(data.getBytes(getProxyIoSession()
+                    .getCharsetName()));
+
+            logger.debug("   write:\n{}", data.replace("\r", "\\r").replace(
+                    "\n", "\\n\n"));
+
+            writeData(nextFilter, buf);
+
+        } catch (UnsupportedEncodingException ex) {
+            closeSession("Unable to send HTTP request: ", ex);
+        }
+    }
+
+    /**
+     * Method to reconnect to proxy when it decides not to maintain the connection during handshake.
+     * @throws ProxyAuthException 
+     */
+    private void reconnect(final NextFilter nextFilter,
+            final HttpProxyRequest request) throws ProxyAuthException {
+        logger.debug("Reconnecting to proxy ...");
+
+        final ProxyIoSession proxyIoSession = getProxyIoSession();
+        final ProxyConnector connector = proxyIoSession.getConnector();
+
+        connector.connect(new IoSessionInitializer<ConnectFuture>() {
+            public void initializeSession(final IoSession session,
+                    ConnectFuture future) {
+                logger.debug("Initializing new session: " + session);
+                session.setAttribute(ProxyIoSession.PROXY_SESSION,
+                        proxyIoSession);
+                proxyIoSession.setSession(session);
+                logger.debug("  setting proxyIoSession: " + proxyIoSession);
+                future.addListener(new IoFutureListener<ConnectFuture>() {
+                    public void operationComplete(ConnectFuture future) {
+                        proxyIoSession.setReconnectionNeeded(false);
+                        writeRequest0(nextFilter, request);
+                    }
+                });
+            }
+        });
+    }
+
+    /**
+     * Parse a HTTP response from the proxy server.
+     * 
+     * @param response The response string.
+     */
+    protected HttpProxyResponse decodeResponse(final String response)
+            throws Exception {
+        logger.debug("  parseResponse()");
+
+        // Break response into lines
+        String[] responseLines = response.split(HttpProxyConstants.CRLF);
+
+        // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
+        // BUG FIX : Trimed to prevent failures with some proxies that add extra space chars
+        // like "Microsoft-IIS/5.0" ...
+        String[] statusLine = responseLines[0].trim().split(" ", 2);
+
+        if (statusLine.length < 2) {
+            throw new Exception("Invalid response status line (" + statusLine
+                    + "). Response: " + response);
+        }
+
+        // Status code is 3 digits
+        if (statusLine[1].matches("^\\d\\d\\d")) {
+            throw new Exception("Invalid response code (" + statusLine[1]
+                    + "). Response: " + response);
+        }
+
+        Map<String, List<String>> headers = new HashMap<String, List<String>>();
+
+        for (int i = 1; i < responseLines.length; i++) {
+            String[] args = responseLines[i].split(":\\s?", 2);
+            StringUtilities.addValueToHeader(headers, args[0], args[1], false);
+        }
+
+        return new HttpProxyResponse(statusLine[0], statusLine[1], headers);
+    }
+}
\ No newline at end of file

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/AbstractHttpLogicHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/AbstractHttpLogicHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpAuthenticationMethods.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpAuthenticationMethods.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpAuthenticationMethods.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpAuthenticationMethods.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,73 @@
+/*
+ *  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.proxy.handlers.http;
+
+import org.apache.mina.proxy.ProxyAuthException;
+import org.apache.mina.proxy.handlers.http.basic.HttpBasicAuthLogicHandler;
+import org.apache.mina.proxy.handlers.http.basic.HttpNoAuthLogicHandler;
+import org.apache.mina.proxy.handlers.http.digest.HttpDigestAuthLogicHandler;
+import org.apache.mina.proxy.handlers.http.ntlm.HttpNTLMAuthLogicHandler;
+import org.apache.mina.proxy.session.ProxyIoSession;
+
+/**
+ * HttpAuthenticationMethods.java - Enumerates all known http authentication methods.
+ * 
+ * @author Edouard De Oliveira <a href="mailto:doe_wanted@yahoo.fr">doe_wanted@yahoo.fr</a>
+ * @version $Id: $
+ */
+public enum HttpAuthenticationMethods {
+
+    NO_AUTH(1), BASIC(2), NTLM(3), DIGEST(4);
+    
+    private final int id;
+    
+    private HttpAuthenticationMethods(int id) {
+    	this.id = id;
+    }
+
+	public int getId() {
+		return id;
+	}
+
+	/**
+     * Creates an {@link AbstractAuthLogicHandler} to handle this authentication mechanism. 
+     */
+    public AbstractAuthLogicHandler getNewHandler(ProxyIoSession proxyIoSession)
+            throws ProxyAuthException {
+        switch (this) {
+        case BASIC:
+            return new HttpBasicAuthLogicHandler(proxyIoSession);
+
+        case DIGEST:
+            HttpDigestAuthLogicHandler authHandler = new HttpDigestAuthLogicHandler(
+                    proxyIoSession);
+            return authHandler;
+
+        case NTLM:
+            return new HttpNTLMAuthLogicHandler(proxyIoSession);
+
+        case NO_AUTH:
+            return new HttpNoAuthLogicHandler(proxyIoSession);
+
+        default:
+            return null;
+        }
+    }
+}

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpAuthenticationMethods.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpAuthenticationMethods.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpProxyConstants.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpProxyConstants.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpProxyConstants.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpProxyConstants.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,51 @@
+/*
+ *  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.proxy.handlers.http;
+
+/**
+ * HttpProxyConstants.java - HTTP Proxy constants.
+ * 
+ * @author James Furness <a href="mailto:james.furness@lehman.com">james.furness@lehman.com</a>
+ * @author Edouard De Oliveira <a href="mailto:doe_wanted@yahoo.fr">doe_wanted@yahoo.fr</a>
+ * @version $Id: $
+ */
+public class HttpProxyConstants {
+    public final static String CONNECT = "CONNECT";
+
+    public final static String GET = "GET";
+
+    public final static String PUT = "PUT";
+
+    public final static String HTTP_1_0 = "HTTP/1.0";
+
+    public final static String HTTP_1_1 = "HTTP/1.1";
+
+    public final static String CRLF = "\r\n";
+
+    public final static String DEFAULT_KEEP_ALIVE_TIME = "300";
+
+    public final static String USER_PROPERTY = "USER";
+
+    public final static String PWD_PROPERTY = "PWD";
+
+    public final static String DOMAIN_PROPERTY = "DOMAIN";
+
+    public final static String WORKSTATION_PROPERTY = "WORKSTATION";
+}
\ No newline at end of file

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpProxyConstants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/handlers/http/HttpProxyConstants.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain