You've already forked cpp-httplib
							
							Code refactoring.
This commit is contained in:
		@@ -57,13 +57,20 @@ std::string log(const httplib::Connection& c)
 | 
			
		||||
    return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void error_handler(httplib::Connection& c)
 | 
			
		||||
{
 | 
			
		||||
    char buf[BUFSIZ];
 | 
			
		||||
    snprintf(buf, sizeof(buf), "Error Status: %d\r\n", c.response.status);
 | 
			
		||||
    c.response.set_content(buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(void)
 | 
			
		||||
{
 | 
			
		||||
    using namespace httplib;
 | 
			
		||||
 | 
			
		||||
    const char* hi = "/hi";
 | 
			
		||||
 | 
			
		||||
    Server svr("localhost", 1234);
 | 
			
		||||
    Server svr("localhost", 8080);
 | 
			
		||||
 | 
			
		||||
    svr.get("/", [=](Connection& c) {
 | 
			
		||||
        c.response.set_redirect(hi);
 | 
			
		||||
@@ -74,9 +81,11 @@ int main(void)
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    svr.get("/dump", [](Connection& c) {
 | 
			
		||||
        c.response.set_content(log(c));
 | 
			
		||||
        c.response.set_content(httplib::dump_headers(c.request.headers));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    svr.error(error_handler);
 | 
			
		||||
 | 
			
		||||
    svr.set_logger([](const Connection& c) {
 | 
			
		||||
        printf("%s", log(c).c_str());
 | 
			
		||||
    });
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										130
									
								
								httplib.h
									
									
									
									
									
								
							
							
						
						
									
										130
									
								
								httplib.h
									
									
									
									
									
								
							@@ -81,8 +81,8 @@ public:
 | 
			
		||||
 | 
			
		||||
    void get(const char* pattern, Handler handler);
 | 
			
		||||
    void post(const char* pattern, Handler handler);
 | 
			
		||||
    void error(Handler handler);
 | 
			
		||||
 | 
			
		||||
    void on_ready(std::function<void ()> callback);
 | 
			
		||||
    void set_logger(std::function<void (const Connection&)> logger);
 | 
			
		||||
 | 
			
		||||
    bool run();
 | 
			
		||||
@@ -91,9 +91,8 @@ public:
 | 
			
		||||
private:
 | 
			
		||||
    void process_request(FILE* fp_read, FILE* fp_write);
 | 
			
		||||
 | 
			
		||||
    bool read_request_line(FILE* fp, Request& request);
 | 
			
		||||
    void write_response(FILE* fp, const Response& response);
 | 
			
		||||
    void write_error(FILE* fp, int status);
 | 
			
		||||
    bool read_request_line(FILE* fp, Request& req);
 | 
			
		||||
    void write_response(FILE* fp, const Response& res);
 | 
			
		||||
 | 
			
		||||
    const std::string host_;
 | 
			
		||||
    const int         port_;
 | 
			
		||||
@@ -101,7 +100,7 @@ private:
 | 
			
		||||
 | 
			
		||||
    std::vector<std::pair<std::regex, Handler>>  get_handlers_;
 | 
			
		||||
    std::vector<std::pair<std::string, Handler>> post_handlers_;
 | 
			
		||||
    std::function<void ()>                       on_ready_;
 | 
			
		||||
    Handler                                      error_handler_;
 | 
			
		||||
    std::function<void (const Connection&)>      logger_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -110,10 +109,10 @@ public:
 | 
			
		||||
    Client(const char* host, int port);
 | 
			
		||||
    ~Client();
 | 
			
		||||
 | 
			
		||||
    int get(const char* url, Response& response);
 | 
			
		||||
    int get(const char* url, Response& res);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool read_response_line(FILE* fp, Response& response);
 | 
			
		||||
    bool read_response_line(FILE* fp, Response& res);
 | 
			
		||||
 | 
			
		||||
    const std::string host_;
 | 
			
		||||
    const int         port_;
 | 
			
		||||
@@ -236,6 +235,26 @@ inline int close_client_socket(socket_t sock)
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline const char* status_message(int status)
 | 
			
		||||
{
 | 
			
		||||
    const char* s = NULL;
 | 
			
		||||
 | 
			
		||||
    switch (status) {
 | 
			
		||||
    case 400:
 | 
			
		||||
        s = "Bad Request";
 | 
			
		||||
        break;
 | 
			
		||||
    case 404:
 | 
			
		||||
        s = "Not Found";
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        status = 500;
 | 
			
		||||
        s = "Internal Server Error";
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline const char* get_header_value(const MultiMap& map, const char* key, const char* def)
 | 
			
		||||
{
 | 
			
		||||
    auto it = map.find(key);
 | 
			
		||||
@@ -296,7 +315,6 @@ inline void Response::set_content(const std::string& s, const char* content_type
 | 
			
		||||
{
 | 
			
		||||
    body = s;
 | 
			
		||||
    headers.insert(std::make_pair("Content-Type", content_type));
 | 
			
		||||
    status = 200;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline Server::Server(const char* host, int port)
 | 
			
		||||
@@ -327,9 +345,9 @@ inline void Server::post(const char* pattern, Handler handler)
 | 
			
		||||
    post_handlers_.push_back(std::make_pair(pattern, handler));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void Server::on_ready(std::function<void ()> callback)
 | 
			
		||||
inline void Server::error(Handler handler)
 | 
			
		||||
{
 | 
			
		||||
    on_ready_ = callback;
 | 
			
		||||
    error_handler_ = handler;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void Server::set_logger(std::function<void (const Connection&)> logger)
 | 
			
		||||
@@ -344,10 +362,6 @@ inline bool Server::run()
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (on_ready_) {
 | 
			
		||||
        on_ready_();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (;;) {
 | 
			
		||||
        socket_t fd = accept(sock_, NULL, NULL);
 | 
			
		||||
        if (fd == -1) {
 | 
			
		||||
@@ -379,7 +393,7 @@ inline void Server::stop()
 | 
			
		||||
    sock_ = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline bool Server::read_request_line(FILE* fp, Request& request)
 | 
			
		||||
inline bool Server::read_request_line(FILE* fp, Request& req)
 | 
			
		||||
{
 | 
			
		||||
    const size_t BUFSIZ_REQUESTLINE = 2048;
 | 
			
		||||
    char buf[BUFSIZ_REQUESTLINE];
 | 
			
		||||
@@ -391,8 +405,8 @@ inline bool Server::read_request_line(FILE* fp, Request& request)
 | 
			
		||||
 | 
			
		||||
    std::cmatch m;
 | 
			
		||||
    if (std::regex_match(buf, m, re)) {
 | 
			
		||||
        request.method = std::string(m[1]);
 | 
			
		||||
        request.url = std::string(m[2]);
 | 
			
		||||
        req.method = std::string(m[1]);
 | 
			
		||||
        req.url = std::string(m[2]);
 | 
			
		||||
 | 
			
		||||
        // Parse query text
 | 
			
		||||
        auto len = std::distance(m[3].first, m[3].second);
 | 
			
		||||
@@ -408,7 +422,7 @@ inline bool Server::read_request_line(FILE* fp, Request& request)
 | 
			
		||||
                        val.assign(b, e);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                request.query[key] = val;
 | 
			
		||||
                req.query[key] = val;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -418,69 +432,42 @@ inline bool Server::read_request_line(FILE* fp, Request& request)
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void Server::write_response(FILE* fp, const Response& response)
 | 
			
		||||
inline void Server::write_response(FILE* fp, const Response& res)
 | 
			
		||||
{
 | 
			
		||||
    fprintf(fp, "HTTP/1.0 %d OK\r\n", response.status);
 | 
			
		||||
    fprintf(fp, "HTTP/1.0 %d %s\r\n", res.status, status_message(res.status));
 | 
			
		||||
    fprintf(fp, "Connection: close\r\n");
 | 
			
		||||
 | 
			
		||||
    for (auto it = response.headers.begin(); it != response.headers.end(); ++it) {
 | 
			
		||||
    for (auto it = res.headers.begin(); it != res.headers.end(); ++it) {
 | 
			
		||||
        if (it->first != "Content-Type" && it->second != "Content-Length") {
 | 
			
		||||
            fprintf(fp, "%s: %s\r\n", it->first.c_str(), it->second.c_str());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!response.body.empty()) {
 | 
			
		||||
        auto content_type = get_header_value(response.headers, "Content-Type", "text/plain");
 | 
			
		||||
    if (!res.body.empty()) {
 | 
			
		||||
        auto content_type = get_header_value(res.headers, "Content-Type", "text/plain");
 | 
			
		||||
        fprintf(fp, "Content-Type: %s\r\n", content_type);
 | 
			
		||||
        fprintf(fp, "Content-Length: %ld\r\n", response.body.size());
 | 
			
		||||
        fprintf(fp, "Content-Length: %ld\r\n", res.body.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fprintf(fp, "\r\n");
 | 
			
		||||
 | 
			
		||||
    if (!response.body.empty()) {
 | 
			
		||||
        fprintf(fp, "%s", response.body.c_str());
 | 
			
		||||
    if (!res.body.empty()) {
 | 
			
		||||
        fprintf(fp, "%s", res.body.c_str());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void Server::write_error(FILE* fp, int status)
 | 
			
		||||
{
 | 
			
		||||
    const char* msg = NULL;
 | 
			
		||||
 | 
			
		||||
    switch (status) {
 | 
			
		||||
    case 400:
 | 
			
		||||
        msg = "Bad Request";
 | 
			
		||||
        break;
 | 
			
		||||
    case 404:
 | 
			
		||||
        msg = "Not Found";
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        status = 500;
 | 
			
		||||
        msg = "Internal Server Error";
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    assert(msg);
 | 
			
		||||
 | 
			
		||||
    fprintf(fp, "HTTP/1.0 %d %s\r\n", status, msg);
 | 
			
		||||
    fprintf(fp, "Content-type: text/plain\r\n");
 | 
			
		||||
    fprintf(fp, "Connection: close\r\n");
 | 
			
		||||
    fprintf(fp, "\r\n");
 | 
			
		||||
    fprintf(fp, "Status: %d\r\n", status);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void Server::process_request(FILE* fp_read, FILE* fp_write)
 | 
			
		||||
{
 | 
			
		||||
    Connection c;
 | 
			
		||||
 | 
			
		||||
    if (!read_request_line(fp_read, c.request)) {
 | 
			
		||||
        write_error(fp_write, 400);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    read_headers(fp_read, c.request.headers);
 | 
			
		||||
    
 | 
			
		||||
    // Routing
 | 
			
		||||
    c.response.status = 404;
 | 
			
		||||
    c.response.status = 0;
 | 
			
		||||
 | 
			
		||||
    if (c.request.method == "GET") {
 | 
			
		||||
        for (auto it = get_handlers_.begin(); it != get_handlers_.end(); ++it) {
 | 
			
		||||
@@ -493,6 +480,9 @@ inline void Server::process_request(FILE* fp_read, FILE* fp_write)
 | 
			
		||||
                    c.request.params.push_back(m[i]);
 | 
			
		||||
                }
 | 
			
		||||
                handler(c);
 | 
			
		||||
                if (!c.response.status) {
 | 
			
		||||
                    c.response.status = 200;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -502,15 +492,21 @@ inline void Server::process_request(FILE* fp_read, FILE* fp_write)
 | 
			
		||||
        c.response.status = 400;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!c.response.status) {
 | 
			
		||||
        c.response.status = 404;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (400 <= c.response.status) {
 | 
			
		||||
        if (error_handler_) {
 | 
			
		||||
            error_handler_(c);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (logger_) {
 | 
			
		||||
        logger_(c);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (200 <= c.response.status && c.response.status < 400) {
 | 
			
		||||
        write_response(fp_write, c.response);
 | 
			
		||||
    } else {
 | 
			
		||||
        write_error(fp_write, c.response.status);
 | 
			
		||||
    }
 | 
			
		||||
    write_response(fp_write, c.response);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HTTP client implementation
 | 
			
		||||
@@ -531,7 +527,7 @@ inline Client::~Client()
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline bool Client::read_response_line(FILE* fp, Response& response)
 | 
			
		||||
inline bool Client::read_response_line(FILE* fp, Response& res)
 | 
			
		||||
{
 | 
			
		||||
    const size_t BUFSIZ_RESPONSELINE = 2048;
 | 
			
		||||
    char buf[BUFSIZ_RESPONSELINE];
 | 
			
		||||
@@ -543,13 +539,13 @@ inline bool Client::read_response_line(FILE* fp, Response& response)
 | 
			
		||||
 | 
			
		||||
    std::cmatch m;
 | 
			
		||||
    if (std::regex_match(buf, m, re)) {
 | 
			
		||||
        response.status = std::atoi(std::string(m[1]).c_str());
 | 
			
		||||
        res.status = std::atoi(std::string(m[1]).c_str());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline int Client::get(const char* url, Response& response)
 | 
			
		||||
inline int Client::get(const char* url, Response& res)
 | 
			
		||||
{
 | 
			
		||||
    socket_t sock = create_client_socket(host_.c_str(), port_);
 | 
			
		||||
    if (sock == -1) {
 | 
			
		||||
@@ -564,17 +560,17 @@ inline int Client::get(const char* url, Response& response)
 | 
			
		||||
    fprintf(fp_write, "GET %s HTTP/1.0\r\n\r\n", url);
 | 
			
		||||
    fflush(fp_write);
 | 
			
		||||
 | 
			
		||||
    if (!read_response_line(fp_read, response)) {
 | 
			
		||||
    if (!read_response_line(fp_read, res)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    read_headers(fp_read, response.headers);
 | 
			
		||||
    read_headers(fp_read, res.headers);
 | 
			
		||||
 | 
			
		||||
    // Read content body
 | 
			
		||||
    auto len = get_header_value_int(response.headers, "Content-Length", 0);
 | 
			
		||||
    auto len = get_header_value_int(res.headers, "Content-Length", 0);
 | 
			
		||||
    if (len) {
 | 
			
		||||
        response.body.assign(len, 0);
 | 
			
		||||
        if (!fgets(&response.body[0], response.body.size() + 1, fp_read)) {
 | 
			
		||||
        res.body.assign(len, 0);
 | 
			
		||||
        if (!fgets(&res.body[0], res.body.size() + 1, fp_read)) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								test/test.cc
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								test/test.cc
									
									
									
									
									
								
							@@ -65,17 +65,20 @@ TEST(ServerTest, GetMethod)
 | 
			
		||||
        c.response.set_content(content);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    //svr.on_ready([&]() { svr.stop(); });
 | 
			
		||||
    
 | 
			
		||||
    auto f = async([&](){ svr.run(); });
 | 
			
		||||
 | 
			
		||||
    sleep(1);
 | 
			
		||||
    {
 | 
			
		||||
        Response res;
 | 
			
		||||
        Client(host, port).get(url, res);
 | 
			
		||||
        EXPECT_EQ(200, res.status);
 | 
			
		||||
        EXPECT_EQ(content, res.body);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Client cli(host, port);
 | 
			
		||||
 | 
			
		||||
    Response res;
 | 
			
		||||
    cli.get(url, res);
 | 
			
		||||
    EXPECT_EQ(content, res.body);
 | 
			
		||||
    {
 | 
			
		||||
        Response res;
 | 
			
		||||
        Client(host, port).get("/invalid", res);
 | 
			
		||||
        EXPECT_EQ(404, res.status);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    svr.stop();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user