summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swiften/Client/CoreClient.cpp23
-rw-r--r--Swiften/Network/BOSHConnectionPool.cpp10
-rw-r--r--Swiften/Network/BOSHConnectionPool.h8
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnection.cpp31
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnection.h7
-rw-r--r--Swiften/Network/HTTPTrafficFilter.h4
-rw-r--r--Swiften/Network/ProxiedConnection.cpp14
-rw-r--r--Swiften/Network/ProxiedConnection.h6
-rw-r--r--Swiften/Network/UnitTest/BOSHConnectionTest.cpp22
-rw-r--r--Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp129
-rw-r--r--Swiften/SConscript2
-rw-r--r--Swiften/Session/BOSHSessionStream.cpp26
-rw-r--r--Swiften/Session/BOSHSessionStream.h17
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();