summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2019-01-04 00:22:29 +0000
committerDan Goodliffe <dan@randomdan.homeip.net>2019-01-04 00:22:29 +0000
commit063f343083b64760214d625d05889a04ee1cd8c3 (patch)
tree6f3efd1bf84cc0fa8ed435bb338cf1533014e8c3
parentTestability (diff)
downloadicespider-embedded-server.tar.bz2
icespider-embedded-server.tar.xz
icespider-embedded-server.zip
-rw-r--r--icespider/embedded/clientSocket.cpp65
-rw-r--r--icespider/embedded/clientSocket.h17
-rw-r--r--icespider/embedded/socketHandler.h6
-rw-r--r--icespider/unittests/testEmbedded.cpp52
4 files changed, 124 insertions, 16 deletions
diff --git a/icespider/embedded/clientSocket.cpp b/icespider/embedded/clientSocket.cpp
index 54aa7cb..900f5d0 100644
--- a/icespider/embedded/clientSocket.cpp
+++ b/icespider/embedded/clientSocket.cpp
@@ -5,13 +5,21 @@
#include <string.h>
#include <sys/socket.h>
#include <sys/epoll.h>
+#include <slicer/modelPartsTypes.h>
namespace IceSpider::Embedded {
static socklen_t clientlen = sizeof(struct sockaddr_in);
+ static const std::string_view crlf("\r\n");
+ static const std::string_view clnsp(": ");
ClientSocket::ClientSocket(int pfd) :
- SocketHandler(accept4(pfd, (struct sockaddr *) &clientaddr, &clientlen, SOCK_NONBLOCK)),
- buf(BUFSIZ),
+ ClientSocket(accept4(pfd, (struct sockaddr *) &clientaddr, &clientlen, SOCK_NONBLOCK), false)
+ {
+ }
+
+ ClientSocket::ClientSocket(int fd, bool) :
+ SocketHandler(fd),
+ buf(BUFSIZ, '\0'),
rec(0),
state(State::reading_headers)
{
@@ -40,13 +48,17 @@ namespace IceSpider::Embedded {
};
int r;
while ((r = readBytes()) > 0) {
- buf[rec + r] = 0;
- auto end = strstr(&buf.at(rec > 3 ? rec - 2 : 0), "\r\n");
- if (end) {
- auto w = ::write(fd, "HTTP/1.1 204 No content\r\n\r\n", 27);
- (void)w;
+ // Recommended ending
+ if (auto end = buf.find("\r\n\r\n", rec > 4 ? rec - 4 : 0, 4); end != std::string::npos) {
+ process_request(std::string_view(buf).substr(0, end));
+ rec = 0;
+ buf.erase(0, end + 3);
+ }
+ // Alternative ending
+ else if (auto end = buf.find("\r\r", rec > 1 ? rec - 2 : 0, 2); end != std::string::npos) {
+ process_request(std::string_view(buf).substr(0, end));
rec = 0;
- buf.erase(buf.begin(), buf.begin() + (end - &buf.front()));
+ buf.erase(0, end + 1);
}
else {
rec += r;
@@ -58,6 +70,43 @@ namespace IceSpider::Embedded {
return -1;
}
+ void ClientSocket::process_request(const std::string_view & hdrs)
+ {
+ parse_request(hdrs);
+ auto w = ::write(fd, "HTTP/1.1 204 No content\r\n\r\n", 27);
+ (void)w;
+ (void)hdrs;
+ }
+
+ void ClientSocket::parse_request(std::string_view hdrs)
+ {
+ auto consumeUpto = [&hdrs](auto endAt, auto skip) {
+ if (auto end = hdrs.find_first_of(endAt); end != std::string_view::npos) {
+ auto rtn = hdrs.substr(0, end);
+ if (auto skipTo = hdrs.find_first_not_of(skip, end); skipTo != std::string_view::npos) {
+ end = skipTo;
+ }
+ hdrs.remove_prefix(end);
+ return rtn;
+ }
+ else {
+ auto rtn = hdrs;
+ hdrs.remove_prefix(hdrs.length());
+ return rtn;
+ }
+ };
+ method = Slicer::ModelPartForEnum<::IceSpider::HttpMethod>::lookup(
+ //TODO: string copy
+ std::string(consumeUpto(' ', ' ')));
+ url = consumeUpto(' ', ' ');
+ version = consumeUpto(crlf, crlf);
+ while (!hdrs.empty()) {
+ auto n = consumeUpto(':', clnsp);
+ auto v = consumeUpto(crlf, crlf);
+ headers.insert_or_assign(n, v);
+ }
+ }
+
int ClientSocket::stream_input()
{
return 0;
diff --git a/icespider/embedded/clientSocket.h b/icespider/embedded/clientSocket.h
index 72449a0..b475eef 100644
--- a/icespider/embedded/clientSocket.h
+++ b/icespider/embedded/clientSocket.h
@@ -2,20 +2,24 @@
#define ICESPIDER_EMBEDDED_CLIENTSOCKET_H
#include "socketHandler.h"
-#include <vector>
+#include <string>
#include <netinet/in.h>
+#include <core.h>
namespace IceSpider::Embedded {
- class ClientSocket : public SocketHandler {
+ class DLL_PUBLIC ClientSocket : public SocketHandler {
public:
ClientSocket(int fd);
int read(Listener * listener) override;
int write(Listener * listener) override;
- private:
+ protected:
+ ClientSocket(int fd, bool unused);
inline int read_headers();
inline int stream_input();
+ void process_request(const std::string_view & hdrs);
+ void parse_request(std::string_view hdrs);
enum class State {
reading_headers,
@@ -23,9 +27,14 @@ namespace IceSpider::Embedded {
};
struct sockaddr_in clientaddr;
- std::vector<char> buf;
+ std::string buf;
std::size_t rec;
State state;
+
+ ::IceSpider::HttpMethod method;
+ std::string_view url, version;
+ typedef std::map<std::string_view, std::string_view> Headers;
+ Headers headers;
};
}
diff --git a/icespider/embedded/socketHandler.h b/icespider/embedded/socketHandler.h
index 1c3e2d8..e796275 100644
--- a/icespider/embedded/socketHandler.h
+++ b/icespider/embedded/socketHandler.h
@@ -1,13 +1,15 @@
#ifndef ICESPIDER_EMBEDDED_SOCKETHANDLER_H
#define ICESPIDER_EMBEDDED_SOCKETHANDLER_H
+#include <visibility.h>
+
namespace IceSpider::Embedded {
class Listener;
- class SocketHandler {
+ class DLL_PUBLIC SocketHandler {
public:
SocketHandler(int f);
- ~SocketHandler();
+ virtual ~SocketHandler();
virtual int read(Listener *) = 0;
virtual int write(Listener *) = 0;
diff --git a/icespider/unittests/testEmbedded.cpp b/icespider/unittests/testEmbedded.cpp
index e77b114..72f60f3 100644
--- a/icespider/unittests/testEmbedded.cpp
+++ b/icespider/unittests/testEmbedded.cpp
@@ -1,10 +1,14 @@
#define BOOST_TEST_MODULE TestEmbedded
-#include <boost/test/unit_test.hpp>
+#include <boost/test/included/unit_test.hpp>
#include <boost/filesystem/convenience.hpp>
#include <embedded.h>
+#include <clientSocket.h>
+#include <core.h>
#include <thread>
+BOOST_TEST_DONT_PRINT_LOG_VALUE(IceSpider::HttpMethod);
+
class EmbeddedIceSpiderInstance : public IceSpider::Embedded::Listener {
public:
EmbeddedIceSpiderInstance() :
@@ -51,6 +55,7 @@ BOOST_AUTO_TEST_CASE(startup_and_shutdown_cycle, * boost::unit_test::timeout(2))
BOOST_FIXTURE_TEST_SUITE(EmbeddedIceSpider, EmbeddedIceSpiderRunner);
BOOST_AUTO_TEST_CASE(simple_curl_test,
+ * boost::unit_test::disabled() // Not usually interested
* boost::unit_test::timeout(5))
{
BOOST_REQUIRE_EQUAL(0, system("curl -s http://localhost:18080/"));
@@ -58,6 +63,7 @@ BOOST_AUTO_TEST_CASE(simple_curl_test,
// Throw some requests at it, get a general performance overview
BOOST_AUTO_TEST_CASE(quick_siege_test,
+ * boost::unit_test::disabled() // Not usually interested
* boost::unit_test::timeout(5))
{
if (wrk_exists()) {
@@ -67,7 +73,7 @@ BOOST_AUTO_TEST_CASE(quick_siege_test,
// Throw lots of requests at it, get a good performance overview
BOOST_AUTO_TEST_CASE(simple_performance_test,
- * boost::unit_test::disabled() // Not usually interested
+ //* boost::unit_test::disabled() // Not usually interested
* boost::unit_test::timeout(15))
{
if (wrk_exists()) {
@@ -77,3 +83,45 @@ BOOST_AUTO_TEST_CASE(simple_performance_test,
BOOST_AUTO_TEST_SUITE_END();
+struct TestClientSocket : public IceSpider::Embedded::ClientSocket {
+ TestClientSocket() : IceSpider::Embedded::ClientSocket(0, false) { }
+};
+
+BOOST_FIXTURE_TEST_SUITE(Client, TestClientSocket);
+
+BOOST_AUTO_TEST_CASE(get_root_1_1, * boost::unit_test::timeout(1))
+{
+ parse_request("GET / HTTP/1.1");
+ BOOST_CHECK_EQUAL(method, IceSpider::HttpMethod::GET);
+ BOOST_CHECK_EQUAL(url, "/");
+ BOOST_CHECK_EQUAL(version, "HTTP/1.1");
+ BOOST_CHECK(headers.empty());
+}
+
+BOOST_AUTO_TEST_CASE(post_path_1_0, * boost::unit_test::timeout(1))
+{
+ parse_request("POST /path/to/resource.cpp HTTP/1.0");
+ BOOST_CHECK_EQUAL(method, IceSpider::HttpMethod::POST);
+ BOOST_CHECK_EQUAL(url, "/path/to/resource.cpp");
+ BOOST_CHECK_EQUAL(version, "HTTP/1.0");
+ BOOST_CHECK(headers.empty());
+}
+
+BOOST_AUTO_TEST_CASE(get_root_1_1_hdr_alt, * boost::unit_test::timeout(1))
+{
+ parse_request("GET / HTTP/1.1\nAccept: text/html");
+ BOOST_CHECK_EQUAL(headers.size(), 1);
+ BOOST_CHECK_EQUAL(headers.begin()->first, "Accept");
+ BOOST_CHECK_EQUAL(headers["Accept"], "text/html");
+}
+
+BOOST_AUTO_TEST_CASE(get_root_1_1_hdrs, * boost::unit_test::timeout(1))
+{
+ parse_request("GET / HTTP/1.1\r\nAccept: text/html\r\nEtag: 43");
+ BOOST_CHECK_EQUAL(headers.size(), 2);
+ BOOST_CHECK_EQUAL(headers["Accept"], "text/html");
+ BOOST_CHECK_EQUAL(headers["Etag"], "43");
+}
+
+BOOST_AUTO_TEST_SUITE_END();
+