From 81be8e2e69bcb00b4fa26df7b6178d0c02b4d1e6 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Mon, 27 Jul 2020 23:13:07 +0000 Subject: [PATCH 01/11] Add base HTTP server files --- .../ext/http/server/HttpServer.h | 895 ++++++++++++++++++ .../ext/http/server/SocketTools.h | 861 +++++++++++++++++ 2 files changed, 1756 insertions(+) create mode 100644 ext/include/opentelemetry/ext/http/server/HttpServer.h create mode 100644 ext/include/opentelemetry/ext/http/server/SocketTools.h diff --git a/ext/include/opentelemetry/ext/http/server/HttpServer.h b/ext/include/opentelemetry/ext/http/server/HttpServer.h new file mode 100644 index 0000000000..de6e93e5eb --- /dev/null +++ b/ext/include/opentelemetry/ext/http/server/HttpServer.h @@ -0,0 +1,895 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +#include "SocketTools.h" + +#ifdef HAVE_HTTP_DEBUG +# ifdef LOG_TRACE +# undef LOG_TRACE +# define LOG_TRACE(x, ...) printf(x "\n", __VA_ARGS__) +# endif +#endif + +#ifndef HTTP_SERVER_NS +# define HTTP_SERVER_NS testing +#endif + +namespace HTTP_SERVER_NS +{ + +constexpr const char *CONTENT_TYPE = "Content-Type"; +constexpr const char *CONTENT_TYPE_TEXT = "text/plain"; +constexpr const char *CONTENT_TYPE_BIN = "application/octet-stream"; + +struct HttpRequest +{ + std::string client; + std::string method; + std::string uri; + std::string protocol; + std::map headers; + std::string content; +}; + +struct HttpResponse +{ + int code; + std::string message; + std::map headers; + std::string body; +}; + +using CallbackFunction = std::function; + +class HttpRequestCallback +{ +protected: + CallbackFunction callback = nullptr; + +public: + HttpRequestCallback(){}; + + HttpRequestCallback &operator=(HttpRequestCallback other) { callback = other.callback; }; + + HttpRequestCallback(CallbackFunction func) : callback(func){}; + + HttpRequestCallback &operator=(CallbackFunction func) + { + callback = func; + return (*this); + } + + virtual int onHttpRequest(HttpRequest const &request, HttpResponse &response) + { + if (callback != nullptr) + { + return callback(request, response); + } + return 0; + }; +}; + +// Simple HTTP server +// Goals: +// - Support enough of HTTP to be used as a mock +// - Be flexible to allow creating various test scenarios +// Out of scope: +// - Performance +// - Full support of RFC 7230-7237 +class HttpServer : private SocketTools::Reactor::SocketCallback +{ + +protected: + struct Connection + { + SocketTools::Socket socket; + std::string receiveBuffer; + std::string sendBuffer; + enum + { + Idle, + ReceivingHeaders, + Sending100Continue, + ReceivingBody, + Processing, + SendingHeaders, + SendingBody, + Closing + } state; + size_t contentLength; + bool keepalive; + HttpRequest request; + HttpResponse response; + }; + + std::string m_serverHost; + bool allowKeepalive{true}; + SocketTools::Reactor m_reactor; + std::list m_listeningSockets; + + class HttpRequestHandler : public std::pair + { + + public: + HttpRequestHandler(std::string key, HttpRequestCallback *value) + { + first = key; + second = value; + }; + + HttpRequestHandler() : std::pair() + { + first = ""; + second = nullptr; + }; + + HttpRequestHandler &operator=(std::pair other) + { + first = other.first; + second = other.second; + return (*this); + }; + + HttpRequestHandler &operator=(HttpRequestCallback &cb) + { + second = &cb; + return (*this); + }; + + HttpRequestHandler &operator=(HttpRequestCallback *cb) + { + second = cb; + return (*this); + }; + }; + + std::list m_handlers; + + std::map m_connections; + size_t m_maxRequestHeadersSize, m_maxRequestContentSize; + +public: + void setKeepalive(bool keepAlive) { allowKeepalive = keepAlive; } + + HttpServer() + : m_serverHost("unnamed"), + allowKeepalive(true), + m_reactor(*this), + m_maxRequestHeadersSize(8192), + m_maxRequestContentSize(2 * 1024 * 1024){}; + + HttpServer(std::string serverHost, int port = 30000) : HttpServer() + { + std::ostringstream os; + os << serverHost << ":" << port; + setServerName(os.str()); + addListeningPort(port); + }; + + ~HttpServer() + { + for (auto &sock : m_listeningSockets) + { + sock.close(); + } + } + + void setRequestLimits(size_t maxRequestHeadersSize, size_t maxRequestContentSize) + { + m_maxRequestHeadersSize = maxRequestHeadersSize; + m_maxRequestContentSize = maxRequestContentSize; + } + + void setServerName(std::string const &name) { m_serverHost = name; } + + int addListeningPort(int port) + { + SocketTools::Socket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + socket.setNonBlocking(); + socket.setReuseAddr(); + + SocketTools::SocketAddr addr(0, port); + socket.bind(addr); + socket.getsockname(addr); + + socket.listen(10); + m_listeningSockets.push_back(socket); + m_reactor.addSocket(socket, SocketTools::Reactor::Acceptable); + LOG_INFO("HttpServer: Listening on %s", addr.toString().c_str()); + + return addr.port(); + } + + HttpRequestHandler &addHandler(const std::string &root, HttpRequestCallback &handler) + { + // No thread-safety here! + m_handlers.push_back({root, &handler}); + LOG_INFO("HttpServer: Added handler for %s", root.c_str()); + return m_handlers.back(); + } + + HttpRequestHandler &operator[](const std::string &root) + { + // No thread-safety here! + m_handlers.push_back({root, nullptr}); + LOG_INFO("HttpServer: Added handler for %s", root.c_str()); + return m_handlers.back(); + } + + HttpServer &operator+=( std::pair other) + { + LOG_INFO("HttpServer: Added handler for %s", other.first.c_str()); + m_handlers.push_back(HttpRequestHandler(other.first, &other.second)); + return (*this); + }; + + void start() + { + m_reactor.start(); + } + + void stop() + { + m_reactor.stop(); + } + +protected: + virtual void onSocketAcceptable(SocketTools::Socket socket) override + { + LOG_TRACE("HttpServer: accepting socket fd=0x%llx", socket.m_sock); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) != + m_listeningSockets.end()); + + SocketTools::Socket csocket; + SocketTools::SocketAddr caddr; + if (socket.accept(csocket, caddr)) + { + csocket.setNonBlocking(); + Connection &conn = m_connections[csocket]; + conn.socket = csocket; + conn.state = Connection::Idle; + conn.request.client = caddr.toString(); + m_reactor.addSocket(csocket, SocketTools::Reactor::Readable | SocketTools::Reactor::Closed); + LOG_TRACE("HttpServer: [%s] accepted", conn.request.client.c_str()); + } + } + + virtual void onSocketReadable(SocketTools::Socket socket) override + { + LOG_TRACE("HttpServer: reading socket fd=0x%llx", socket.m_sock); + // No thread-safety here! + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == + m_listeningSockets.end()); + + // No thread-safety here! + auto connIt = m_connections.find(socket); + if (connIt == m_connections.end()) + { + return; + } + Connection &conn = connIt->second; + + char buffer[2048] = {0}; + int received = socket.recv(buffer, sizeof(buffer)); + LOG_TRACE("HttpServer: [%s] received %d", conn.request.client.c_str(), received); + if (received <= 0) + { + handleConnectionClosed(conn); + return; + } + conn.receiveBuffer.append(buffer, buffer + received); + + handleConnection(conn); + } + + virtual void onSocketWritable(SocketTools::Socket socket) override + { + LOG_TRACE("HttpServer: writing socket fd=0x%llx", socket.m_sock); + + // No thread-safety here! + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == + m_listeningSockets.end()); + + // No thread-safety here! + auto connIt = m_connections.find(socket); + if (connIt == m_connections.end()) + { + return; + } + Connection &conn = connIt->second; + + if (!sendMore(conn)) + { + handleConnection(conn); + } + } + + virtual void onSocketClosed(SocketTools::Socket socket) override + { + LOG_TRACE("HttpServer: closing socket fd=0x%llx", socket.m_sock); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == + m_listeningSockets.end()); + + auto connIt = m_connections.find(socket); + if (connIt == m_connections.end()) + { + return; + } + Connection &conn = connIt->second; + + handleConnectionClosed(conn); + } + + bool sendMore(Connection &conn) + { + if (conn.sendBuffer.empty()) + { + return false; + } + + int sent = conn.socket.send(conn.sendBuffer.data(), static_cast(conn.sendBuffer.size())); + LOG_TRACE("HttpServer: [%s] sent %d", conn.request.client.c_str(), sent); + if (sent < 0 && conn.socket.error() != SocketTools::Socket::ErrorWouldBlock) + { + return true; + } + conn.sendBuffer.erase(0, sent); + + if (!conn.sendBuffer.empty()) + { + m_reactor.addSocket(conn.socket, + SocketTools::Reactor::Writable | SocketTools::Reactor::Closed); + return true; + } + + return false; + } + +protected: + void handleConnectionClosed(Connection &conn) + { + LOG_TRACE("HttpServer: [%s] closed", conn.request.client.c_str()); + if (conn.state != Connection::Idle && conn.state != Connection::Closing) + { + LOG_WARN("HttpServer: [%s] connection closed unexpectedly", conn.request.client.c_str()); + } + m_reactor.removeSocket(conn.socket); + auto connIt = m_connections.find(conn.socket); + conn.socket.close(); + m_connections.erase(connIt); + } + + void handleConnection(Connection &conn) + { + for (;;) + { + if (conn.state == Connection::Idle) + { + conn.response.code = 0; + conn.state = Connection::ReceivingHeaders; + LOG_TRACE("HttpServer: [%s] receiving headers", conn.request.client.c_str()); + } + + if (conn.state == Connection::ReceivingHeaders) + { + bool lfOnly = false; + size_t ofs = conn.receiveBuffer.find("\r\n\r\n"); + if (ofs == std::string::npos) + { + lfOnly = true; + ofs = conn.receiveBuffer.find("\n\n"); + } + size_t headersLen = (ofs != std::string::npos) ? ofs : conn.receiveBuffer.length(); + if (headersLen > m_maxRequestHeadersSize) + { + LOG_WARN("HttpServer: [%s] headers too long - %u", conn.request.client.c_str(), + static_cast(headersLen)); + conn.response.code = 431; // Request Header Fields Too Large + conn.keepalive = false; + conn.state = Connection::Processing; + continue; + } + if (ofs == std::string::npos) + { + return; + } + + if (!parseHeaders(conn)) + { + LOG_WARN("HttpServer: [%s] invalid headers", conn.request.client.c_str()); + conn.response.code = 400; // Bad Request + conn.keepalive = false; + conn.state = Connection::Processing; + continue; + } + LOG_INFO("HttpServer: [%s] %s %s %s", conn.request.client.c_str(), + conn.request.method.c_str(), conn.request.uri.c_str(), + conn.request.protocol.c_str()); + conn.receiveBuffer.erase(0, ofs + (lfOnly ? 2 : 4)); + + conn.keepalive = (conn.request.protocol == "HTTP/1.1"); + auto const connection = conn.request.headers.find("Connection"); + if (connection != conn.request.headers.end()) + { + if (equalsLowercased(connection->second, "keep-alive")) + { + conn.keepalive = true; + } + else if (equalsLowercased(connection->second, "close")) + { + conn.keepalive = false; + } + } + + auto const contentLength = conn.request.headers.find("Content-Length"); + if (contentLength != conn.request.headers.end()) + { + conn.contentLength = atoi(contentLength->second.c_str()); + } + else + { + conn.contentLength = 0; + } + if (conn.contentLength > m_maxRequestContentSize) + { + LOG_WARN("HttpServer: [%s] content too long - %u", conn.request.client.c_str(), + static_cast(conn.contentLength)); + conn.response.code = 413; // Payload Too Large + conn.keepalive = false; + conn.state = Connection::Processing; + continue; + } + + auto const expect = conn.request.headers.find("Expect"); + if (expect != conn.request.headers.end() && conn.request.protocol == "HTTP/1.1") + { + if (!equalsLowercased(expect->second, "100-continue")) + { + LOG_WARN("HttpServer: [%s] unknown expectation - %s", conn.request.client.c_str(), + expect->second.c_str()); + conn.response.code = 417; // Expectation Failed + conn.keepalive = false; + conn.state = Connection::Processing; + continue; + } + conn.sendBuffer = "HTTP/1.1 100 Continue\r\n\r\n"; + conn.state = Connection::Sending100Continue; + LOG_TRACE("HttpServer: [%s] sending \"100 Continue\"", conn.request.client.c_str()); + continue; + } + + conn.state = Connection::ReceivingBody; + LOG_TRACE("HttpServer: [%s] receiving body", conn.request.client.c_str()); + } + + if (conn.state == Connection::Sending100Continue) + { + if (sendMore(conn)) + { + return; + } + + conn.state = Connection::ReceivingBody; + LOG_TRACE("HttpServer: [%s] receiving body", conn.request.client.c_str()); + } + + if (conn.state == Connection::ReceivingBody) + { + if (conn.receiveBuffer.length() < conn.contentLength) + { + return; + } + + if (conn.receiveBuffer.length() == conn.contentLength) + { + conn.request.content = std::move(conn.receiveBuffer); + conn.receiveBuffer.clear(); + } + else + { + conn.request.content.assign(conn.receiveBuffer, 0, conn.contentLength); + conn.receiveBuffer.erase(0, conn.contentLength); + } + + conn.state = Connection::Processing; + LOG_TRACE("HttpServer: [%s] processing request", conn.request.client.c_str()); + } + + if (conn.state == Connection::Processing) + { + processRequest(conn); + + std::ostringstream os; + os << conn.request.protocol << ' ' << conn.response.code << ' ' << conn.response.message + << "\r\n"; + for (auto const &header : conn.response.headers) + { + os << header.first << ": " << header.second << "\r\n"; + } + os << "\r\n"; + + conn.sendBuffer = os.str(); + conn.state = Connection::SendingHeaders; + LOG_TRACE("HttpServer: [%s] sending headers", conn.request.client.c_str()); + } + + if (conn.state == Connection::SendingHeaders) + { + if (sendMore(conn)) + { + return; + } + + conn.sendBuffer = std::move(conn.response.body); + conn.state = Connection::SendingBody; + LOG_TRACE("HttpServer: [%s] sending body", conn.request.client.c_str()); + } + + if (conn.state == Connection::SendingBody) + { + if (sendMore(conn)) + { + return; + } + + conn.keepalive &= allowKeepalive; + + if (conn.keepalive) + { + m_reactor.addSocket(conn.socket, + SocketTools::Reactor::Readable | SocketTools::Reactor::Closed); + conn.state = Connection::Idle; + LOG_TRACE("HttpServer: [%s] idle (keep-alive)", conn.request.client.c_str()); + if (conn.receiveBuffer.empty()) + { + return; + } + } + else + { + conn.socket.shutdown(SocketTools::Socket::ShutdownSend); + m_reactor.addSocket(conn.socket, SocketTools::Reactor::Closed); + conn.state = Connection::Closing; + LOG_TRACE("HttpServer: [%s] closing", conn.request.client.c_str()); + } + } + + if (conn.state == Connection::Closing) + { + return; + } + } + } + + bool parseHeaders(Connection &conn) + { + // Method + char const *begin = conn.receiveBuffer.c_str(); + char const *ptr = begin; + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { + ptr++; + } + if (*ptr != ' ') + { + return false; + } + conn.request.method.assign(begin, ptr); + while (*ptr == ' ') + { + ptr++; + } + + // URI + begin = ptr; + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { + ptr++; + } + if (*ptr != ' ') + { + return false; + } + conn.request.uri.assign(begin, ptr); + while (*ptr == ' ') + { + ptr++; + } + + // Protocol + begin = ptr; + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { + ptr++; + } + if (*ptr != '\r' && *ptr != '\n') + { + return false; + } + conn.request.protocol.assign(begin, ptr); + if (*ptr == '\r') + { + ptr++; + } + if (*ptr != '\n') + { + return false; + } + ptr++; + + // Headers + conn.request.headers.clear(); + while (*ptr != '\r' && *ptr != '\n') + { + // Name + begin = ptr; + while (*ptr && *ptr != ':' && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { + ptr++; + } + if (*ptr != ':') + { + return false; + } + std::string name = normalizeHeaderName(begin, ptr); + ptr++; + while (*ptr == ' ') + { + ptr++; + } + + // Value + begin = ptr; + while (*ptr && *ptr != '\r' && *ptr != '\n') + { + ptr++; + } + conn.request.headers[name] = std::string(begin, ptr); + if (*ptr == '\r') + { + ptr++; + } + if (*ptr != '\n') + { + return false; + } + ptr++; + } + + if (*ptr == '\r') + { + ptr++; + } + if (*ptr != '\n') + { + return false; + } + ptr++; + + return true; + } + + static bool equalsLowercased(std::string const &str, char const *mask) + { + char const *ptr = str.c_str(); + while (*ptr && *mask && ::tolower(*ptr) == *mask) + { + ptr++; + mask++; + } + return !*ptr && !*mask; + } + + static std::string normalizeHeaderName(char const *begin, char const *end) + { + std::string result(begin, end); + bool first = true; + for (char &ch : result) + { + if (first) + { + ch = static_cast(::toupper(ch)); + first = false; + } + else if (ch == '-') + { + first = true; + } + else + { + ch = static_cast(::tolower(ch)); + } + } + return result; + } + + void processRequest(Connection &conn) + { + conn.response.message.clear(); + conn.response.headers.clear(); + conn.response.body.clear(); + + if (conn.response.code == 0) + { + conn.response.code = 404; // Not Found + for (auto &handler : m_handlers) + { + if (conn.request.uri.length() >= handler.first.length() && + strncmp(conn.request.uri.c_str(), handler.first.c_str(), handler.first.length()) == 0) + { + LOG_TRACE("HttpServer: [%s] using handler for %s", conn.request.client.c_str(), + handler.first.c_str()); + auto callback = handler.second; + int result = handler.second->onHttpRequest(conn.request, conn.response); + if (result != 0) + { + conn.response.code = result; + break; + } + } + } + + if (conn.response.code == -1) + { + LOG_TRACE("HttpServer: [%s] closing by request", conn.request.client.c_str()); + handleConnectionClosed(conn); + } + } + + if (conn.response.message.empty()) + { + conn.response.message = getDefaultResponseMessage(conn.response.code); + } + + conn.response.headers["Host"] = m_serverHost; + conn.response.headers["Connection"] = (conn.keepalive ? "keep-alive" : "close"); + conn.response.headers["Date"] = formatTimestamp(time(nullptr)); + conn.response.headers["Content-Length"] = std::to_string(conn.response.body.size()); + } + + static std::string formatTimestamp(time_t time) + { + tm tm; +#ifdef _WIN32 + gmtime_s(&tm, &time); +#else + gmtime_r(&time, &tm); +#endif + char buf[32]; + strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", &tm); + return buf; + } + +public: + + static char const *getDefaultResponseMessage(int code) + { + switch (code) + { + // *INDENT-OFF* + case 100: + return "Continue"; + case 101: + return "Switching Protocols"; + case 200: + return "OK"; + case 201: + return "Created"; + case 202: + return "Accepted"; + case 203: + return "Non-Authoritative Information"; + case 204: + return "No Content"; + case 205: + return "Reset Content"; + case 206: + return "Partial Content"; + case 300: + return "Multiple Choices"; + case 301: + return "Moved Permanently"; + case 302: + return "Found"; + case 303: + return "See Other"; + case 304: + return "Not Modified"; + case 305: + return "Use Proxy"; + case 306: + return "Switch Proxy"; + case 307: + return "Temporary Redirect"; + case 308: + return "Permanent Redirect"; + case 400: + return "Bad Request"; + case 401: + return "Unauthorized"; + case 402: + return "Payment Required"; + case 403: + return "Forbidden"; + case 404: + return "Not Found"; + case 405: + return "Method Not Allowed"; + case 406: + return "Not Acceptable"; + case 407: + return "Proxy Authentication Required"; + case 408: + return "Request Timeout"; + case 409: + return "Conflict"; + case 410: + return "Gone"; + case 411: + return "Length Required"; + case 412: + return "Precondition Failed"; + case 413: + return "Payload Too Large"; + case 414: + return "URI Too Long"; + case 415: + return "Unsupported Media Type"; + case 416: + return "Range Not Satisfiable"; + case 417: + return "Expectation Failed"; + case 421: + return "Misdirected Request"; + case 426: + return "Upgrade Required"; + case 428: + return "Precondition Required"; + case 429: + return "Too Many Requests"; + case 431: + return "Request Header Fields Too Large"; + case 500: + return "Internal Server Error"; + case 501: + return "Not Implemented"; + case 502: + return "Bad Gateway"; + case 503: + return "Service Unavailable"; + case 504: + return "Gateway Timeout"; + case 505: + return "HTTP Version Not Supported"; + case 506: + return "Variant Also Negotiates"; + case 510: + return "Not Extended"; + case 511: + return "Network Authentication Required"; + default: + return "???"; + // *INDENT-ON* + } + } +}; + +} // namespace HTTP_SERVER_NS + diff --git a/ext/include/opentelemetry/ext/http/server/SocketTools.h b/ext/include/opentelemetry/ext/http/server/SocketTools.h new file mode 100644 index 0000000000..1cdc8a6881 --- /dev/null +++ b/ext/include/opentelemetry/ext/http/server/SocketTools.h @@ -0,0 +1,861 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 + +//# include + +# include + +// TODO: consider NOMINMAX +# undef min +# undef max +# pragma comment(lib, "ws2_32.lib") + +#else + +# include + +# ifdef __linux__ +# include +# endif + +# if __APPLE__ +# include "TargetConditionals.h" +// Use kqueue on mac +# include +# include +# include +# endif + +// Common POSIX headers for Linux and Mac OS X +# include +# include +# include +# include +# include +# include + +#endif + +#ifndef _Out_cap_ +# define _Out_cap_(size) +#endif + +#if defined(HAVE_CONSOLE_LOG) && !defined(LOG_DEBUG) +// Log to console if there's no standard log facility defined +# include +# ifndef LOG_DEBUG +# define LOG_DEBUG(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_TRACE(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_INFO(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_WARN(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_ERROR(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# endif +#endif + +#ifndef LOG_DEBUG +// Don't log anything if there's no standard log facility defined +# define LOG_DEBUG(fmt_, ...) +# define LOG_TRACE(fmt_, ...) +# define LOG_INFO(fmt_, ...) +# define LOG_WARN(fmt_, ...) +# define LOG_ERROR(fmt_, ...) +#endif + +namespace common +{ + +/// +/// A simple thread, derived class overloads onThread() method. +/// +struct Thread +{ + + std::thread m_thread; + + volatile bool m_terminate{false}; + + /// + /// Thread Constructor + /// + /// Thread + Thread() {} + + /// + /// Start Thread + /// + void startThread() + { + m_terminate = false; + m_thread = std::thread([&]() { this->onThread(); }); + } + + /// + /// Join Thread + /// + void joinThread() + { + m_terminate = true; + if (m_thread.joinable()) + { + m_thread.join(); + } + } + + /// + /// Indicates if this thread should terminate + /// + /// + bool shouldTerminate() const { return m_terminate; } + + /// + /// Must be implemented by children + /// + virtual void onThread() = 0; + + /// + /// Thread destructor + /// + /// + virtual ~Thread() noexcept {} +}; + +}; // namespace common +namespace SocketTools +{ + +#ifdef _WIN32 +// WinSocks need extra (de)initialization, solved by a global object here, +// whose constructor/destructor will be called before and after main(). +struct WsaInitializer +{ + + WsaInitializer() + { + WSADATA wsaData; + WSAStartup(MAKEWORD(2, 2), &wsaData); + } + + ~WsaInitializer() { WSACleanup(); } +}; + +static WsaInitializer g_wsaInitializer; + +#endif + +/// +/// Encapsulation of sockaddr(_in) +/// +struct SocketAddr +{ + static u_long const Loopback = 0x7F000001; + + sockaddr m_data; + + /// + /// SocketAddr constructor + /// + /// SocketAddr + SocketAddr() { memset(&m_data, 0, sizeof(m_data)); } + + SocketAddr(u_long addr, int port) + { + sockaddr_in &inet4 = reinterpret_cast(m_data); + inet4.sin_family = AF_INET; + inet4.sin_port = htons(static_cast(port)); + inet4.sin_addr.s_addr = htonl(addr); + } + + SocketAddr(char const *addr) + { +#ifdef _WIN32 + INT addrlen = sizeof(m_data); + WCHAR buf[200]; + for (int i = 0; i < sizeof(buf) && addr[i]; i++) + { + buf[i] = addr[i]; + } + buf[199] = L'\0'; + ::WSAStringToAddressW(buf, AF_INET, nullptr, &m_data, &addrlen); +#else + sockaddr_in &inet4 = reinterpret_cast(m_data); + inet4.sin_family = AF_INET; + char const *colon = strchr(addr, ':'); + if (colon) + { + inet4.sin_port = htons(atoi(colon + 1)); + char buf[16]; + memcpy(buf, addr, std::min(15, colon - addr)); + buf[15] = '\0'; + ::inet_pton(AF_INET, buf, &inet4.sin_addr); + } + else + { + inet4.sin_port = 0; + ::inet_pton(AF_INET, addr, &inet4.sin_addr); + } +#endif + } + + SocketAddr(SocketAddr const &other) = default; + + SocketAddr &operator=(SocketAddr const &other) = default; + + operator sockaddr *() { return &m_data; } + + operator const sockaddr *() const { return &m_data; } + + int port() const + { + switch (m_data.sa_family) + { + case AF_INET: { + sockaddr_in const &inet4 = reinterpret_cast(m_data); + return ntohs(inet4.sin_port); + } + + default: + return -1; + } + } + + std::string toString() const + { + std::ostringstream os; + + switch (m_data.sa_family) + { + case AF_INET: { + sockaddr_in const &inet4 = reinterpret_cast(m_data); + u_long addr = ntohl(inet4.sin_addr.s_addr); + os << (addr >> 24) << '.' << ((addr >> 16) & 255) << '.' << ((addr >> 8) & 255) << '.' + << (addr & 255); + os << ':' << ntohs(inet4.sin_port); + break; + } + + default: + os << "[?AF?" << m_data.sa_family << ']'; + } + return os.str(); + } +}; + +/// +/// Encapsulation of a socket (non-exclusive ownership) +/// +struct Socket +{ + +#ifdef _WIN32 + typedef SOCKET Type; + static Type const Invalid = INVALID_SOCKET; +#else + typedef int Type; + static Type const Invalid = -1; +#endif + + Type m_sock; + + Socket(Type sock = Invalid) : m_sock(sock) {} + + Socket(int af, int type, int proto) { m_sock = ::socket(af, type, proto); } + + ~Socket() {} + + operator Socket::Type() const { return m_sock; } + + bool operator==(Socket const &other) const { return (m_sock == other.m_sock); } + + bool operator!=(Socket const &other) const { return (m_sock != other.m_sock); } + + bool operator<(Socket const &other) const { return (m_sock < other.m_sock); } + + bool invalid() const { return (m_sock == Invalid); } + + void setNonBlocking() + { + assert(m_sock != Invalid); +#ifdef _WIN32 + u_long value = 1; + ::ioctlsocket(m_sock, FIONBIO, &value); +#else + int flags = ::fcntl(m_sock, F_GETFL, 0); + ::fcntl(m_sock, F_SETFL, flags | O_NONBLOCK); +#endif + } + + bool setReuseAddr() + { + assert(m_sock != Invalid); +#ifdef _WIN32 + BOOL value = TRUE; +#else + int value = 1; +#endif + return (::setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&value), + sizeof(value)) == 0); + } + + bool setNoDelay() + { + assert(m_sock != Invalid); +#ifdef _WIN32 + BOOL value = TRUE; +#else + int value = 1; +#endif + return (::setsockopt(m_sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&value), + sizeof(value)) == 0); + } + + bool connect(SocketAddr const &addr) + { + assert(m_sock != Invalid); + return (::connect(m_sock, addr, sizeof(addr)) == 0); + } + + void close() + { + assert(m_sock != Invalid); +#ifdef _WIN32 + ::closesocket(m_sock); +#else + ::close(m_sock); +#endif + m_sock = Invalid; + } + + int recv(_Out_cap_(size) void *buffer, unsigned size) + { + assert(m_sock != Invalid); + int flags = 0; + return static_cast(::recv(m_sock, reinterpret_cast(buffer), size, flags)); + } + + int send(void const *buffer, unsigned size) + { + assert(m_sock != Invalid); + return static_cast(::send(m_sock, reinterpret_cast(buffer), size, 0)); + } + + bool bind(SocketAddr const &addr) + { + assert(m_sock != Invalid); + return (::bind(m_sock, addr, sizeof(addr)) == 0); + } + + bool getsockname(SocketAddr &addr) const + { + assert(m_sock != Invalid); +#ifdef _WIN32 + int addrlen = sizeof(addr); +#else + socklen_t addrlen = sizeof(addr); +#endif + return (::getsockname(m_sock, addr, &addrlen) == 0); + } + + bool listen(int backlog) + { + assert(m_sock != Invalid); + return (::listen(m_sock, backlog) == 0); + } + + bool accept(Socket &csock, SocketAddr &caddr) + { + assert(m_sock != Invalid); +#ifdef _WIN32 + int addrlen = sizeof(caddr); +#else + socklen_t addrlen = sizeof(caddr); +#endif + csock = ::accept(m_sock, caddr, &addrlen); + return !csock.invalid(); + } + + bool shutdown(int how) + { + assert(m_sock != Invalid); + return (::shutdown(m_sock, how) == 0); + } + + int error() const + { +#ifdef _WIN32 + return ::WSAGetLastError(); +#else + return errno; +#endif + } + + enum + { +#ifdef _WIN32 + ErrorWouldBlock = WSAEWOULDBLOCK +#else + ErrorWouldBlock = EWOULDBLOCK +#endif + }; + + enum + { +#ifdef _WIN32 + ShutdownReceive = SD_RECEIVE, + ShutdownSend = SD_SEND, + ShutdownBoth = SD_BOTH +#else + ShutdownReceive = SHUT_RD, + ShutdownSend = SHUT_WR, + ShutdownBoth = SHUT_RDWR +#endif + }; +}; + +/// +/// Socket Data +/// +struct SocketData +{ + Socket socket; + int flags; + + SocketData() : socket(), flags(0) {} + + bool operator==(Socket s) { return (socket == s); } +}; + +/// +/// Socket Reactor +/// +struct Reactor : protected common::Thread +{ + + /// + /// Socket State callback + /// + class SocketCallback + { + public: + virtual void onSocketReadable(Socket sock) = 0; + virtual void onSocketWritable(Socket sock) = 0; + virtual void onSocketAcceptable(Socket sock) = 0; + virtual void onSocketClosed(Socket sock) = 0; + }; + + /// + /// Socket State + /// + enum State + { + Readable = 1, + Writable = 2, + Acceptable = 4, + Closed = 8 + }; + + SocketCallback &m_callback; + + std::vector m_sockets; + +#ifdef _WIN32 + /* use WinSock events on Windows */ + std::vector m_events{}; +#endif + +#ifdef __linux__ + /* use epoll on Linux */ + int m_epollFd; +#endif + +#ifdef TARGET_OS_MAC + /* use kqueue on Mac */ +# define KQUEUE_SIZE 32 + int kq{0}; + struct kevent m_events[KQUEUE_SIZE]; +#endif + +public: + Reactor(SocketCallback &callback) : m_callback(callback) + { +#ifdef __linux__ +# ifdef ANDROID + m_epollFd = ::epoll_create(0); +# else + m_epollFd = ::epoll_create1(0); +# endif +#endif + +#ifdef TARGET_OS_MAC + bzero(&m_events[0], sizeof(m_events)); + kq = kqueue(); +#endif + } + + ~Reactor() + { +#ifdef __linux__ + ::close(m_epollFd); +#endif +#ifdef TARGET_OS_MAC + ::close(kq); +#endif + } + + /// + /// Add Socket + /// + /// + /// + void addSocket(const Socket &socket, int flags) + { + if (flags == 0) + { + removeSocket(socket); + } + else + { + auto it = std::find(m_sockets.begin(), m_sockets.end(), socket); + if (it == m_sockets.end()) + { + LOG_TRACE("Reactor: Adding socket 0x%x with flags 0x%x", static_cast(socket), flags); +#ifdef _WIN32 + m_events.push_back(::WSACreateEvent()); +#endif +#ifdef __linux__ + epoll_event event = {}; + event.data.fd = socket; + event.events = 0; + ::epoll_ctl(m_epollFd, EPOLL_CTL_ADD, socket, &event); +#endif +#ifdef TARGET_OS_MAC + struct kevent event; + bzero(&event, sizeof(event)); + event.ident = socket.m_sock; + EV_SET(&event, event.ident, EVFILT_READ, EV_ADD, 0, 0, NULL); + kevent(kq, &event, 1, NULL, 0, NULL); + EV_SET(&event, event.ident, EVFILT_WRITE, EV_ADD, 0, 0, NULL); + kevent(kq, &event, 1, NULL, 0, NULL); +#endif + m_sockets.push_back(SocketData()); + m_sockets.back().socket = socket; + m_sockets.back().flags = 0; + it = m_sockets.end() - 1; + } + else + { + LOG_TRACE("Reactor: Updating socket 0x%x with flags 0x%x", static_cast(socket), flags); + } + + if (it->flags != flags) + { + it->flags = flags; +#ifdef _WIN32 + long lNetworkEvents = 0; + if (it->flags & Readable) + { + lNetworkEvents |= FD_READ; + } + if (it->flags & Writable) + { + lNetworkEvents |= FD_WRITE; + } + if (it->flags & Acceptable) + { + lNetworkEvents |= FD_ACCEPT; + } + if (it->flags & Closed) + { + lNetworkEvents |= FD_CLOSE; + } + auto eventIt = m_events.begin() + std::distance(m_sockets.begin(), it); + ::WSAEventSelect(socket, *eventIt, lNetworkEvents); +#endif +#ifdef __linux__ + int events = 0; + if (it->flags & Readable) + { + events |= EPOLLIN; + } + if (it->flags & Writable) + { + events |= EPOLLOUT; + } + if (it->flags & Acceptable) + { + events |= EPOLLIN; + } + // if (it->flags & Closed) - always handled (EPOLLERR | EPOLLHUP) + epoll_event event = {}; + event.data.fd = socket; + event.events = events; + ::epoll_ctl(m_epollFd, EPOLL_CTL_MOD, socket, &event); +#endif +#ifdef TARGET_OS_MAC + // TODO: [MG] - Mac OS X socket doesn't currently support updating flags +#endif + } + } + } + + /// + /// Remove Socket + /// + /// + void removeSocket(const Socket &socket) + { + LOG_TRACE("Reactor: Removing socket 0x%x", static_cast(socket)); + auto it = std::find(m_sockets.begin(), m_sockets.end(), socket); + if (it != m_sockets.end()) + { +#ifdef _WIN32 + auto eventIt = m_events.begin() + std::distance(m_sockets.begin(), it); + ::WSAEventSelect(it->socket, *eventIt, 0); + ::WSACloseEvent(*eventIt); + m_events.erase(eventIt); +#endif +#ifdef __linux__ + ::epoll_ctl(m_epollFd, EPOLL_CTL_DEL, socket, nullptr); +#endif +#ifdef TARGET_OS_MAC + struct kevent event; + bzero(&event, sizeof(event)); + event.ident = socket; + EV_SET(&event, socket, EVFILT_READ, EV_DELETE, 0, 0, NULL); + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { + //// Already removed? + LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); + } + EV_SET(&event, socket, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { + //// Already removed? + LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); + } +#endif + m_sockets.erase(it); + } + } + + /// + /// Start server + /// + void start() + { + LOG_INFO("Reactor: Starting..."); + startThread(); + } + + /// + /// Stop server + /// + void stop() + { + LOG_INFO("Reactor: Stopping..."); + joinThread(); +#ifdef _WIN32 + for (auto &hEvent : m_events) + { + ::WSACloseEvent(hEvent); + } +#else /* Linux and Mac */ + for (auto &sd : m_sockets) + { +# ifdef __linux__ + ::epoll_ctl(m_epollFd, EPOLL_CTL_DEL, sd.socket, nullptr); +# endif +# ifdef TARGET_OS_MAC + struct kevent event; + bzero(&event, sizeof(event)); + event.ident = sd.socket; + EV_SET(&event, sd.socket, EVFILT_READ, EV_DELETE, 0, 0, NULL); + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { + LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); + } + EV_SET(&event, sd.socket, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { + LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); + } +# endif + } +#endif + m_sockets.clear(); + } + + /// + /// Thread Loop for async events processing + /// + virtual void onThread() override + { + LOG_INFO("Reactor: Thread started"); + while (!shouldTerminate()) + { +#ifdef _WIN32 + DWORD dwResult = ::WSAWaitForMultipleEvents(static_cast(m_events.size()), + m_events.data(), FALSE, 500, FALSE); + if (dwResult == WSA_WAIT_TIMEOUT) + { + continue; + } + + assert(dwResult <= WSA_WAIT_EVENT_0 + m_events.size()); + int index = dwResult - WSA_WAIT_EVENT_0; + Socket socket = m_sockets[index].socket; + int flags = m_sockets[index].flags; + + WSANETWORKEVENTS ne; + ::WSAEnumNetworkEvents(socket, m_events[index], &ne); + LOG_TRACE("Reactor: Handling socket 0x%x (index %d) with active flags 0x%x (armed 0x%x)", + static_cast(socket), index, ne.lNetworkEvents, flags); + + if ((flags & Readable) && (ne.lNetworkEvents & FD_READ)) + { + m_callback.onSocketReadable(socket); + } + if ((flags & Writable) && (ne.lNetworkEvents & FD_WRITE)) + { + m_callback.onSocketWritable(socket); + } + if ((flags & Acceptable) && (ne.lNetworkEvents & FD_ACCEPT)) + { + m_callback.onSocketAcceptable(socket); + } + if ((flags & Closed) && (ne.lNetworkEvents & FD_CLOSE)) + { + m_callback.onSocketClosed(socket); + } +#endif + +#ifdef __linux__ + epoll_event events[4]; + int result = ::epoll_wait(m_epollFd, events, sizeof(events) / sizeof(events[0]), 500); + if (result == 0 || (result == -1 && errno == EINTR)) + { + continue; + } + + assert(result >= 1 && static_cast(result) <= sizeof(events) / sizeof(events[0])); + for (int i = 0; i < result; i++) + { + auto it = std::find(m_sockets.begin(), m_sockets.end(), events[i].data.fd); + assert(it != m_sockets.end()); + Socket socket = it->socket; + int flags = it->flags; + + LOG_TRACE("Reactor: Handling socket 0x%x active flags 0x%x (armed 0x%x)", + static_cast(socket), events[i].events, flags); + + if ((flags & Readable) && (events[i].events & EPOLLIN)) + { + m_callback.onSocketReadable(socket); + } + if ((flags & Writable) && (events[i].events & EPOLLOUT)) + { + m_callback.onSocketWritable(socket); + } + if ((flags & Acceptable) && (events[i].events & EPOLLIN)) + { + m_callback.onSocketAcceptable(socket); + } + if ((flags & Closed) && (events[i].events & (EPOLLHUP | EPOLLERR))) + { + m_callback.onSocketClosed(socket); + } + } +#endif + +#if defined(TARGET_OS_MAC) + unsigned waitms = 500; // never block for more than 500ms + struct timespec timeout; + timeout.tv_sec = waitms / 1000; + timeout.tv_nsec = (waitms % 1000) * 1000 * 1000; + + int nev = kevent(kq, NULL, 0, m_events, KQUEUE_SIZE, &timeout); + for (int i = 0; i < nev; i++) + { + struct kevent &event = m_events[i]; + int fd = (int)event.ident; + auto it = std::find(m_sockets.begin(), m_sockets.end(), fd); + assert(it != m_sockets.end()); + Socket socket = it->socket; + int flags = it->flags; + + LOG_TRACE("Handling socket 0x%x active flags 0x%x (armed 0x%x)", static_cast(socket), + event.flags, event.fflags); + + if (event.filter == EVFILT_READ) + { + if (flags & Acceptable) + { + m_callback.onSocketAcceptable(socket); + } + if (flags & Readable) + { + m_callback.onSocketReadable(socket); + } + continue; + } + + if (event.filter == EVFILT_WRITE) + { + if (flags & Writable) + { + m_callback.onSocketWritable(socket); + } + continue; + } + + if ((event.flags & EV_EOF) || (event.flags & EV_ERROR)) + { + LOG_TRACE("event.filter=%s", "EVFILT_WRITE"); + m_callback.onSocketClosed(socket); + it->flags = Closed; + struct kevent kevt; + EV_SET(&kevt, event.ident, EVFILT_READ, EV_DELETE, 0, 0, NULL); + if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) + { + LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); + } + EV_SET(&kevt, event.ident, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) + { + LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); + } + continue; + } + LOG_ERROR("Reactor: unhandled kevent!"); + } +#endif + } + LOG_TRACE("Reactor: Thread done"); + } +}; + +} // namespace SocketTools From c1b7ab78c9c25c9b3c3590bf4b775b24d9fa0ad3 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 17:52:30 +0000 Subject: [PATCH 02/11] Silence bazel error, unused variable --- ext/include/opentelemetry/ext/http/server/HttpServer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/include/opentelemetry/ext/http/server/HttpServer.h b/ext/include/opentelemetry/ext/http/server/HttpServer.h index de6e93e5eb..93eaa0e8e3 100644 --- a/ext/include/opentelemetry/ext/http/server/HttpServer.h +++ b/ext/include/opentelemetry/ext/http/server/HttpServer.h @@ -736,7 +736,7 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { LOG_TRACE("HttpServer: [%s] using handler for %s", conn.request.client.c_str(), handler.first.c_str()); - auto callback = handler.second; + // auto callback = handler.second; // Bazel gets mad at this unused var, uncomment when using int result = handler.second->onHttpRequest(conn.request, conn.response); if (result != 0) { From 8d5e9d1fb32631310489a8a0246ecf7fc359512f Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 17:58:23 +0000 Subject: [PATCH 03/11] Rename file to OT naming convention --- .../opentelemetry/ext/http/server/{HttpServer.h => http_server.h} | 0 .../ext/http/server/{SocketTools.h => socket_tools.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename ext/include/opentelemetry/ext/http/server/{HttpServer.h => http_server.h} (100%) rename ext/include/opentelemetry/ext/http/server/{SocketTools.h => socket_tools.h} (100%) diff --git a/ext/include/opentelemetry/ext/http/server/HttpServer.h b/ext/include/opentelemetry/ext/http/server/http_server.h similarity index 100% rename from ext/include/opentelemetry/ext/http/server/HttpServer.h rename to ext/include/opentelemetry/ext/http/server/http_server.h diff --git a/ext/include/opentelemetry/ext/http/server/SocketTools.h b/ext/include/opentelemetry/ext/http/server/socket_tools.h similarity index 100% rename from ext/include/opentelemetry/ext/http/server/SocketTools.h rename to ext/include/opentelemetry/ext/http/server/socket_tools.h From ca5728241ccb18218fb4de5d6e39bd264a97076e Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 18:06:53 +0000 Subject: [PATCH 04/11] Add derived file server --- .../ext/http/server/file_http_server.h | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 ext/include/opentelemetry/ext/http/server/file_http_server.h diff --git a/ext/include/opentelemetry/ext/http/server/file_http_server.h b/ext/include/opentelemetry/ext/http/server/file_http_server.h new file mode 100644 index 0000000000..c1cf7258cf --- /dev/null +++ b/ext/include/opentelemetry/ext/http/server/file_http_server.h @@ -0,0 +1,141 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "opentelemetry/ext/http/server/HttpServer.h" + +namespace HTTP_SERVER_NS { + +class FileHttpServer : public HTTP_SERVER_NS::HttpServer { + protected: + /** + * Construct the server by initializing the endpoint for serving static files, which show up on the + * web if the user is on the given host:port. Static files can be seen relative to the folder where the + * executable was ran. + */ + FileHttpServer(const std::string& host = "127.0.0.1", int port = "3333") : HttpServer() { + std::ostringstream os; + os << host << ":" << port; + setServerName(os.str()); + addListeningPort(port); + }; + + /** + * Set the HTTP server to serve static files from the root of host:port. + * Derived HTTP servers should initialize the file endpoint AFTER they + * initialize their own, otherwise everything will be served like a file + * @param server should be an instance of this object + */ + void InitializeFileEndpoint(zPagesHttpServer& server) { + server[root_endpt_] = ServeFile; + } + + private: + /** + * Return whether a file is found whose location is searched for relative to where + * the executable was triggered. If the file is valid, fill result with the file data/information + * required to display it on a webpage + * @param name of the file to look for, + * @param resulting file information, necessary for displaying them on a webpage + * @returns whether a file was found and result filled with display information + */ + bool FileGetSuccess (const std::string& filename, std::vector& result) { + #ifdef _WIN32 + std::replace(filename.begin(), filename.end(), '/', '\\'); + #endif + std::streampos size; + std::ifstream file(filename, std::ios::in | std::ios::binary | std::ios::ate); + if (file.is_open()) { + size = file.tellg(); + if (size) { + result.resize(size); + file.seekg(0, std::ios::beg); + file.read(result.data(), size); + } + file.close(); + return true; + } + return false; + }; + + /** + * Returns the extension of a file + * @param name of the file + * @returns file extension type under HTTP protocol + */ + std::string GetMimeContentType(const std::string& filename) { + std::string file_ext = filename.substr(filename.find_last_of(".") + 1); + auto file_type = mime_types_.find(file_ext); + return (file_type != mime_types_.end()) + ? file_type->second + : HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + }; + + /** + * Returns the standardized name of a file by removing backslashes, and + * assuming index.html is the wanted file if a directory is given + * @param name of the file + */ + std::string GetFileName(std::string S) { + if (S.back() == '/') { + auto temp = S.substr(0, S.size() - 1); + S = temp; + } + // If filename appears to be a directory, serve the hypothetical index.html file there + if (S.find(".") == std::string::npos) S += "/index.html"; + + return S; + } + + /** + * Sets the response object with the correct file data based on the requested file address, + * or return 404 error if a file isn't found + * @param req is the HTTP request, which we use to figure out the response to send + * @param resp is the HTTP response we want to send to the frontend, including file data + */ + HTTP_SERVER_NS::HttpRequestCallback ServeFile{[&](HTTP_SERVER_NS::HttpRequest const& req, + HTTP_SERVER_NS::HttpResponse& resp) { + LOG_INFO("File: %s\n", req.uri.c_str()); + auto f = GetFileName(req.uri); + auto filename = f.c_str() + 1; + + std::vector content; + if (FileGetSuccess(filename, content)) { + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = GetMimeContentType(filename); + resp.body = std::string(content.data(), content.size()); + resp.code = 200; + resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); + return resp.code; + } + // Two additional 'special' return codes possible here: + // 0 - proceed to next handler + // -1 - immediately terminate and close connection + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + resp.code = 404; + resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); + resp.body = resp.message; + return 404; + }}; + + + // Maps file extensions to their HTTP-compatible mime file type + const std::unordered_map mime_types_ = { + {"css", "text/css"}, + {"png", "image/png"}, + {"js", "text/javascript"}, + {"htm", "text/html"}, + {"html", "text/html"}, + {"json", "application/json"}, + {"txt", "text/plain"}, + {"jpg", "image/jpeg"}, + {"jpeg", "image/jpeg"}, + }; + const std::string root_endpt_ = "/"; + +}; + +} // namespace HTTP_SERVER_NS From 7e67beba397e5563e9d8e3b1ee712a3c1d70b902 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 18:42:09 +0000 Subject: [PATCH 05/11] Update references to new header file names --- ext/include/opentelemetry/ext/http/server/file_http_server.h | 2 +- ext/include/opentelemetry/ext/http/server/http_server.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/include/opentelemetry/ext/http/server/file_http_server.h b/ext/include/opentelemetry/ext/http/server/file_http_server.h index c1cf7258cf..a95ff594d1 100644 --- a/ext/include/opentelemetry/ext/http/server/file_http_server.h +++ b/ext/include/opentelemetry/ext/http/server/file_http_server.h @@ -6,7 +6,7 @@ #include #include -#include "opentelemetry/ext/http/server/HttpServer.h" +#include "opentelemetry/ext/http/server/http_server.h" namespace HTTP_SERVER_NS { diff --git a/ext/include/opentelemetry/ext/http/server/http_server.h b/ext/include/opentelemetry/ext/http/server/http_server.h index 93eaa0e8e3..e1a57254b2 100644 --- a/ext/include/opentelemetry/ext/http/server/http_server.h +++ b/ext/include/opentelemetry/ext/http/server/http_server.h @@ -18,7 +18,7 @@ #include #include -#include "SocketTools.h" +#include "socket_tools.h" #ifdef HAVE_HTTP_DEBUG # ifdef LOG_TRACE From da074f840520429fd6a267c58e647127b005d3a6 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 18:52:44 +0000 Subject: [PATCH 06/11] Add return statement in = overload --- ext/include/opentelemetry/ext/http/server/http_server.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/include/opentelemetry/ext/http/server/http_server.h b/ext/include/opentelemetry/ext/http/server/http_server.h index e1a57254b2..83af6a7ca2 100644 --- a/ext/include/opentelemetry/ext/http/server/http_server.h +++ b/ext/include/opentelemetry/ext/http/server/http_server.h @@ -66,7 +66,10 @@ class HttpRequestCallback public: HttpRequestCallback(){}; - HttpRequestCallback &operator=(HttpRequestCallback other) { callback = other.callback; }; + HttpRequestCallback &operator=(HttpRequestCallback other) { + callback = other.callback; + return *this; + }; HttpRequestCallback(CallbackFunction func) : callback(func){}; From 0a35712bb3d6725f7d219a6d668a016c302f3be6 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 22:55:03 +0000 Subject: [PATCH 07/11] Run formatter --- .../ext/http/server/file_http_server.h | 129 +++++++++--------- .../ext/http/server/http_server.h | 24 ++-- 2 files changed, 73 insertions(+), 80 deletions(-) diff --git a/ext/include/opentelemetry/ext/http/server/file_http_server.h b/ext/include/opentelemetry/ext/http/server/file_http_server.h index a95ff594d1..4c88f0ecb4 100644 --- a/ext/include/opentelemetry/ext/http/server/file_http_server.h +++ b/ext/include/opentelemetry/ext/http/server/file_http_server.h @@ -8,16 +8,19 @@ #include "opentelemetry/ext/http/server/http_server.h" -namespace HTTP_SERVER_NS { +namespace HTTP_SERVER_NS +{ -class FileHttpServer : public HTTP_SERVER_NS::HttpServer { - protected: +class FileHttpServer : public HTTP_SERVER_NS::HttpServer +{ +protected: /** - * Construct the server by initializing the endpoint for serving static files, which show up on the - * web if the user is on the given host:port. Static files can be seen relative to the folder where the - * executable was ran. + * Construct the server by initializing the endpoint for serving static files, which show up on + * the web if the user is on the given host:port. Static files can be seen relative to the folder + * where the executable was ran. */ - FileHttpServer(const std::string& host = "127.0.0.1", int port = "3333") : HttpServer() { + FileHttpServer(const std::string &host = "127.0.0.1", int port = "3333") : HttpServer() + { std::ostringstream os; os << host << ":" << port; setServerName(os.str()); @@ -30,11 +33,9 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * initialize their own, otherwise everything will be served like a file * @param server should be an instance of this object */ - void InitializeFileEndpoint(zPagesHttpServer& server) { - server[root_endpt_] = ServeFile; - } + void InitializeFileEndpoint(zPagesHttpServer &server) { server[root_endpt_] = ServeFile; } - private: +private: /** * Return whether a file is found whose location is searched for relative to where * the executable was triggered. If the file is valid, fill result with the file data/information @@ -43,18 +44,21 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * @param resulting file information, necessary for displaying them on a webpage * @returns whether a file was found and result filled with display information */ - bool FileGetSuccess (const std::string& filename, std::vector& result) { - #ifdef _WIN32 + bool FileGetSuccess(const std::string &filename, std::vector &result) + { +#ifdef _WIN32 std::replace(filename.begin(), filename.end(), '/', '\\'); - #endif +#endif std::streampos size; std::ifstream file(filename, std::ios::in | std::ios::binary | std::ios::ate); - if (file.is_open()) { + if (file.is_open()) + { size = file.tellg(); - if (size) { - result.resize(size); - file.seekg(0, std::ios::beg); - file.read(result.data(), size); + if (size) + { + result.resize(size); + file.seekg(0, std::ios::beg); + file.read(result.data(), size); } file.close(); return true; @@ -67,12 +71,11 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * @param name of the file * @returns file extension type under HTTP protocol */ - std::string GetMimeContentType(const std::string& filename) { + std::string GetMimeContentType(const std::string &filename) + { std::string file_ext = filename.substr(filename.find_last_of(".") + 1); - auto file_type = mime_types_.find(file_ext); - return (file_type != mime_types_.end()) - ? file_type->second - : HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + auto file_type = mime_types_.find(file_ext); + return (file_type != mime_types_.end()) ? file_type->second : HTTP_SERVER_NS::CONTENT_TYPE_TEXT; }; /** @@ -80,13 +83,16 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * assuming index.html is the wanted file if a directory is given * @param name of the file */ - std::string GetFileName(std::string S) { - if (S.back() == '/') { + std::string GetFileName(std::string S) + { + if (S.back() == '/') + { auto temp = S.substr(0, S.size() - 1); - S = temp; + S = temp; } // If filename appears to be a directory, serve the hypothetical index.html file there - if (S.find(".") == std::string::npos) S += "/index.html"; + if (S.find(".") == std::string::npos) + S += "/index.html"; return S; } @@ -97,45 +103,38 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * @param req is the HTTP request, which we use to figure out the response to send * @param resp is the HTTP response we want to send to the frontend, including file data */ - HTTP_SERVER_NS::HttpRequestCallback ServeFile{[&](HTTP_SERVER_NS::HttpRequest const& req, - HTTP_SERVER_NS::HttpResponse& resp) { - LOG_INFO("File: %s\n", req.uri.c_str()); - auto f = GetFileName(req.uri); - auto filename = f.c_str() + 1; + HTTP_SERVER_NS::HttpRequestCallback ServeFile{ + [&](HTTP_SERVER_NS::HttpRequest const &req, HTTP_SERVER_NS::HttpResponse &resp) { + LOG_INFO("File: %s\n", req.uri.c_str()); + auto f = GetFileName(req.uri); + auto filename = f.c_str() + 1; - std::vector content; - if (FileGetSuccess(filename, content)) { - resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = GetMimeContentType(filename); - resp.body = std::string(content.data(), content.size()); - resp.code = 200; + std::vector content; + if (FileGetSuccess(filename, content)) + { + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = GetMimeContentType(filename); + resp.body = std::string(content.data(), content.size()); + resp.code = 200; + resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); + return resp.code; + } + // Two additional 'special' return codes possible here: + // 0 - proceed to next handler + // -1 - immediately terminate and close connection + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + resp.code = 404; resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); - return resp.code; - } - // Two additional 'special' return codes possible here: - // 0 - proceed to next handler - // -1 - immediately terminate and close connection - resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = HTTP_SERVER_NS::CONTENT_TYPE_TEXT; - resp.code = 404; - resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); - resp.body = resp.message; - return 404; - }}; - - - // Maps file extensions to their HTTP-compatible mime file type - const std::unordered_map mime_types_ = { - {"css", "text/css"}, - {"png", "image/png"}, - {"js", "text/javascript"}, - {"htm", "text/html"}, - {"html", "text/html"}, - {"json", "application/json"}, - {"txt", "text/plain"}, - {"jpg", "image/jpeg"}, - {"jpeg", "image/jpeg"}, - }; - const std::string root_endpt_ = "/"; + resp.body = resp.message; + return 404; + }}; + // Maps file extensions to their HTTP-compatible mime file type + const std::unordered_map mime_types_ = { + {"css", "text/css"}, {"png", "image/png"}, {"js", "text/javascript"}, + {"htm", "text/html"}, {"html", "text/html"}, {"json", "application/json"}, + {"txt", "text/plain"}, {"jpg", "image/jpeg"}, {"jpeg", "image/jpeg"}, + }; + const std::string root_endpt_ = "/"; }; -} // namespace HTTP_SERVER_NS +} // namespace HTTP_SERVER_NS diff --git a/ext/include/opentelemetry/ext/http/server/http_server.h b/ext/include/opentelemetry/ext/http/server/http_server.h index 83af6a7ca2..a4cc6cc814 100644 --- a/ext/include/opentelemetry/ext/http/server/http_server.h +++ b/ext/include/opentelemetry/ext/http/server/http_server.h @@ -66,7 +66,8 @@ class HttpRequestCallback public: HttpRequestCallback(){}; - HttpRequestCallback &operator=(HttpRequestCallback other) { + HttpRequestCallback &operator=(HttpRequestCallback other) + { callback = other.callback; return *this; }; @@ -145,7 +146,7 @@ class HttpServer : private SocketTools::Reactor::SocketCallback HttpRequestHandler &operator=(std::pair other) { - first = other.first; + first = other.first; second = other.second; return (*this); }; @@ -236,22 +237,16 @@ class HttpServer : private SocketTools::Reactor::SocketCallback return m_handlers.back(); } - HttpServer &operator+=( std::pair other) + HttpServer &operator+=(std::pair other) { LOG_INFO("HttpServer: Added handler for %s", other.first.c_str()); m_handlers.push_back(HttpRequestHandler(other.first, &other.second)); return (*this); }; - void start() - { - m_reactor.start(); - } + void start() { m_reactor.start(); } - void stop() - { - m_reactor.stop(); - } + void stop() { m_reactor.stop(); } protected: virtual void onSocketAcceptable(SocketTools::Socket socket) override @@ -739,8 +734,9 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { LOG_TRACE("HttpServer: [%s] using handler for %s", conn.request.client.c_str(), handler.first.c_str()); - // auto callback = handler.second; // Bazel gets mad at this unused var, uncomment when using - int result = handler.second->onHttpRequest(conn.request, conn.response); + // auto callback = handler.second; // Bazel gets mad at this unused var, uncomment when + // using + int result = handler.second->onHttpRequest(conn.request, conn.response); if (result != 0) { conn.response.code = result; @@ -781,7 +777,6 @@ class HttpServer : private SocketTools::Reactor::SocketCallback } public: - static char const *getDefaultResponseMessage(int code) { switch (code) @@ -895,4 +890,3 @@ class HttpServer : private SocketTools::Reactor::SocketCallback }; } // namespace HTTP_SERVER_NS - From de0d4a9b37e9130aa2fe66376eeb6df346eb9f92 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 22:59:11 +0000 Subject: [PATCH 08/11] Run formatter with style=google --- .../ext/http/server/file_http_server.h | 116 ++-- .../ext/http/server/http_server.h | 533 ++++++++---------- .../ext/http/server/socket_tools.h | 476 +++++++--------- 3 files changed, 482 insertions(+), 643 deletions(-) diff --git a/ext/include/opentelemetry/ext/http/server/file_http_server.h b/ext/include/opentelemetry/ext/http/server/file_http_server.h index 4c88f0ecb4..2e1cfa8066 100644 --- a/ext/include/opentelemetry/ext/http/server/file_http_server.h +++ b/ext/include/opentelemetry/ext/http/server/file_http_server.h @@ -8,19 +8,17 @@ #include "opentelemetry/ext/http/server/http_server.h" -namespace HTTP_SERVER_NS -{ +namespace HTTP_SERVER_NS { -class FileHttpServer : public HTTP_SERVER_NS::HttpServer -{ -protected: +class FileHttpServer : public HTTP_SERVER_NS::HttpServer { + protected: /** - * Construct the server by initializing the endpoint for serving static files, which show up on - * the web if the user is on the given host:port. Static files can be seen relative to the folder - * where the executable was ran. + * Construct the server by initializing the endpoint for serving static files, + * which show up on the web if the user is on the given host:port. Static + * files can be seen relative to the folder where the executable was ran. */ - FileHttpServer(const std::string &host = "127.0.0.1", int port = "3333") : HttpServer() - { + FileHttpServer(const std::string &host = "127.0.0.1", int port = "3333") + : HttpServer() { std::ostringstream os; os << host << ":" << port; setServerName(os.str()); @@ -33,29 +31,31 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer * initialize their own, otherwise everything will be served like a file * @param server should be an instance of this object */ - void InitializeFileEndpoint(zPagesHttpServer &server) { server[root_endpt_] = ServeFile; } + void InitializeFileEndpoint(zPagesHttpServer &server) { + server[root_endpt_] = ServeFile; + } -private: + private: /** - * Return whether a file is found whose location is searched for relative to where - * the executable was triggered. If the file is valid, fill result with the file data/information - * required to display it on a webpage + * Return whether a file is found whose location is searched for relative to + * where the executable was triggered. If the file is valid, fill result with + * the file data/information required to display it on a webpage * @param name of the file to look for, - * @param resulting file information, necessary for displaying them on a webpage - * @returns whether a file was found and result filled with display information + * @param resulting file information, necessary for displaying them on a + * webpage + * @returns whether a file was found and result filled with display + * information */ - bool FileGetSuccess(const std::string &filename, std::vector &result) - { + bool FileGetSuccess(const std::string &filename, std::vector &result) { #ifdef _WIN32 std::replace(filename.begin(), filename.end(), '/', '\\'); #endif std::streampos size; - std::ifstream file(filename, std::ios::in | std::ios::binary | std::ios::ate); - if (file.is_open()) - { + std::ifstream file(filename, + std::ios::in | std::ios::binary | std::ios::ate); + if (file.is_open()) { size = file.tellg(); - if (size) - { + if (size) { result.resize(size); file.seekg(0, std::ios::beg); file.read(result.data(), size); @@ -71,11 +71,11 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer * @param name of the file * @returns file extension type under HTTP protocol */ - std::string GetMimeContentType(const std::string &filename) - { + std::string GetMimeContentType(const std::string &filename) { std::string file_ext = filename.substr(filename.find_last_of(".") + 1); - auto file_type = mime_types_.find(file_ext); - return (file_type != mime_types_.end()) ? file_type->second : HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + auto file_type = mime_types_.find(file_ext); + return (file_type != mime_types_.end()) ? file_type->second + : HTTP_SERVER_NS::CONTENT_TYPE_TEXT; }; /** @@ -83,56 +83,62 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer * assuming index.html is the wanted file if a directory is given * @param name of the file */ - std::string GetFileName(std::string S) - { - if (S.back() == '/') - { + std::string GetFileName(std::string S) { + if (S.back() == '/') { auto temp = S.substr(0, S.size() - 1); - S = temp; + S = temp; } - // If filename appears to be a directory, serve the hypothetical index.html file there - if (S.find(".") == std::string::npos) - S += "/index.html"; + // If filename appears to be a directory, serve the hypothetical index.html + // file there + if (S.find(".") == std::string::npos) S += "/index.html"; return S; } /** - * Sets the response object with the correct file data based on the requested file address, - * or return 404 error if a file isn't found - * @param req is the HTTP request, which we use to figure out the response to send - * @param resp is the HTTP response we want to send to the frontend, including file data + * Sets the response object with the correct file data based on the requested + * file address, or return 404 error if a file isn't found + * @param req is the HTTP request, which we use to figure out the response to + * send + * @param resp is the HTTP response we want to send to the frontend, including + * file data */ HTTP_SERVER_NS::HttpRequestCallback ServeFile{ - [&](HTTP_SERVER_NS::HttpRequest const &req, HTTP_SERVER_NS::HttpResponse &resp) { + [&](HTTP_SERVER_NS::HttpRequest const &req, + HTTP_SERVER_NS::HttpResponse &resp) { LOG_INFO("File: %s\n", req.uri.c_str()); - auto f = GetFileName(req.uri); + auto f = GetFileName(req.uri); auto filename = f.c_str() + 1; std::vector content; - if (FileGetSuccess(filename, content)) - { - resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = GetMimeContentType(filename); - resp.body = std::string(content.data(), content.size()); - resp.code = 200; - resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); + if (FileGetSuccess(filename, content)) { + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = + GetMimeContentType(filename); + resp.body = std::string(content.data(), content.size()); + resp.code = 200; + resp.message = + HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); return resp.code; } // Two additional 'special' return codes possible here: // 0 - proceed to next handler // -1 - immediately terminate and close connection - resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = HTTP_SERVER_NS::CONTENT_TYPE_TEXT; - resp.code = 404; - resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); - resp.body = resp.message; + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = + HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + resp.code = 404; + resp.message = + HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); + resp.body = resp.message; return 404; }}; // Maps file extensions to their HTTP-compatible mime file type const std::unordered_map mime_types_ = { - {"css", "text/css"}, {"png", "image/png"}, {"js", "text/javascript"}, - {"htm", "text/html"}, {"html", "text/html"}, {"json", "application/json"}, - {"txt", "text/plain"}, {"jpg", "image/jpeg"}, {"jpeg", "image/jpeg"}, + {"css", "text/css"}, {"png", "image/png"}, + {"js", "text/javascript"}, {"htm", "text/html"}, + {"html", "text/html"}, {"json", "application/json"}, + {"txt", "text/plain"}, {"jpg", "image/jpeg"}, + {"jpeg", "image/jpeg"}, }; const std::string root_endpt_ = "/"; }; diff --git a/ext/include/opentelemetry/ext/http/server/http_server.h b/ext/include/opentelemetry/ext/http/server/http_server.h index a4cc6cc814..d345eb3e13 100644 --- a/ext/include/opentelemetry/ext/http/server/http_server.h +++ b/ext/include/opentelemetry/ext/http/server/http_server.h @@ -21,25 +21,23 @@ #include "socket_tools.h" #ifdef HAVE_HTTP_DEBUG -# ifdef LOG_TRACE -# undef LOG_TRACE -# define LOG_TRACE(x, ...) printf(x "\n", __VA_ARGS__) -# endif +#ifdef LOG_TRACE +#undef LOG_TRACE +#define LOG_TRACE(x, ...) printf(x "\n", __VA_ARGS__) +#endif #endif #ifndef HTTP_SERVER_NS -# define HTTP_SERVER_NS testing +#define HTTP_SERVER_NS testing #endif -namespace HTTP_SERVER_NS -{ +namespace HTTP_SERVER_NS { -constexpr const char *CONTENT_TYPE = "Content-Type"; +constexpr const char *CONTENT_TYPE = "Content-Type"; constexpr const char *CONTENT_TYPE_TEXT = "text/plain"; -constexpr const char *CONTENT_TYPE_BIN = "application/octet-stream"; +constexpr const char *CONTENT_TYPE_BIN = "application/octet-stream"; -struct HttpRequest -{ +struct HttpRequest { std::string client; std::string method; std::string uri; @@ -48,42 +46,38 @@ struct HttpRequest std::string content; }; -struct HttpResponse -{ +struct HttpResponse { int code; std::string message; std::map headers; std::string body; }; -using CallbackFunction = std::function; +using CallbackFunction = + std::function; -class HttpRequestCallback -{ -protected: +class HttpRequestCallback { + protected: CallbackFunction callback = nullptr; -public: + public: HttpRequestCallback(){}; - HttpRequestCallback &operator=(HttpRequestCallback other) - { + HttpRequestCallback &operator=(HttpRequestCallback other) { callback = other.callback; return *this; }; HttpRequestCallback(CallbackFunction func) : callback(func){}; - HttpRequestCallback &operator=(CallbackFunction func) - { + HttpRequestCallback &operator=(CallbackFunction func) { callback = func; return (*this); } - virtual int onHttpRequest(HttpRequest const &request, HttpResponse &response) - { - if (callback != nullptr) - { + virtual int onHttpRequest(HttpRequest const &request, + HttpResponse &response) { + if (callback != nullptr) { return callback(request, response); } return 0; @@ -97,17 +91,13 @@ class HttpRequestCallback // Out of scope: // - Performance // - Full support of RFC 7230-7237 -class HttpServer : private SocketTools::Reactor::SocketCallback -{ - -protected: - struct Connection - { +class HttpServer : private SocketTools::Reactor::SocketCallback { + protected: + struct Connection { SocketTools::Socket socket; std::string receiveBuffer; std::string sendBuffer; - enum - { + enum { Idle, ReceivingHeaders, Sending100Continue, @@ -128,37 +118,32 @@ class HttpServer : private SocketTools::Reactor::SocketCallback SocketTools::Reactor m_reactor; std::list m_listeningSockets; - class HttpRequestHandler : public std::pair - { - - public: - HttpRequestHandler(std::string key, HttpRequestCallback *value) - { - first = key; + class HttpRequestHandler + : public std::pair { + public: + HttpRequestHandler(std::string key, HttpRequestCallback *value) { + first = key; second = value; }; - HttpRequestHandler() : std::pair() - { - first = ""; + HttpRequestHandler() : std::pair() { + first = ""; second = nullptr; }; - HttpRequestHandler &operator=(std::pair other) - { - first = other.first; + HttpRequestHandler &operator=( + std::pair other) { + first = other.first; second = other.second; return (*this); }; - HttpRequestHandler &operator=(HttpRequestCallback &cb) - { + HttpRequestHandler &operator=(HttpRequestCallback &cb) { second = &cb; return (*this); }; - HttpRequestHandler &operator=(HttpRequestCallback *cb) - { + HttpRequestHandler &operator=(HttpRequestCallback *cb) { second = cb; return (*this); }; @@ -169,7 +154,7 @@ class HttpServer : private SocketTools::Reactor::SocketCallback std::map m_connections; size_t m_maxRequestHeadersSize, m_maxRequestContentSize; -public: + public: void setKeepalive(bool keepAlive) { allowKeepalive = keepAlive; } HttpServer() @@ -179,32 +164,28 @@ class HttpServer : private SocketTools::Reactor::SocketCallback m_maxRequestHeadersSize(8192), m_maxRequestContentSize(2 * 1024 * 1024){}; - HttpServer(std::string serverHost, int port = 30000) : HttpServer() - { + HttpServer(std::string serverHost, int port = 30000) : HttpServer() { std::ostringstream os; os << serverHost << ":" << port; setServerName(os.str()); addListeningPort(port); }; - ~HttpServer() - { - for (auto &sock : m_listeningSockets) - { + ~HttpServer() { + for (auto &sock : m_listeningSockets) { sock.close(); } } - void setRequestLimits(size_t maxRequestHeadersSize, size_t maxRequestContentSize) - { + void setRequestLimits(size_t maxRequestHeadersSize, + size_t maxRequestContentSize) { m_maxRequestHeadersSize = maxRequestHeadersSize; m_maxRequestContentSize = maxRequestContentSize; } void setServerName(std::string const &name) { m_serverHost = name; } - int addListeningPort(int port) - { + int addListeningPort(int port) { SocketTools::Socket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); socket.setNonBlocking(); socket.setReuseAddr(); @@ -221,24 +202,23 @@ class HttpServer : private SocketTools::Reactor::SocketCallback return addr.port(); } - HttpRequestHandler &addHandler(const std::string &root, HttpRequestCallback &handler) - { + HttpRequestHandler &addHandler(const std::string &root, + HttpRequestCallback &handler) { // No thread-safety here! m_handlers.push_back({root, &handler}); LOG_INFO("HttpServer: Added handler for %s", root.c_str()); return m_handlers.back(); } - HttpRequestHandler &operator[](const std::string &root) - { + HttpRequestHandler &operator[](const std::string &root) { // No thread-safety here! m_handlers.push_back({root, nullptr}); LOG_INFO("HttpServer: Added handler for %s", root.c_str()); return m_handlers.back(); } - HttpServer &operator+=(std::pair other) - { + HttpServer &operator+=( + std::pair other) { LOG_INFO("HttpServer: Added handler for %s", other.first.c_str()); m_handlers.push_back(HttpRequestHandler(other.first, &other.second)); return (*this); @@ -248,47 +228,44 @@ class HttpServer : private SocketTools::Reactor::SocketCallback void stop() { m_reactor.stop(); } -protected: - virtual void onSocketAcceptable(SocketTools::Socket socket) override - { + protected: + virtual void onSocketAcceptable(SocketTools::Socket socket) override { LOG_TRACE("HttpServer: accepting socket fd=0x%llx", socket.m_sock); - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) != - m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), + socket) != m_listeningSockets.end()); SocketTools::Socket csocket; SocketTools::SocketAddr caddr; - if (socket.accept(csocket, caddr)) - { + if (socket.accept(csocket, caddr)) { csocket.setNonBlocking(); - Connection &conn = m_connections[csocket]; - conn.socket = csocket; - conn.state = Connection::Idle; + Connection &conn = m_connections[csocket]; + conn.socket = csocket; + conn.state = Connection::Idle; conn.request.client = caddr.toString(); - m_reactor.addSocket(csocket, SocketTools::Reactor::Readable | SocketTools::Reactor::Closed); + m_reactor.addSocket(csocket, SocketTools::Reactor::Readable | + SocketTools::Reactor::Closed); LOG_TRACE("HttpServer: [%s] accepted", conn.request.client.c_str()); } } - virtual void onSocketReadable(SocketTools::Socket socket) override - { + virtual void onSocketReadable(SocketTools::Socket socket) override { LOG_TRACE("HttpServer: reading socket fd=0x%llx", socket.m_sock); // No thread-safety here! - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == - m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), + socket) == m_listeningSockets.end()); // No thread-safety here! auto connIt = m_connections.find(socket); - if (connIt == m_connections.end()) - { + if (connIt == m_connections.end()) { return; } Connection &conn = connIt->second; char buffer[2048] = {0}; - int received = socket.recv(buffer, sizeof(buffer)); - LOG_TRACE("HttpServer: [%s] received %d", conn.request.client.c_str(), received); - if (received <= 0) - { + int received = socket.recv(buffer, sizeof(buffer)); + LOG_TRACE("HttpServer: [%s] received %d", conn.request.client.c_str(), + received); + if (received <= 0) { handleConnectionClosed(conn); return; } @@ -297,37 +274,32 @@ class HttpServer : private SocketTools::Reactor::SocketCallback handleConnection(conn); } - virtual void onSocketWritable(SocketTools::Socket socket) override - { + virtual void onSocketWritable(SocketTools::Socket socket) override { LOG_TRACE("HttpServer: writing socket fd=0x%llx", socket.m_sock); // No thread-safety here! - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == - m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), + socket) == m_listeningSockets.end()); // No thread-safety here! auto connIt = m_connections.find(socket); - if (connIt == m_connections.end()) - { + if (connIt == m_connections.end()) { return; } Connection &conn = connIt->second; - if (!sendMore(conn)) - { + if (!sendMore(conn)) { handleConnection(conn); } } - virtual void onSocketClosed(SocketTools::Socket socket) override - { + virtual void onSocketClosed(SocketTools::Socket socket) override { LOG_TRACE("HttpServer: closing socket fd=0x%llx", socket.m_sock); - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == - m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), + socket) == m_listeningSockets.end()); auto connIt = m_connections.find(socket); - if (connIt == m_connections.end()) - { + if (connIt == m_connections.end()) { return; } Connection &conn = connIt->second; @@ -335,38 +307,35 @@ class HttpServer : private SocketTools::Reactor::SocketCallback handleConnectionClosed(conn); } - bool sendMore(Connection &conn) - { - if (conn.sendBuffer.empty()) - { + bool sendMore(Connection &conn) { + if (conn.sendBuffer.empty()) { return false; } - int sent = conn.socket.send(conn.sendBuffer.data(), static_cast(conn.sendBuffer.size())); + int sent = conn.socket.send(conn.sendBuffer.data(), + static_cast(conn.sendBuffer.size())); LOG_TRACE("HttpServer: [%s] sent %d", conn.request.client.c_str(), sent); - if (sent < 0 && conn.socket.error() != SocketTools::Socket::ErrorWouldBlock) - { + if (sent < 0 && + conn.socket.error() != SocketTools::Socket::ErrorWouldBlock) { return true; } conn.sendBuffer.erase(0, sent); - if (!conn.sendBuffer.empty()) - { - m_reactor.addSocket(conn.socket, - SocketTools::Reactor::Writable | SocketTools::Reactor::Closed); + if (!conn.sendBuffer.empty()) { + m_reactor.addSocket(conn.socket, SocketTools::Reactor::Writable | + SocketTools::Reactor::Closed); return true; } return false; } -protected: - void handleConnectionClosed(Connection &conn) - { + protected: + void handleConnectionClosed(Connection &conn) { LOG_TRACE("HttpServer: [%s] closed", conn.request.client.c_str()); - if (conn.state != Connection::Idle && conn.state != Connection::Closing) - { - LOG_WARN("HttpServer: [%s] connection closed unexpectedly", conn.request.client.c_str()); + if (conn.state != Connection::Idle && conn.state != Connection::Closing) { + LOG_WARN("HttpServer: [%s] connection closed unexpectedly", + conn.request.client.c_str()); } m_reactor.removeSocket(conn.socket); auto connIt = m_connections.find(conn.socket); @@ -374,47 +343,43 @@ class HttpServer : private SocketTools::Reactor::SocketCallback m_connections.erase(connIt); } - void handleConnection(Connection &conn) - { - for (;;) - { - if (conn.state == Connection::Idle) - { + void handleConnection(Connection &conn) { + for (;;) { + if (conn.state == Connection::Idle) { conn.response.code = 0; - conn.state = Connection::ReceivingHeaders; - LOG_TRACE("HttpServer: [%s] receiving headers", conn.request.client.c_str()); + conn.state = Connection::ReceivingHeaders; + LOG_TRACE("HttpServer: [%s] receiving headers", + conn.request.client.c_str()); } - if (conn.state == Connection::ReceivingHeaders) - { + if (conn.state == Connection::ReceivingHeaders) { bool lfOnly = false; - size_t ofs = conn.receiveBuffer.find("\r\n\r\n"); - if (ofs == std::string::npos) - { + size_t ofs = conn.receiveBuffer.find("\r\n\r\n"); + if (ofs == std::string::npos) { lfOnly = true; - ofs = conn.receiveBuffer.find("\n\n"); + ofs = conn.receiveBuffer.find("\n\n"); } - size_t headersLen = (ofs != std::string::npos) ? ofs : conn.receiveBuffer.length(); - if (headersLen > m_maxRequestHeadersSize) - { - LOG_WARN("HttpServer: [%s] headers too long - %u", conn.request.client.c_str(), + size_t headersLen = + (ofs != std::string::npos) ? ofs : conn.receiveBuffer.length(); + if (headersLen > m_maxRequestHeadersSize) { + LOG_WARN("HttpServer: [%s] headers too long - %u", + conn.request.client.c_str(), static_cast(headersLen)); conn.response.code = 431; // Request Header Fields Too Large - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } - if (ofs == std::string::npos) - { + if (ofs == std::string::npos) { return; } - if (!parseHeaders(conn)) - { - LOG_WARN("HttpServer: [%s] invalid headers", conn.request.client.c_str()); + if (!parseHeaders(conn)) { + LOG_WARN("HttpServer: [%s] invalid headers", + conn.request.client.c_str()); conn.response.code = 400; // Bad Request - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } LOG_INFO("HttpServer: [%s] %s %s %s", conn.request.client.c_str(), @@ -422,146 +387,128 @@ class HttpServer : private SocketTools::Reactor::SocketCallback conn.request.protocol.c_str()); conn.receiveBuffer.erase(0, ofs + (lfOnly ? 2 : 4)); - conn.keepalive = (conn.request.protocol == "HTTP/1.1"); + conn.keepalive = (conn.request.protocol == "HTTP/1.1"); auto const connection = conn.request.headers.find("Connection"); - if (connection != conn.request.headers.end()) - { - if (equalsLowercased(connection->second, "keep-alive")) - { + if (connection != conn.request.headers.end()) { + if (equalsLowercased(connection->second, "keep-alive")) { conn.keepalive = true; - } - else if (equalsLowercased(connection->second, "close")) - { + } else if (equalsLowercased(connection->second, "close")) { conn.keepalive = false; } } auto const contentLength = conn.request.headers.find("Content-Length"); - if (contentLength != conn.request.headers.end()) - { + if (contentLength != conn.request.headers.end()) { conn.contentLength = atoi(contentLength->second.c_str()); - } - else - { + } else { conn.contentLength = 0; } - if (conn.contentLength > m_maxRequestContentSize) - { - LOG_WARN("HttpServer: [%s] content too long - %u", conn.request.client.c_str(), + if (conn.contentLength > m_maxRequestContentSize) { + LOG_WARN("HttpServer: [%s] content too long - %u", + conn.request.client.c_str(), static_cast(conn.contentLength)); conn.response.code = 413; // Payload Too Large - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } auto const expect = conn.request.headers.find("Expect"); - if (expect != conn.request.headers.end() && conn.request.protocol == "HTTP/1.1") - { - if (!equalsLowercased(expect->second, "100-continue")) - { - LOG_WARN("HttpServer: [%s] unknown expectation - %s", conn.request.client.c_str(), - expect->second.c_str()); + if (expect != conn.request.headers.end() && + conn.request.protocol == "HTTP/1.1") { + if (!equalsLowercased(expect->second, "100-continue")) { + LOG_WARN("HttpServer: [%s] unknown expectation - %s", + conn.request.client.c_str(), expect->second.c_str()); conn.response.code = 417; // Expectation Failed - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } conn.sendBuffer = "HTTP/1.1 100 Continue\r\n\r\n"; - conn.state = Connection::Sending100Continue; - LOG_TRACE("HttpServer: [%s] sending \"100 Continue\"", conn.request.client.c_str()); + conn.state = Connection::Sending100Continue; + LOG_TRACE("HttpServer: [%s] sending \"100 Continue\"", + conn.request.client.c_str()); continue; } conn.state = Connection::ReceivingBody; - LOG_TRACE("HttpServer: [%s] receiving body", conn.request.client.c_str()); + LOG_TRACE("HttpServer: [%s] receiving body", + conn.request.client.c_str()); } - if (conn.state == Connection::Sending100Continue) - { - if (sendMore(conn)) - { + if (conn.state == Connection::Sending100Continue) { + if (sendMore(conn)) { return; } conn.state = Connection::ReceivingBody; - LOG_TRACE("HttpServer: [%s] receiving body", conn.request.client.c_str()); + LOG_TRACE("HttpServer: [%s] receiving body", + conn.request.client.c_str()); } - if (conn.state == Connection::ReceivingBody) - { - if (conn.receiveBuffer.length() < conn.contentLength) - { + if (conn.state == Connection::ReceivingBody) { + if (conn.receiveBuffer.length() < conn.contentLength) { return; } - if (conn.receiveBuffer.length() == conn.contentLength) - { + if (conn.receiveBuffer.length() == conn.contentLength) { conn.request.content = std::move(conn.receiveBuffer); conn.receiveBuffer.clear(); - } - else - { - conn.request.content.assign(conn.receiveBuffer, 0, conn.contentLength); + } else { + conn.request.content.assign(conn.receiveBuffer, 0, + conn.contentLength); conn.receiveBuffer.erase(0, conn.contentLength); } conn.state = Connection::Processing; - LOG_TRACE("HttpServer: [%s] processing request", conn.request.client.c_str()); + LOG_TRACE("HttpServer: [%s] processing request", + conn.request.client.c_str()); } - if (conn.state == Connection::Processing) - { + if (conn.state == Connection::Processing) { processRequest(conn); std::ostringstream os; - os << conn.request.protocol << ' ' << conn.response.code << ' ' << conn.response.message - << "\r\n"; - for (auto const &header : conn.response.headers) - { + os << conn.request.protocol << ' ' << conn.response.code << ' ' + << conn.response.message << "\r\n"; + for (auto const &header : conn.response.headers) { os << header.first << ": " << header.second << "\r\n"; } os << "\r\n"; conn.sendBuffer = os.str(); - conn.state = Connection::SendingHeaders; - LOG_TRACE("HttpServer: [%s] sending headers", conn.request.client.c_str()); + conn.state = Connection::SendingHeaders; + LOG_TRACE("HttpServer: [%s] sending headers", + conn.request.client.c_str()); } - if (conn.state == Connection::SendingHeaders) - { - if (sendMore(conn)) - { + if (conn.state == Connection::SendingHeaders) { + if (sendMore(conn)) { return; } conn.sendBuffer = std::move(conn.response.body); - conn.state = Connection::SendingBody; + conn.state = Connection::SendingBody; LOG_TRACE("HttpServer: [%s] sending body", conn.request.client.c_str()); } - if (conn.state == Connection::SendingBody) - { - if (sendMore(conn)) - { + if (conn.state == Connection::SendingBody) { + if (sendMore(conn)) { return; } conn.keepalive &= allowKeepalive; - if (conn.keepalive) - { - m_reactor.addSocket(conn.socket, - SocketTools::Reactor::Readable | SocketTools::Reactor::Closed); + if (conn.keepalive) { + m_reactor.addSocket(conn.socket, SocketTools::Reactor::Readable | + SocketTools::Reactor::Closed); conn.state = Connection::Idle; - LOG_TRACE("HttpServer: [%s] idle (keep-alive)", conn.request.client.c_str()); - if (conn.receiveBuffer.empty()) - { + LOG_TRACE("HttpServer: [%s] idle (keep-alive)", + conn.request.client.c_str()); + if (conn.receiveBuffer.empty()) { return; } - } - else - { + } else { conn.socket.shutdown(SocketTools::Socket::ShutdownSend); m_reactor.addSocket(conn.socket, SocketTools::Reactor::Closed); conn.state = Connection::Closing; @@ -569,114 +516,94 @@ class HttpServer : private SocketTools::Reactor::SocketCallback } } - if (conn.state == Connection::Closing) - { + if (conn.state == Connection::Closing) { return; } } } - bool parseHeaders(Connection &conn) - { + bool parseHeaders(Connection &conn) { // Method char const *begin = conn.receiveBuffer.c_str(); - char const *ptr = begin; - while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') - { + char const *ptr = begin; + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { ptr++; } - if (*ptr != ' ') - { + if (*ptr != ' ') { return false; } conn.request.method.assign(begin, ptr); - while (*ptr == ' ') - { + while (*ptr == ' ') { ptr++; } // URI begin = ptr; - while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') - { + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { ptr++; } - if (*ptr != ' ') - { + if (*ptr != ' ') { return false; } conn.request.uri.assign(begin, ptr); - while (*ptr == ' ') - { + while (*ptr == ' ') { ptr++; } // Protocol begin = ptr; - while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') - { + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { ptr++; } - if (*ptr != '\r' && *ptr != '\n') - { + if (*ptr != '\r' && *ptr != '\n') { return false; } conn.request.protocol.assign(begin, ptr); - if (*ptr == '\r') - { + if (*ptr == '\r') { ptr++; } - if (*ptr != '\n') - { + if (*ptr != '\n') { return false; } ptr++; // Headers conn.request.headers.clear(); - while (*ptr != '\r' && *ptr != '\n') - { + while (*ptr != '\r' && *ptr != '\n') { // Name begin = ptr; - while (*ptr && *ptr != ':' && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') - { + while (*ptr && *ptr != ':' && *ptr != ' ' && *ptr != '\r' && + *ptr != '\n') { ptr++; } - if (*ptr != ':') - { + if (*ptr != ':') { return false; } std::string name = normalizeHeaderName(begin, ptr); ptr++; - while (*ptr == ' ') - { + while (*ptr == ' ') { ptr++; } // Value begin = ptr; - while (*ptr && *ptr != '\r' && *ptr != '\n') - { + while (*ptr && *ptr != '\r' && *ptr != '\n') { ptr++; } conn.request.headers[name] = std::string(begin, ptr); - if (*ptr == '\r') - { + if (*ptr == '\r') { ptr++; } - if (*ptr != '\n') - { + if (*ptr != '\n') { return false; } ptr++; } - if (*ptr == '\r') - { + if (*ptr == '\r') { ptr++; } - if (*ptr != '\n') - { + if (*ptr != '\n') { return false; } ptr++; @@ -684,87 +611,75 @@ class HttpServer : private SocketTools::Reactor::SocketCallback return true; } - static bool equalsLowercased(std::string const &str, char const *mask) - { + static bool equalsLowercased(std::string const &str, char const *mask) { char const *ptr = str.c_str(); - while (*ptr && *mask && ::tolower(*ptr) == *mask) - { + while (*ptr && *mask && ::tolower(*ptr) == *mask) { ptr++; mask++; } return !*ptr && !*mask; } - static std::string normalizeHeaderName(char const *begin, char const *end) - { + static std::string normalizeHeaderName(char const *begin, char const *end) { std::string result(begin, end); bool first = true; - for (char &ch : result) - { - if (first) - { - ch = static_cast(::toupper(ch)); + for (char &ch : result) { + if (first) { + ch = static_cast(::toupper(ch)); first = false; - } - else if (ch == '-') - { + } else if (ch == '-') { first = true; - } - else - { + } else { ch = static_cast(::tolower(ch)); } } return result; } - void processRequest(Connection &conn) - { + void processRequest(Connection &conn) { conn.response.message.clear(); conn.response.headers.clear(); conn.response.body.clear(); - if (conn.response.code == 0) - { + if (conn.response.code == 0) { conn.response.code = 404; // Not Found - for (auto &handler : m_handlers) - { + for (auto &handler : m_handlers) { if (conn.request.uri.length() >= handler.first.length() && - strncmp(conn.request.uri.c_str(), handler.first.c_str(), handler.first.length()) == 0) - { - LOG_TRACE("HttpServer: [%s] using handler for %s", conn.request.client.c_str(), - handler.first.c_str()); - // auto callback = handler.second; // Bazel gets mad at this unused var, uncomment when - // using - int result = handler.second->onHttpRequest(conn.request, conn.response); - if (result != 0) - { + strncmp(conn.request.uri.c_str(), handler.first.c_str(), + handler.first.length()) == 0) { + LOG_TRACE("HttpServer: [%s] using handler for %s", + conn.request.client.c_str(), handler.first.c_str()); + // auto callback = handler.second; // Bazel gets mad at this unused + // var, uncomment when using + int result = + handler.second->onHttpRequest(conn.request, conn.response); + if (result != 0) { conn.response.code = result; break; } } } - if (conn.response.code == -1) - { - LOG_TRACE("HttpServer: [%s] closing by request", conn.request.client.c_str()); + if (conn.response.code == -1) { + LOG_TRACE("HttpServer: [%s] closing by request", + conn.request.client.c_str()); handleConnectionClosed(conn); } } - if (conn.response.message.empty()) - { + if (conn.response.message.empty()) { conn.response.message = getDefaultResponseMessage(conn.response.code); } - conn.response.headers["Host"] = m_serverHost; - conn.response.headers["Connection"] = (conn.keepalive ? "keep-alive" : "close"); - conn.response.headers["Date"] = formatTimestamp(time(nullptr)); - conn.response.headers["Content-Length"] = std::to_string(conn.response.body.size()); + conn.response.headers["Host"] = m_serverHost; + conn.response.headers["Connection"] = + (conn.keepalive ? "keep-alive" : "close"); + conn.response.headers["Date"] = formatTimestamp(time(nullptr)); + conn.response.headers["Content-Length"] = + std::to_string(conn.response.body.size()); } - static std::string formatTimestamp(time_t time) - { + static std::string formatTimestamp(time_t time) { tm tm; #ifdef _WIN32 gmtime_s(&tm, &time); @@ -776,11 +691,9 @@ class HttpServer : private SocketTools::Reactor::SocketCallback return buf; } -public: - static char const *getDefaultResponseMessage(int code) - { - switch (code) - { + public: + static char const *getDefaultResponseMessage(int code) { + switch (code) { // *INDENT-OFF* case 100: return "Continue"; diff --git a/ext/include/opentelemetry/ext/http/server/socket_tools.h b/ext/include/opentelemetry/ext/http/server/socket_tools.h index 1cdc8a6881..0d9c8667ab 100644 --- a/ext/include/opentelemetry/ext/http/server/socket_tools.h +++ b/ext/include/opentelemetry/ext/http/server/socket_tools.h @@ -28,73 +28,70 @@ //# include -# include +#include // TODO: consider NOMINMAX -# undef min -# undef max -# pragma comment(lib, "ws2_32.lib") +#undef min +#undef max +#pragma comment(lib, "ws2_32.lib") #else -# include +#include -# ifdef __linux__ -# include -# endif +#ifdef __linux__ +#include +#endif -# if __APPLE__ -# include "TargetConditionals.h" +#if __APPLE__ +#include "TargetConditionals.h" // Use kqueue on mac -# include -# include -# include -# endif +#include +#include +#include +#endif // Common POSIX headers for Linux and Mac OS X -# include -# include -# include -# include -# include -# include +#include +#include +#include +#include +#include +#include #endif #ifndef _Out_cap_ -# define _Out_cap_(size) +#define _Out_cap_(size) #endif #if defined(HAVE_CONSOLE_LOG) && !defined(LOG_DEBUG) // Log to console if there's no standard log facility defined -# include -# ifndef LOG_DEBUG -# define LOG_DEBUG(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -# define LOG_TRACE(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -# define LOG_INFO(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -# define LOG_WARN(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -# define LOG_ERROR(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -# endif +#include +#ifndef LOG_DEBUG +#define LOG_DEBUG(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +#define LOG_TRACE(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +#define LOG_INFO(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +#define LOG_WARN(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +#define LOG_ERROR(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +#endif #endif #ifndef LOG_DEBUG // Don't log anything if there's no standard log facility defined -# define LOG_DEBUG(fmt_, ...) -# define LOG_TRACE(fmt_, ...) -# define LOG_INFO(fmt_, ...) -# define LOG_WARN(fmt_, ...) -# define LOG_ERROR(fmt_, ...) +#define LOG_DEBUG(fmt_, ...) +#define LOG_TRACE(fmt_, ...) +#define LOG_INFO(fmt_, ...) +#define LOG_WARN(fmt_, ...) +#define LOG_ERROR(fmt_, ...) #endif -namespace common -{ +namespace common { /// /// A simple thread, derived class overloads onThread() method. /// -struct Thread -{ - +struct Thread { std::thread m_thread; volatile bool m_terminate{false}; @@ -108,20 +105,17 @@ struct Thread /// /// Start Thread /// - void startThread() - { + void startThread() { m_terminate = false; - m_thread = std::thread([&]() { this->onThread(); }); + m_thread = std::thread([&]() { this->onThread(); }); } /// /// Join Thread /// - void joinThread() - { + void joinThread() { m_terminate = true; - if (m_thread.joinable()) - { + if (m_thread.joinable()) { m_thread.join(); } } @@ -145,17 +139,13 @@ struct Thread }; }; // namespace common -namespace SocketTools -{ +namespace SocketTools { #ifdef _WIN32 // WinSocks need extra (de)initialization, solved by a global object here, // whose constructor/destructor will be called before and after main(). -struct WsaInitializer -{ - - WsaInitializer() - { +struct WsaInitializer { + WsaInitializer() { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); } @@ -170,8 +160,7 @@ static WsaInitializer g_wsaInitializer; /// /// Encapsulation of sockaddr(_in) /// -struct SocketAddr -{ +struct SocketAddr { static u_long const Loopback = 0x7F000001; sockaddr m_data; @@ -182,39 +171,33 @@ struct SocketAddr /// SocketAddr SocketAddr() { memset(&m_data, 0, sizeof(m_data)); } - SocketAddr(u_long addr, int port) - { - sockaddr_in &inet4 = reinterpret_cast(m_data); - inet4.sin_family = AF_INET; - inet4.sin_port = htons(static_cast(port)); + SocketAddr(u_long addr, int port) { + sockaddr_in &inet4 = reinterpret_cast(m_data); + inet4.sin_family = AF_INET; + inet4.sin_port = htons(static_cast(port)); inet4.sin_addr.s_addr = htonl(addr); } - SocketAddr(char const *addr) - { + SocketAddr(char const *addr) { #ifdef _WIN32 INT addrlen = sizeof(m_data); WCHAR buf[200]; - for (int i = 0; i < sizeof(buf) && addr[i]; i++) - { + for (int i = 0; i < sizeof(buf) && addr[i]; i++) { buf[i] = addr[i]; } buf[199] = L'\0'; ::WSAStringToAddressW(buf, AF_INET, nullptr, &m_data, &addrlen); #else sockaddr_in &inet4 = reinterpret_cast(m_data); - inet4.sin_family = AF_INET; - char const *colon = strchr(addr, ':'); - if (colon) - { + inet4.sin_family = AF_INET; + char const *colon = strchr(addr, ':'); + if (colon) { inet4.sin_port = htons(atoi(colon + 1)); char buf[16]; memcpy(buf, addr, std::min(15, colon - addr)); buf[15] = '\0'; ::inet_pton(AF_INET, buf, &inet4.sin_addr); - } - else - { + } else { inet4.sin_port = 0; ::inet_pton(AF_INET, addr, &inet4.sin_addr); } @@ -229,12 +212,11 @@ struct SocketAddr operator const sockaddr *() const { return &m_data; } - int port() const - { - switch (m_data.sa_family) - { + int port() const { + switch (m_data.sa_family) { case AF_INET: { - sockaddr_in const &inet4 = reinterpret_cast(m_data); + sockaddr_in const &inet4 = + reinterpret_cast(m_data); return ntohs(inet4.sin_port); } @@ -243,17 +225,16 @@ struct SocketAddr } } - std::string toString() const - { + std::string toString() const { std::ostringstream os; - switch (m_data.sa_family) - { + switch (m_data.sa_family) { case AF_INET: { - sockaddr_in const &inet4 = reinterpret_cast(m_data); - u_long addr = ntohl(inet4.sin_addr.s_addr); - os << (addr >> 24) << '.' << ((addr >> 16) & 255) << '.' << ((addr >> 8) & 255) << '.' - << (addr & 255); + sockaddr_in const &inet4 = + reinterpret_cast(m_data); + u_long addr = ntohl(inet4.sin_addr.s_addr); + os << (addr >> 24) << '.' << ((addr >> 16) & 255) << '.' + << ((addr >> 8) & 255) << '.' << (addr & 255); os << ':' << ntohs(inet4.sin_port); break; } @@ -268,9 +249,7 @@ struct SocketAddr /// /// Encapsulation of a socket (non-exclusive ownership) /// -struct Socket -{ - +struct Socket { #ifdef _WIN32 typedef SOCKET Type; static Type const Invalid = INVALID_SOCKET; @@ -289,16 +268,19 @@ struct Socket operator Socket::Type() const { return m_sock; } - bool operator==(Socket const &other) const { return (m_sock == other.m_sock); } + bool operator==(Socket const &other) const { + return (m_sock == other.m_sock); + } - bool operator!=(Socket const &other) const { return (m_sock != other.m_sock); } + bool operator!=(Socket const &other) const { + return (m_sock != other.m_sock); + } bool operator<(Socket const &other) const { return (m_sock < other.m_sock); } bool invalid() const { return (m_sock == Invalid); } - void setNonBlocking() - { + void setNonBlocking() { assert(m_sock != Invalid); #ifdef _WIN32 u_long value = 1; @@ -309,38 +291,34 @@ struct Socket #endif } - bool setReuseAddr() - { + bool setReuseAddr() { assert(m_sock != Invalid); #ifdef _WIN32 BOOL value = TRUE; #else int value = 1; #endif - return (::setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&value), - sizeof(value)) == 0); + return (::setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, + reinterpret_cast(&value), sizeof(value)) == 0); } - bool setNoDelay() - { + bool setNoDelay() { assert(m_sock != Invalid); #ifdef _WIN32 BOOL value = TRUE; #else int value = 1; #endif - return (::setsockopt(m_sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&value), - sizeof(value)) == 0); + return (::setsockopt(m_sock, IPPROTO_TCP, TCP_NODELAY, + reinterpret_cast(&value), sizeof(value)) == 0); } - bool connect(SocketAddr const &addr) - { + bool connect(SocketAddr const &addr) { assert(m_sock != Invalid); return (::connect(m_sock, addr, sizeof(addr)) == 0); } - void close() - { + void close() { assert(m_sock != Invalid); #ifdef _WIN32 ::closesocket(m_sock); @@ -350,27 +328,25 @@ struct Socket m_sock = Invalid; } - int recv(_Out_cap_(size) void *buffer, unsigned size) - { + int recv(_Out_cap_(size) void *buffer, unsigned size) { assert(m_sock != Invalid); int flags = 0; - return static_cast(::recv(m_sock, reinterpret_cast(buffer), size, flags)); + return static_cast( + ::recv(m_sock, reinterpret_cast(buffer), size, flags)); } - int send(void const *buffer, unsigned size) - { + int send(void const *buffer, unsigned size) { assert(m_sock != Invalid); - return static_cast(::send(m_sock, reinterpret_cast(buffer), size, 0)); + return static_cast( + ::send(m_sock, reinterpret_cast(buffer), size, 0)); } - bool bind(SocketAddr const &addr) - { + bool bind(SocketAddr const &addr) { assert(m_sock != Invalid); return (::bind(m_sock, addr, sizeof(addr)) == 0); } - bool getsockname(SocketAddr &addr) const - { + bool getsockname(SocketAddr &addr) const { assert(m_sock != Invalid); #ifdef _WIN32 int addrlen = sizeof(addr); @@ -380,14 +356,12 @@ struct Socket return (::getsockname(m_sock, addr, &addrlen) == 0); } - bool listen(int backlog) - { + bool listen(int backlog) { assert(m_sock != Invalid); return (::listen(m_sock, backlog) == 0); } - bool accept(Socket &csock, SocketAddr &caddr) - { + bool accept(Socket &csock, SocketAddr &caddr) { assert(m_sock != Invalid); #ifdef _WIN32 int addrlen = sizeof(caddr); @@ -398,14 +372,12 @@ struct Socket return !csock.invalid(); } - bool shutdown(int how) - { + bool shutdown(int how) { assert(m_sock != Invalid); return (::shutdown(m_sock, how) == 0); } - int error() const - { + int error() const { #ifdef _WIN32 return ::WSAGetLastError(); #else @@ -413,8 +385,7 @@ struct Socket #endif } - enum - { + enum { #ifdef _WIN32 ErrorWouldBlock = WSAEWOULDBLOCK #else @@ -422,16 +393,15 @@ struct Socket #endif }; - enum - { + enum { #ifdef _WIN32 ShutdownReceive = SD_RECEIVE, - ShutdownSend = SD_SEND, - ShutdownBoth = SD_BOTH + ShutdownSend = SD_SEND, + ShutdownBoth = SD_BOTH #else ShutdownReceive = SHUT_RD, - ShutdownSend = SHUT_WR, - ShutdownBoth = SHUT_RDWR + ShutdownSend = SHUT_WR, + ShutdownBoth = SHUT_RDWR #endif }; }; @@ -439,8 +409,7 @@ struct Socket /// /// Socket Data /// -struct SocketData -{ +struct SocketData { Socket socket; int flags; @@ -452,31 +421,22 @@ struct SocketData /// /// Socket Reactor /// -struct Reactor : protected common::Thread -{ - +struct Reactor : protected common::Thread { /// /// Socket State callback /// - class SocketCallback - { - public: - virtual void onSocketReadable(Socket sock) = 0; - virtual void onSocketWritable(Socket sock) = 0; + class SocketCallback { + public: + virtual void onSocketReadable(Socket sock) = 0; + virtual void onSocketWritable(Socket sock) = 0; virtual void onSocketAcceptable(Socket sock) = 0; - virtual void onSocketClosed(Socket sock) = 0; + virtual void onSocketClosed(Socket sock) = 0; }; /// /// Socket State /// - enum State - { - Readable = 1, - Writable = 2, - Acceptable = 4, - Closed = 8 - }; + enum State { Readable = 1, Writable = 2, Acceptable = 4, Closed = 8 }; SocketCallback &m_callback; @@ -494,20 +454,19 @@ struct Reactor : protected common::Thread #ifdef TARGET_OS_MAC /* use kqueue on Mac */ -# define KQUEUE_SIZE 32 +#define KQUEUE_SIZE 32 int kq{0}; struct kevent m_events[KQUEUE_SIZE]; #endif -public: - Reactor(SocketCallback &callback) : m_callback(callback) - { + public: + Reactor(SocketCallback &callback) : m_callback(callback) { #ifdef __linux__ -# ifdef ANDROID +#ifdef ANDROID m_epollFd = ::epoll_create(0); -# else +#else m_epollFd = ::epoll_create1(0); -# endif +#endif #endif #ifdef TARGET_OS_MAC @@ -516,8 +475,7 @@ struct Reactor : protected common::Thread #endif } - ~Reactor() - { + ~Reactor() { #ifdef __linux__ ::close(m_epollFd); #endif @@ -531,25 +489,21 @@ struct Reactor : protected common::Thread /// /// /// - void addSocket(const Socket &socket, int flags) - { - if (flags == 0) - { + void addSocket(const Socket &socket, int flags) { + if (flags == 0) { removeSocket(socket); - } - else - { + } else { auto it = std::find(m_sockets.begin(), m_sockets.end(), socket); - if (it == m_sockets.end()) - { - LOG_TRACE("Reactor: Adding socket 0x%x with flags 0x%x", static_cast(socket), flags); + if (it == m_sockets.end()) { + LOG_TRACE("Reactor: Adding socket 0x%x with flags 0x%x", + static_cast(socket), flags); #ifdef _WIN32 m_events.push_back(::WSACreateEvent()); #endif #ifdef __linux__ epoll_event event = {}; - event.data.fd = socket; - event.events = 0; + event.data.fd = socket; + event.events = 0; ::epoll_ctl(m_epollFd, EPOLL_CTL_ADD, socket, &event); #endif #ifdef TARGET_OS_MAC @@ -563,33 +517,27 @@ struct Reactor : protected common::Thread #endif m_sockets.push_back(SocketData()); m_sockets.back().socket = socket; - m_sockets.back().flags = 0; - it = m_sockets.end() - 1; - } - else - { - LOG_TRACE("Reactor: Updating socket 0x%x with flags 0x%x", static_cast(socket), flags); + m_sockets.back().flags = 0; + it = m_sockets.end() - 1; + } else { + LOG_TRACE("Reactor: Updating socket 0x%x with flags 0x%x", + static_cast(socket), flags); } - if (it->flags != flags) - { + if (it->flags != flags) { it->flags = flags; #ifdef _WIN32 long lNetworkEvents = 0; - if (it->flags & Readable) - { + if (it->flags & Readable) { lNetworkEvents |= FD_READ; } - if (it->flags & Writable) - { + if (it->flags & Writable) { lNetworkEvents |= FD_WRITE; } - if (it->flags & Acceptable) - { + if (it->flags & Acceptable) { lNetworkEvents |= FD_ACCEPT; } - if (it->flags & Closed) - { + if (it->flags & Closed) { lNetworkEvents |= FD_CLOSE; } auto eventIt = m_events.begin() + std::distance(m_sockets.begin(), it); @@ -597,22 +545,19 @@ struct Reactor : protected common::Thread #endif #ifdef __linux__ int events = 0; - if (it->flags & Readable) - { + if (it->flags & Readable) { events |= EPOLLIN; } - if (it->flags & Writable) - { + if (it->flags & Writable) { events |= EPOLLOUT; } - if (it->flags & Acceptable) - { + if (it->flags & Acceptable) { events |= EPOLLIN; } // if (it->flags & Closed) - always handled (EPOLLERR | EPOLLHUP) epoll_event event = {}; - event.data.fd = socket; - event.events = events; + event.data.fd = socket; + event.events = events; ::epoll_ctl(m_epollFd, EPOLL_CTL_MOD, socket, &event); #endif #ifdef TARGET_OS_MAC @@ -626,12 +571,10 @@ struct Reactor : protected common::Thread /// Remove Socket /// /// - void removeSocket(const Socket &socket) - { + void removeSocket(const Socket &socket) { LOG_TRACE("Reactor: Removing socket 0x%x", static_cast(socket)); auto it = std::find(m_sockets.begin(), m_sockets.end(), socket); - if (it != m_sockets.end()) - { + if (it != m_sockets.end()) { #ifdef _WIN32 auto eventIt = m_events.begin() + std::distance(m_sockets.begin(), it); ::WSAEventSelect(it->socket, *eventIt, 0); @@ -646,14 +589,12 @@ struct Reactor : protected common::Thread bzero(&event, sizeof(event)); event.ident = socket; EV_SET(&event, socket, EVFILT_READ, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) - { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { //// Already removed? LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } EV_SET(&event, socket, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) - { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { //// Already removed? LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } @@ -665,8 +606,7 @@ struct Reactor : protected common::Thread /// /// Start server /// - void start() - { + void start() { LOG_INFO("Reactor: Starting..."); startThread(); } @@ -674,36 +614,31 @@ struct Reactor : protected common::Thread /// /// Stop server /// - void stop() - { + void stop() { LOG_INFO("Reactor: Stopping..."); joinThread(); #ifdef _WIN32 - for (auto &hEvent : m_events) - { + for (auto &hEvent : m_events) { ::WSACloseEvent(hEvent); } #else /* Linux and Mac */ - for (auto &sd : m_sockets) - { -# ifdef __linux__ + for (auto &sd : m_sockets) { +#ifdef __linux__ ::epoll_ctl(m_epollFd, EPOLL_CTL_DEL, sd.socket, nullptr); -# endif -# ifdef TARGET_OS_MAC +#endif +#ifdef TARGET_OS_MAC struct kevent event; bzero(&event, sizeof(event)); event.ident = sd.socket; EV_SET(&event, sd.socket, EVFILT_READ, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) - { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } EV_SET(&event, sd.socket, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) - { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } -# endif +#endif } #endif m_sockets.clear(); @@ -712,80 +647,74 @@ struct Reactor : protected common::Thread /// /// Thread Loop for async events processing /// - virtual void onThread() override - { + virtual void onThread() override { LOG_INFO("Reactor: Thread started"); - while (!shouldTerminate()) - { + while (!shouldTerminate()) { #ifdef _WIN32 - DWORD dwResult = ::WSAWaitForMultipleEvents(static_cast(m_events.size()), - m_events.data(), FALSE, 500, FALSE); - if (dwResult == WSA_WAIT_TIMEOUT) - { + DWORD dwResult = + ::WSAWaitForMultipleEvents(static_cast(m_events.size()), + m_events.data(), FALSE, 500, FALSE); + if (dwResult == WSA_WAIT_TIMEOUT) { continue; } assert(dwResult <= WSA_WAIT_EVENT_0 + m_events.size()); - int index = dwResult - WSA_WAIT_EVENT_0; + int index = dwResult - WSA_WAIT_EVENT_0; Socket socket = m_sockets[index].socket; - int flags = m_sockets[index].flags; + int flags = m_sockets[index].flags; WSANETWORKEVENTS ne; ::WSAEnumNetworkEvents(socket, m_events[index], &ne); - LOG_TRACE("Reactor: Handling socket 0x%x (index %d) with active flags 0x%x (armed 0x%x)", - static_cast(socket), index, ne.lNetworkEvents, flags); + LOG_TRACE( + "Reactor: Handling socket 0x%x (index %d) with active flags 0x%x " + "(armed 0x%x)", + static_cast(socket), index, ne.lNetworkEvents, flags); - if ((flags & Readable) && (ne.lNetworkEvents & FD_READ)) - { + if ((flags & Readable) && (ne.lNetworkEvents & FD_READ)) { m_callback.onSocketReadable(socket); } - if ((flags & Writable) && (ne.lNetworkEvents & FD_WRITE)) - { + if ((flags & Writable) && (ne.lNetworkEvents & FD_WRITE)) { m_callback.onSocketWritable(socket); } - if ((flags & Acceptable) && (ne.lNetworkEvents & FD_ACCEPT)) - { + if ((flags & Acceptable) && (ne.lNetworkEvents & FD_ACCEPT)) { m_callback.onSocketAcceptable(socket); } - if ((flags & Closed) && (ne.lNetworkEvents & FD_CLOSE)) - { + if ((flags & Closed) && (ne.lNetworkEvents & FD_CLOSE)) { m_callback.onSocketClosed(socket); } #endif #ifdef __linux__ epoll_event events[4]; - int result = ::epoll_wait(m_epollFd, events, sizeof(events) / sizeof(events[0]), 500); - if (result == 0 || (result == -1 && errno == EINTR)) - { + int result = ::epoll_wait(m_epollFd, events, + sizeof(events) / sizeof(events[0]), 500); + if (result == 0 || (result == -1 && errno == EINTR)) { continue; } - assert(result >= 1 && static_cast(result) <= sizeof(events) / sizeof(events[0])); - for (int i = 0; i < result; i++) - { - auto it = std::find(m_sockets.begin(), m_sockets.end(), events[i].data.fd); + assert(result >= 1 && + static_cast(result) <= sizeof(events) / sizeof(events[0])); + for (int i = 0; i < result; i++) { + auto it = + std::find(m_sockets.begin(), m_sockets.end(), events[i].data.fd); assert(it != m_sockets.end()); Socket socket = it->socket; - int flags = it->flags; + int flags = it->flags; - LOG_TRACE("Reactor: Handling socket 0x%x active flags 0x%x (armed 0x%x)", - static_cast(socket), events[i].events, flags); + LOG_TRACE( + "Reactor: Handling socket 0x%x active flags 0x%x (armed 0x%x)", + static_cast(socket), events[i].events, flags); - if ((flags & Readable) && (events[i].events & EPOLLIN)) - { + if ((flags & Readable) && (events[i].events & EPOLLIN)) { m_callback.onSocketReadable(socket); } - if ((flags & Writable) && (events[i].events & EPOLLOUT)) - { + if ((flags & Writable) && (events[i].events & EPOLLOUT)) { m_callback.onSocketWritable(socket); } - if ((flags & Acceptable) && (events[i].events & EPOLLIN)) - { + if ((flags & Acceptable) && (events[i].events & EPOLLIN)) { m_callback.onSocketAcceptable(socket); } - if ((flags & Closed) && (events[i].events & (EPOLLHUP | EPOLLERR))) - { + if ((flags & Closed) && (events[i].events & (EPOLLHUP | EPOLLERR))) { m_callback.onSocketClosed(socket); } } @@ -794,58 +723,49 @@ struct Reactor : protected common::Thread #if defined(TARGET_OS_MAC) unsigned waitms = 500; // never block for more than 500ms struct timespec timeout; - timeout.tv_sec = waitms / 1000; + timeout.tv_sec = waitms / 1000; timeout.tv_nsec = (waitms % 1000) * 1000 * 1000; int nev = kevent(kq, NULL, 0, m_events, KQUEUE_SIZE, &timeout); - for (int i = 0; i < nev; i++) - { + for (int i = 0; i < nev; i++) { struct kevent &event = m_events[i]; - int fd = (int)event.ident; - auto it = std::find(m_sockets.begin(), m_sockets.end(), fd); + int fd = (int)event.ident; + auto it = std::find(m_sockets.begin(), m_sockets.end(), fd); assert(it != m_sockets.end()); Socket socket = it->socket; - int flags = it->flags; + int flags = it->flags; - LOG_TRACE("Handling socket 0x%x active flags 0x%x (armed 0x%x)", static_cast(socket), - event.flags, event.fflags); + LOG_TRACE("Handling socket 0x%x active flags 0x%x (armed 0x%x)", + static_cast(socket), event.flags, event.fflags); - if (event.filter == EVFILT_READ) - { - if (flags & Acceptable) - { + if (event.filter == EVFILT_READ) { + if (flags & Acceptable) { m_callback.onSocketAcceptable(socket); } - if (flags & Readable) - { + if (flags & Readable) { m_callback.onSocketReadable(socket); } continue; } - if (event.filter == EVFILT_WRITE) - { - if (flags & Writable) - { + if (event.filter == EVFILT_WRITE) { + if (flags & Writable) { m_callback.onSocketWritable(socket); } continue; } - if ((event.flags & EV_EOF) || (event.flags & EV_ERROR)) - { + if ((event.flags & EV_EOF) || (event.flags & EV_ERROR)) { LOG_TRACE("event.filter=%s", "EVFILT_WRITE"); m_callback.onSocketClosed(socket); it->flags = Closed; struct kevent kevt; EV_SET(&kevt, event.ident, EVFILT_READ, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) - { + if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } EV_SET(&kevt, event.ident, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) - { + if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } continue; From adac7cf449a4b6831a4b0444758b7828490830e2 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 23:04:14 +0000 Subject: [PATCH 09/11] Try running formatter again, default settings --- .../ext/http/server/file_http_server.h | 85 ++- .../ext/http/server/http_server.h | 527 ++++++++++-------- .../ext/http/server/socket_tools.h | 466 +++++++++------- 3 files changed, 620 insertions(+), 458 deletions(-) diff --git a/ext/include/opentelemetry/ext/http/server/file_http_server.h b/ext/include/opentelemetry/ext/http/server/file_http_server.h index 2e1cfa8066..77b77b0394 100644 --- a/ext/include/opentelemetry/ext/http/server/file_http_server.h +++ b/ext/include/opentelemetry/ext/http/server/file_http_server.h @@ -8,17 +8,19 @@ #include "opentelemetry/ext/http/server/http_server.h" -namespace HTTP_SERVER_NS { +namespace HTTP_SERVER_NS +{ -class FileHttpServer : public HTTP_SERVER_NS::HttpServer { - protected: +class FileHttpServer : public HTTP_SERVER_NS::HttpServer +{ +protected: /** * Construct the server by initializing the endpoint for serving static files, * which show up on the web if the user is on the given host:port. Static * files can be seen relative to the folder where the executable was ran. */ - FileHttpServer(const std::string &host = "127.0.0.1", int port = "3333") - : HttpServer() { + FileHttpServer(const std::string &host = "127.0.0.1", int port = "3333") : HttpServer() + { std::ostringstream os; os << host << ":" << port; setServerName(os.str()); @@ -31,11 +33,9 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * initialize their own, otherwise everything will be served like a file * @param server should be an instance of this object */ - void InitializeFileEndpoint(zPagesHttpServer &server) { - server[root_endpt_] = ServeFile; - } + void InitializeFileEndpoint(zPagesHttpServer &server) { server[root_endpt_] = ServeFile; } - private: +private: /** * Return whether a file is found whose location is searched for relative to * where the executable was triggered. If the file is valid, fill result with @@ -46,16 +46,18 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * @returns whether a file was found and result filled with display * information */ - bool FileGetSuccess(const std::string &filename, std::vector &result) { + bool FileGetSuccess(const std::string &filename, std::vector &result) + { #ifdef _WIN32 std::replace(filename.begin(), filename.end(), '/', '\\'); #endif std::streampos size; - std::ifstream file(filename, - std::ios::in | std::ios::binary | std::ios::ate); - if (file.is_open()) { + std::ifstream file(filename, std::ios::in | std::ios::binary | std::ios::ate); + if (file.is_open()) + { size = file.tellg(); - if (size) { + if (size) + { result.resize(size); file.seekg(0, std::ios::beg); file.read(result.data(), size); @@ -71,11 +73,11 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * @param name of the file * @returns file extension type under HTTP protocol */ - std::string GetMimeContentType(const std::string &filename) { + std::string GetMimeContentType(const std::string &filename) + { std::string file_ext = filename.substr(filename.find_last_of(".") + 1); - auto file_type = mime_types_.find(file_ext); - return (file_type != mime_types_.end()) ? file_type->second - : HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + auto file_type = mime_types_.find(file_ext); + return (file_type != mime_types_.end()) ? file_type->second : HTTP_SERVER_NS::CONTENT_TYPE_TEXT; }; /** @@ -83,14 +85,17 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * assuming index.html is the wanted file if a directory is given * @param name of the file */ - std::string GetFileName(std::string S) { - if (S.back() == '/') { + std::string GetFileName(std::string S) + { + if (S.back() == '/') + { auto temp = S.substr(0, S.size() - 1); - S = temp; + S = temp; } // If filename appears to be a directory, serve the hypothetical index.html // file there - if (S.find(".") == std::string::npos) S += "/index.html"; + if (S.find(".") == std::string::npos) + S += "/index.html"; return S; } @@ -104,41 +109,35 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * file data */ HTTP_SERVER_NS::HttpRequestCallback ServeFile{ - [&](HTTP_SERVER_NS::HttpRequest const &req, - HTTP_SERVER_NS::HttpResponse &resp) { + [&](HTTP_SERVER_NS::HttpRequest const &req, HTTP_SERVER_NS::HttpResponse &resp) { LOG_INFO("File: %s\n", req.uri.c_str()); - auto f = GetFileName(req.uri); + auto f = GetFileName(req.uri); auto filename = f.c_str() + 1; std::vector content; - if (FileGetSuccess(filename, content)) { - resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = - GetMimeContentType(filename); - resp.body = std::string(content.data(), content.size()); - resp.code = 200; - resp.message = - HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); + if (FileGetSuccess(filename, content)) + { + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = GetMimeContentType(filename); + resp.body = std::string(content.data(), content.size()); + resp.code = 200; + resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); return resp.code; } // Two additional 'special' return codes possible here: // 0 - proceed to next handler // -1 - immediately terminate and close connection - resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = - HTTP_SERVER_NS::CONTENT_TYPE_TEXT; - resp.code = 404; - resp.message = - HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); - resp.body = resp.message; + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + resp.code = 404; + resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); + resp.body = resp.message; return 404; }}; // Maps file extensions to their HTTP-compatible mime file type const std::unordered_map mime_types_ = { - {"css", "text/css"}, {"png", "image/png"}, - {"js", "text/javascript"}, {"htm", "text/html"}, - {"html", "text/html"}, {"json", "application/json"}, - {"txt", "text/plain"}, {"jpg", "image/jpeg"}, - {"jpeg", "image/jpeg"}, + {"css", "text/css"}, {"png", "image/png"}, {"js", "text/javascript"}, + {"htm", "text/html"}, {"html", "text/html"}, {"json", "application/json"}, + {"txt", "text/plain"}, {"jpg", "image/jpeg"}, {"jpeg", "image/jpeg"}, }; const std::string root_endpt_ = "/"; }; diff --git a/ext/include/opentelemetry/ext/http/server/http_server.h b/ext/include/opentelemetry/ext/http/server/http_server.h index d345eb3e13..672bf95c6a 100644 --- a/ext/include/opentelemetry/ext/http/server/http_server.h +++ b/ext/include/opentelemetry/ext/http/server/http_server.h @@ -21,23 +21,25 @@ #include "socket_tools.h" #ifdef HAVE_HTTP_DEBUG -#ifdef LOG_TRACE -#undef LOG_TRACE -#define LOG_TRACE(x, ...) printf(x "\n", __VA_ARGS__) -#endif +# ifdef LOG_TRACE +# undef LOG_TRACE +# define LOG_TRACE(x, ...) printf(x "\n", __VA_ARGS__) +# endif #endif #ifndef HTTP_SERVER_NS -#define HTTP_SERVER_NS testing +# define HTTP_SERVER_NS testing #endif -namespace HTTP_SERVER_NS { +namespace HTTP_SERVER_NS +{ -constexpr const char *CONTENT_TYPE = "Content-Type"; +constexpr const char *CONTENT_TYPE = "Content-Type"; constexpr const char *CONTENT_TYPE_TEXT = "text/plain"; -constexpr const char *CONTENT_TYPE_BIN = "application/octet-stream"; +constexpr const char *CONTENT_TYPE_BIN = "application/octet-stream"; -struct HttpRequest { +struct HttpRequest +{ std::string client; std::string method; std::string uri; @@ -46,38 +48,42 @@ struct HttpRequest { std::string content; }; -struct HttpResponse { +struct HttpResponse +{ int code; std::string message; std::map headers; std::string body; }; -using CallbackFunction = - std::function; +using CallbackFunction = std::function; -class HttpRequestCallback { - protected: +class HttpRequestCallback +{ +protected: CallbackFunction callback = nullptr; - public: +public: HttpRequestCallback(){}; - HttpRequestCallback &operator=(HttpRequestCallback other) { + HttpRequestCallback &operator=(HttpRequestCallback other) + { callback = other.callback; return *this; }; HttpRequestCallback(CallbackFunction func) : callback(func){}; - HttpRequestCallback &operator=(CallbackFunction func) { + HttpRequestCallback &operator=(CallbackFunction func) + { callback = func; return (*this); } - virtual int onHttpRequest(HttpRequest const &request, - HttpResponse &response) { - if (callback != nullptr) { + virtual int onHttpRequest(HttpRequest const &request, HttpResponse &response) + { + if (callback != nullptr) + { return callback(request, response); } return 0; @@ -91,13 +97,16 @@ class HttpRequestCallback { // Out of scope: // - Performance // - Full support of RFC 7230-7237 -class HttpServer : private SocketTools::Reactor::SocketCallback { - protected: - struct Connection { +class HttpServer : private SocketTools::Reactor::SocketCallback +{ +protected: + struct Connection + { SocketTools::Socket socket; std::string receiveBuffer; std::string sendBuffer; - enum { + enum + { Idle, ReceivingHeaders, Sending100Continue, @@ -118,32 +127,36 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { SocketTools::Reactor m_reactor; std::list m_listeningSockets; - class HttpRequestHandler - : public std::pair { - public: - HttpRequestHandler(std::string key, HttpRequestCallback *value) { - first = key; + class HttpRequestHandler : public std::pair + { + public: + HttpRequestHandler(std::string key, HttpRequestCallback *value) + { + first = key; second = value; }; - HttpRequestHandler() : std::pair() { - first = ""; + HttpRequestHandler() : std::pair() + { + first = ""; second = nullptr; }; - HttpRequestHandler &operator=( - std::pair other) { - first = other.first; + HttpRequestHandler &operator=(std::pair other) + { + first = other.first; second = other.second; return (*this); }; - HttpRequestHandler &operator=(HttpRequestCallback &cb) { + HttpRequestHandler &operator=(HttpRequestCallback &cb) + { second = &cb; return (*this); }; - HttpRequestHandler &operator=(HttpRequestCallback *cb) { + HttpRequestHandler &operator=(HttpRequestCallback *cb) + { second = cb; return (*this); }; @@ -154,7 +167,7 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { std::map m_connections; size_t m_maxRequestHeadersSize, m_maxRequestContentSize; - public: +public: void setKeepalive(bool keepAlive) { allowKeepalive = keepAlive; } HttpServer() @@ -164,28 +177,32 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { m_maxRequestHeadersSize(8192), m_maxRequestContentSize(2 * 1024 * 1024){}; - HttpServer(std::string serverHost, int port = 30000) : HttpServer() { + HttpServer(std::string serverHost, int port = 30000) : HttpServer() + { std::ostringstream os; os << serverHost << ":" << port; setServerName(os.str()); addListeningPort(port); }; - ~HttpServer() { - for (auto &sock : m_listeningSockets) { + ~HttpServer() + { + for (auto &sock : m_listeningSockets) + { sock.close(); } } - void setRequestLimits(size_t maxRequestHeadersSize, - size_t maxRequestContentSize) { + void setRequestLimits(size_t maxRequestHeadersSize, size_t maxRequestContentSize) + { m_maxRequestHeadersSize = maxRequestHeadersSize; m_maxRequestContentSize = maxRequestContentSize; } void setServerName(std::string const &name) { m_serverHost = name; } - int addListeningPort(int port) { + int addListeningPort(int port) + { SocketTools::Socket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); socket.setNonBlocking(); socket.setReuseAddr(); @@ -202,23 +219,24 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { return addr.port(); } - HttpRequestHandler &addHandler(const std::string &root, - HttpRequestCallback &handler) { + HttpRequestHandler &addHandler(const std::string &root, HttpRequestCallback &handler) + { // No thread-safety here! m_handlers.push_back({root, &handler}); LOG_INFO("HttpServer: Added handler for %s", root.c_str()); return m_handlers.back(); } - HttpRequestHandler &operator[](const std::string &root) { + HttpRequestHandler &operator[](const std::string &root) + { // No thread-safety here! m_handlers.push_back({root, nullptr}); LOG_INFO("HttpServer: Added handler for %s", root.c_str()); return m_handlers.back(); } - HttpServer &operator+=( - std::pair other) { + HttpServer &operator+=(std::pair other) + { LOG_INFO("HttpServer: Added handler for %s", other.first.c_str()); m_handlers.push_back(HttpRequestHandler(other.first, &other.second)); return (*this); @@ -228,44 +246,47 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { void stop() { m_reactor.stop(); } - protected: - virtual void onSocketAcceptable(SocketTools::Socket socket) override { +protected: + virtual void onSocketAcceptable(SocketTools::Socket socket) override + { LOG_TRACE("HttpServer: accepting socket fd=0x%llx", socket.m_sock); - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), - socket) != m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) != + m_listeningSockets.end()); SocketTools::Socket csocket; SocketTools::SocketAddr caddr; - if (socket.accept(csocket, caddr)) { + if (socket.accept(csocket, caddr)) + { csocket.setNonBlocking(); - Connection &conn = m_connections[csocket]; - conn.socket = csocket; - conn.state = Connection::Idle; + Connection &conn = m_connections[csocket]; + conn.socket = csocket; + conn.state = Connection::Idle; conn.request.client = caddr.toString(); - m_reactor.addSocket(csocket, SocketTools::Reactor::Readable | - SocketTools::Reactor::Closed); + m_reactor.addSocket(csocket, SocketTools::Reactor::Readable | SocketTools::Reactor::Closed); LOG_TRACE("HttpServer: [%s] accepted", conn.request.client.c_str()); } } - virtual void onSocketReadable(SocketTools::Socket socket) override { + virtual void onSocketReadable(SocketTools::Socket socket) override + { LOG_TRACE("HttpServer: reading socket fd=0x%llx", socket.m_sock); // No thread-safety here! - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), - socket) == m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == + m_listeningSockets.end()); // No thread-safety here! auto connIt = m_connections.find(socket); - if (connIt == m_connections.end()) { + if (connIt == m_connections.end()) + { return; } Connection &conn = connIt->second; char buffer[2048] = {0}; - int received = socket.recv(buffer, sizeof(buffer)); - LOG_TRACE("HttpServer: [%s] received %d", conn.request.client.c_str(), - received); - if (received <= 0) { + int received = socket.recv(buffer, sizeof(buffer)); + LOG_TRACE("HttpServer: [%s] received %d", conn.request.client.c_str(), received); + if (received <= 0) + { handleConnectionClosed(conn); return; } @@ -274,32 +295,37 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { handleConnection(conn); } - virtual void onSocketWritable(SocketTools::Socket socket) override { + virtual void onSocketWritable(SocketTools::Socket socket) override + { LOG_TRACE("HttpServer: writing socket fd=0x%llx", socket.m_sock); // No thread-safety here! - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), - socket) == m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == + m_listeningSockets.end()); // No thread-safety here! auto connIt = m_connections.find(socket); - if (connIt == m_connections.end()) { + if (connIt == m_connections.end()) + { return; } Connection &conn = connIt->second; - if (!sendMore(conn)) { + if (!sendMore(conn)) + { handleConnection(conn); } } - virtual void onSocketClosed(SocketTools::Socket socket) override { + virtual void onSocketClosed(SocketTools::Socket socket) override + { LOG_TRACE("HttpServer: closing socket fd=0x%llx", socket.m_sock); - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), - socket) == m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == + m_listeningSockets.end()); auto connIt = m_connections.find(socket); - if (connIt == m_connections.end()) { + if (connIt == m_connections.end()) + { return; } Connection &conn = connIt->second; @@ -307,35 +333,38 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { handleConnectionClosed(conn); } - bool sendMore(Connection &conn) { - if (conn.sendBuffer.empty()) { + bool sendMore(Connection &conn) + { + if (conn.sendBuffer.empty()) + { return false; } - int sent = conn.socket.send(conn.sendBuffer.data(), - static_cast(conn.sendBuffer.size())); + int sent = conn.socket.send(conn.sendBuffer.data(), static_cast(conn.sendBuffer.size())); LOG_TRACE("HttpServer: [%s] sent %d", conn.request.client.c_str(), sent); - if (sent < 0 && - conn.socket.error() != SocketTools::Socket::ErrorWouldBlock) { + if (sent < 0 && conn.socket.error() != SocketTools::Socket::ErrorWouldBlock) + { return true; } conn.sendBuffer.erase(0, sent); - if (!conn.sendBuffer.empty()) { - m_reactor.addSocket(conn.socket, SocketTools::Reactor::Writable | - SocketTools::Reactor::Closed); + if (!conn.sendBuffer.empty()) + { + m_reactor.addSocket(conn.socket, + SocketTools::Reactor::Writable | SocketTools::Reactor::Closed); return true; } return false; } - protected: - void handleConnectionClosed(Connection &conn) { +protected: + void handleConnectionClosed(Connection &conn) + { LOG_TRACE("HttpServer: [%s] closed", conn.request.client.c_str()); - if (conn.state != Connection::Idle && conn.state != Connection::Closing) { - LOG_WARN("HttpServer: [%s] connection closed unexpectedly", - conn.request.client.c_str()); + if (conn.state != Connection::Idle && conn.state != Connection::Closing) + { + LOG_WARN("HttpServer: [%s] connection closed unexpectedly", conn.request.client.c_str()); } m_reactor.removeSocket(conn.socket); auto connIt = m_connections.find(conn.socket); @@ -343,43 +372,47 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { m_connections.erase(connIt); } - void handleConnection(Connection &conn) { - for (;;) { - if (conn.state == Connection::Idle) { + void handleConnection(Connection &conn) + { + for (;;) + { + if (conn.state == Connection::Idle) + { conn.response.code = 0; - conn.state = Connection::ReceivingHeaders; - LOG_TRACE("HttpServer: [%s] receiving headers", - conn.request.client.c_str()); + conn.state = Connection::ReceivingHeaders; + LOG_TRACE("HttpServer: [%s] receiving headers", conn.request.client.c_str()); } - if (conn.state == Connection::ReceivingHeaders) { + if (conn.state == Connection::ReceivingHeaders) + { bool lfOnly = false; - size_t ofs = conn.receiveBuffer.find("\r\n\r\n"); - if (ofs == std::string::npos) { + size_t ofs = conn.receiveBuffer.find("\r\n\r\n"); + if (ofs == std::string::npos) + { lfOnly = true; - ofs = conn.receiveBuffer.find("\n\n"); + ofs = conn.receiveBuffer.find("\n\n"); } - size_t headersLen = - (ofs != std::string::npos) ? ofs : conn.receiveBuffer.length(); - if (headersLen > m_maxRequestHeadersSize) { - LOG_WARN("HttpServer: [%s] headers too long - %u", - conn.request.client.c_str(), + size_t headersLen = (ofs != std::string::npos) ? ofs : conn.receiveBuffer.length(); + if (headersLen > m_maxRequestHeadersSize) + { + LOG_WARN("HttpServer: [%s] headers too long - %u", conn.request.client.c_str(), static_cast(headersLen)); conn.response.code = 431; // Request Header Fields Too Large - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } - if (ofs == std::string::npos) { + if (ofs == std::string::npos) + { return; } - if (!parseHeaders(conn)) { - LOG_WARN("HttpServer: [%s] invalid headers", - conn.request.client.c_str()); + if (!parseHeaders(conn)) + { + LOG_WARN("HttpServer: [%s] invalid headers", conn.request.client.c_str()); conn.response.code = 400; // Bad Request - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } LOG_INFO("HttpServer: [%s] %s %s %s", conn.request.client.c_str(), @@ -387,128 +420,146 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { conn.request.protocol.c_str()); conn.receiveBuffer.erase(0, ofs + (lfOnly ? 2 : 4)); - conn.keepalive = (conn.request.protocol == "HTTP/1.1"); + conn.keepalive = (conn.request.protocol == "HTTP/1.1"); auto const connection = conn.request.headers.find("Connection"); - if (connection != conn.request.headers.end()) { - if (equalsLowercased(connection->second, "keep-alive")) { + if (connection != conn.request.headers.end()) + { + if (equalsLowercased(connection->second, "keep-alive")) + { conn.keepalive = true; - } else if (equalsLowercased(connection->second, "close")) { + } + else if (equalsLowercased(connection->second, "close")) + { conn.keepalive = false; } } auto const contentLength = conn.request.headers.find("Content-Length"); - if (contentLength != conn.request.headers.end()) { + if (contentLength != conn.request.headers.end()) + { conn.contentLength = atoi(contentLength->second.c_str()); - } else { + } + else + { conn.contentLength = 0; } - if (conn.contentLength > m_maxRequestContentSize) { - LOG_WARN("HttpServer: [%s] content too long - %u", - conn.request.client.c_str(), + if (conn.contentLength > m_maxRequestContentSize) + { + LOG_WARN("HttpServer: [%s] content too long - %u", conn.request.client.c_str(), static_cast(conn.contentLength)); conn.response.code = 413; // Payload Too Large - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } auto const expect = conn.request.headers.find("Expect"); - if (expect != conn.request.headers.end() && - conn.request.protocol == "HTTP/1.1") { - if (!equalsLowercased(expect->second, "100-continue")) { - LOG_WARN("HttpServer: [%s] unknown expectation - %s", - conn.request.client.c_str(), expect->second.c_str()); + if (expect != conn.request.headers.end() && conn.request.protocol == "HTTP/1.1") + { + if (!equalsLowercased(expect->second, "100-continue")) + { + LOG_WARN("HttpServer: [%s] unknown expectation - %s", conn.request.client.c_str(), + expect->second.c_str()); conn.response.code = 417; // Expectation Failed - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } conn.sendBuffer = "HTTP/1.1 100 Continue\r\n\r\n"; - conn.state = Connection::Sending100Continue; - LOG_TRACE("HttpServer: [%s] sending \"100 Continue\"", - conn.request.client.c_str()); + conn.state = Connection::Sending100Continue; + LOG_TRACE("HttpServer: [%s] sending \"100 Continue\"", conn.request.client.c_str()); continue; } conn.state = Connection::ReceivingBody; - LOG_TRACE("HttpServer: [%s] receiving body", - conn.request.client.c_str()); + LOG_TRACE("HttpServer: [%s] receiving body", conn.request.client.c_str()); } - if (conn.state == Connection::Sending100Continue) { - if (sendMore(conn)) { + if (conn.state == Connection::Sending100Continue) + { + if (sendMore(conn)) + { return; } conn.state = Connection::ReceivingBody; - LOG_TRACE("HttpServer: [%s] receiving body", - conn.request.client.c_str()); + LOG_TRACE("HttpServer: [%s] receiving body", conn.request.client.c_str()); } - if (conn.state == Connection::ReceivingBody) { - if (conn.receiveBuffer.length() < conn.contentLength) { + if (conn.state == Connection::ReceivingBody) + { + if (conn.receiveBuffer.length() < conn.contentLength) + { return; } - if (conn.receiveBuffer.length() == conn.contentLength) { + if (conn.receiveBuffer.length() == conn.contentLength) + { conn.request.content = std::move(conn.receiveBuffer); conn.receiveBuffer.clear(); - } else { - conn.request.content.assign(conn.receiveBuffer, 0, - conn.contentLength); + } + else + { + conn.request.content.assign(conn.receiveBuffer, 0, conn.contentLength); conn.receiveBuffer.erase(0, conn.contentLength); } conn.state = Connection::Processing; - LOG_TRACE("HttpServer: [%s] processing request", - conn.request.client.c_str()); + LOG_TRACE("HttpServer: [%s] processing request", conn.request.client.c_str()); } - if (conn.state == Connection::Processing) { + if (conn.state == Connection::Processing) + { processRequest(conn); std::ostringstream os; - os << conn.request.protocol << ' ' << conn.response.code << ' ' - << conn.response.message << "\r\n"; - for (auto const &header : conn.response.headers) { + os << conn.request.protocol << ' ' << conn.response.code << ' ' << conn.response.message + << "\r\n"; + for (auto const &header : conn.response.headers) + { os << header.first << ": " << header.second << "\r\n"; } os << "\r\n"; conn.sendBuffer = os.str(); - conn.state = Connection::SendingHeaders; - LOG_TRACE("HttpServer: [%s] sending headers", - conn.request.client.c_str()); + conn.state = Connection::SendingHeaders; + LOG_TRACE("HttpServer: [%s] sending headers", conn.request.client.c_str()); } - if (conn.state == Connection::SendingHeaders) { - if (sendMore(conn)) { + if (conn.state == Connection::SendingHeaders) + { + if (sendMore(conn)) + { return; } conn.sendBuffer = std::move(conn.response.body); - conn.state = Connection::SendingBody; + conn.state = Connection::SendingBody; LOG_TRACE("HttpServer: [%s] sending body", conn.request.client.c_str()); } - if (conn.state == Connection::SendingBody) { - if (sendMore(conn)) { + if (conn.state == Connection::SendingBody) + { + if (sendMore(conn)) + { return; } conn.keepalive &= allowKeepalive; - if (conn.keepalive) { - m_reactor.addSocket(conn.socket, SocketTools::Reactor::Readable | - SocketTools::Reactor::Closed); + if (conn.keepalive) + { + m_reactor.addSocket(conn.socket, + SocketTools::Reactor::Readable | SocketTools::Reactor::Closed); conn.state = Connection::Idle; - LOG_TRACE("HttpServer: [%s] idle (keep-alive)", - conn.request.client.c_str()); - if (conn.receiveBuffer.empty()) { + LOG_TRACE("HttpServer: [%s] idle (keep-alive)", conn.request.client.c_str()); + if (conn.receiveBuffer.empty()) + { return; } - } else { + } + else + { conn.socket.shutdown(SocketTools::Socket::ShutdownSend); m_reactor.addSocket(conn.socket, SocketTools::Reactor::Closed); conn.state = Connection::Closing; @@ -516,94 +567,114 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { } } - if (conn.state == Connection::Closing) { + if (conn.state == Connection::Closing) + { return; } } } - bool parseHeaders(Connection &conn) { + bool parseHeaders(Connection &conn) + { // Method char const *begin = conn.receiveBuffer.c_str(); - char const *ptr = begin; - while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { + char const *ptr = begin; + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { ptr++; } - if (*ptr != ' ') { + if (*ptr != ' ') + { return false; } conn.request.method.assign(begin, ptr); - while (*ptr == ' ') { + while (*ptr == ' ') + { ptr++; } // URI begin = ptr; - while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { ptr++; } - if (*ptr != ' ') { + if (*ptr != ' ') + { return false; } conn.request.uri.assign(begin, ptr); - while (*ptr == ' ') { + while (*ptr == ' ') + { ptr++; } // Protocol begin = ptr; - while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { ptr++; } - if (*ptr != '\r' && *ptr != '\n') { + if (*ptr != '\r' && *ptr != '\n') + { return false; } conn.request.protocol.assign(begin, ptr); - if (*ptr == '\r') { + if (*ptr == '\r') + { ptr++; } - if (*ptr != '\n') { + if (*ptr != '\n') + { return false; } ptr++; // Headers conn.request.headers.clear(); - while (*ptr != '\r' && *ptr != '\n') { + while (*ptr != '\r' && *ptr != '\n') + { // Name begin = ptr; - while (*ptr && *ptr != ':' && *ptr != ' ' && *ptr != '\r' && - *ptr != '\n') { + while (*ptr && *ptr != ':' && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { ptr++; } - if (*ptr != ':') { + if (*ptr != ':') + { return false; } std::string name = normalizeHeaderName(begin, ptr); ptr++; - while (*ptr == ' ') { + while (*ptr == ' ') + { ptr++; } // Value begin = ptr; - while (*ptr && *ptr != '\r' && *ptr != '\n') { + while (*ptr && *ptr != '\r' && *ptr != '\n') + { ptr++; } conn.request.headers[name] = std::string(begin, ptr); - if (*ptr == '\r') { + if (*ptr == '\r') + { ptr++; } - if (*ptr != '\n') { + if (*ptr != '\n') + { return false; } ptr++; } - if (*ptr == '\r') { + if (*ptr == '\r') + { ptr++; } - if (*ptr != '\n') { + if (*ptr != '\n') + { return false; } ptr++; @@ -611,75 +682,87 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { return true; } - static bool equalsLowercased(std::string const &str, char const *mask) { + static bool equalsLowercased(std::string const &str, char const *mask) + { char const *ptr = str.c_str(); - while (*ptr && *mask && ::tolower(*ptr) == *mask) { + while (*ptr && *mask && ::tolower(*ptr) == *mask) + { ptr++; mask++; } return !*ptr && !*mask; } - static std::string normalizeHeaderName(char const *begin, char const *end) { + static std::string normalizeHeaderName(char const *begin, char const *end) + { std::string result(begin, end); bool first = true; - for (char &ch : result) { - if (first) { - ch = static_cast(::toupper(ch)); + for (char &ch : result) + { + if (first) + { + ch = static_cast(::toupper(ch)); first = false; - } else if (ch == '-') { + } + else if (ch == '-') + { first = true; - } else { + } + else + { ch = static_cast(::tolower(ch)); } } return result; } - void processRequest(Connection &conn) { + void processRequest(Connection &conn) + { conn.response.message.clear(); conn.response.headers.clear(); conn.response.body.clear(); - if (conn.response.code == 0) { + if (conn.response.code == 0) + { conn.response.code = 404; // Not Found - for (auto &handler : m_handlers) { + for (auto &handler : m_handlers) + { if (conn.request.uri.length() >= handler.first.length() && - strncmp(conn.request.uri.c_str(), handler.first.c_str(), - handler.first.length()) == 0) { - LOG_TRACE("HttpServer: [%s] using handler for %s", - conn.request.client.c_str(), handler.first.c_str()); + strncmp(conn.request.uri.c_str(), handler.first.c_str(), handler.first.length()) == 0) + { + LOG_TRACE("HttpServer: [%s] using handler for %s", conn.request.client.c_str(), + handler.first.c_str()); // auto callback = handler.second; // Bazel gets mad at this unused // var, uncomment when using - int result = - handler.second->onHttpRequest(conn.request, conn.response); - if (result != 0) { + int result = handler.second->onHttpRequest(conn.request, conn.response); + if (result != 0) + { conn.response.code = result; break; } } } - if (conn.response.code == -1) { - LOG_TRACE("HttpServer: [%s] closing by request", - conn.request.client.c_str()); + if (conn.response.code == -1) + { + LOG_TRACE("HttpServer: [%s] closing by request", conn.request.client.c_str()); handleConnectionClosed(conn); } } - if (conn.response.message.empty()) { + if (conn.response.message.empty()) + { conn.response.message = getDefaultResponseMessage(conn.response.code); } - conn.response.headers["Host"] = m_serverHost; - conn.response.headers["Connection"] = - (conn.keepalive ? "keep-alive" : "close"); - conn.response.headers["Date"] = formatTimestamp(time(nullptr)); - conn.response.headers["Content-Length"] = - std::to_string(conn.response.body.size()); + conn.response.headers["Host"] = m_serverHost; + conn.response.headers["Connection"] = (conn.keepalive ? "keep-alive" : "close"); + conn.response.headers["Date"] = formatTimestamp(time(nullptr)); + conn.response.headers["Content-Length"] = std::to_string(conn.response.body.size()); } - static std::string formatTimestamp(time_t time) { + static std::string formatTimestamp(time_t time) + { tm tm; #ifdef _WIN32 gmtime_s(&tm, &time); @@ -691,9 +774,11 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { return buf; } - public: - static char const *getDefaultResponseMessage(int code) { - switch (code) { +public: + static char const *getDefaultResponseMessage(int code) + { + switch (code) + { // *INDENT-OFF* case 100: return "Continue"; diff --git a/ext/include/opentelemetry/ext/http/server/socket_tools.h b/ext/include/opentelemetry/ext/http/server/socket_tools.h index 0d9c8667ab..5c135b7a2a 100644 --- a/ext/include/opentelemetry/ext/http/server/socket_tools.h +++ b/ext/include/opentelemetry/ext/http/server/socket_tools.h @@ -28,70 +28,72 @@ //# include -#include +# include // TODO: consider NOMINMAX -#undef min -#undef max -#pragma comment(lib, "ws2_32.lib") +# undef min +# undef max +# pragma comment(lib, "ws2_32.lib") #else -#include +# include -#ifdef __linux__ -#include -#endif +# ifdef __linux__ +# include +# endif -#if __APPLE__ -#include "TargetConditionals.h" +# if __APPLE__ +# include "TargetConditionals.h" // Use kqueue on mac -#include -#include -#include -#endif +# include +# include +# include +# endif // Common POSIX headers for Linux and Mac OS X -#include -#include -#include -#include -#include -#include +# include +# include +# include +# include +# include +# include #endif #ifndef _Out_cap_ -#define _Out_cap_(size) +# define _Out_cap_(size) #endif #if defined(HAVE_CONSOLE_LOG) && !defined(LOG_DEBUG) // Log to console if there's no standard log facility defined -#include -#ifndef LOG_DEBUG -#define LOG_DEBUG(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -#define LOG_TRACE(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -#define LOG_INFO(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -#define LOG_WARN(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -#define LOG_ERROR(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -#endif +# include +# ifndef LOG_DEBUG +# define LOG_DEBUG(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_TRACE(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_INFO(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_WARN(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_ERROR(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# endif #endif #ifndef LOG_DEBUG // Don't log anything if there's no standard log facility defined -#define LOG_DEBUG(fmt_, ...) -#define LOG_TRACE(fmt_, ...) -#define LOG_INFO(fmt_, ...) -#define LOG_WARN(fmt_, ...) -#define LOG_ERROR(fmt_, ...) +# define LOG_DEBUG(fmt_, ...) +# define LOG_TRACE(fmt_, ...) +# define LOG_INFO(fmt_, ...) +# define LOG_WARN(fmt_, ...) +# define LOG_ERROR(fmt_, ...) #endif -namespace common { +namespace common +{ /// /// A simple thread, derived class overloads onThread() method. /// -struct Thread { +struct Thread +{ std::thread m_thread; volatile bool m_terminate{false}; @@ -105,17 +107,20 @@ struct Thread { /// /// Start Thread /// - void startThread() { + void startThread() + { m_terminate = false; - m_thread = std::thread([&]() { this->onThread(); }); + m_thread = std::thread([&]() { this->onThread(); }); } /// /// Join Thread /// - void joinThread() { + void joinThread() + { m_terminate = true; - if (m_thread.joinable()) { + if (m_thread.joinable()) + { m_thread.join(); } } @@ -139,13 +144,16 @@ struct Thread { }; }; // namespace common -namespace SocketTools { +namespace SocketTools +{ #ifdef _WIN32 // WinSocks need extra (de)initialization, solved by a global object here, // whose constructor/destructor will be called before and after main(). -struct WsaInitializer { - WsaInitializer() { +struct WsaInitializer +{ + WsaInitializer() + { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); } @@ -160,7 +168,8 @@ static WsaInitializer g_wsaInitializer; /// /// Encapsulation of sockaddr(_in) /// -struct SocketAddr { +struct SocketAddr +{ static u_long const Loopback = 0x7F000001; sockaddr m_data; @@ -171,33 +180,39 @@ struct SocketAddr { /// SocketAddr SocketAddr() { memset(&m_data, 0, sizeof(m_data)); } - SocketAddr(u_long addr, int port) { - sockaddr_in &inet4 = reinterpret_cast(m_data); - inet4.sin_family = AF_INET; - inet4.sin_port = htons(static_cast(port)); + SocketAddr(u_long addr, int port) + { + sockaddr_in &inet4 = reinterpret_cast(m_data); + inet4.sin_family = AF_INET; + inet4.sin_port = htons(static_cast(port)); inet4.sin_addr.s_addr = htonl(addr); } - SocketAddr(char const *addr) { + SocketAddr(char const *addr) + { #ifdef _WIN32 INT addrlen = sizeof(m_data); WCHAR buf[200]; - for (int i = 0; i < sizeof(buf) && addr[i]; i++) { + for (int i = 0; i < sizeof(buf) && addr[i]; i++) + { buf[i] = addr[i]; } buf[199] = L'\0'; ::WSAStringToAddressW(buf, AF_INET, nullptr, &m_data, &addrlen); #else sockaddr_in &inet4 = reinterpret_cast(m_data); - inet4.sin_family = AF_INET; - char const *colon = strchr(addr, ':'); - if (colon) { + inet4.sin_family = AF_INET; + char const *colon = strchr(addr, ':'); + if (colon) + { inet4.sin_port = htons(atoi(colon + 1)); char buf[16]; memcpy(buf, addr, std::min(15, colon - addr)); buf[15] = '\0'; ::inet_pton(AF_INET, buf, &inet4.sin_addr); - } else { + } + else + { inet4.sin_port = 0; ::inet_pton(AF_INET, addr, &inet4.sin_addr); } @@ -212,11 +227,12 @@ struct SocketAddr { operator const sockaddr *() const { return &m_data; } - int port() const { - switch (m_data.sa_family) { + int port() const + { + switch (m_data.sa_family) + { case AF_INET: { - sockaddr_in const &inet4 = - reinterpret_cast(m_data); + sockaddr_in const &inet4 = reinterpret_cast(m_data); return ntohs(inet4.sin_port); } @@ -225,16 +241,17 @@ struct SocketAddr { } } - std::string toString() const { + std::string toString() const + { std::ostringstream os; - switch (m_data.sa_family) { + switch (m_data.sa_family) + { case AF_INET: { - sockaddr_in const &inet4 = - reinterpret_cast(m_data); - u_long addr = ntohl(inet4.sin_addr.s_addr); - os << (addr >> 24) << '.' << ((addr >> 16) & 255) << '.' - << ((addr >> 8) & 255) << '.' << (addr & 255); + sockaddr_in const &inet4 = reinterpret_cast(m_data); + u_long addr = ntohl(inet4.sin_addr.s_addr); + os << (addr >> 24) << '.' << ((addr >> 16) & 255) << '.' << ((addr >> 8) & 255) << '.' + << (addr & 255); os << ':' << ntohs(inet4.sin_port); break; } @@ -249,7 +266,8 @@ struct SocketAddr { /// /// Encapsulation of a socket (non-exclusive ownership) /// -struct Socket { +struct Socket +{ #ifdef _WIN32 typedef SOCKET Type; static Type const Invalid = INVALID_SOCKET; @@ -268,19 +286,16 @@ struct Socket { operator Socket::Type() const { return m_sock; } - bool operator==(Socket const &other) const { - return (m_sock == other.m_sock); - } + bool operator==(Socket const &other) const { return (m_sock == other.m_sock); } - bool operator!=(Socket const &other) const { - return (m_sock != other.m_sock); - } + bool operator!=(Socket const &other) const { return (m_sock != other.m_sock); } bool operator<(Socket const &other) const { return (m_sock < other.m_sock); } bool invalid() const { return (m_sock == Invalid); } - void setNonBlocking() { + void setNonBlocking() + { assert(m_sock != Invalid); #ifdef _WIN32 u_long value = 1; @@ -291,34 +306,38 @@ struct Socket { #endif } - bool setReuseAddr() { + bool setReuseAddr() + { assert(m_sock != Invalid); #ifdef _WIN32 BOOL value = TRUE; #else int value = 1; #endif - return (::setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, - reinterpret_cast(&value), sizeof(value)) == 0); + return (::setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&value), + sizeof(value)) == 0); } - bool setNoDelay() { + bool setNoDelay() + { assert(m_sock != Invalid); #ifdef _WIN32 BOOL value = TRUE; #else int value = 1; #endif - return (::setsockopt(m_sock, IPPROTO_TCP, TCP_NODELAY, - reinterpret_cast(&value), sizeof(value)) == 0); + return (::setsockopt(m_sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&value), + sizeof(value)) == 0); } - bool connect(SocketAddr const &addr) { + bool connect(SocketAddr const &addr) + { assert(m_sock != Invalid); return (::connect(m_sock, addr, sizeof(addr)) == 0); } - void close() { + void close() + { assert(m_sock != Invalid); #ifdef _WIN32 ::closesocket(m_sock); @@ -328,25 +347,27 @@ struct Socket { m_sock = Invalid; } - int recv(_Out_cap_(size) void *buffer, unsigned size) { + int recv(_Out_cap_(size) void *buffer, unsigned size) + { assert(m_sock != Invalid); int flags = 0; - return static_cast( - ::recv(m_sock, reinterpret_cast(buffer), size, flags)); + return static_cast(::recv(m_sock, reinterpret_cast(buffer), size, flags)); } - int send(void const *buffer, unsigned size) { + int send(void const *buffer, unsigned size) + { assert(m_sock != Invalid); - return static_cast( - ::send(m_sock, reinterpret_cast(buffer), size, 0)); + return static_cast(::send(m_sock, reinterpret_cast(buffer), size, 0)); } - bool bind(SocketAddr const &addr) { + bool bind(SocketAddr const &addr) + { assert(m_sock != Invalid); return (::bind(m_sock, addr, sizeof(addr)) == 0); } - bool getsockname(SocketAddr &addr) const { + bool getsockname(SocketAddr &addr) const + { assert(m_sock != Invalid); #ifdef _WIN32 int addrlen = sizeof(addr); @@ -356,12 +377,14 @@ struct Socket { return (::getsockname(m_sock, addr, &addrlen) == 0); } - bool listen(int backlog) { + bool listen(int backlog) + { assert(m_sock != Invalid); return (::listen(m_sock, backlog) == 0); } - bool accept(Socket &csock, SocketAddr &caddr) { + bool accept(Socket &csock, SocketAddr &caddr) + { assert(m_sock != Invalid); #ifdef _WIN32 int addrlen = sizeof(caddr); @@ -372,12 +395,14 @@ struct Socket { return !csock.invalid(); } - bool shutdown(int how) { + bool shutdown(int how) + { assert(m_sock != Invalid); return (::shutdown(m_sock, how) == 0); } - int error() const { + int error() const + { #ifdef _WIN32 return ::WSAGetLastError(); #else @@ -385,7 +410,8 @@ struct Socket { #endif } - enum { + enum + { #ifdef _WIN32 ErrorWouldBlock = WSAEWOULDBLOCK #else @@ -393,15 +419,16 @@ struct Socket { #endif }; - enum { + enum + { #ifdef _WIN32 ShutdownReceive = SD_RECEIVE, - ShutdownSend = SD_SEND, - ShutdownBoth = SD_BOTH + ShutdownSend = SD_SEND, + ShutdownBoth = SD_BOTH #else ShutdownReceive = SHUT_RD, - ShutdownSend = SHUT_WR, - ShutdownBoth = SHUT_RDWR + ShutdownSend = SHUT_WR, + ShutdownBoth = SHUT_RDWR #endif }; }; @@ -409,7 +436,8 @@ struct Socket { /// /// Socket Data /// -struct SocketData { +struct SocketData +{ Socket socket; int flags; @@ -421,22 +449,30 @@ struct SocketData { /// /// Socket Reactor /// -struct Reactor : protected common::Thread { +struct Reactor : protected common::Thread +{ /// /// Socket State callback /// - class SocketCallback { - public: - virtual void onSocketReadable(Socket sock) = 0; - virtual void onSocketWritable(Socket sock) = 0; + class SocketCallback + { + public: + virtual void onSocketReadable(Socket sock) = 0; + virtual void onSocketWritable(Socket sock) = 0; virtual void onSocketAcceptable(Socket sock) = 0; - virtual void onSocketClosed(Socket sock) = 0; + virtual void onSocketClosed(Socket sock) = 0; }; /// /// Socket State /// - enum State { Readable = 1, Writable = 2, Acceptable = 4, Closed = 8 }; + enum State + { + Readable = 1, + Writable = 2, + Acceptable = 4, + Closed = 8 + }; SocketCallback &m_callback; @@ -454,19 +490,20 @@ struct Reactor : protected common::Thread { #ifdef TARGET_OS_MAC /* use kqueue on Mac */ -#define KQUEUE_SIZE 32 +# define KQUEUE_SIZE 32 int kq{0}; struct kevent m_events[KQUEUE_SIZE]; #endif - public: - Reactor(SocketCallback &callback) : m_callback(callback) { +public: + Reactor(SocketCallback &callback) : m_callback(callback) + { #ifdef __linux__ -#ifdef ANDROID +# ifdef ANDROID m_epollFd = ::epoll_create(0); -#else +# else m_epollFd = ::epoll_create1(0); -#endif +# endif #endif #ifdef TARGET_OS_MAC @@ -475,7 +512,8 @@ struct Reactor : protected common::Thread { #endif } - ~Reactor() { + ~Reactor() + { #ifdef __linux__ ::close(m_epollFd); #endif @@ -489,21 +527,25 @@ struct Reactor : protected common::Thread { /// /// /// - void addSocket(const Socket &socket, int flags) { - if (flags == 0) { + void addSocket(const Socket &socket, int flags) + { + if (flags == 0) + { removeSocket(socket); - } else { + } + else + { auto it = std::find(m_sockets.begin(), m_sockets.end(), socket); - if (it == m_sockets.end()) { - LOG_TRACE("Reactor: Adding socket 0x%x with flags 0x%x", - static_cast(socket), flags); + if (it == m_sockets.end()) + { + LOG_TRACE("Reactor: Adding socket 0x%x with flags 0x%x", static_cast(socket), flags); #ifdef _WIN32 m_events.push_back(::WSACreateEvent()); #endif #ifdef __linux__ epoll_event event = {}; - event.data.fd = socket; - event.events = 0; + event.data.fd = socket; + event.events = 0; ::epoll_ctl(m_epollFd, EPOLL_CTL_ADD, socket, &event); #endif #ifdef TARGET_OS_MAC @@ -517,27 +559,33 @@ struct Reactor : protected common::Thread { #endif m_sockets.push_back(SocketData()); m_sockets.back().socket = socket; - m_sockets.back().flags = 0; - it = m_sockets.end() - 1; - } else { - LOG_TRACE("Reactor: Updating socket 0x%x with flags 0x%x", - static_cast(socket), flags); + m_sockets.back().flags = 0; + it = m_sockets.end() - 1; + } + else + { + LOG_TRACE("Reactor: Updating socket 0x%x with flags 0x%x", static_cast(socket), flags); } - if (it->flags != flags) { + if (it->flags != flags) + { it->flags = flags; #ifdef _WIN32 long lNetworkEvents = 0; - if (it->flags & Readable) { + if (it->flags & Readable) + { lNetworkEvents |= FD_READ; } - if (it->flags & Writable) { + if (it->flags & Writable) + { lNetworkEvents |= FD_WRITE; } - if (it->flags & Acceptable) { + if (it->flags & Acceptable) + { lNetworkEvents |= FD_ACCEPT; } - if (it->flags & Closed) { + if (it->flags & Closed) + { lNetworkEvents |= FD_CLOSE; } auto eventIt = m_events.begin() + std::distance(m_sockets.begin(), it); @@ -545,19 +593,22 @@ struct Reactor : protected common::Thread { #endif #ifdef __linux__ int events = 0; - if (it->flags & Readable) { + if (it->flags & Readable) + { events |= EPOLLIN; } - if (it->flags & Writable) { + if (it->flags & Writable) + { events |= EPOLLOUT; } - if (it->flags & Acceptable) { + if (it->flags & Acceptable) + { events |= EPOLLIN; } // if (it->flags & Closed) - always handled (EPOLLERR | EPOLLHUP) epoll_event event = {}; - event.data.fd = socket; - event.events = events; + event.data.fd = socket; + event.events = events; ::epoll_ctl(m_epollFd, EPOLL_CTL_MOD, socket, &event); #endif #ifdef TARGET_OS_MAC @@ -571,10 +622,12 @@ struct Reactor : protected common::Thread { /// Remove Socket /// /// - void removeSocket(const Socket &socket) { + void removeSocket(const Socket &socket) + { LOG_TRACE("Reactor: Removing socket 0x%x", static_cast(socket)); auto it = std::find(m_sockets.begin(), m_sockets.end(), socket); - if (it != m_sockets.end()) { + if (it != m_sockets.end()) + { #ifdef _WIN32 auto eventIt = m_events.begin() + std::distance(m_sockets.begin(), it); ::WSAEventSelect(it->socket, *eventIt, 0); @@ -589,12 +642,14 @@ struct Reactor : protected common::Thread { bzero(&event, sizeof(event)); event.ident = socket; EV_SET(&event, socket, EVFILT_READ, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { //// Already removed? LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } EV_SET(&event, socket, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { //// Already removed? LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } @@ -606,7 +661,8 @@ struct Reactor : protected common::Thread { /// /// Start server /// - void start() { + void start() + { LOG_INFO("Reactor: Starting..."); startThread(); } @@ -614,31 +670,36 @@ struct Reactor : protected common::Thread { /// /// Stop server /// - void stop() { + void stop() + { LOG_INFO("Reactor: Stopping..."); joinThread(); #ifdef _WIN32 - for (auto &hEvent : m_events) { + for (auto &hEvent : m_events) + { ::WSACloseEvent(hEvent); } #else /* Linux and Mac */ - for (auto &sd : m_sockets) { -#ifdef __linux__ + for (auto &sd : m_sockets) + { +# ifdef __linux__ ::epoll_ctl(m_epollFd, EPOLL_CTL_DEL, sd.socket, nullptr); -#endif -#ifdef TARGET_OS_MAC +# endif +# ifdef TARGET_OS_MAC struct kevent event; bzero(&event, sizeof(event)); event.ident = sd.socket; EV_SET(&event, sd.socket, EVFILT_READ, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } EV_SET(&event, sd.socket, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } -#endif +# endif } #endif m_sockets.clear(); @@ -647,21 +708,23 @@ struct Reactor : protected common::Thread { /// /// Thread Loop for async events processing /// - virtual void onThread() override { + virtual void onThread() override + { LOG_INFO("Reactor: Thread started"); - while (!shouldTerminate()) { + while (!shouldTerminate()) + { #ifdef _WIN32 - DWORD dwResult = - ::WSAWaitForMultipleEvents(static_cast(m_events.size()), - m_events.data(), FALSE, 500, FALSE); - if (dwResult == WSA_WAIT_TIMEOUT) { + DWORD dwResult = ::WSAWaitForMultipleEvents(static_cast(m_events.size()), + m_events.data(), FALSE, 500, FALSE); + if (dwResult == WSA_WAIT_TIMEOUT) + { continue; } assert(dwResult <= WSA_WAIT_EVENT_0 + m_events.size()); - int index = dwResult - WSA_WAIT_EVENT_0; + int index = dwResult - WSA_WAIT_EVENT_0; Socket socket = m_sockets[index].socket; - int flags = m_sockets[index].flags; + int flags = m_sockets[index].flags; WSANETWORKEVENTS ne; ::WSAEnumNetworkEvents(socket, m_events[index], &ne); @@ -670,51 +733,57 @@ struct Reactor : protected common::Thread { "(armed 0x%x)", static_cast(socket), index, ne.lNetworkEvents, flags); - if ((flags & Readable) && (ne.lNetworkEvents & FD_READ)) { + if ((flags & Readable) && (ne.lNetworkEvents & FD_READ)) + { m_callback.onSocketReadable(socket); } - if ((flags & Writable) && (ne.lNetworkEvents & FD_WRITE)) { + if ((flags & Writable) && (ne.lNetworkEvents & FD_WRITE)) + { m_callback.onSocketWritable(socket); } - if ((flags & Acceptable) && (ne.lNetworkEvents & FD_ACCEPT)) { + if ((flags & Acceptable) && (ne.lNetworkEvents & FD_ACCEPT)) + { m_callback.onSocketAcceptable(socket); } - if ((flags & Closed) && (ne.lNetworkEvents & FD_CLOSE)) { + if ((flags & Closed) && (ne.lNetworkEvents & FD_CLOSE)) + { m_callback.onSocketClosed(socket); } #endif #ifdef __linux__ epoll_event events[4]; - int result = ::epoll_wait(m_epollFd, events, - sizeof(events) / sizeof(events[0]), 500); - if (result == 0 || (result == -1 && errno == EINTR)) { + int result = ::epoll_wait(m_epollFd, events, sizeof(events) / sizeof(events[0]), 500); + if (result == 0 || (result == -1 && errno == EINTR)) + { continue; } - assert(result >= 1 && - static_cast(result) <= sizeof(events) / sizeof(events[0])); - for (int i = 0; i < result; i++) { - auto it = - std::find(m_sockets.begin(), m_sockets.end(), events[i].data.fd); + assert(result >= 1 && static_cast(result) <= sizeof(events) / sizeof(events[0])); + for (int i = 0; i < result; i++) + { + auto it = std::find(m_sockets.begin(), m_sockets.end(), events[i].data.fd); assert(it != m_sockets.end()); Socket socket = it->socket; - int flags = it->flags; + int flags = it->flags; - LOG_TRACE( - "Reactor: Handling socket 0x%x active flags 0x%x (armed 0x%x)", - static_cast(socket), events[i].events, flags); + LOG_TRACE("Reactor: Handling socket 0x%x active flags 0x%x (armed 0x%x)", + static_cast(socket), events[i].events, flags); - if ((flags & Readable) && (events[i].events & EPOLLIN)) { + if ((flags & Readable) && (events[i].events & EPOLLIN)) + { m_callback.onSocketReadable(socket); } - if ((flags & Writable) && (events[i].events & EPOLLOUT)) { + if ((flags & Writable) && (events[i].events & EPOLLOUT)) + { m_callback.onSocketWritable(socket); } - if ((flags & Acceptable) && (events[i].events & EPOLLIN)) { + if ((flags & Acceptable) && (events[i].events & EPOLLIN)) + { m_callback.onSocketAcceptable(socket); } - if ((flags & Closed) && (events[i].events & (EPOLLHUP | EPOLLERR))) { + if ((flags & Closed) && (events[i].events & (EPOLLHUP | EPOLLERR))) + { m_callback.onSocketClosed(socket); } } @@ -723,49 +792,58 @@ struct Reactor : protected common::Thread { #if defined(TARGET_OS_MAC) unsigned waitms = 500; // never block for more than 500ms struct timespec timeout; - timeout.tv_sec = waitms / 1000; + timeout.tv_sec = waitms / 1000; timeout.tv_nsec = (waitms % 1000) * 1000 * 1000; int nev = kevent(kq, NULL, 0, m_events, KQUEUE_SIZE, &timeout); - for (int i = 0; i < nev; i++) { + for (int i = 0; i < nev; i++) + { struct kevent &event = m_events[i]; - int fd = (int)event.ident; - auto it = std::find(m_sockets.begin(), m_sockets.end(), fd); + int fd = (int)event.ident; + auto it = std::find(m_sockets.begin(), m_sockets.end(), fd); assert(it != m_sockets.end()); Socket socket = it->socket; - int flags = it->flags; + int flags = it->flags; - LOG_TRACE("Handling socket 0x%x active flags 0x%x (armed 0x%x)", - static_cast(socket), event.flags, event.fflags); + LOG_TRACE("Handling socket 0x%x active flags 0x%x (armed 0x%x)", static_cast(socket), + event.flags, event.fflags); - if (event.filter == EVFILT_READ) { - if (flags & Acceptable) { + if (event.filter == EVFILT_READ) + { + if (flags & Acceptable) + { m_callback.onSocketAcceptable(socket); } - if (flags & Readable) { + if (flags & Readable) + { m_callback.onSocketReadable(socket); } continue; } - if (event.filter == EVFILT_WRITE) { - if (flags & Writable) { + if (event.filter == EVFILT_WRITE) + { + if (flags & Writable) + { m_callback.onSocketWritable(socket); } continue; } - if ((event.flags & EV_EOF) || (event.flags & EV_ERROR)) { + if ((event.flags & EV_EOF) || (event.flags & EV_ERROR)) + { LOG_TRACE("event.filter=%s", "EVFILT_WRITE"); m_callback.onSocketClosed(socket); it->flags = Closed; struct kevent kevt; EV_SET(&kevt, event.ident, EVFILT_READ, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) { + if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) + { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } EV_SET(&kevt, event.ident, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) { + if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) + { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } continue; From 4ff777c231b3f7a427d4c57fdbbe0c7bf0f3d8c5 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Fri, 31 Jul 2020 13:40:52 +0000 Subject: [PATCH 10/11] Fix wrong type inputs --- ext/include/opentelemetry/ext/http/server/file_http_server.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/include/opentelemetry/ext/http/server/file_http_server.h b/ext/include/opentelemetry/ext/http/server/file_http_server.h index 77b77b0394..0b4d3cccc9 100644 --- a/ext/include/opentelemetry/ext/http/server/file_http_server.h +++ b/ext/include/opentelemetry/ext/http/server/file_http_server.h @@ -19,7 +19,7 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer * which show up on the web if the user is on the given host:port. Static * files can be seen relative to the folder where the executable was ran. */ - FileHttpServer(const std::string &host = "127.0.0.1", int port = "3333") : HttpServer() + FileHttpServer(const std::string &host = "127.0.0.1", int port = 3333) : HttpServer() { std::ostringstream os; os << host << ":" << port; @@ -33,7 +33,7 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer * initialize their own, otherwise everything will be served like a file * @param server should be an instance of this object */ - void InitializeFileEndpoint(zPagesHttpServer &server) { server[root_endpt_] = ServeFile; } + void InitializeFileEndpoint(FileHttpServer &server) { server[root_endpt_] = ServeFile; } private: /** From def53be5cb1009203c5859514144c6eca6970967 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Mon, 3 Aug 2020 16:44:18 +0000 Subject: [PATCH 11/11] Try clang-format-8, use better param bname --- .../ext/http/server/file_http_server.h | 14 +++++++------- .../opentelemetry/ext/http/server/socket_tools.h | 6 ++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/ext/include/opentelemetry/ext/http/server/file_http_server.h b/ext/include/opentelemetry/ext/http/server/file_http_server.h index 0b4d3cccc9..b93e545968 100644 --- a/ext/include/opentelemetry/ext/http/server/file_http_server.h +++ b/ext/include/opentelemetry/ext/http/server/file_http_server.h @@ -85,19 +85,19 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer * assuming index.html is the wanted file if a directory is given * @param name of the file */ - std::string GetFileName(std::string S) + std::string GetFileName(std::string name) { - if (S.back() == '/') + if (name.back() == '/') { - auto temp = S.substr(0, S.size() - 1); - S = temp; + auto temp = name.substr(0, name.size() - 1); + name = temp; } // If filename appears to be a directory, serve the hypothetical index.html // file there - if (S.find(".") == std::string::npos) - S += "/index.html"; + if (name.find(".") == std::string::npos) + name += "/index.html"; - return S; + return name; } /** diff --git a/ext/include/opentelemetry/ext/http/server/socket_tools.h b/ext/include/opentelemetry/ext/http/server/socket_tools.h index 5c135b7a2a..e980b78940 100644 --- a/ext/include/opentelemetry/ext/http/server/socket_tools.h +++ b/ext/include/opentelemetry/ext/http/server/socket_tools.h @@ -231,7 +231,8 @@ struct SocketAddr { switch (m_data.sa_family) { - case AF_INET: { + case AF_INET: + { sockaddr_in const &inet4 = reinterpret_cast(m_data); return ntohs(inet4.sin_port); } @@ -247,7 +248,8 @@ struct SocketAddr switch (m_data.sa_family) { - case AF_INET: { + case AF_INET: + { sockaddr_in const &inet4 = reinterpret_cast(m_data); u_long addr = ntohl(inet4.sin_addr.s_addr); os << (addr >> 24) << '.' << ((addr >> 16) & 255) << '.' << ((addr >> 8) & 255) << '.'