summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2015-03-16 11:56:22 (GMT)
committerTobias Markmann <tm@ayena.de>2015-03-16 11:56:22 (GMT)
commit1f072d6858f98e2717f50cffca4acb17e663267d (patch)
tree6f97e65f014b05bd18398da58e262d677eecd286 /Swiften/Network
parentcb9f7ecff59034e9678b1aca22b608b6e2522e1a (diff)
downloadswift-1f072d6858f98e2717f50cffca4acb17e663267d.zip
swift-1f072d6858f98e2717f50cffca4acb17e663267d.tar.bz2
Add ability to modify HTTP CONNECT proxy initialization
This patch adds HTTPTrafficFilter and integrates it into HTTPConnectProxiedConnection. This allows the HTTP CONNECT proxy initialization process to be customized. Test-Information: Added a unit test that verifies the new functionality. Change-Id: I0b93c319fb205487b8be65717276cd0dd38851a3
Diffstat (limited to 'Swiften/Network')
-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
8 files changed, 191 insertions, 15 deletions
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, "", "");