Browse Source

Removed Connection class.

yhirose 13 years ago
parent
commit
e8a18ad447
5 changed files with 107 additions and 105 deletions
  1. 5 5
      README.md
  2. 4 4
      example/hello.cc
  3. 17 24
      example/server.cc
  4. 57 57
      httplib.h
  5. 24 15
      test/test.cc

+ 5 - 5
README.md

@@ -10,7 +10,7 @@ It's extremely easy to setup. Just include **httplib.h** file in your code!
 Server Example
 --------------
 
-Inspired by [Sinatra](http://www.sinatrarb.com/) 
+Inspired by [Sinatra](http://www.sinatrarb.com/) and [express](https://github.com/visionmedia/express).
 
     #include <httplib.h>
 
@@ -18,13 +18,13 @@ Inspired by [Sinatra](http://www.sinatrarb.com/)
     {
         using namespace httplib;
 
-        Server svr("localhost", 1234);
+        Server svr;
 
-        svr.get("/hi", [](Connection& c) {
-            c.response.set_content("Hello World!", "text/plain");
+        svr.get("/hi", [](const Request& req, Response& res) {
+            res.set_content("Hello World!", "text/plain");
         });
 
-        svr.run();
+        svr.listen("localhost", 1234);
     }
 
 Client Example

+ 4 - 4
example/hello.cc

@@ -10,13 +10,13 @@ using namespace httplib;
 
 int main(void)
 {
-    Server svr("localhost", 1234);
+    Server svr;
 
-    svr.get("/hi", [](Connection& c) {
-        c.response.set_content("Hello World!", "text/plain");
+    svr.get("/hi", [](const Request& req, Response& res) {
+        res.set_content("Hello World!", "text/plain");
     });
 
-    svr.run();
+    svr.listen("localhost", 1234);
 }
 
 // vim: et ts=4 sw=4 cin cino={1s ff=unix

+ 17 - 24
example/server.cc

@@ -8,11 +8,9 @@
 #include <httplib.h>
 #include <cstdio>
 
-#ifdef _WIN32
-#define snprintf sprintf_s
-#endif
+using namespace httplib;
 
-std::string dump_headers(const httplib::MultiMap& headers)
+std::string dump_headers(const MultiMap& headers)
 {
     std::string s;
     char buf[BUFSIZ];
@@ -26,11 +24,8 @@ std::string dump_headers(const httplib::MultiMap& headers)
     return s;
 }
 
-std::string log(const httplib::Connection& c)
+std::string log(const Request& req, Response& res)
 {
-    const auto& req = c.request;
-    const auto& res = c.response;
-
     std::string s;
     char buf[BUFSIZ];
 
@@ -68,38 +63,36 @@ std::string log(const httplib::Connection& c)
 
 int main(void)
 {
-    using namespace httplib;
-
-    Server svr("localhost", 8080);
+    Server svr;
 
-    svr.get("/", [=](Connection& c) {
-        c.response.set_redirect("/hi");
+    svr.get("/", [=](const Request& req, Response& res) {
+        res.set_redirect("/hi");
     });
 
-    svr.get("/hi", [](Connection& c) {
-        c.response.set_content("Hello World!", "text/plain");
+    svr.get("/hi", [](const Request& req, Response& res) {
+        res.set_content("Hello World!", "text/plain");
     });
 
-    svr.get("/dump", [](Connection& c) {
-        c.response.set_content(dump_headers(c.request.headers), "text/plain");
+    svr.get("/dump", [](const Request& req, Response& res) {
+        res.set_content(dump_headers(req.headers), "text/plain");
     });
 
-    svr.get("/stop", [&](Connection& c) {
+    svr.get("/stop", [&](const Request& req, Response& res) {
         svr.stop();
     });
 
-    svr.set_error_handler([](Connection& c) {
+    svr.set_error_handler([](const Request& req, Response& res) {
         const char* fmt = "<p>Error Status: <span style='color:red;'>%d</span></p>";
         char buf[BUFSIZ];
-        snprintf(buf, sizeof(buf), fmt, c.response.status);
-        c.response.set_content(buf, "text/html");
+        snprintf(buf, sizeof(buf), fmt, res.status);
+        res.set_content(buf, "text/html");
     });
 
-    svr.set_logger([](const Connection& c) {
-        printf("%s", log(c).c_str());
+    svr.set_logger([](const Request& req, Response& res) {
+        printf("%s", log(req, res).c_str());
     });
 
-    svr.run();
+    svr.listen("localhost", 8080);
 
     return 0;
 }

+ 57 - 57
httplib.h

@@ -18,6 +18,9 @@
 #ifndef SO_OPENTYPE
 #define SO_OPENTYPE 0x7008
 #endif
+#ifndef snprintf
+#define snprintf _snprintf_s
+#endif
 
 #include <fcntl.h>
 #include <io.h>
@@ -78,16 +81,18 @@ struct Response {
     Response() : status(-1) {}
 };
 
+/*
 struct Connection {
     Request  request;
     Response response;
 };
+*/
 
 class Server {
 public:
-    typedef std::function<void (Connection& c)> Handler;
+    typedef std::function<void (const Request&, Response&)> Handler;
 
-    Server(const char* host, int port);
+    Server();
     ~Server();
 
     void get(const char* pattern, Handler handler);
@@ -96,7 +101,7 @@ public:
     void set_error_handler(Handler handler);
     void set_logger(Handler logger);
 
-    bool run();
+    bool listen(const char* host, int port);
     void stop();
 
 private:
@@ -104,13 +109,10 @@ private:
 
     void process_request(socket_t sock);
     bool read_request_line(FILE* fp, Request& req);
-    bool routing(Connection& c);
-    bool dispatch_request(Connection& c, Handlers& handlers);
-
-    const std::string host_;
-    const int         port_;
-    socket_t          svr_sock_;
+    bool routing(Request& req, Response& res);
+    bool dispatch_request(Request& req, Response& res, Handlers& handlers);
 
+    socket_t svr_sock_;
     Handlers get_handlers_;
     Handlers post_handlers_;
     Handler  error_handler_;
@@ -358,7 +360,7 @@ inline std::string encode_url(const std::string& s)
             if (s[i] < 0) {
                 result += '%';
                 char hex[4];
-                size_t len = sprintf(hex, "%02X", (int)(unsigned char)s[i]);
+                size_t len = snprintf(hex, sizeof(hex), "%02X", (unsigned char)s[i]);
                 assert(len == 2);
                 result.append(hex, len);
             } else {
@@ -404,35 +406,34 @@ inline int from_hex_to_i(const std::string& s, int i, int cnt, int& val)
 size_t to_utf8(int code, char* buff)
 {
     if (code < 0x0080) {
-        buff[0] = (uint8_t)(code & 0x7F);
+        buff[0] = (code & 0x7F);
         return 1;
     } else if (code < 0x0800) {
-        buff[0] = (uint8_t)(0xC0 | ((code >> 6) & 0x1F));
-        buff[1] = (uint8_t)(0x80 | (code & 0x3F));
+        buff[0] = (0xC0 | ((code >> 6) & 0x1F));
+        buff[1] = (0x80 | (code & 0x3F));
         return 2;
     } else if (code < 0xD800) {
-        buff[0] = (uint8_t)(0xE0 | ((code >> 12) & 0xF));
-        buff[1] = (uint8_t)(0x80 | ((code >> 6) & 0x3F));
-        buff[2] = (uint8_t)(0x80 | (code & 0x3F));
+        buff[0] = (0xE0 | ((code >> 12) & 0xF));
+        buff[1] = (0x80 | ((code >> 6) & 0x3F));
+        buff[2] = (0x80 | (code & 0x3F));
         return 3;
     } else if (code < 0xE000)  { // D800 - DFFF is invalid...
-        assert(!"NOTREACHED");
         return 0;
     } else if (code < 0x10000) {
-        buff[0] = (uint8_t)(0xE0 | ((code >> 12) & 0xF));
-        buff[1] = (uint8_t)(0x80 | ((code >> 6) & 0x3F));
-        buff[2] = (uint8_t)(0x80 | (code & 0x3F));
+        buff[0] = (0xE0 | ((code >> 12) & 0xF));
+        buff[1] = (0x80 | ((code >> 6) & 0x3F));
+        buff[2] = (0x80 | (code & 0x3F));
         return 3;
     } else if (code < 0x110000) {
-        buff[0] = (uint8_t)(0xF0 | ((code >> 18) & 0x7));
-        buff[1] = (uint8_t)(0x80 | ((code >> 12) & 0x3F));
-        buff[2] = (uint8_t)(0x80 | ((code >> 6) & 0x3F));
-        buff[3] = (uint8_t)(0x80 | (code & 0x3F));
+        buff[0] = (0xF0 | ((code >> 18) & 0x7));
+        buff[1] = (0x80 | ((code >> 12) & 0x3F));
+        buff[2] = (0x80 | ((code >> 6) & 0x3F));
+        buff[3] = (0x80 | (code & 0x3F));
         return 4;
     }
 
-    assert(!"NOTREACHED");
     // NOTREACHED
+    return 0;
 }
 
 inline std::string decode_url(const std::string& s)
@@ -461,10 +462,10 @@ inline std::string decode_url(const std::string& s)
                     result.append(buff, len);
                 }
             } else {
-                // ASCII
+                // HEX
                 int val = 0;
                 i = from_hex_to_i(s, i, 2, val);
-                result += (char)val;
+                result += val;
             }
         } else if (s[i] == '+') {
             result += ' ';
@@ -560,10 +561,8 @@ inline void Response::set_content(const std::string& s, const char* content_type
 }
 
 // HTTP server implementation
-inline Server::Server(const char* host, int port)
-    : host_(host)
-    , port_(port)
-    , svr_sock_(-1)
+inline Server::Server()
+    : svr_sock_(-1)
 {
 #ifdef _WIN32
     WSADATA wsaData;
@@ -598,9 +597,9 @@ inline void Server::set_logger(Handler logger)
     logger_ = logger;
 }
 
-inline bool Server::run()
+inline bool Server::listen(const char* host, int port)
 {
-    svr_sock_ = detail::create_server_socket(host_.c_str(), port_);
+    svr_sock_ = detail::create_server_socket(host, port);
     if (svr_sock_ == -1) {
         return false;
     }
@@ -663,24 +662,24 @@ inline bool Server::read_request_line(FILE* fp, Request& req)
     return false;
 }
 
-inline bool Server::routing(Connection& c)
+inline bool Server::routing(Request& req, Response& res)
 {
-    if (c.request.method == "GET") {
-        return dispatch_request(c, get_handlers_);
-    } else if (c.request.method == "POST") {
-        return dispatch_request(c, post_handlers_);
+    if (req.method == "GET") {
+        return dispatch_request(req, res, get_handlers_);
+    } else if (req.method == "POST") {
+        return dispatch_request(req, res, post_handlers_);
     }
     return false;
 }
 
-inline bool Server::dispatch_request(Connection& c, Handlers& handlers)
+inline bool Server::dispatch_request(Request& req, Response& res, Handlers& handlers)
 {
     for (auto it = handlers.begin(); it != handlers.end(); ++it) {
         const auto& pattern = it->first;
         const auto& handler = it->second;
 
-        if (std::regex_match(c.request.url, c.request.matches, pattern)) {
-            handler(c);
+        if (std::regex_match(req.url, req.matches, pattern)) {
+            handler(req, res);
             return true;
         }
     }
@@ -693,40 +692,41 @@ inline void Server::process_request(socket_t sock)
     FILE* fp_write;
     detail::get_flie_pointers(sock, fp_read, fp_write);
 
-    Connection c;
+    Request req;
+    Response res;
 
-    if (!read_request_line(fp_read, c.request) ||
-        !detail::read_headers(fp_read, c.request.headers)) {
+    if (!read_request_line(fp_read, req) ||
+        !detail::read_headers(fp_read, req.headers)) {
         return;
     }
 
-    if (c.request.method == "POST") {
-        if (!detail::read_content(c.request, fp_read)) {
+    if (req.method == "POST") {
+        if (!detail::read_content(req, fp_read)) {
             return;
         }
-        if (c.request.get_header_value("Content-Type") == "application/x-www-form-urlencoded") {
-            detail::parse_query_text(detail::decode_url(c.request.body), c.request.params);
+        if (req.get_header_value("Content-Type") == "application/x-www-form-urlencoded") {
+            detail::parse_query_text(detail::decode_url(req.body), req.params);
         }
     }
     
-    if (routing(c)) {
-        if (c.response.status == -1) {
-            c.response.status = 200;
+    if (routing(req, res)) {
+        if (res.status == -1) {
+            res.status = 200;
         }
     } else {
-        c.response.status = 404;
+        res.status = 404;
     }
-    assert(c.response.status != -1);
+    assert(res.status != -1);
 
-    if (400 <= c.response.status && error_handler_) {
-        error_handler_(c);
+    if (400 <= res.status && error_handler_) {
+        error_handler_(req, res);
     }
 
-    detail::write_response(fp_write, c.response);
+    detail::write_response(fp_write, res);
     fflush(fp_write);
 
     if (logger_) {
-        logger_(c);
+        logger_(req, res);
     }
 }
 

+ 24 - 15
test/test.cc

@@ -6,6 +6,9 @@
 
 #ifdef _WIN32
 #include <process.h>
+#define msleep(n) ::Sleep(n)
+#else
+#define msleep(n) ::usleep(n * 1000)
 #endif
 
 using namespace std;
@@ -170,46 +173,51 @@ TEST(GetHeaderValueTest, RegularValueInt)
 
 class ServerTest : public ::testing::Test {
 protected:
-    ServerTest() : svr_(HOST, PORT), cli_(HOST, PORT) {
+    ServerTest() : cli_(HOST, PORT), up_(false) {
     }
 
     virtual void SetUp() {
-        svr_.get("/hi", [&](Connection& c) {
-            c.response.set_content("Hello World!", "text/plain");
+        svr_.get("/hi", [&](const Request& req, Response& res) {
+            res.set_content("Hello World!", "text/plain");
         });
 
-        svr_.get("/", [&](httplib::Connection& c) {
-            c.response.set_redirect("/hi");
+        svr_.get("/", [&](const Request& req, Response& res) {
+            res.set_redirect("/hi");
         });
 
-        svr_.post("/person", [&](Connection& c) {
-            const auto& req = c.request;
+        svr_.post("/person", [&](const Request& req, Response& res) {
             if (req.has_param("name") && req.has_param("note")) {
                 persons_[req.params.at("name")] = req.params.at("note");
             } else {
-                c.response.status = 400;
+                res.status = 400;
             }
         });
 
-        svr_.get("/person/(.*)", [&](Connection& c) {
-            const auto& req = c.request;
+        svr_.get("/person/(.*)", [&](const Request& req, Response& res) {
             std::string name = req.matches[1];
             if (persons_.find(name) != persons_.end()) {
                 auto note = persons_[name];
-                c.response.set_content(note, "text/plain");
+                res.set_content(note, "text/plain");
             } else {
-                c.response.status = 404;
+                res.status = 404;
             }
         });
 
-        svr_.get("/stop", [&](Connection& c) {
+        svr_.get("/stop", [&](const Request& req, Response& res) {
             svr_.stop();
         });
 
         persons_["john"] = "programmer";
 
-        //f_ = async([&](){ svr_.run(); });
-        t_ = std::make_shared<thread>([&](){ svr_.run(); });
+        //f_ = async([&](){ svr_.listen(HOST, PORT); });
+        t_ = std::make_shared<thread>([&](){
+            up_ = true;
+            svr_.listen(HOST, PORT);
+        });
+
+        while (!up_) {
+            msleep(1);
+        }
     }
 
     virtual void TearDown() {
@@ -225,6 +233,7 @@ protected:
     Client                             cli_;
     //std::future<void>                  f_;
     std::shared_ptr<thread>            t_;
+    bool up_;
 };
 
 TEST_F(ServerTest, GetMethod200)