diff options
| -rw-r--r-- | Swiften/Client/CoreClient.cpp | 23 | ||||
| -rw-r--r-- | Swiften/Network/BOSHConnectionPool.cpp | 10 | ||||
| -rw-r--r-- | Swiften/Network/BOSHConnectionPool.h | 8 | ||||
| -rw-r--r-- | Swiften/Network/HTTPConnectProxiedConnection.cpp | 31 | ||||
| -rw-r--r-- | Swiften/Network/HTTPConnectProxiedConnection.h | 7 | ||||
| -rw-r--r-- | Swiften/Network/HTTPTrafficFilter.h | 4 | ||||
| -rw-r--r-- | Swiften/Network/ProxiedConnection.cpp | 14 | ||||
| -rw-r--r-- | Swiften/Network/ProxiedConnection.h | 6 | ||||
| -rw-r--r-- | Swiften/Network/UnitTest/BOSHConnectionTest.cpp | 22 | ||||
| -rw-r--r-- | Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp | 129 | ||||
| -rw-r--r-- | Swiften/SConscript | 2 | ||||
| -rw-r--r-- | Swiften/Session/BOSHSessionStream.cpp | 26 | ||||
| -rw-r--r-- | Swiften/Session/BOSHSessionStream.h | 17 | 
13 files changed, 218 insertions, 81 deletions
| diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp index b1a375b..fa9bd33 100644 --- a/Swiften/Client/CoreClient.cpp +++ b/Swiften/Client/CoreClient.cpp @@ -10,24 +10,24 @@  #include <boost/optional.hpp>  #include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Base/Algorithm.h>  #include <Swiften/Base/IDGenerator.h>  #include <Swiften/Base/Log.h>  #include <Swiften/Base/foreach.h> -#include <Swiften/Base/Algorithm.h>  #include <Swiften/Client/ClientSession.h> -#include <Swiften/TLS/CertificateVerificationError.h> -#include <Swiften/TLS/TLSError.h> +#include <Swiften/Client/ClientSessionStanzaChannel.h>  #include <Swiften/Network/ChainedConnector.h> +#include <Swiften/Network/DomainNameResolveError.h> +#include <Swiften/Network/HTTPConnectProxiedConnectionFactory.h>  #include <Swiften/Network/NetworkFactories.h>  #include <Swiften/Network/ProxyProvider.h> -#include <Swiften/Network/DomainNameResolveError.h> -#include <Swiften/TLS/PKCS12Certificate.h> -#include <Swiften/Session/BasicSessionStream.h> -#include <Swiften/Session/BOSHSessionStream.h> -#include <Swiften/Queries/IQRouter.h> -#include <Swiften/Client/ClientSessionStanzaChannel.h>  #include <Swiften/Network/SOCKS5ProxiedConnectionFactory.h> -#include <Swiften/Network/HTTPConnectProxiedConnectionFactory.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Session/BOSHSessionStream.h> +#include <Swiften/Session/BasicSessionStream.h> +#include <Swiften/TLS/CertificateVerificationError.h> +#include <Swiften/TLS/PKCS12Certificate.h> +#include <Swiften/TLS/TLSError.h>  namespace Swift { @@ -139,7 +139,8 @@ void CoreClient::connect(const ClientOptions& o) {  				options.boshHTTPConnectProxyURL,  				options.boshHTTPConnectProxyAuthID,  				options.boshHTTPConnectProxyAuthPassword, -				options.tlsOptions)); +				options.tlsOptions, +				options.httpTrafficFilter));  		sessionStream_->onDataRead.connect(boost::bind(&CoreClient::handleDataRead, this, _1));  		sessionStream_->onDataWritten.connect(boost::bind(&CoreClient::handleDataWritten, this, _1));  		bindSessionToStream(); diff --git a/Swiften/Network/BOSHConnectionPool.cpp b/Swiften/Network/BOSHConnectionPool.cpp index c037b34..c23e2de 100644 --- a/Swiften/Network/BOSHConnectionPool.cpp +++ b/Swiften/Network/BOSHConnectionPool.cpp @@ -10,14 +10,14 @@  #include <boost/bind.hpp>  #include <boost/lexical_cast.hpp> -#include <Swiften/Base/foreach.h>  #include <Swiften/Base/SafeString.h> -#include <Swiften/Network/TLSConnectionFactory.h> -#include <Swiften/Network/HTTPConnectProxiedConnectionFactory.h> +#include <Swiften/Base/foreach.h>  #include <Swiften/Network/CachingDomainNameResolver.h> +#include <Swiften/Network/HTTPConnectProxiedConnectionFactory.h> +#include <Swiften/Network/TLSConnectionFactory.h>  namespace Swift { -BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, DomainNameResolver* realResolver, ConnectionFactory* connectionFactoryParameter, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& to, unsigned long long initialRID, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, const SafeString& boshHTTPConnectProxyAuthPassword, const TLSOptions& tlsOptions) : +BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, DomainNameResolver* realResolver, ConnectionFactory* connectionFactoryParameter, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& to, unsigned long long initialRID, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, const SafeString& boshHTTPConnectProxyAuthPassword, const TLSOptions& tlsOptions, boost::shared_ptr<HTTPTrafficFilter> trafficFilter) :  		boshURL(boshURL),  		connectionFactory(connectionFactoryParameter),  		xmlParserFactory(parserFactory), @@ -34,7 +34,7 @@ BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, DomainNameResolver* r  			connectionFactory = new TLSConnectionFactory(tlsFactory, connectionFactory, tlsOptions);  			myConnectionFactories.push_back(connectionFactory);  		} -		connectionFactory = new HTTPConnectProxiedConnectionFactory(realResolver, connectionFactory, timerFactory, boshHTTPConnectProxyURL.getHost(), URL::getPortOrDefaultPort(boshHTTPConnectProxyURL), boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword); +		connectionFactory = new HTTPConnectProxiedConnectionFactory(realResolver, connectionFactory, timerFactory, boshHTTPConnectProxyURL.getHost(), URL::getPortOrDefaultPort(boshHTTPConnectProxyURL), boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword, trafficFilter);  	}  	if (boshURL.getScheme() == "https") {  		connectionFactory = new TLSConnectionFactory(tlsFactory, connectionFactory, tlsOptions); diff --git a/Swiften/Network/BOSHConnectionPool.h b/Swiften/Network/BOSHConnectionPool.h index d845a3d..eaef56c 100644 --- a/Swiften/Network/BOSHConnectionPool.h +++ b/Swiften/Network/BOSHConnectionPool.h @@ -14,16 +14,16 @@  #include <Swiften/Network/BOSHConnection.h>  #include <Swiften/TLS/TLSOptions.h> -  namespace Swift { -	class HTTPConnectProxiedConnectionFactory; -	class TLSConnectionFactory;  	class CachingDomainNameResolver;  	class EventLoop; +	class HTTPConnectProxiedConnectionFactory; +	class HTTPTrafficFilter; +	class TLSConnectionFactory;  	class SWIFTEN_API BOSHConnectionPool : public boost::bsignals::trackable {  		public: -			BOSHConnectionPool(const URL& boshURL, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& to, unsigned long long initialRID, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, const SafeString& boshHTTPConnectProxyAuthPassword, const TLSOptions& tlsOptions); +			BOSHConnectionPool(const URL& boshURL, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& to, unsigned long long initialRID, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, const SafeString& boshHTTPConnectProxyAuthPassword, const TLSOptions& tlsOptions, boost::shared_ptr<HTTPTrafficFilter> trafficFilter = boost::shared_ptr<HTTPTrafficFilter>());  			~BOSHConnectionPool();  			void write(const SafeByteArray& data);  			void writeFooter(); diff --git a/Swiften/Network/HTTPConnectProxiedConnection.cpp b/Swiften/Network/HTTPConnectProxiedConnection.cpp index 942361e..3ed2ac5 100644 --- a/Swiften/Network/HTTPConnectProxiedConnection.cpp +++ b/Swiften/Network/HTTPConnectProxiedConnection.cpp @@ -16,18 +16,18 @@  #include <iostream>  #include <utility> +#include <boost/algorithm/string.hpp>  #include <boost/bind.hpp>  #include <boost/lexical_cast.hpp> -#include <boost/algorithm/string.hpp> -#include <Swiften/Base/foreach.h>  #include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/ByteArray.h>  #include <Swiften/Base/Log.h>  #include <Swiften/Base/String.h> -#include <Swiften/Base/ByteArray.h> -#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Base/foreach.h>  #include <Swiften/Network/ConnectionFactory.h>  #include <Swiften/Network/HTTPTrafficFilter.h> +#include <Swiften/Network/HostAddressPort.h>  #include <Swiften/StringCodecs/Base64.h>  using namespace Swift; @@ -45,11 +45,17 @@ HTTPConnectProxiedConnection::HTTPConnectProxiedConnection(  			authPassword_(authPassword) {  } +HTTPConnectProxiedConnection::~HTTPConnectProxiedConnection() { + +} +  void HTTPConnectProxiedConnection::setHTTPTrafficFilter(boost::shared_ptr<HTTPTrafficFilter> trafficFilter) {  	trafficFilter_ = trafficFilter;  }  void HTTPConnectProxiedConnection::initializeProxy() { +	httpResponseBuffer_.clear(); +  	std::stringstream connect;  	connect << "CONNECT " << getServer().getAddress().toString() << ":" << getServer().getPort() << " HTTP/1.1\r\n";  	SafeByteArray data = createSafeByteArray(connect.str()); @@ -61,6 +67,17 @@ void HTTPConnectProxiedConnection::initializeProxy() {  		append(data, Base64::encode(credentials));  		append(data, createSafeByteArray("\r\n"));  	} +	else if (!nextHTTPRequestHeaders_.empty()) { +		typedef std::pair<std::string, std::string> StringPair; +		foreach(const StringPair& headerField, nextHTTPRequestHeaders_) { +			append(data, createSafeByteArray(headerField.first)); +			append(data, createSafeByteArray(": ")); +			append(data, createSafeByteArray(headerField.second)); +			append(data, createSafeByteArray("\r\n")); +		} + +		nextHTTPRequestHeaders_.clear(); +	}  	append(data, createSafeByteArray("\r\n"));  	SWIFT_LOG(debug) << "HTTP Proxy send headers: " << byteArrayToString(ByteArray(data.begin(), data.end())) << std::endl;  	write(data); @@ -114,11 +131,11 @@ void HTTPConnectProxiedConnection::handleProxyInitializeData(boost::shared_ptr<S  	parseHTTPHeader(httpResponseBuffer_.substr(0, headerEnd), statusLine, headerFields);  	if (trafficFilter_) { -		std::vector<std::pair<std::string, std::string> > newHeaderFields = trafficFilter_->filterHTTPResponseHeader(headerFields); +		std::vector<std::pair<std::string, std::string> > newHeaderFields = trafficFilter_->filterHTTPResponseHeader(statusLine, headerFields);  		if (!newHeaderFields.empty()) {  			std::stringstream statusLine; -			statusLine << "CONNECT " << getServer().getAddress().toString() << ":" << getServer().getPort(); -			sendHTTPRequest(statusLine.str(), newHeaderFields); +			reconnect(); +			nextHTTPRequestHeaders_ = newHeaderFields;  			return;  		}  	} diff --git a/Swiften/Network/HTTPConnectProxiedConnection.h b/Swiften/Network/HTTPConnectProxiedConnection.h index 11431bf..24f36b9 100644 --- a/Swiften/Network/HTTPConnectProxiedConnection.h +++ b/Swiften/Network/HTTPConnectProxiedConnection.h @@ -19,16 +19,18 @@  #include <Swiften/Network/ProxiedConnection.h>  namespace Swift { -	class DomainNameResolver;  	class ConnectionFactory; +	class DomainNameResolver;  	class EventLoop; -	class TimerFactory;  	class HTTPTrafficFilter; +	class TimerFactory;  	class SWIFTEN_API HTTPConnectProxiedConnection : public ProxiedConnection {  		public:  			typedef boost::shared_ptr<HTTPConnectProxiedConnection> ref; +			virtual ~HTTPConnectProxiedConnection(); +  			static ref create(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword) {  				return ref(new HTTPConnectProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort, authID, authPassword));  			} @@ -49,5 +51,6 @@ namespace Swift {  			SafeByteArray authPassword_;  			boost::shared_ptr<HTTPTrafficFilter> trafficFilter_;  			std::string httpResponseBuffer_; +			std::vector<std::pair<std::string, std::string> > nextHTTPRequestHeaders_;  	};  } diff --git a/Swiften/Network/HTTPTrafficFilter.h b/Swiften/Network/HTTPTrafficFilter.h index da96c96..cc1af21 100644 --- a/Swiften/Network/HTTPTrafficFilter.h +++ b/Swiften/Network/HTTPTrafficFilter.h @@ -6,9 +6,9 @@  #pragma once -#include <vector>  #include <string>  #include <utility> +#include <vector>  #include <boost/optional.hpp> @@ -25,7 +25,7 @@ class SWIFTEN_API HTTPTrafficFilter {  		 * @return A vector of HTTP header fields to use in a new request. If an empty vector is returned,  		 *         no new request will be send and the normal proxy logic continues.  		 */ -		virtual std::vector<std::pair<std::string, std::string> > filterHTTPResponseHeader(const std::vector<std::pair<std::string, std::string> >& /* responseHeader */) = 0; +		virtual std::vector<std::pair<std::string, std::string> > filterHTTPResponseHeader(const std::string& statusLine, const std::vector<std::pair<std::string, std::string> >& /* responseHeader */) = 0;  };  } diff --git a/Swiften/Network/ProxiedConnection.cpp b/Swiften/Network/ProxiedConnection.cpp index a3fb352..17f7e09 100644 --- a/Swiften/Network/ProxiedConnection.cpp +++ b/Swiften/Network/ProxiedConnection.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2012 Isode Limited. + * Copyright (c) 2012-2015 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -8,11 +8,12 @@  #include <Swiften/Network/ProxiedConnection.h>  #include <iostream> +  #include <boost/bind.hpp>  #include <Swiften/Base/ByteArray.h> -#include <Swiften/Network/HostAddressPort.h>  #include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/HostAddressPort.h>  using namespace Swift; @@ -110,3 +111,12 @@ void ProxiedConnection::setProxyInitializeFinished(bool success) {  	}  	onConnectFinished(!success);  } + +void ProxiedConnection::reconnect() { +	if (connected_) { +		connection_->onDataRead.disconnect(boost::bind(&ProxiedConnection::handleDataRead, shared_from_this(), _1)); +		connection_->onDisconnected.disconnect(boost::bind(&ProxiedConnection::handleDisconnected, shared_from_this(), _1)); +		connection_->disconnect(); +	} +	connect(server_); +} diff --git a/Swiften/Network/ProxiedConnection.h b/Swiften/Network/ProxiedConnection.h index 91488a1..f301e84 100644 --- a/Swiften/Network/ProxiedConnection.h +++ b/Swiften/Network/ProxiedConnection.h @@ -10,10 +10,10 @@  #include <boost/enable_shared_from_this.hpp>  #include <Swiften/Base/API.h> +#include <Swiften/Base/SafeString.h>  #include <Swiften/Network/Connection.h>  #include <Swiften/Network/Connector.h>  #include <Swiften/Network/HostAddressPort.h> -#include <Swiften/Base/SafeString.h>  namespace boost {  	class thread; @@ -28,7 +28,7 @@ namespace Swift {  	class SWIFTEN_API ProxiedConnection : public Connection, public boost::enable_shared_from_this<ProxiedConnection> {  		public:  			ProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort); -			~ProxiedConnection(); +			virtual ~ProxiedConnection();  			virtual void listen();  			virtual void connect(const HostAddressPort& address); @@ -53,6 +53,8 @@ namespace Swift {  				return server_;  			} +			void reconnect(); +  		private:  			bool connected_;  			DomainNameResolver* resolver_; diff --git a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp index a115f9b..c8bf1f0 100644 --- a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp +++ b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp @@ -1,28 +1,28 @@  /* - * Copyright (c) 2011 Isode Limited. + * Copyright (c) 2011-2015 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ +#include <boost/bind.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> +  #include <QA/Checker/IO.h>  #include <cppunit/extensions/HelperMacros.h>  #include <cppunit/extensions/TestFactoryRegistry.h> -#include <boost/optional.hpp> -#include <boost/bind.hpp> -#include <boost/smart_ptr/make_shared.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/lexical_cast.hpp> -  #include <Swiften/Base/Algorithm.h> +#include <Swiften/EventLoop/DummyEventLoop.h> +#include <Swiften/Network/BOSHConnection.h>  #include <Swiften/Network/Connection.h>  #include <Swiften/Network/ConnectionFactory.h> -#include <Swiften/Network/BOSHConnection.h> +#include <Swiften/Network/DummyTimerFactory.h>  #include <Swiften/Network/HostAddressPort.h>  #include <Swiften/Network/StaticDomainNameResolver.h> -#include <Swiften/Network/DummyTimerFactory.h> -#include <Swiften/EventLoop/DummyEventLoop.h>  #include <Swiften/Parser/PlatformXMLParserFactory.h>  using namespace Swift; @@ -39,7 +39,7 @@ class BOSHConnectionTest : public CppUnit::TestFixture {  	CPPUNIT_TEST(testRead_Fragment);  	CPPUNIT_TEST(testHTTPRequest);  	CPPUNIT_TEST(testHTTPRequest_Empty); -	CPPUNIT_TEST_SUITE_END();	 +	CPPUNIT_TEST_SUITE_END();  	public:  		void setUp() { diff --git a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp index d3db79d..56ace5c 100644 --- a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp +++ b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp @@ -3,26 +3,30 @@   * All rights reserved.   * See the COPYING file for more information.   */ + +#include <boost/algorithm/string.hpp> +#include <boost/bind.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> +  #include <QA/Checker/IO.h>  #include <cppunit/extensions/HelperMacros.h>  #include <cppunit/extensions/TestFactoryRegistry.h> -#include <boost/optional.hpp> -#include <boost/bind.hpp> -#include <boost/smart_ptr/make_shared.hpp> -#include <boost/shared_ptr.hpp> -  #include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/Log.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/EventLoop/DummyEventLoop.h>  #include <Swiften/Network/Connection.h>  #include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/DummyTimerFactory.h>  #include <Swiften/Network/HTTPConnectProxiedConnection.h>  #include <Swiften/Network/HTTPTrafficFilter.h>  #include <Swiften/Network/HostAddressPort.h>  #include <Swiften/Network/StaticDomainNameResolver.h> -#include <Swiften/Network/DummyTimerFactory.h> -#include <Swiften/EventLoop/DummyEventLoop.h> -#include <Swiften/Base/Log.h>  using namespace Swift; @@ -32,7 +36,7 @@ namespace {  			ExampleHTTPTrafficFilter() {}  			virtual ~ExampleHTTPTrafficFilter() {} -			virtual std::vector<std::pair<std::string, std::string> > filterHTTPResponseHeader(const std::vector<std::pair<std::string, std::string> >& response) { +			virtual std::vector<std::pair<std::string, std::string> > filterHTTPResponseHeader(const std::string& /* statusLine */, const std::vector<std::pair<std::string, std::string> >& response) {  				filterResponses.push_back(response);  				SWIFT_LOG(debug) << std::endl;  				return filterResponseReturn; @@ -42,6 +46,46 @@ namespace {  			std::vector<std::pair<std::string, std::string> > filterResponseReturn;  	}; + +	class ProxyAuthenticationHTTPTrafficFilter : public HTTPTrafficFilter { +			static std::string to_lower(const std::string& str) { +				std::string lower = str; +				boost::algorithm::to_lower(lower); +				return lower; +			} + +		public: +			ProxyAuthenticationHTTPTrafficFilter() {} +			virtual ~ProxyAuthenticationHTTPTrafficFilter() {} + +			virtual std::vector<std::pair<std::string, std::string> > filterHTTPResponseHeader(const std::string& statusLine, const std::vector<std::pair<std::string, std::string> >& response) { +				std::vector<std::pair<std::string, std::string> > filterResponseReturn; +				std::vector<std::string> statusLineFields; +				boost::split(statusLineFields, statusLine, boost::is_any_of(" "), boost::token_compress_on); + +				int statusCode = boost::lexical_cast<int>(statusLineFields[1]); +				if (statusCode == 407) { +					typedef std::pair<std::string, std::string> StrPair; +					foreach (const StrPair& field, response) { +						if (to_lower(field.first) == to_lower("Proxy-Authenticate")) { +							if (field.second.size() >= 6 && field.second.substr(0, 6) == " NTLM ") { +								filterResponseReturn.push_back(std::pair<std::string, std::string>("Proxy-Authorization", "NTLM TlRMTVNTUAADAAAAGAAYAHIAAAAYABgAigAAABIAEgBIAAAABgAGAFoAAAASABIVNTUAADAAYAAAABAAEACiAAAANYKI4gUBKAoAAAAPTABBAEIAUwBNAE8ASwBFADMAXwBxAGEATABBAEIAUwBNAE8ASwBFADMA0NKq8HYYhj8AAAAAAAAAAAAAAAAAAAAAOIiih3mR+AkyM4r99sy1mdFonCu2ILODro1WTTrJ4b4JcXEzUBA2Ig==")); +								return filterResponseReturn; +							} +							else if (field.second.size() >= 5 && field.second.substr(0, 5) == " NTLM") { +								filterResponseReturn.push_back(std::pair<std::string, std::string>("Proxy-Authorization", "NTLM TlRMTVNTUAABAAAAt7II4gkACQAxAAAACQAJACgAAAVNTUAADAAFASgKAAAAD0xBQlNNT0tFM1dPUktHUk9VUA==")); +								return filterResponseReturn; +							} +						} +					} + +					return filterResponseReturn; +				} +				else { +					return std::vector<std::pair<std::string, std::string> >(); +				} +			} +	};  }  class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { @@ -57,6 +101,7 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture {  		CPPUNIT_TEST(testDisconnect_AfterConnectRequest);  		CPPUNIT_TEST(testDisconnect_AfterConnect);  		CPPUNIT_TEST(testTrafficFilter); +		CPPUNIT_TEST(testTrafficFilterNoConnectionReuse);  		CPPUNIT_TEST_SUITE_END();  	public: @@ -71,6 +116,7 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture {  			timerFactory = new DummyTimerFactory();  			connectionFactory = new MockConnectionFactory(eventLoop);  			connectFinished = false; +			connectFinishedWithError = false;  			disconnected = false;  		} @@ -238,12 +284,69 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture {  			eventLoop->processEvents();  			// verify that the traffic filter answer is send over the wire -			CPPUNIT_ASSERT_EQUAL(createByteArray("CONNECT 2.2.2.2:2345\r\nAuthorization:Negotiate a87421000492aa874209af8bc028\r\n\r\n"), connectionFactory->connections[0]->dataWritten); +			CPPUNIT_ASSERT_EQUAL(createByteArray("CONNECT 2.2.2.2:2345 HTTP/1.1\r\nAuthorization: Negotiate a87421000492aa874209af8bc028\r\n\r\n"), connectionFactory->connections[1]->dataWritten);  			// verify that after without the default response, the traffic filter is skipped, authentication proceeds and traffic goes right through -			connectionFactory->connections[0]->dataWritten.clear(); +			connectionFactory->connections[1]->dataWritten.clear();  			testling->write(createSafeByteArray("abcdef")); -			CPPUNIT_ASSERT_EQUAL(createByteArray("abcdef"), connectionFactory->connections[0]->dataWritten); +			CPPUNIT_ASSERT_EQUAL(createByteArray("abcdef"), connectionFactory->connections[1]->dataWritten); +		} + +		void testTrafficFilterNoConnectionReuse() { +			HTTPConnectProxiedConnection::ref testling = createTestling(); + +			boost::shared_ptr<ProxyAuthenticationHTTPTrafficFilter> httpTrafficFilter = boost::make_shared<ProxyAuthenticationHTTPTrafficFilter>(); +			testling->setHTTPTrafficFilter(httpTrafficFilter); + +			connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); + +			// First HTTP CONNECT request assumes the proxy will work. +			CPPUNIT_ASSERT_EQUAL(createByteArray("CONNECT 2.2.2.2:2345 HTTP/1.1\r\n" +												"\r\n"), connectionFactory->connections[0]->dataWritten); + +			// First reply presents initiator with authentication options. +			connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef( +				"HTTP/1.0 407 ProxyAuthentication Required\r\n" +				"proxy-Authenticate: Negotiate\r\n" +				"Proxy-Authenticate: Kerberos\r\n" +				"proxy-Authenticate: NTLM\r\n" +				"\r\n")); +			eventLoop->processEvents(); +			CPPUNIT_ASSERT_EQUAL(false, connectFinished); +			CPPUNIT_ASSERT_EQUAL(false, connectFinishedWithError); + +			// The HTTP proxy responds with code 407, so the traffic filter should inject the authentication response on a new connection. +			CPPUNIT_ASSERT_EQUAL(createByteArray("CONNECT 2.2.2.2:2345 HTTP/1.1\r\n" +												"Proxy-Authorization: NTLM TlRMTVNTUAABAAAAt7II4gkACQAxAAAACQAJACgAAAVNTUAADAAFASgKAAAAD0xBQlNNT0tFM1dPUktHUk9VUA==\r\n" +												"\r\n"), connectionFactory->connections[1]->dataWritten); + +			// The proxy responds with another authentication step. +			connectionFactory->connections[1]->onDataRead(createSafeByteArrayRef( +				"HTTP/1.0 407 ProxyAuthentication Required\r\n" +				"Proxy-Authenticate: NTLM TlRMTVNTUAACAAAAEAAQADgAAAA1goriluCDYHcYI/sAAAAAAAAAAFQAVABIAAAABQLODgAAAA9TAFAASQBSAEkAVAAxAEIAAgAQAFMAUABJAFIASQBUADEAQgABABAAUwBQAEkAUgBJAFQAMQBCAAQAEABzAHAAaQByAGkAdAAxAGIAAwAQAHMAcABpAHIAaQB0ADEAYgAAAAAA\r\n" +				"\r\n")); +			eventLoop->processEvents(); +			CPPUNIT_ASSERT_EQUAL(false, connectFinished); +			CPPUNIT_ASSERT_EQUAL(false, connectFinishedWithError); + +			// Last HTTP request that should succeed. Further traffic will go over the connection of this request. +			CPPUNIT_ASSERT_EQUAL(createByteArray("CONNECT 2.2.2.2:2345 HTTP/1.1\r\n" +												"Proxy-Authorization: NTLM TlRMTVNTUAADAAAAGAAYAHIAAAAYABgAigAAABIAEgBIAAAABgAGAFoAAAASABIVNTUAADAAYAAAABAAEACiAAAANYKI4gUBKAoAAAAPTABBAEIAUwBNAE8ASwBFADMAXwBxAGEATABBAEIAUwBNAE8ASwBFADMA0NKq8HYYhj8AAAAAAAAAAAAAAAAAAAAAOIiih3mR+AkyM4r99sy1mdFonCu2ILODro1WTTrJ4b4JcXEzUBA2Ig==\r\n" +												"\r\n"), connectionFactory->connections[2]->dataWritten); + +			connectionFactory->connections[2]->onDataRead(createSafeByteArrayRef( +				"HTTP/1.0 200 OK\r\n" +				"\r\n")); +			eventLoop->processEvents(); + +			// The HTTP CONNECT proxy initialization finished without error. +			CPPUNIT_ASSERT_EQUAL(true, connectFinished); +			CPPUNIT_ASSERT_EQUAL(false, connectFinishedWithError); + +			// Further traffic is written directly, without interception of the filter. +			connectionFactory->connections[2]->dataWritten.clear(); +			testling->write(createSafeByteArray("This is some basic data traffic.")); +			CPPUNIT_ASSERT_EQUAL(createByteArray("This is some basic data traffic."), connectionFactory->connections[2]->dataWritten);  		}  	private: @@ -307,6 +410,7 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture {  			boost::shared_ptr<Connection> createConnection() {  				boost::shared_ptr<MockConnection> connection = boost::make_shared<MockConnection>(failingPorts, eventLoop);  				connections.push_back(connection); +				SWIFT_LOG(debug) << "new connection created" << std::endl;  				return connection;  			} @@ -324,7 +428,6 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture {  		StaticDomainNameResolver* resolver;  		MockConnectionFactory* connectionFactory;  		TimerFactory* timerFactory; -		std::vector< boost::shared_ptr<MockConnection> > connections;  		bool connectFinished;  		bool connectFinishedWithError;  		bool disconnected; diff --git a/Swiften/SConscript b/Swiften/SConscript index 9b82434..97dc39c 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -407,7 +407,7 @@ if env["SCONS_STAGE"] == "build" :  			File("Network/UnitTest/HostAddressTest.cpp"),  			File("Network/UnitTest/ConnectorTest.cpp"),  			File("Network/UnitTest/ChainedConnectorTest.cpp"), -			File("Network/UnitTest/DomainNameServiceQueryTest.cpp"),	 +			File("Network/UnitTest/DomainNameServiceQueryTest.cpp"),  			File("Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp"),  			File("Network/UnitTest/BOSHConnectionTest.cpp"),  			File("Network/UnitTest/BOSHConnectionPoolTest.cpp"), diff --git a/Swiften/Session/BOSHSessionStream.cpp b/Swiften/Session/BOSHSessionStream.cpp index 62942b9..c5d0dd5 100644 --- a/Swiften/Session/BOSHSessionStream.cpp +++ b/Swiften/Session/BOSHSessionStream.cpp @@ -14,24 +14,23 @@  #include <Swiften/Base/foreach.h>  #include <Swiften/Elements/StreamType.h> -#include <Swiften/StreamStack/XMPPLayer.h> -#include <Swiften/StreamStack/StreamStack.h> -#include <Swiften/StreamStack/ConnectionLayer.h> -#include <Swiften/StreamStack/WhitespacePingLayer.h> +#include <Swiften/EventLoop/EventLoop.h>  #include <Swiften/StreamStack/CompressionLayer.h> +#include <Swiften/StreamStack/ConnectionLayer.h> +#include <Swiften/StreamStack/StreamStack.h>  #include <Swiften/StreamStack/TLSLayer.h> -#include <Swiften/TLS/TLSContextFactory.h> +#include <Swiften/StreamStack/WhitespacePingLayer.h> +#include <Swiften/StreamStack/XMPPLayer.h>  #include <Swiften/TLS/TLSContext.h> -#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/TLS/TLSContextFactory.h>  namespace Swift { -BOSHSessionStream::BOSHSessionStream( -		const URL& boshURL, -		PayloadParserFactoryCollection* payloadParserFactories,  -		PayloadSerializerCollection* payloadSerializers,  +BOSHSessionStream::BOSHSessionStream(const URL& boshURL, +		PayloadParserFactoryCollection* payloadParserFactories, +		PayloadSerializerCollection* payloadSerializers,  		ConnectionFactory* connectionFactory, -		TLSContextFactory* tlsContextFactory,  +		TLSContextFactory* tlsContextFactory,  		TimerFactory* timerFactory,  		XMLParserFactory* xmlParserFactory,  		EventLoop* eventLoop, @@ -40,7 +39,8 @@ BOSHSessionStream::BOSHSessionStream(  		const URL& boshHTTPConnectProxyURL,  		const SafeString& boshHTTPConnectProxyAuthID,  		const SafeString& boshHTTPConnectProxyAuthPassword, -		const TLSOptions& tlsOptions) : +		const TLSOptions& tlsOptions, +		boost::shared_ptr<HTTPTrafficFilter> trafficFilter) :  			available(false),   			eventLoop(eventLoop),  			firstHeader(true) { @@ -50,7 +50,7 @@ BOSHSessionStream::BOSHSessionStream(  	random.seed(static_cast<unsigned int>(time(NULL)));  	unsigned long long initialRID = boost::variate_generator<boost::mt19937&, boost::uniform_int<unsigned long long> >(random, dist)(); -	connectionPool = new BOSHConnectionPool(boshURL, resolver, connectionFactory, xmlParserFactory, tlsContextFactory, timerFactory, eventLoop, to, initialRID, boshHTTPConnectProxyURL, boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword, tlsOptions); +	connectionPool = new BOSHConnectionPool(boshURL, resolver, connectionFactory, xmlParserFactory, tlsContextFactory, timerFactory, eventLoop, to, initialRID, boshHTTPConnectProxyURL, boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword, tlsOptions, trafficFilter);  	connectionPool->onSessionTerminated.connect(boost::bind(&BOSHSessionStream::handlePoolSessionTerminated, this, _1));  	connectionPool->onSessionStarted.connect(boost::bind(&BOSHSessionStream::handlePoolSessionStarted, this));  	connectionPool->onXMPPDataRead.connect(boost::bind(&BOSHSessionStream::handlePoolXMPPDataRead, this, _1)); diff --git a/Swiften/Session/BOSHSessionStream.h b/Swiften/Session/BOSHSessionStream.h index 436b941..817f5e9 100644 --- a/Swiften/Session/BOSHSessionStream.h +++ b/Swiften/Session/BOSHSessionStream.h @@ -17,18 +17,18 @@  #include <Swiften/Session/SessionStream.h>  #include <Swiften/TLS/TLSOptions.h> -  namespace Swift { -	class TimerFactory; +	class CompressionLayer; +	class ConnectionLayer; +	class EventLoop; +	class HTTPTrafficFilter;  	class PayloadParserFactoryCollection;  	class PayloadSerializerCollection;  	class StreamStack; -	class XMPPLayer; -	class ConnectionLayer; -	class CompressionLayer; -	class XMLParserFactory;  	class TLSContextFactory; -	class EventLoop; +	class TimerFactory; +	class XMLParserFactory; +	class XMPPLayer;  	class SWIFTEN_API BOSHSessionStream : public SessionStream, public EventOwner, public boost::enable_shared_from_this<BOSHSessionStream> {  		public: @@ -46,7 +46,8 @@ namespace Swift {  					const URL& boshHTTPConnectProxyURL,  					const SafeString& boshHTTPConnectProxyAuthID,  					const SafeString& boshHTTPConnectProxyAuthPassword, -					const TLSOptions& tlsOptions +					const TLSOptions& tlsOptions, +					boost::shared_ptr<HTTPTrafficFilter> trafficFilter  			);  			~BOSHSessionStream(); | 
 Swift
 Swift