summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften')
-rw-r--r--Swiften/Client/ClientOptions.h12
-rw-r--r--Swiften/Client/CoreClient.cpp4
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnection.cpp63
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnection.h11
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp10
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnectionFactory.h9
-rw-r--r--Swiften/Network/HTTPTrafficFilter.cpp15
-rw-r--r--Swiften/Network/HTTPTrafficFilter.h31
-rw-r--r--Swiften/Network/SConscript7
-rw-r--r--Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp60
10 files changed, 204 insertions, 18 deletions
diff --git a/Swiften/Client/ClientOptions.h b/Swiften/Client/ClientOptions.h
index 884b1bb..20e7443 100644
--- a/Swiften/Client/ClientOptions.h
+++ b/Swiften/Client/ClientOptions.h
@@ -1,15 +1,19 @@
/*
- * Copyright (c) 2011 Isode Limited.
+ * Copyright (c) 2011-2015 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
+#include <boost/shared_ptr.hpp>
+
#include <Swiften/Base/URL.h>
#include <Swiften/Base/SafeString.h>
namespace Swift {
+ class HTTPTrafficFilter;
+
struct ClientOptions {
enum UseTLS {
NeverUseTLS,
@@ -134,5 +138,11 @@ namespace Swift {
*/
SafeString boshHTTPConnectProxyAuthID;
SafeString boshHTTPConnectProxyAuthPassword;
+
+ /**
+ * This can be initialized with a custom HTTPTrafficFilter, which allows HTTP CONNECT
+ * proxy initialization to be customized.
+ */
+ boost::shared_ptr<HTTPTrafficFilter> httpTrafficFilter;
};
}
diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp
index 4416ee4..842488d 100644
--- a/Swiften/Client/CoreClient.cpp
+++ b/Swiften/Client/CoreClient.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2014 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -96,7 +96,7 @@ void CoreClient::connect(const ClientOptions& o) {
std::string proxyHostname = o.manualProxyHostname.empty() ? systemHTTPConnectProxy.getAddress().toString() : o.manualProxyHostname;
int proxyPort = o.manualProxyPort == -1 ? systemHTTPConnectProxy.getPort() : o.manualProxyPort;
SWIFT_LOG(debug) << "Proxy: " << proxyHostname << ":" << proxyPort << std::endl;
- proxyConnectionFactories.push_back(new HTTPConnectProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), proxyHostname, proxyPort));
+ proxyConnectionFactories.push_back(new HTTPConnectProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), proxyHostname, proxyPort, o.httpTrafficFilter));
useDirectConnection = false;
break;
}
diff --git a/Swiften/Network/HTTPConnectProxiedConnection.cpp b/Swiften/Network/HTTPConnectProxiedConnection.cpp
index ead48e9..fc5a6c6 100644
--- a/Swiften/Network/HTTPConnectProxiedConnection.cpp
+++ b/Swiften/Network/HTTPConnectProxiedConnection.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (c) 2011-2012 Isode Limited.
+ * Copyright (c) 2011-2015 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -14,15 +14,20 @@
#include <Swiften/Network/HTTPConnectProxiedConnection.h>
#include <iostream>
+#include <utility>
+
#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/Log.h>
#include <Swiften/Base/String.h>
#include <Swiften/Base/ByteArray.h>
#include <Swiften/Network/HostAddressPort.h>
#include <Swiften/Network/ConnectionFactory.h>
+#include <Swiften/Network/HTTPTrafficFilter.h>
#include <Swiften/StringCodecs/Base64.h>
using namespace Swift;
@@ -40,6 +45,9 @@ HTTPConnectProxiedConnection::HTTPConnectProxiedConnection(
authPassword_(authPassword) {
}
+void HTTPConnectProxiedConnection::setHTTPTrafficFilter(boost::shared_ptr<HTTPTrafficFilter> trafficFilter) {
+ trafficFilter_ = trafficFilter;
+}
void HTTPConnectProxiedConnection::initializeProxy() {
std::stringstream connect;
@@ -58,9 +66,58 @@ void HTTPConnectProxiedConnection::initializeProxy() {
write(data);
}
+void HTTPConnectProxiedConnection::parseHTTPHeader(const std::string& data, std::string& statusLine, std::vector<std::pair<std::string, std::string> >& headerFields) {
+ std::istringstream dataStream(data);
+
+ // parse status line
+ std::getline(dataStream, statusLine);
+
+ // parse fields
+ std::string headerLine;
+ std::string::size_type splitIndex;
+ while (std::getline(dataStream, headerLine) && headerLine != "\r") {
+ splitIndex = headerLine.find(':', 0);
+ if (splitIndex != std::string::npos) {
+ headerFields.push_back(std::pair<std::string, std::string>(headerLine.substr(0, splitIndex), headerLine.substr(splitIndex + 1)));
+ }
+ }
+}
+
+void HTTPConnectProxiedConnection::sendHTTPRequest(const std::string& statusLine, std::vector<std::pair<std::string, std::string> >& headerFields) {
+ typedef std::pair<std::string, std::string> HTTPHeaderField;
+ std::stringstream request;
+
+ request << statusLine << "\r\n";
+ foreach (const HTTPHeaderField& field, headerFields) {
+ request << field.first << ":" << field.second << "\r\n";
+ }
+ request << "\r\n";
+ write(createSafeByteArray(request.str()));
+}
+
void HTTPConnectProxiedConnection::handleProxyInitializeData(boost::shared_ptr<SafeByteArray> data) {
- SWIFT_LOG(debug) << byteArrayToString(ByteArray(data->begin(), data->end())) << std::endl;
- std::vector<std::string> tmp = String::split(byteArrayToString(ByteArray(data->begin(), data->end())), ' ');
+ std::string dataString = byteArrayToString(ByteArray(data->begin(), data->end()));
+ SWIFT_LOG(debug) << data << std::endl;
+
+ std::string statusLine;
+ std::vector<std::pair<std::string, std::string> > headerFields;
+
+ std::string::size_type headerEnd = dataString.find("\r\n\r\n", 0);
+
+ parseHTTPHeader(dataString.substr(0, headerEnd), statusLine, headerFields);
+
+ if (trafficFilter_) {
+ std::vector<std::pair<std::string, std::string> > newHeaderFields = trafficFilter_->filterHTTPResponseHeader(headerFields);
+ if (!newHeaderFields.empty()) {
+ std::stringstream statusLine;
+ statusLine << "CONNECT " << getServer().getAddress().toString() << ":" << getServer().getPort();
+ sendHTTPRequest(statusLine.str(), newHeaderFields);
+ SWIFT_LOG(debug) << "send HTTP request from traffic filter" << std::endl;
+ return;
+ }
+ }
+
+ std::vector<std::string> tmp = String::split(statusLine, ' ');
if (tmp.size() > 1) {
try {
int status = boost::lexical_cast<int>(tmp[1]);
diff --git a/Swiften/Network/HTTPConnectProxiedConnection.h b/Swiften/Network/HTTPConnectProxiedConnection.h
index 5b28242..7d83863 100644
--- a/Swiften/Network/HTTPConnectProxiedConnection.h
+++ b/Swiften/Network/HTTPConnectProxiedConnection.h
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (c) 2011-2012 Isode Limited.
+ * Copyright (c) 2011-2015 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -13,6 +13,8 @@
#pragma once
+#include <boost/shared_ptr.hpp>
+
#include <Swiften/Base/API.h>
#include <Swiften/Network/ProxiedConnection.h>
@@ -21,6 +23,7 @@ namespace Swift {
class ConnectionFactory;
class EventLoop;
class TimerFactory;
+ class HTTPTrafficFilter;
class SWIFTEN_API HTTPConnectProxiedConnection : public ProxiedConnection {
public:
@@ -30,14 +33,20 @@ namespace Swift {
return ref(new HTTPConnectProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort, authID, authPassword));
}
+ void setHTTPTrafficFilter(boost::shared_ptr<HTTPTrafficFilter> trafficFilter);
+
private:
HTTPConnectProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword);
virtual void initializeProxy();
virtual void handleProxyInitializeData(boost::shared_ptr<SafeByteArray> data);
+ void sendHTTPRequest(const std::string& statusLine, std::vector<std::pair<std::string, std::string> >& headerFields);
+ void parseHTTPHeader(const std::string& data, std::string& statusLine, std::vector<std::pair<std::string, std::string> >& headerFields);
+
private:
SafeByteArray authID_;
SafeByteArray authPassword_;
+ boost::shared_ptr<HTTPTrafficFilter> trafficFilter_;
};
}
diff --git a/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp b/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp
index e50c5d0..91b241e 100644
--- a/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp
+++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.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.
*/
@@ -16,15 +16,17 @@
namespace Swift {
-HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(""), authPassword_("") {
+HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, boost::shared_ptr<HTTPTrafficFilter> httpTrafficFilter) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(""), authPassword_(""), httpTrafficFilter_(httpTrafficFilter) {
}
-HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(authID), authPassword_(authPassword) {
+HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword, boost::shared_ptr<HTTPTrafficFilter> httpTrafficFilter) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(authID), authPassword_(authPassword), httpTrafficFilter_(httpTrafficFilter) {
}
boost::shared_ptr<Connection> HTTPConnectProxiedConnectionFactory::createConnection() {
- return HTTPConnectProxiedConnection::create(resolver_, connectionFactory_, timerFactory_, proxyHost_, proxyPort_, authID_, authPassword_);
+ HTTPConnectProxiedConnection::ref proxyConnection = HTTPConnectProxiedConnection::create(resolver_, connectionFactory_, timerFactory_, proxyHost_, proxyPort_, authID_, authPassword_);
+ proxyConnection->setHTTPTrafficFilter(httpTrafficFilter_);
+ return proxyConnection;
}
}
diff --git a/Swiften/Network/HTTPConnectProxiedConnectionFactory.h b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h
index e7a4283..b4ddd4e 100644
--- a/Swiften/Network/HTTPConnectProxiedConnectionFactory.h
+++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h
@@ -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.
*/
@@ -20,10 +20,12 @@ namespace Swift {
class DomainNameResolver;
class TimerFactory;
class EventLoop;
+ class HTTPTrafficFilter;
+
class HTTPConnectProxiedConnectionFactory : public ConnectionFactory {
public:
- HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort);
- HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword);
+ HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, boost::shared_ptr<HTTPTrafficFilter> httpTrafficFilter = boost::shared_ptr<HTTPTrafficFilter>());
+ HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword, boost::shared_ptr<HTTPTrafficFilter> httpTrafficFilter = boost::shared_ptr<HTTPTrafficFilter>());
virtual boost::shared_ptr<Connection> createConnection();
@@ -35,5 +37,6 @@ namespace Swift {
int proxyPort_;
SafeString authID_;
SafeString authPassword_;
+ boost::shared_ptr<HTTPTrafficFilter> httpTrafficFilter_;
};
}
diff --git a/Swiften/Network/HTTPTrafficFilter.cpp b/Swiften/Network/HTTPTrafficFilter.cpp
new file mode 100644
index 0000000..d40fbdf
--- /dev/null
+++ b/Swiften/Network/HTTPTrafficFilter.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Network/HTTPTrafficFilter.h>
+
+namespace Swift {
+
+HTTPTrafficFilter::~HTTPTrafficFilter() {
+
+}
+
+}
diff --git a/Swiften/Network/HTTPTrafficFilter.h b/Swiften/Network/HTTPTrafficFilter.h
new file mode 100644
index 0000000..da96c96
--- /dev/null
+++ b/Swiften/Network/HTTPTrafficFilter.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <vector>
+#include <string>
+#include <utility>
+
+#include <boost/optional.hpp>
+
+#include <Swiften/Base/API.h>
+
+namespace Swift {
+
+class SWIFTEN_API HTTPTrafficFilter {
+ public:
+ virtual ~HTTPTrafficFilter();
+ /**
+ * @brief This method is called by the HTTPConnectPRoxiedConnection on every incoming HTTP response.
+ * It can be used to insert additional HTTP requests into the HTTP CONNECT proxy initalization process.
+ * @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;
+};
+
+}
diff --git a/Swiften/Network/SConscript b/Swiften/Network/SConscript
index 284c1f4..c1f5c19 100644
--- a/Swiften/Network/SConscript
+++ b/Swiften/Network/SConscript
@@ -25,9 +25,9 @@ sourceList = [
"ConnectionServerFactory.cpp",
"DummyConnection.cpp",
"FakeConnection.cpp",
- "ChainedConnector.cpp",
- "Connector.cpp",
- "Connection.cpp",
+ "ChainedConnector.cpp",
+ "Connector.cpp",
+ "Connection.cpp",
"TimerFactory.cpp",
"DummyTimerFactory.cpp",
"BoostTimerFactory.cpp",
@@ -53,6 +53,7 @@ sourceList = [
"NATTraversalForwardPortRequest.cpp",
"NATTraversalRemovePortForwardingRequest.cpp",
"NATTraversalInterface.cpp",
+ "HTTPTrafficFilter.cpp",
]
if myenv.get("unbound", False) :
diff --git a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp
index 7b9a5e6..fb6914e 100644
--- a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp
+++ b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -17,13 +17,33 @@
#include <Swiften/Network/Connection.h>
#include <Swiften/Network/ConnectionFactory.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;
+namespace {
+ class ExampleHTTPTrafficFilter : public HTTPTrafficFilter {
+ public:
+ ExampleHTTPTrafficFilter() {}
+ virtual ~ExampleHTTPTrafficFilter() {}
+
+ virtual std::vector<std::pair<std::string, std::string> > filterHTTPResponseHeader(const std::vector<std::pair<std::string, std::string> >& response) {
+ filterResponses.push_back(response);
+ SWIFT_LOG(debug) << std::endl;
+ return filterResponseReturn;
+ }
+
+ std::vector<std::vector<std::pair<std::string, std::string> > > filterResponses;
+
+ std::vector<std::pair<std::string, std::string> > filterResponseReturn;
+ };
+}
+
class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(HTTPConnectProxiedConnectionTest);
CPPUNIT_TEST(testConnect_CreatesConnectionToProxy);
@@ -35,6 +55,7 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testWrite_AfterConnect);
CPPUNIT_TEST(testDisconnect_AfterConnectRequest);
CPPUNIT_TEST(testDisconnect_AfterConnect);
+ CPPUNIT_TEST(testTrafficFilter);
CPPUNIT_TEST_SUITE_END();
public:
@@ -168,6 +189,43 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT(!disconnectedError);
}
+ void testTrafficFilter() {
+ HTTPConnectProxiedConnection::ref testling(createTestling());
+
+ boost::shared_ptr<ExampleHTTPTrafficFilter> httpTrafficFilter = boost::make_shared<ExampleHTTPTrafficFilter>();
+
+ testling->setHTTPTrafficFilter(httpTrafficFilter);
+ connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345));
+
+ // set a default response so the server response is answered by the traffic filter
+ httpTrafficFilter->filterResponseReturn.clear();
+ httpTrafficFilter->filterResponseReturn.push_back(std::pair<std::string, std::string>("Authorization", "Negotiate a87421000492aa874209af8bc028"));
+
+ connectionFactory->connections[0]->dataWritten.clear();
+
+ connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef(
+ "HTTP/1.0 401 Unauthorized\r\n"
+ "WWW-Authenticate: Negotiate\r\n"
+ "\r\n"));
+ eventLoop->processEvents();
+
+ // verify that the traffic filter got called and answered with its response
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), httpTrafficFilter->filterResponses.size());
+ CPPUNIT_ASSERT_EQUAL(std::string("WWW-Authenticate"), httpTrafficFilter->filterResponses[0][0].first);
+
+ // remove the default response from the traffic filter
+ httpTrafficFilter->filterResponseReturn.clear();
+ 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);
+
+ // verify that after without the default response, the traffic filter is skipped, authentication proceeds and traffic goes right through
+ connectionFactory->connections[0]->dataWritten.clear();
+ testling->write(createSafeByteArray("abcdef"));
+ CPPUNIT_ASSERT_EQUAL(createByteArray("abcdef"), connectionFactory->connections[0]->dataWritten);
+ }
+
private:
HTTPConnectProxiedConnection::ref createTestling() {
boost::shared_ptr<HTTPConnectProxiedConnection> c = HTTPConnectProxiedConnection::create(resolver, connectionFactory, timerFactory, proxyHost, proxyPort, "", "");