2019-05-21 20:54:12 -05:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
|
|
|
/*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <cassert>
|
|
|
|
|
|
|
|
#include <helpers.hpp>
|
|
|
|
#include <Poco/Util/Application.h>
|
2019-05-22 04:54:36 -05:00
|
|
|
#include <Poco/Net/StreamSocket.h>
|
2019-05-21 20:54:12 -05:00
|
|
|
#include <Poco/Net/StringPartSource.h>
|
|
|
|
#include <Poco/Net/HTMLForm.h>
|
|
|
|
#include <Poco/Net/HTTPRequest.h>
|
|
|
|
#include <Poco/Net/HTTPResponse.h>
|
|
|
|
#include <Poco/Net/HTTPSClientSession.h>
|
2019-07-08 11:20:19 -05:00
|
|
|
#include <Poco/StreamCopier.h>
|
2019-05-21 20:54:12 -05:00
|
|
|
|
|
|
|
#include <Log.hpp>
|
|
|
|
#include <Util.hpp>
|
|
|
|
#include <Unit.hpp>
|
|
|
|
|
|
|
|
class UnitHTTP : public UnitWSD
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
UnitHTTP()
|
2021-04-07 09:50:06 -05:00
|
|
|
: UnitWSD("UnitHTTP")
|
2019-05-21 20:54:12 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void configure(Poco::Util::LayeredConfiguration& config) override
|
|
|
|
{
|
|
|
|
UnitWSD::configure(config);
|
|
|
|
// force HTTPS - to test harder
|
|
|
|
config.setBool("ssl.enable", true);
|
|
|
|
}
|
|
|
|
|
2019-05-22 04:54:36 -05:00
|
|
|
void testContinue()
|
2019-05-21 20:54:12 -05:00
|
|
|
{
|
2020-05-24 08:10:18 -05:00
|
|
|
//FIXME: use logging
|
2021-04-07 09:50:06 -05:00
|
|
|
LOG_TST("testContinue");
|
2019-05-21 20:54:12 -05:00
|
|
|
for (int i = 0; i < 3; ++i)
|
|
|
|
{
|
|
|
|
std::unique_ptr<Poco::Net::HTTPClientSession> session(helpers::createSession(Poco::URI(helpers::getTestServerURI())));
|
|
|
|
|
|
|
|
std::string sent = "Hello world test\n";
|
|
|
|
|
2021-11-15 09:41:58 -06:00
|
|
|
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/cool/convert-to/txt");
|
2019-05-21 20:54:12 -05:00
|
|
|
|
|
|
|
switch(i)
|
|
|
|
{
|
|
|
|
case 0:
|
2019-07-08 11:20:19 -05:00
|
|
|
request.erase("Expect");
|
2019-05-21 20:54:12 -05:00
|
|
|
break;
|
|
|
|
case 1:
|
2019-07-08 11:20:19 -05:00
|
|
|
request.set("Expect", "100-continue");
|
2019-05-21 20:54:12 -05:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Poco::Net::HTMLForm form;
|
|
|
|
form.setEncoding(Poco::Net::HTMLForm::ENCODING_MULTIPART);
|
|
|
|
form.set("format", "txt");
|
|
|
|
form.addPart("data", new Poco::Net::StringPartSource(sent, "text/plain", "foobaa.txt"));
|
|
|
|
form.prepareSubmit(request);
|
|
|
|
form.write(session->sendRequest(request));
|
|
|
|
|
|
|
|
Poco::Net::HTTPResponse response;
|
|
|
|
std::stringstream actualStream;
|
|
|
|
std::istream& responseStream = session->receiveResponse(response);
|
|
|
|
Poco::StreamCopier::copyStream(responseStream, actualStream);
|
|
|
|
|
|
|
|
std::string responseStr = actualStream.str();
|
|
|
|
responseStr.erase(0,3); // remove utf-8 bom.
|
|
|
|
|
|
|
|
if (sent != responseStr)
|
|
|
|
{
|
2021-04-07 09:50:06 -05:00
|
|
|
LOG_TST("Test " << i << " failed - mismatching string '" << responseStr << " vs. '"
|
|
|
|
<< sent << "'");
|
2019-05-21 20:54:12 -05:00
|
|
|
exitTest(TestResult::Failed);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2019-05-22 04:54:36 -05:00
|
|
|
}
|
|
|
|
|
2019-06-06 02:46:53 -05:00
|
|
|
void writeString(const std::shared_ptr<Poco::Net::StreamSocket> &socket, const std::string& str)
|
2019-05-22 04:54:36 -05:00
|
|
|
{
|
2021-04-09 10:50:41 -05:00
|
|
|
LOG_TST("Sending " << str.size() << " bytes:\n" << str);
|
2019-05-22 04:54:36 -05:00
|
|
|
socket->sendBytes(str.c_str(), str.size());
|
|
|
|
}
|
|
|
|
|
2019-06-13 01:44:05 -05:00
|
|
|
bool expectString(const std::shared_ptr<Poco::Net::StreamSocket> &socket, const std::string& str)
|
2019-05-22 04:54:36 -05:00
|
|
|
{
|
2021-04-09 10:50:41 -05:00
|
|
|
LOG_TST("Expecting " << str.size() << " bytes:\n" << str);
|
|
|
|
|
2019-11-25 01:28:03 -06:00
|
|
|
std::vector<char> buffer(str.size() + 64);
|
2019-11-17 07:46:19 -06:00
|
|
|
const int got = socket->receiveBytes(buffer.data(), str.size());
|
2020-01-20 10:45:53 -06:00
|
|
|
LOK_ASSERT_EQUAL(str, std::string(buffer.data(), got));
|
2019-11-17 07:46:19 -06:00
|
|
|
|
2019-05-22 04:54:36 -05:00
|
|
|
if (got != (int)str.size() ||
|
2019-11-25 01:28:03 -06:00
|
|
|
strncmp(buffer.data(), str.c_str(), got))
|
2019-05-22 04:54:36 -05:00
|
|
|
{
|
2021-04-07 09:50:06 -05:00
|
|
|
LOG_TST("testChunks got " << got << " mismatching strings '" << buffer.data()
|
|
|
|
<< " vs. expected '" << str << "'");
|
2019-05-22 04:54:36 -05:00
|
|
|
exitTest(TestResult::Failed);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void testChunks()
|
|
|
|
{
|
2021-04-07 09:50:06 -05:00
|
|
|
LOG_TST("testChunks");
|
2019-05-22 04:54:36 -05:00
|
|
|
|
|
|
|
std::shared_ptr<Poco::Net::StreamSocket> socket = helpers::createRawSocket();
|
|
|
|
|
|
|
|
writeString(
|
|
|
|
socket,
|
2021-11-15 09:41:58 -06:00
|
|
|
"POST /cool/convert-to/txt HTTP/1.1\r\n"
|
2019-05-22 04:54:36 -05:00
|
|
|
"Host: localhost:9980\r\n"
|
2021-11-18 06:08:14 -06:00
|
|
|
"User-Agent: cooltests/1.2.3\r\n"
|
2019-05-22 04:54:36 -05:00
|
|
|
"Accept: */*\r\n"
|
|
|
|
"Expect: 100-continue\r\n"
|
|
|
|
"Transfer-Encoding: chunked\r\n"
|
|
|
|
"Content-Type: multipart/form-data; "
|
|
|
|
"boundary=------------------------5a0cd5c881663db4\r\n\r\n");
|
|
|
|
if (!expectString(
|
|
|
|
socket,
|
|
|
|
"HTTP/1.1 100 Continue\r\n\r\n"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
#define START_CHUNK_HEX(len) len "\r\n"
|
|
|
|
#define END_CHUNK "\r\n"
|
|
|
|
writeString(
|
|
|
|
socket,
|
|
|
|
START_CHUNK_HEX("8A")
|
|
|
|
"--------------------------5a0cd5c881663db4\r\n"
|
|
|
|
"Content-Disposition: form-data; name=\"data\"; filename=\"test.txt\"\r\n"
|
|
|
|
"Content-Type: text/plain\r\n"
|
|
|
|
"\r\n"
|
|
|
|
END_CHUNK
|
|
|
|
|
|
|
|
START_CHUNK_HEX("12")
|
|
|
|
"This is some text."
|
|
|
|
END_CHUNK
|
|
|
|
|
|
|
|
START_CHUNK_HEX("1")
|
|
|
|
"\n"
|
|
|
|
END_CHUNK
|
|
|
|
|
2019-10-08 04:23:29 -05:00
|
|
|
" 4 room:for expansion!! cf. leading spaces and nasties <>!\"\'?=)\r\n"
|
2019-05-22 04:54:36 -05:00
|
|
|
"And "
|
|
|
|
END_CHUNK
|
|
|
|
|
|
|
|
START_CHUNK_HEX("1")
|
|
|
|
"s"
|
|
|
|
END_CHUNK
|
|
|
|
|
|
|
|
START_CHUNK_HEX("a")
|
|
|
|
"ome more.\n"
|
|
|
|
END_CHUNK
|
|
|
|
);
|
|
|
|
writeString(
|
|
|
|
socket,
|
|
|
|
START_CHUNK_HEX("30")
|
|
|
|
"\r\n"
|
|
|
|
"--------------------------5a0cd5c881663db4--\r\n"
|
|
|
|
END_CHUNK);
|
|
|
|
|
|
|
|
writeString(socket, START_CHUNK_HEX("0"));
|
|
|
|
|
2021-04-09 10:50:41 -05:00
|
|
|
LOG_TST("Receiving...");
|
2019-05-22 04:54:36 -05:00
|
|
|
char buffer[4096] = { 0, };
|
|
|
|
int got = socket->receiveBytes(buffer, 4096);
|
2019-11-17 07:46:19 -06:00
|
|
|
static const std::string start =
|
2019-05-22 04:54:36 -05:00
|
|
|
"HTTP/1.0 200 OK\r\n"
|
|
|
|
"Content-Disposition: attachment; filename=\"test.txt\"\r\n";
|
|
|
|
|
|
|
|
if (strncmp(buffer, start.c_str(), start.size()))
|
|
|
|
{
|
2021-04-07 09:50:06 -05:00
|
|
|
LOG_TST("missing pre-amble " << got << " [" << buffer << "] vs. expected [" << start
|
|
|
|
<< ']');
|
|
|
|
LOK_ASSERT(Util::startsWith(std::string(buffer), start));
|
2019-05-22 04:54:36 -05:00
|
|
|
exitTest(TestResult::Failed);
|
|
|
|
return;
|
|
|
|
}
|
2019-05-21 20:54:12 -05:00
|
|
|
|
2019-05-22 04:54:36 -05:00
|
|
|
// TODO: check content-length etc.
|
|
|
|
|
|
|
|
const char *ptr = strstr(buffer, "\r\n\r\n");
|
2020-01-20 10:45:53 -06:00
|
|
|
LOK_ASSERT_MESSAGE("Missing separator, got " + std::string(buffer), ptr);
|
2019-05-22 04:54:36 -05:00
|
|
|
if (!ptr)
|
|
|
|
{
|
2021-04-07 09:50:06 -05:00
|
|
|
LOG_TST("missing separator " << got << " '" << buffer);
|
2019-05-22 04:54:36 -05:00
|
|
|
exitTest(TestResult::Failed);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-26 15:55:16 -05:00
|
|
|
// Sometimes we get the content with the first receive.
|
2020-02-24 07:58:22 -06:00
|
|
|
if (strstr(buffer, "\357\273\277This is some text.\nAnd some more.\n"))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-22 04:54:36 -05:00
|
|
|
// Oddly we need another read to get the content.
|
2021-04-09 10:50:41 -05:00
|
|
|
LOG_TST("Receiving...");
|
2019-05-22 04:54:36 -05:00
|
|
|
got = socket->receiveBytes(buffer, 4096);
|
2020-01-20 10:45:53 -06:00
|
|
|
LOK_ASSERT_MESSAGE("No content returned.", got >= 0);
|
2019-05-22 04:54:36 -05:00
|
|
|
if (got >=0 )
|
|
|
|
buffer[got] = '\0';
|
|
|
|
else
|
|
|
|
{
|
2021-04-07 09:50:06 -05:00
|
|
|
LOG_TST("No content returned " << got);
|
2019-05-22 04:54:36 -05:00
|
|
|
exitTest(TestResult::Failed);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(buffer, "\357\273\277This is some text.\nAnd some more.\n"))
|
|
|
|
{
|
2021-04-07 09:50:06 -05:00
|
|
|
LOG_TST("unexpected file content " << got << " '" << buffer);
|
2019-05-22 04:54:36 -05:00
|
|
|
exitTest(TestResult::Failed);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-24 11:15:37 -06:00
|
|
|
void invokeWSDTest() override
|
2019-05-22 04:54:36 -05:00
|
|
|
{
|
|
|
|
testChunks();
|
|
|
|
testContinue();
|
2021-04-07 09:50:06 -05:00
|
|
|
LOG_TST("All tests passed.");
|
2019-05-21 20:54:12 -05:00
|
|
|
exitTest(TestResult::Ok);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
UnitBase *unit_create_wsd(void)
|
|
|
|
{
|
|
|
|
return new UnitHTTP();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|