#ifndef BELL_BASE_HTTP_SERV #define BELL_BASE_HTTP_SERV #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #else #include #endif namespace bell { class ResponseReader { public: ResponseReader(){}; virtual ~ResponseReader() = default; virtual size_t getTotalSize() = 0; virtual size_t read(char *buffer, size_t size) = 0; virtual void close() = 0; }; class RequestBodyReader : public ResponseReader { public: std::vector partialBuffer; int fd = 0; size_t contentLength = 0; size_t sizeRead = 0; RequestBodyReader(size_t contentLength, int fd, std::vector &partialBuffer) { this->contentLength = contentLength; this->partialBuffer = partialBuffer; this->fd = fd; }; size_t read(char *buffer, size_t size) { if (sizeRead < partialBuffer.size()) { size_t toRead = std::min(size, partialBuffer.size() - sizeRead); memcpy(buffer, &partialBuffer[sizeRead], toRead); sizeRead += toRead; return toRead; } else { size_t toRead = std::min(size, contentLength - sizeRead); size_t read = recv(fd, buffer, toRead, 0); sizeRead += read; return read; } } void close() { } size_t getTotalSize() { return contentLength; } }; class FileResponseReader : public ResponseReader { public: FILE *file; size_t fileSize; FileResponseReader(std::string fileName) { file = fopen(fileName.c_str(), "r"); fseek(file, 0, SEEK_END); // seek to end of file fileSize = ftell(file); // get current file pointer fseek(file, 0, SEEK_SET); // seek back to beginning of file }; size_t read(char *buffer, size_t size) { return fread(buffer, 1, size, file); } void close() { fclose(file); } size_t getTotalSize() { return fileSize; } }; enum class RequestType { GET, POST }; struct HTTPRequest { std::map urlParams; std::map queryParams; std::unique_ptr responseReader = std::unique_ptr(nullptr); std::string body; std::string url; int handlerId; int connection; int contentLength; }; struct HTTPResponse { int connectionFd; int status; bool useGzip = false; std::string body; std::string contentType; std::vector extraHeaders = std::vector(); std::unique_ptr responseReader; }; typedef std::function)> httpHandler; struct HTTPRoute { RequestType requestType; httpHandler handler; bool readBodyToStr; }; struct HTTPConnection { int fd = 0; std::vector buffer; std::vector partialBuffer = std::vector(); int contentLength = 0; std::string httpMethod; bool toBeClosed = false; bool headersRead = false; bool isEventConnection = false; bool isCaptivePortal = false; }; class BaseHTTPServer { public: BaseHTTPServer() {}; virtual ~BaseHTTPServer() = default; /** * Should contain server's bind port */ int serverPort; /** * Called when handler is being registered on the http server * * @param requestType GET or POST * @param endpoint registering under * @param readResponseToStr if true, response will be read to string, otherwise it will return a reader object * httpHandler lambda to be called when given endpoint gets executed */ virtual void registerHandler(RequestType requestType, const std::string & endpoint, httpHandler, bool readResponseToStr = true) = 0; /** * Writes given response to a fd */ virtual void respond(const HTTPResponse &) = 0; }; } // namespace bell #endif