summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swiften/Network/Connection.cpp15
-rw-r--r--Swiften/Network/Connection.h4
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnection.cpp30
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnection.h5
-rw-r--r--Swiften/Network/SConscript1
-rw-r--r--Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp244
-rw-r--r--Swiften/SConscript1
7 files changed, 275 insertions, 25 deletions
diff --git a/Swiften/Network/Connection.cpp b/Swiften/Network/Connection.cpp
new file mode 100644
index 0000000..9bb29e1
--- /dev/null
+++ b/Swiften/Network/Connection.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Network/Connection.h>
+
+using namespace Swift;
+
+Connection::Connection() {
+}
+
+Connection::~Connection() {
+}
diff --git a/Swiften/Network/Connection.h b/Swiften/Network/Connection.h
index fdbbef6..74d25aa 100644
--- a/Swiften/Network/Connection.h
+++ b/Swiften/Network/Connection.h
@@ -23,8 +23,8 @@ namespace Swift {
WriteError
};
- Connection() {}
- virtual ~Connection() {}
+ Connection();
+ virtual ~Connection();
virtual void listen() = 0;
virtual void connect(const HostAddressPort& address) = 0;
diff --git a/Swiften/Network/HTTPConnectProxiedConnection.cpp b/Swiften/Network/HTTPConnectProxiedConnection.cpp
index 2e90b52..51130e5 100644
--- a/Swiften/Network/HTTPConnectProxiedConnection.cpp
+++ b/Swiften/Network/HTTPConnectProxiedConnection.cpp
@@ -64,7 +64,6 @@ void HTTPConnectProxiedConnection::write(const ByteArray& data) {
void HTTPConnectProxiedConnection::handleConnectionConnectFinished(bool error) {
connection_->onConnectFinished.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1));
if (!error) {
- proxyState_ = ProxyConnecting;
std::stringstream connect;
connect << "CONNECT " << server_.getAddress().toString() << ":" << server_.getPort() << " HTTP/1.1\r\n\r\n";
connection_->write(ByteArray(connect.str()));
@@ -76,29 +75,24 @@ void HTTPConnectProxiedConnection::handleConnectionConnectFinished(bool error) {
void HTTPConnectProxiedConnection::handleDataRead(const ByteArray& data) {
if (!connected_) {
- if (proxyState_ == ProxyConnecting) {
- SWIFT_LOG(debug) << data.toString() << std::endl;
- std::vector<std::string> tmp = String::split(data.toString(), ' ');
- if(tmp.size() > 1) {
- int status = boost::lexical_cast<int> (tmp[1].c_str());
- SWIFT_LOG(debug) << "Proxy Status: " << status << std::endl;
- if (status / 100 == 2) { // all 2XX states are OK
- connected_ = true;
- onConnectFinished(false);
- return;
- }
+ SWIFT_LOG(debug) << data.toString() << std::endl;
+ std::vector<std::string> tmp = String::split(data.toString(), ' ');
+ if(tmp.size() > 1) {
+ int status = boost::lexical_cast<int> (tmp[1].c_str());
+ SWIFT_LOG(debug) << "Proxy Status: " << status << std::endl;
+ if (status / 100 == 2) { // all 2XX states are OK
+ connected_ = true;
+ onConnectFinished(false);
+ return;
}
-
- std::cerr << "HTTP Proxy returned an error: " << data.toString() << std::endl;
- return;
+ SWIFT_LOG(debug) << "HTTP Proxy returned an error: " << data.toString() << std::endl;
}
+ disconnect();
+ onConnectFinished(true);
}
else {
onDataRead(data);
- return;
}
- disconnect();
- onConnectFinished(true);
}
HostAddressPort HTTPConnectProxiedConnection::getLocalAddress() const {
diff --git a/Swiften/Network/HTTPConnectProxiedConnection.h b/Swiften/Network/HTTPConnectProxiedConnection.h
index 232f4eb..930f5e1 100644
--- a/Swiften/Network/HTTPConnectProxiedConnection.h
+++ b/Swiften/Network/HTTPConnectProxiedConnection.h
@@ -38,11 +38,6 @@ namespace Swift {
virtual HostAddressPort getLocalAddress() const;
private:
- enum {
- ProxyAuthenticating = 0,
- ProxyConnecting,
- } proxyState_;
-
HTTPConnectProxiedConnection(ConnectionFactory* connectionFactory, HostAddressPort proxy);
void handleConnectionConnectFinished(bool error);
diff --git a/Swiften/Network/SConscript b/Swiften/Network/SConscript
index 61eb69a..ecfc66a 100644
--- a/Swiften/Network/SConscript
+++ b/Swiften/Network/SConscript
@@ -20,6 +20,7 @@ sourceList = [
"FakeConnection.cpp",
"ChainedConnector.cpp",
"Connector.cpp",
+ "Connection.cpp",
"TimerFactory.cpp",
"DummyTimerFactory.cpp",
"BoostTimerFactory.cpp",
diff --git a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp
new file mode 100644
index 0000000..6c4c89c
--- /dev/null
+++ b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#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/Network/Connection.h>
+#include <Swiften/Network/ConnectionFactory.h>
+#include <Swiften/Network/HTTPConnectProxiedConnection.h>
+#include <Swiften/Network/HostAddressPort.h>
+#include <Swiften/EventLoop/DummyEventLoop.h>
+
+using namespace Swift;
+
+class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(HTTPConnectProxiedConnectionTest);
+ CPPUNIT_TEST(testConnect_CreatesConnectionToProxy);
+ CPPUNIT_TEST(testConnect_SendsConnectRequest);
+ CPPUNIT_TEST(testConnect_ReceiveConnectResponse);
+ CPPUNIT_TEST(testConnect_ReceiveMalformedConnectResponse);
+ CPPUNIT_TEST(testConnect_ReceiveErrorConnectResponse);
+ CPPUNIT_TEST(testConnect_ReceiveDataAfterConnect);
+ CPPUNIT_TEST(testWrite_AfterConnect);
+ CPPUNIT_TEST(testDisconnect_AfterConnectRequest);
+ CPPUNIT_TEST(testDisconnect_AfterConnect);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ proxyHost = HostAddressPort(HostAddress("1.1.1.1"), 1234);
+ host = HostAddressPort(HostAddress("2.2.2.2"), 2345);
+ eventLoop = new DummyEventLoop();
+ connectionFactory = new MockConnectionFactory(eventLoop);
+ connectFinished = false;
+ disconnected = false;
+ }
+
+ void tearDown() {
+ delete connectionFactory;
+ delete eventLoop;
+ }
+
+ void testConnect_CreatesConnectionToProxy() {
+ HTTPConnectProxiedConnection::ref testling(createTestling());
+
+ testling->connect(host);
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connectionFactory->connections.size()));
+ CPPUNIT_ASSERT(connectionFactory->connections[0]->hostAddressPort);
+ CPPUNIT_ASSERT(proxyHost == *connectionFactory->connections[0]->hostAddressPort);
+ CPPUNIT_ASSERT(!connectFinished);
+ }
+
+ void testConnect_SendsConnectRequest() {
+ HTTPConnectProxiedConnection::ref testling(createTestling());
+
+ testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345));
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT_EQUAL(ByteArray("CONNECT 2.2.2.2:2345 HTTP/1.1\r\n\r\n"), connectionFactory->connections[0]->dataWritten);
+ }
+
+ void testConnect_ReceiveConnectResponse() {
+ HTTPConnectProxiedConnection::ref testling(createTestling());
+ testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345));
+ eventLoop->processEvents();
+
+ connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 200 Connection established\r\n\r\n"));
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT(connectFinished);
+ CPPUNIT_ASSERT(!connectFinishedWithError);
+ CPPUNIT_ASSERT(dataRead.isEmpty());
+ }
+
+ void testConnect_ReceiveMalformedConnectResponse() {
+ HTTPConnectProxiedConnection::ref testling(createTestling());
+ testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345));
+ eventLoop->processEvents();
+
+ connectionFactory->connections[0]->onDataRead(ByteArray("FLOOP"));
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT(connectFinished);
+ CPPUNIT_ASSERT(connectFinishedWithError);
+ CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected);
+ }
+
+ void testConnect_ReceiveErrorConnectResponse() {
+ HTTPConnectProxiedConnection::ref testling(createTestling());
+ testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345));
+ eventLoop->processEvents();
+
+ connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 401 Unauthorized\r\n\r\n"));
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT(connectFinished);
+ CPPUNIT_ASSERT(connectFinishedWithError);
+ CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected);
+ }
+
+ void testConnect_ReceiveDataAfterConnect() {
+ HTTPConnectProxiedConnection::ref testling(createTestling());
+ testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345));
+ eventLoop->processEvents();
+ connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 200 Connection established\r\n\r\n"));
+ eventLoop->processEvents();
+
+ connectionFactory->connections[0]->onDataRead(ByteArray("abcdef"));
+
+ CPPUNIT_ASSERT_EQUAL(ByteArray("abcdef"), dataRead);
+ }
+
+ void testWrite_AfterConnect() {
+ HTTPConnectProxiedConnection::ref testling(createTestling());
+ testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345));
+ eventLoop->processEvents();
+ connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 200 Connection established\r\n\r\n"));
+ eventLoop->processEvents();
+ connectionFactory->connections[0]->dataWritten.clear();
+
+ testling->write(ByteArray("abcdef"));
+
+ CPPUNIT_ASSERT_EQUAL(ByteArray("abcdef"), connectionFactory->connections[0]->dataWritten);
+ }
+
+ void testDisconnect_AfterConnectRequest() {
+ HTTPConnectProxiedConnection::ref testling(createTestling());
+ testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345));
+ eventLoop->processEvents();
+
+ testling->disconnect();
+
+ CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected);
+ CPPUNIT_ASSERT(disconnected);
+ CPPUNIT_ASSERT(!disconnectedError);
+ }
+
+ void testDisconnect_AfterConnect() {
+ HTTPConnectProxiedConnection::ref testling(createTestling());
+ testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345));
+ eventLoop->processEvents();
+ connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 200 Connection established\r\n\r\n"));
+ eventLoop->processEvents();
+
+ testling->disconnect();
+
+ CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected);
+ CPPUNIT_ASSERT(disconnected);
+ CPPUNIT_ASSERT(!disconnectedError);
+ }
+
+ private:
+ HTTPConnectProxiedConnection::ref createTestling() {
+ boost::shared_ptr<HTTPConnectProxiedConnection> c = HTTPConnectProxiedConnection::create(connectionFactory, proxyHost);
+ c->onConnectFinished.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleConnectFinished, this, _1));
+ c->onDisconnected.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleDisconnected, this, _1));
+ c->onDataRead.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleDataRead, this, _1));
+ return c;
+ }
+
+ void handleConnectFinished(bool error) {
+ connectFinished = true;
+ connectFinishedWithError = error;
+ }
+
+ void handleDisconnected(const boost::optional<Connection::Error>& e) {
+ disconnected = true;
+ disconnectedError = e;
+ }
+
+ void handleDataRead(const ByteArray& d) {
+ dataRead += d;
+ }
+
+ struct MockConnection : public Connection {
+ public:
+ MockConnection(const std::vector<HostAddressPort>& failingPorts, EventLoop* eventLoop) : eventLoop(eventLoop), failingPorts(failingPorts), disconnected(false) {
+ }
+
+ void listen() { assert(false); }
+
+ void connect(const HostAddressPort& address) {
+ hostAddressPort = address;
+ bool fail = std::find(failingPorts.begin(), failingPorts.end(), address) != failingPorts.end();
+ eventLoop->postEvent(boost::bind(boost::ref(onConnectFinished), fail));
+ }
+
+ HostAddressPort getLocalAddress() const { return HostAddressPort(); }
+
+ void disconnect() {
+ disconnected = true;
+ onDisconnected(boost::optional<Connection::Error>());
+ }
+
+ void write(const ByteArray& d) {
+ dataWritten += d;
+ }
+
+ EventLoop* eventLoop;
+ boost::optional<HostAddressPort> hostAddressPort;
+ std::vector<HostAddressPort> failingPorts;
+ ByteArray dataWritten;
+ bool disconnected;
+ };
+
+ struct MockConnectionFactory : public ConnectionFactory {
+ MockConnectionFactory(EventLoop* eventLoop) : eventLoop(eventLoop) {
+ }
+
+ boost::shared_ptr<Connection> createConnection() {
+ boost::shared_ptr<MockConnection> connection = boost::make_shared<MockConnection>(failingPorts, eventLoop);
+ connections.push_back(connection);
+ return connection;
+ }
+
+ EventLoop* eventLoop;
+ std::vector< boost::shared_ptr<MockConnection> > connections;
+ std::vector<HostAddressPort> failingPorts;
+ };
+
+ private:
+ HostAddressPort proxyHost;
+ HostAddressPort host;
+ DummyEventLoop* eventLoop;
+ MockConnectionFactory* connectionFactory;
+ std::vector< boost::shared_ptr<MockConnection> > connections;
+ bool connectFinished;
+ bool connectFinishedWithError;
+ bool disconnected;
+ boost::optional<Connection::Error> disconnectedError;
+ ByteArray dataRead;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(HTTPConnectProxiedConnectionTest);
diff --git a/Swiften/SConscript b/Swiften/SConscript
index 0a229e8..f207c62 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -232,6 +232,7 @@ if env["SCONS_STAGE"] == "build" :
File("Network/UnitTest/HostAddressTest.cpp"),
File("Network/UnitTest/ConnectorTest.cpp"),
File("Network/UnitTest/ChainedConnectorTest.cpp"),
+ File("Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp"),
File("Parser/PayloadParsers/UnitTest/BodyParserTest.cpp"),
File("Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp"),
File("Parser/PayloadParsers/UnitTest/ErrorParserTest.cpp"),