Skip to content

Commit

Permalink
use thread pool in http server
Browse files Browse the repository at this point in the history
  • Loading branch information
mpoegel committed Sep 14, 2023
1 parent 56bc855 commit a3769e2
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 8 deletions.
4 changes: 4 additions & 0 deletions http/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
add_library(fwoophttp STATIC
fwoop_httpclient.cpp
fwoop_httpconnhandler.cpp
fwoop_httpdataframe.cpp
fwoop_httpframe.cpp
fwoop_httpgoawayframe.cpp
Expand All @@ -21,8 +22,10 @@ target_link_libraries(fwoophttp fwoopbasis)
install(TARGETS fwoophttp DESTINATION lib)
install(FILES
fwoop_httpclient.h
fwoop_httpconnhandler.h
fwoop_httpdataframe.h
fwoop_httpframe.h
fwoop_httpfunc.h
fwoop_httpgoawayframe.h
fwoop_httpheader.h
fwoop_httpheadersframe.h
Expand All @@ -39,6 +42,7 @@ install(FILES

include(GoogleTest)
add_executable(fwoophttp_test
fwoop_httpconnhandler.g.cpp
fwoop_httpheadersframe.g.cpp
fwoop_httphpacker.g.cpp
fwoop_httprequest.g.cpp
Expand Down
78 changes: 78 additions & 0 deletions http/fwoop_httpconnhandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include <fwoop_httpconnhandler.h>

#include <fwoop_log.h>
#include <fwoop_socketio.h>

namespace fwoop {

HttpConnHandler::HttpConnHandler(int fd, const std::unordered_map<std::string, HttpHandlerFunc_t> &routeMap,
const std::unordered_map<std::string, HttpServerEventHandlerFunc_t> &serverEventMap)
: d_fd(fd), d_routeMap(routeMap), d_serverEventMap(serverEventMap)
{
}

HttpConnHandler::~HttpConnHandler()
{
if (d_fd > 0) {
close(d_fd);
d_fd = -1;
}
}

HttpConnHandler::HttpConnHandler(HttpConnHandler &&rhs)
: d_fd(rhs.d_fd), d_routeMap(rhs.d_routeMap), d_serverEventMap(rhs.d_serverEventMap)
{
rhs.d_fd = -1;
}

void HttpConnHandler::operator()()
{
Log::Debug("received http/1.1 connection");
constexpr unsigned int bufferSize = 2048;
uint8_t buffer[bufferSize];
unsigned int bytesRead;
std::error_code ec = SocketIO::read(d_fd, buffer, bufferSize, bytesRead);
if (ec) {
Log::Error("socket read failed", ec);
}

unsigned int bytesParsed = 0;
int rc;
std::shared_ptr<HttpRequest> request = HttpRequest::parse(buffer, bytesRead, bytesParsed);
if (!request) {
Log::Error("did not receive full http request");
}

Log::Debug("Recieved request: ", *request);

auto routeFunc = d_routeMap.find(request->getPath());
auto serverEventFunc = d_serverEventMap.find(request->getPath());
HttpResponse response;
if (routeFunc != d_routeMap.end()) {
routeFunc->second(*request, response);
} else if (serverEventFunc != d_serverEventMap.end()) {
response.addHeader(HttpHeader::ContentType, "text/event-stream");
response.addHeader(HttpHeader::CacheControl, "no-store");
response.setStatus("200 OK");
} else {
response.setStatus("404 Not Found");
}

Log::Debug("Sending response: ", response);
uint32_t length;
uint8_t *encResp = response.encode(length);
rc = SocketIO::write(d_fd, encResp, length);
delete[] encResp;
if (0 != rc) {
Log::Error("socket write failed, ec=", ec);
}

if (serverEventFunc != d_serverEventMap.end()) {
HttpServerEvent serverEvent(d_fd);
serverEventFunc->second(*request, serverEvent);
}

Log::Debug("done");
}

} // namespace fwoop
12 changes: 12 additions & 0 deletions http/fwoop_httpconnhandler.g.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <fwoop_httpconnhandler.h>

#include <gtest/gtest.h>

TEST(HttpConnHandler, Constructor)
{
// GIVEN

// WHEN

// THEN
}
24 changes: 24 additions & 0 deletions http/fwoop_httpconnhandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include <fwoop_httpfunc.h>

namespace fwoop {

class HttpConnHandler {
private:
int d_fd;
const std::unordered_map<std::string, HttpHandlerFunc_t> d_routeMap;
const std::unordered_map<std::string, HttpServerEventHandlerFunc_t> d_serverEventMap;

public:
HttpConnHandler(int fd, const std::unordered_map<std::string, HttpHandlerFunc_t> &routeMap,
const std::unordered_map<std::string, HttpServerEventHandlerFunc_t> &serverEventMap);
~HttpConnHandler();
HttpConnHandler(const HttpConnHandler &rhs) = delete;
HttpConnHandler operator=(const HttpConnHandler &rhs) = delete;
HttpConnHandler(HttpConnHandler &&rhs);

void operator()();
};

} // namespace fwoop
14 changes: 14 additions & 0 deletions http/fwoop_httpfunc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include <fwoop_httprequest.h>
#include <fwoop_httpresponse.h>
#include <fwoop_httpserverevent.h>

#include <functional>

namespace fwoop {

typedef std::function<void(const HttpRequest &, HttpResponse &)> HttpHandlerFunc_t;
typedef std::function<void(const HttpRequest &, HttpServerEvent &)> HttpServerEventHandlerFunc_t;

} // namespace fwoop
16 changes: 12 additions & 4 deletions http/fwoop_httpserver.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <fwoop_httpconnhandler.h>
#include <fwoop_httpdataframe.h>
#include <fwoop_httpframe.h>
#include <fwoop_httpgoawayframe.h>
Expand All @@ -15,6 +16,7 @@
#include <iostream>
#include <string>
#include <system_error>
#include <thread>

#include <netinet/in.h>
#include <sys/socket.h>
Expand All @@ -24,7 +26,7 @@
namespace fwoop {

HttpServer::HttpServer(int port, HttpVersion::Value version)
: d_port(port), d_serverFd(-1), d_version(version), d_isActive(false)
: d_port(port), d_serverFd(-1), d_version(version), d_isActive(false), d_handlerPool(5)
{
}

Expand Down Expand Up @@ -61,7 +63,7 @@ int HttpServer::serve()

const int maxQueued = 1;
if (0 != listen(d_serverFd, maxQueued)) {
std::cerr << "failed to listen, errno" << errno << '\n';
std::cerr << "failed to listen, errno=" << std::strerror(errno) << '\n';
return -1;
}

Expand All @@ -71,17 +73,23 @@ int HttpServer::serve()
while (d_isActive) {
int clientFd = accept4(d_serverFd, (struct sockaddr *)&clientAddr, (socklen_t *)&addrLen, SOCK_NONBLOCK);
if (clientFd < 0) {
std::cerr << "failed to accept, errno" << errno << '\n';
std::cerr << "failed to accept, errno" << std::strerror(errno) << '\n';
return -1;
}

switch (d_version) {
case HttpVersion::Value::Http1_1:
handleHttp1Connection(clientFd);
{
HttpConnHandler handler(clientFd, d_routeMap, d_serverEventMap);
d_handlerPool.enqueue(std::move(handler));
break;
}
case HttpVersion::Value::Http2:
{
// TODO use the thread pool
handleHttp2Connection(clientFd);
break;
}
default:
std::cerr << "unsupported HTTP version: " << d_version;
return -1;
Expand Down
14 changes: 10 additions & 4 deletions http/fwoop_httpserver.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
#pragma once

#include <fwoop_httpconnhandler.h>
#include <fwoop_httpfunc.h>
#include <fwoop_httprequest.h>
#include <fwoop_httpresponse.h>
#include <fwoop_httpserverevent.h>
#include <fwoop_httpversion.h>
#include <fwoop_threadpool.h>

#include <functional>
#include <string>
#include <unordered_map>

namespace fwoop {

typedef std::function<void(const HttpRequest &, HttpResponse &)> HttpHandlerFunc_t;
typedef std::function<void(const HttpRequest &, HttpServerEvent &)> HttpServerEventHandlerFunc_t;

class HttpServer {
private:
int d_port;
Expand All @@ -22,6 +22,7 @@ class HttpServer {
std::unordered_map<std::string, HttpHandlerFunc_t> d_routeMap;
std::unordered_map<std::string, HttpServerEventHandlerFunc_t> d_serverEventMap;
bool d_isActive;
ThreadPool<HttpConnHandler> d_handlerPool;

int parsePayloadBody(uint8_t *buffer, unsigned bufferSize, unsigned int &bytesParsed) const;
int handleHttp1Connection(int clientFd) const;
Expand All @@ -39,6 +40,11 @@ class HttpServer {
void addServerEventRoute(const std::string &route, HttpServerEventHandlerFunc_t func);
};

inline void HttpServer::stop() { d_isActive = false; }
inline void HttpServer::stop()
{
d_isActive = false;
d_handlerPool.close();
d_handlerPool.wait();
}

} // namespace fwoop

0 comments on commit a3769e2

Please sign in to comment.