summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2015-03-17 12:55:12 (GMT)
committerKevin Smith <kevin.smith@isode.com>2015-03-19 18:44:21 (GMT)
commitcd193389d65c4abd51c557f942348f36356f4788 (patch)
tree77f6fea1542cc1f9dba6c299f74dc3bfbe0b1dde
parentfedd8d88befb0fa19a58a78a163c200889b5272c (diff)
downloadswift-cd193389d65c4abd51c557f942348f36356f4788.zip
swift-cd193389d65c4abd51c557f942348f36356f4788.tar.bz2
Fix for HTTPConnectProxiedConnection to support responses in pieces
This fix lets HTTPConnectProxiedConnection buffer response data in pieces until the end of the HTTP header is reached. Only then it will try to parse the HTTP header. This is *not* the HTTP chunked transfer encoding. Test-Information: Adjusted one test to respond in pieces and added a new test case that verifies that response data is buffered. Change-Id: Icfb987bdf2fc5771401a8a9c6979fa9ad1eebdca
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnection.cpp17
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnection.h3
-rw-r--r--Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp22
3 files changed, 35 insertions, 7 deletions
diff --git a/Swiften/Network/HTTPConnectProxiedConnection.cpp b/Swiften/Network/HTTPConnectProxiedConnection.cpp
index fc5a6c6..942361e 100644
--- a/Swiften/Network/HTTPConnectProxiedConnection.cpp
+++ b/Swiften/Network/HTTPConnectProxiedConnection.cpp
@@ -80,13 +80,13 @@ void HTTPConnectProxiedConnection::parseHTTPHeader(const std::string& data, std:
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) {
+void HTTPConnectProxiedConnection::sendHTTPRequest(const std::string& statusLine, const 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";
@@ -95,27 +95,33 @@ void HTTPConnectProxiedConnection::sendHTTPRequest(const std::string& statusLine
write(createSafeByteArray(request.str()));
}
void HTTPConnectProxiedConnection::handleProxyInitializeData(boost::shared_ptr<SafeByteArray> data) {
std::string dataString = byteArrayToString(ByteArray(data->begin(), data->end()));
SWIFT_LOG(debug) << data << std::endl;
+ httpResponseBuffer_.append(dataString);
std::string statusLine;
std::vector<std::pair<std::string, std::string> > headerFields;
- std::string::size_type headerEnd = dataString.find("\r\n\r\n", 0);
+ std::string::size_type headerEnd = httpResponseBuffer_.find("\r\n\r\n", 0);
+ if (headerEnd == std::string::npos) {
+ if ((httpResponseBuffer_.size() > 4) && (httpResponseBuffer_.substr(0, 4) != "HTTP")) {
+ setProxyInitializeFinished(false);
+ }
+ return;
+ }
- parseHTTPHeader(dataString.substr(0, headerEnd), statusLine, headerFields);
+ parseHTTPHeader(httpResponseBuffer_.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) {
@@ -123,19 +129,20 @@ void HTTPConnectProxiedConnection::handleProxyInitializeData(boost::shared_ptr<S
int status = boost::lexical_cast<int>(tmp[1]);
SWIFT_LOG(debug) << "Proxy Status: " << status << std::endl;
if (status / 100 == 2) { // all 2XX states are OK
setProxyInitializeFinished(true);
}
else {
- SWIFT_LOG(debug) << "HTTP Proxy returned an error: " << byteArrayToString(ByteArray(data->begin(), data->end())) << std::endl;
+ SWIFT_LOG(debug) << "HTTP Proxy returned an error: " << httpResponseBuffer_ << std::endl;
setProxyInitializeFinished(false);
}
}
catch (boost::bad_lexical_cast&) {
SWIFT_LOG(warning) << "Unexpected response: " << tmp[1] << std::endl;
setProxyInitializeFinished(false);
}
}
else {
setProxyInitializeFinished(false);
}
+ httpResponseBuffer_.clear();
}
diff --git a/Swiften/Network/HTTPConnectProxiedConnection.h b/Swiften/Network/HTTPConnectProxiedConnection.h
index 7d83863..11431bf 100644
--- a/Swiften/Network/HTTPConnectProxiedConnection.h
+++ b/Swiften/Network/HTTPConnectProxiedConnection.h
@@ -38,15 +38,16 @@ namespace Swift {
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 sendHTTPRequest(const std::string& statusLine, const 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_;
+ std::string httpResponseBuffer_;
};
}
diff --git a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp
index fb6914e..d3db79d 100644
--- a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp
+++ b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp
@@ -46,12 +46,13 @@ namespace {
class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(HTTPConnectProxiedConnectionTest);
CPPUNIT_TEST(testConnect_CreatesConnectionToProxy);
CPPUNIT_TEST(testConnect_SendsConnectRequest);
CPPUNIT_TEST(testConnect_ReceiveConnectResponse);
+ CPPUNIT_TEST(testConnect_ReceiveConnectChunkedResponse);
CPPUNIT_TEST(testConnect_ReceiveMalformedConnectResponse);
CPPUNIT_TEST(testConnect_ReceiveErrorConnectResponse);
CPPUNIT_TEST(testConnect_ReceiveDataAfterConnect);
CPPUNIT_TEST(testWrite_AfterConnect);
CPPUNIT_TEST(testDisconnect_AfterConnectRequest);
CPPUNIT_TEST(testDisconnect_AfterConnect);
@@ -115,12 +116,27 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT(connectFinished);
CPPUNIT_ASSERT(!connectFinishedWithError);
CPPUNIT_ASSERT(dataRead.empty());
}
+ void testConnect_ReceiveConnectChunkedResponse() {
+ HTTPConnectProxiedConnection::ref testling(createTestling());
+ connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345));
+
+ connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 "));
+ eventLoop->processEvents();
+ connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("200 Connection established\r\n\r\n"));
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT(connectFinished);
+ CPPUNIT_ASSERT(!connectFinishedWithError);
+ CPPUNIT_ASSERT(dataRead.empty());
+ }
+
+
void testConnect_ReceiveMalformedConnectResponse() {
HTTPConnectProxiedConnection::ref testling(createTestling());
connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345));
connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("FLOOP"));
eventLoop->processEvents();
@@ -200,18 +216,22 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture {
// 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();
+ // test chunked response
+ connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef(
+ "HTTP/1.0 401 Unauthorized\r\n"));
+ eventLoop->processEvents();
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();