| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 | #ifndef BELL_BASE_HTTP_SERV#define BELL_BASE_HTTP_SERV#include <cstdio>#include <string>#include <map>#include <memory>#include <functional>#include <iostream>#include <vector>#include <cstring>#ifdef _WIN32#include <winsock2.h>#else#include <sys/socket.h>#endifnamespace 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<uint8_t> partialBuffer;    int fd = 0;    size_t contentLength = 0;    size_t sizeRead = 0;    RequestBodyReader(size_t contentLength, int fd, std::vector<uint8_t> &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<std::string, std::string> urlParams;    std::map<std::string, std::string> queryParams;    std::unique_ptr<ResponseReader> responseReader = std::unique_ptr<RequestBodyReader>(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<std::string> extraHeaders = std::vector<std::string>();    std::unique_ptr<ResponseReader> responseReader;};typedef std::function<void(std::unique_ptr<bell::HTTPRequest>)> httpHandler;struct HTTPRoute {    RequestType requestType;    httpHandler handler;    bool readBodyToStr;};struct HTTPConnection {    int fd = 0;    std::vector<uint8_t> buffer;    std::vector<uint8_t> partialBuffer = std::vector<uint8_t>();    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
 |