diff --git a/example/sample.cc b/example/sample.cc index d8c30f5..01f41d2 100644 --- a/example/sample.cc +++ b/example/sample.cc @@ -14,17 +14,17 @@ int main(void) Server svr; - svr.post("/", [](const Request& /*req*/, Response& res) { - res.body_ = ""; + svr.get("/", [](Context& cxt) { + cxt.response.body = ""; }); - svr.post("/item", [](const Request& req, Response& res) { - res.body_ = req.pattern_; + svr.post("/item", [](Context& cxt) { + cxt.response.body = cxt.request.pattern; }); - svr.get("/item/:name", [](const Request& req, Response& res) { + svr.get("/item/:name", [](Context& cxt) { try { - res.body_ = req.params_.at("name"); + cxt.response.body = cxt.request.params.at("name"); } catch (...) { // Error... } diff --git a/httpsvrkit.h b/httpsvrkit.h index b9d297c..5a9893c 100644 --- a/httpsvrkit.h +++ b/httpsvrkit.h @@ -37,27 +37,32 @@ typedef int socket_t; namespace httpsvrkit { -// HTTP request -class Request { -public: - std::map headers_; - std::string body_; +typedef std::map Map; +typedef std::multimap MultiMap; - std::string pattern_; - std::map params_; +// HTTP request +struct Request { + Map headers; + std::string body; + std::string pattern; + Map params; }; // HTTP response -class Response { -public: - std::multimap headers_; - std::string body_; +struct Response { + MultiMap headers; + std::string body; +}; + +struct Context { + const Request request; + Response response; }; // HTTP server class Server { public: - typedef std::function Handler; + typedef std::function Handler; Server(); ~Server(); @@ -71,8 +76,6 @@ public: private: void process_request(int fd); - const size_t BUFSIZ_REQUESTLINE = 2048; - socket_t sock_; std::multimap handlers_; }; @@ -200,18 +203,41 @@ inline void Server::stop() sock_ = -1; } -inline bool parse_request_line(const char* s, std::string& cmd, std::string& url) +inline bool read_request_line(FILE* fp, std::string& method, std::string& url) { - std::regex re("(GET|POST) (.+) HTTP/1\\.1\r\n"); + static std::regex re("(GET|POST) (.+) HTTP/1\\.1\r\n"); + + const size_t BUFSIZ_REQUESTLINE = 2048; + char buf[BUFSIZ_REQUESTLINE]; + fgets(buf, BUFSIZ_REQUESTLINE, fp); + std::cmatch m; - if (std::regex_match(s, m, re)) { - cmd = std::string(m[1]); + if (std::regex_match(buf, m, re)) { + method = std::string(m[1]); url = std::string(m[2]); return true; } + return false; } +inline void read_headers(FILE* fp, Map& headers) +{ + static std::regex re("(.+?): (.+?)\r\n"); + + const size_t BUFSIZ_HEADER = 2048; + char buf[BUFSIZ_HEADER]; + + while (fgets(buf, BUFSIZ_HEADER, fp) && strcmp(buf, "\r\n")) { + std::cmatch m; + if (std::regex_match(buf, m, re)) { + auto key = std::string(m[1]); + auto val = std::string(m[2]); + headers[key] = val; + } + } +} + inline void write_plain_text(int fd, const char* s) { fdopen_b(fd, "w", [=](FILE* fp) { @@ -254,20 +280,27 @@ inline void write_error(int fd, int code) inline void Server::process_request(int fd) { fdopen_b(fd, "r", [=](FILE* fp) { - // Parse request line - char request_line[BUFSIZ_REQUESTLINE]; - fgets(request_line, BUFSIZ_REQUESTLINE, fp); - - std::string cmd, url; - if (!parse_request_line(request_line, cmd, url)) { + // Read and parse request line + std::string method, url; + if (!read_request_line(fp, method, url)) { write_error(fd, 400); return; } + // Read headers + Map headers; + read_headers(fp, headers); + // Write content - char content[BUFSIZ]; - sprintf(content, "cmd: %s, url: %s\n", cmd.c_str(), url.c_str()); - write_plain_text(fd, content); + char buf[BUFSIZ]; + std::string content; + sprintf(buf, "Method: %s, URL: %s\n", method.c_str(), url.c_str()); + content += buf; + for (const auto& x : headers) { + sprintf(buf, "%s: %s\n", x.first.c_str(), x.second.c_str()); + content += buf; + } + write_plain_text(fd, content.c_str()); }); }