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