Browse Source

Refactoring. Removed some client methods.

yhirose 13 years ago
parent
commit
6062ea592b
5 changed files with 132 additions and 184 deletions
  1. 6 4
      README.md
  2. 2 5
      example/client.cc
  3. 6 0
      example/example.sln
  4. 77 91
      httplib.h
  5. 41 84
      test/test.cc

+ 6 - 4
README.md

@@ -1,20 +1,23 @@
 cpp-httplib
 cpp-httplib
 ===========
 ===========
 
 
-A C++ HTTP library.
+A C++11 header-only HTTP library.
 
 
 [The Boost Software License 1.0](http://www.boost.org/LICENSE_1_0.txt)
 [The Boost Software License 1.0](http://www.boost.org/LICENSE_1_0.txt)
 
 
+It's extremely easy to setup. Just include **httplib.h** file in your code!
+
 Server Example
 Server Example
 --------------
 --------------
 
 
 Inspired by [Sinatra](http://www.sinatrarb.com/) 
 Inspired by [Sinatra](http://www.sinatrarb.com/) 
 
 
     #include <httplib.h>
     #include <httplib.h>
-    using namespace httplib;
 
 
     int main(void)
     int main(void)
     {
     {
+        using namespace httplib;
+
         Server svr("localhost", 1234);
         Server svr("localhost", 1234);
 
 
         svr.get("/hi", [](Connection& c) {
         svr.get("/hi", [](Connection& c) {
@@ -29,11 +32,10 @@ Client Example
 
 
     #include <httplib.h>
     #include <httplib.h>
     #include <iostream>
     #include <iostream>
-    using namespace httplib;
 
 
     int main(void)
     int main(void)
     {
     {
-        Client cli("localhost", 1234);
+        httplib::Client cli("localhost", 1234);
 
 
         auto res = cli.get("/hi");
         auto res = cli.get("/hi");
         if (res && res->status == 200) {
         if (res && res->status == 200) {

+ 2 - 5
example/client.cc

@@ -9,15 +9,12 @@
 #include <iostream>
 #include <iostream>
 
 
 using namespace std;
 using namespace std;
-using namespace httplib;
 
 
 int main(void)
 int main(void)
 {
 {
-    const char* hi = "/hi";
+    httplib::Client cli("localhost", 8080);
 
 
-    Client cli("localhost", 8080);
-
-    auto res = cli.get(hi);
+    auto res = cli.get("/hi");
     if (res) {
     if (res) {
         cout << res->status << endl;
         cout << res->status << endl;
         cout << res->get_header_value("Content-Type") << endl;
         cout << res->get_header_value("Content-Type") << endl;

+ 6 - 0
example/example.sln

@@ -5,6 +5,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "server", "server.vcxproj",
 EndProject
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "client.vcxproj", "{6DB1FC63-B153-4279-92B7-D8A11AF285D6}"
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "client.vcxproj", "{6DB1FC63-B153-4279-92B7-D8A11AF285D6}"
 EndProject
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{280E605F-0CB8-4336-8D9F-CE50A9472AE2}"
+	ProjectSection(SolutionItems) = preProject
+		..\httplib.h = ..\httplib.h
+		..\README.md = ..\README.md
+	EndProjectSection
+EndProject
 Global
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Win32 = Debug|Win32
 		Debug|Win32 = Debug|Win32

+ 77 - 91
httplib.h

@@ -102,14 +102,14 @@ public:
 private:
 private:
     typedef std::vector<std::pair<std::regex, Handler>> Handlers;
     typedef std::vector<std::pair<std::regex, Handler>> Handlers;
 
 
-    void process_request(FILE* fp_read, FILE* fp_write);
+    void process_request(socket_t sock);
     bool read_request_line(FILE* fp, Request& req);
     bool read_request_line(FILE* fp, Request& req);
     bool routing(Connection& c);
     bool routing(Connection& c);
     bool dispatch_request(Connection& c, Handlers& handlers);
     bool dispatch_request(Connection& c, Handlers& handlers);
 
 
     const std::string host_;
     const std::string host_;
     const int         port_;
     const int         port_;
-    socket_t          sock_;
+    socket_t          svr_sock_;
 
 
     Handlers get_handlers_;
     Handlers get_handlers_;
     Handlers post_handlers_;
     Handlers post_handlers_;
@@ -122,12 +122,11 @@ public:
     Client(const char* host, int port);
     Client(const char* host, int port);
     ~Client();
     ~Client();
 
 
-    bool get(const char* url, Response& res);
-    bool post(const char* url, const std::string& body, const char* content_type, Response& res);
-    bool send(const Request& req, Response& res);
-
     std::shared_ptr<Response> get(const char* url);
     std::shared_ptr<Response> get(const char* url);
-    std::shared_ptr<Response> post(const char* url, const std::string& body, const char* content_type);
+    std::shared_ptr<Response> post(
+        const char* url, const std::string& body, const char* content_type);
+
+    bool send(const Request& req, Response& res);
 
 
 private:
 private:
     bool read_response_line(FILE* fp, Response& res);
     bool read_response_line(FILE* fp, Response& res);
@@ -137,6 +136,7 @@ private:
 };
 };
 
 
 // Implementation
 // Implementation
+namespace detail {
 
 
 template <class Fn>
 template <class Fn>
 void split(const char* b, const char* e, char d, Fn fn)
 void split(const char* b, const char* e, char d, Fn fn)
@@ -177,7 +177,7 @@ socket_t create_socket(const char* host, int port, Fn fn)
     setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char*)&opt, sizeof(opt));
     setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char*)&opt, sizeof(opt));
 #endif
 #endif
 
 
-    // Create a server socket
+    // Create a socket
     socket_t sock = socket(AF_INET, SOCK_STREAM, 0);
     socket_t sock = socket(AF_INET, SOCK_STREAM, 0);
     if (sock == -1) {
     if (sock == -1) {
         return -1;
         return -1;
@@ -206,21 +206,17 @@ socket_t create_socket(const char* host, int port, Fn fn)
 inline socket_t create_server_socket(const char* host, int port)
 inline socket_t create_server_socket(const char* host, int port)
 {
 {
     return create_socket(host, port, [](socket_t sock, struct sockaddr_in& addr) -> socket_t {
     return create_socket(host, port, [](socket_t sock, struct sockaddr_in& addr) -> socket_t {
-
         if (::bind(sock, (struct sockaddr*)&addr, sizeof(addr))) {
         if (::bind(sock, (struct sockaddr*)&addr, sizeof(addr))) {
             return -1;
             return -1;
         }
         }
-
-        // Listen through 5 channels
-        if (listen(sock, 5)) {
+        if (listen(sock, 5)) { // Listen through 5 channels
             return -1;
             return -1;
         }
         }
-
         return sock;
         return sock;
     });
     });
 }
 }
 
 
-inline int close_socket(socket_t sock)
+inline int shutdown_and_close_socket(socket_t sock)
 {
 {
 #ifdef _WIN32
 #ifdef _WIN32
     shutdown(sock, SD_BOTH);
     shutdown(sock, SD_BOTH);
@@ -233,35 +229,23 @@ inline int close_socket(socket_t sock)
 
 
 inline socket_t create_client_socket(const char* host, int port)
 inline socket_t create_client_socket(const char* host, int port)
 {
 {
-    return create_socket(host, port,
-            [](socket_t sock, struct sockaddr_in& addr) -> socket_t {
-
+    return create_socket(host, port, [](socket_t sock, struct sockaddr_in& addr) -> socket_t {
         if (connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in))) {
         if (connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in))) {
             return -1;
             return -1;
         }
         }
-
         return sock;
         return sock;
     });
     });
 }
 }
 
 
 inline const char* status_message(int status)
 inline const char* status_message(int status)
 {
 {
-    const char* s = NULL;
-
     switch (status) {
     switch (status) {
-    case 400:
-        s = "Bad Request";
-        break;
-    case 404:
-        s = "Not Found";
-        break;
+    case 400: return "Bad Request";
+    case 404: return "Not Found";
     default:
     default:
         status = 500;
         status = 500;
-        s = "Internal Server Error";
-        break;
+        return "Internal Server Error";
     }
     }
-
-    return s;
 }
 }
 
 
 inline const char* get_header_value_text(const MultiMap& map, const char* key, const char* def)
 inline const char* get_header_value_text(const MultiMap& map, const char* key, const char* def)
@@ -378,7 +362,14 @@ inline void parse_query_text(const char* b, const char* e, Map& params)
     });
     });
 }
 }
 
 
-// HTTP server implementation
+inline void parse_query_text(const std::string& s, Map& params)
+{
+    parse_query_text(&s[0], &s[s.size()], params);
+}
+
+} // namespace detail
+
+// Request implementation
 inline bool Request::has_header(const char* key) const
 inline bool Request::has_header(const char* key) const
 {
 {
     return headers.find(key) != headers.end();
     return headers.find(key) != headers.end();
@@ -386,7 +377,7 @@ inline bool Request::has_header(const char* key) const
 
 
 inline std::string Request::get_header_value(const char* key) const
 inline std::string Request::get_header_value(const char* key) const
 {
 {
-    return get_header_value_text(headers, key, "");
+    return detail::get_header_value_text(headers, key, "");
 }
 }
 
 
 inline void Request::set_header(const char* key, const char* val)
 inline void Request::set_header(const char* key, const char* val)
@@ -399,6 +390,7 @@ inline bool Request::has_param(const char* key) const
     return params.find(key) != params.end();
     return params.find(key) != params.end();
 }
 }
 
 
+// Response implementation
 inline bool Response::has_header(const char* key) const
 inline bool Response::has_header(const char* key) const
 {
 {
     return headers.find(key) != headers.end();
     return headers.find(key) != headers.end();
@@ -406,7 +398,7 @@ inline bool Response::has_header(const char* key) const
 
 
 inline std::string Response::get_header_value(const char* key) const
 inline std::string Response::get_header_value(const char* key) const
 {
 {
-    return get_header_value_text(headers, key, "");
+    return detail::get_header_value_text(headers, key, "");
 }
 }
 
 
 inline void Response::set_header(const char* key, const char* val)
 inline void Response::set_header(const char* key, const char* val)
@@ -426,10 +418,11 @@ inline void Response::set_content(const std::string& s, const char* content_type
     set_header("Content-Type", content_type);
     set_header("Content-Type", content_type);
 }
 }
 
 
+// HTTP server implementation
 inline Server::Server(const char* host, int port)
 inline Server::Server(const char* host, int port)
     : host_(host)
     : host_(host)
     , port_(port)
     , port_(port)
-    , sock_(-1)
+    , svr_sock_(-1)
 {
 {
 #ifdef _WIN32
 #ifdef _WIN32
     WSADATA wsaData;
     WSADATA wsaData;
@@ -466,31 +459,26 @@ inline void Server::set_logger(Handler logger)
 
 
 inline bool Server::run()
 inline bool Server::run()
 {
 {
-    sock_ = create_server_socket(host_.c_str(), port_);
-    if (sock_ == -1) {
+    svr_sock_ = detail::create_server_socket(host_.c_str(), port_);
+    if (svr_sock_ == -1) {
         return false;
         return false;
     }
     }
     
     
     for (;;) {
     for (;;) {
-        socket_t fd = accept(sock_, NULL, NULL);
-        if (fd == -1) {
-            // The server socket was closed by user.
-            if (sock_ == -1) {
+        socket_t sock = accept(svr_sock_, NULL, NULL);
+        if (sock == -1) {
+            if (svr_sock_ == -1) {
+                // The server socket was closed by user.
                 return true;
                 return true;
-            } 
-
-            close_socket(sock_);
-            return false;
+            } else {
+                detail::shutdown_and_close_socket(svr_sock_);
+                return false;
+            }
         }
         }
 
 
-        FILE* fp_read;
-        FILE* fp_write;
-        get_flie_pointers(fd, fp_read, fp_write);
-
-        process_request(fp_read, fp_write);
-
-        fflush(fp_write);
-        close_socket(fd);
+        // TODO: should be async
+        process_request(sock);
+        detail::shutdown_and_close_socket(sock);
     }
     }
 
 
     // NOTREACHED
     // NOTREACHED
@@ -498,8 +486,8 @@ inline bool Server::run()
 
 
 inline void Server::stop()
 inline void Server::stop()
 {
 {
-    close_socket(sock_);
-    sock_ = -1;
+    detail::shutdown_and_close_socket(svr_sock_);
+    svr_sock_ = -1;
 }
 }
 
 
 inline bool Server::read_request_line(FILE* fp, Request& req)
 inline bool Server::read_request_line(FILE* fp, Request& req)
@@ -521,7 +509,7 @@ inline bool Server::read_request_line(FILE* fp, Request& req)
         auto len = std::distance(m[3].first, m[3].second);
         auto len = std::distance(m[3].first, m[3].second);
         if (len > 0) {
         if (len > 0) {
             const auto& pos = m[3];
             const auto& pos = m[3];
-            parse_query_text(pos.first, pos.second, req.params);
+            detail::parse_query_text(pos.first, pos.second, req.params);
         }
         }
 
 
         return true;
         return true;
@@ -554,22 +542,25 @@ inline bool Server::dispatch_request(Connection& c, Handlers& handlers)
     return false;
     return false;
 }
 }
 
 
-inline void Server::process_request(FILE* fp_read, FILE* fp_write)
+inline void Server::process_request(socket_t sock)
 {
 {
+    FILE* fp_read;
+    FILE* fp_write;
+    detail::get_flie_pointers(sock, fp_read, fp_write);
+
     Connection c;
     Connection c;
-    auto& req = c.request;
 
 
-    if (!read_request_line(fp_read, req) ||
-        !read_headers(fp_read, req.headers)) {
+    if (!read_request_line(fp_read, c.request) ||
+        !detail::read_headers(fp_read, c.request.headers)) {
         return;
         return;
     }
     }
 
 
-    if (req.method == "POST") {
-        if (!read_content(req, fp_read)) {
+    if (c.request.method == "POST") {
+        if (!detail::read_content(c.request, fp_read)) {
             return;
             return;
         }
         }
-        if (req.get_header_value("Content-Type") == "application/x-www-form-urlencoded") {
-            parse_query_text(&req.body[0], &req.body[req.body.size()], req.params);
+        if (c.request.get_header_value("Content-Type") == "application/x-www-form-urlencoded") {
+            detail::parse_query_text(c.request.body, c.request.params);
         }
         }
     }
     }
     
     
@@ -586,7 +577,9 @@ inline void Server::process_request(FILE* fp_read, FILE* fp_write)
         error_handler_(c);
         error_handler_(c);
     }
     }
 
 
-    write_response(fp_write, c.response);
+    detail::write_response(fp_write, c.response);
+
+    fflush(fp_write);
 
 
     if (logger_) {
     if (logger_) {
         logger_(c);
         logger_(c);
@@ -629,62 +622,55 @@ inline bool Client::read_response_line(FILE* fp, Response& res)
     return true;
     return true;
 }
 }
 
 
-inline bool Client::get(const char* url, Response& res)
-{
-    Request req;
-    req.method = "GET";
-    req.url = url;
-    return send(req, res);
-}
-
-inline bool Client::post(
-    const char* url, const std::string& body, const char* content_type, Response& res)
-{
-    Request req;
-    req.method = "POST";
-    req.url = url;
-    req.set_header("Content-Type", content_type);
-    req.body = body;
-    return send(req, res);
-}
-
 inline bool Client::send(const Request& req, Response& res)
 inline bool Client::send(const Request& req, Response& res)
 {
 {
-    socket_t sock = create_client_socket(host_.c_str(), port_);
+    socket_t sock = detail::create_client_socket(host_.c_str(), port_);
     if (sock == -1) {
     if (sock == -1) {
         return false;
         return false;
     }
     }
 
 
     FILE* fp_read;
     FILE* fp_read;
     FILE* fp_write;
     FILE* fp_write;
-    get_flie_pointers(sock, fp_read, fp_write);
+    detail::get_flie_pointers(sock, fp_read, fp_write);
 
 
     // Send request
     // Send request
-    write_request(fp_write, req);
+    detail::write_request(fp_write, req);
     fflush(fp_write);
     fflush(fp_write);
 
 
     if (!read_response_line(fp_read, res) ||
     if (!read_response_line(fp_read, res) ||
-        !read_headers(fp_read, res.headers) ||
-        !read_content(res, fp_read)) {
+        !detail::read_headers(fp_read, res.headers) ||
+        !detail::read_content(res, fp_read)) {
         return false;
         return false;
     }
     }
 
 
-    close_socket(sock);
+    detail::shutdown_and_close_socket(sock);
 
 
     return true;
     return true;
 }
 }
 
 
 inline std::shared_ptr<Response> Client::get(const char* url)
 inline std::shared_ptr<Response> Client::get(const char* url)
 {
 {
+    Request req;
+    req.method = "GET";
+    req.url = url;
+
     auto res = std::make_shared<Response>();
     auto res = std::make_shared<Response>();
-    return get(url, *res) ? res : nullptr;
+
+    return send(req, *res) ? res : nullptr;
 }
 }
 
 
 inline std::shared_ptr<Response> Client::post(
 inline std::shared_ptr<Response> Client::post(
     const char* url, const std::string& body, const char* content_type)
     const char* url, const std::string& body, const char* content_type)
 {
 {
+    Request req;
+    req.method = "POST";
+    req.url = url;
+    req.set_header("Content-Type", content_type);
+    req.body = body;
+
     auto res = std::make_shared<Response>();
     auto res = std::make_shared<Response>();
-    return post(url, body, content_type, *res) ? res : nullptr;
+
+    return send(req, *res) ? res : nullptr;
 }
 }
 
 
 } // namespace httplib
 } // namespace httplib

+ 41 - 84
test/test.cc

@@ -12,9 +12,9 @@ TEST(SplitTest, ParseQueryString)
     string s = "key1=val1&key2=val2&key3=val3";
     string s = "key1=val1&key2=val2&key3=val3";
     map<string, string> dic;
     map<string, string> dic;
 
 
-    split(&s[0], &s[s.size()], '&', [&](const char* b, const char* e) {
+    detail::split(&s[0], &s[s.size()], '&', [&](const char* b, const char* e) {
         string key, val;
         string key, val;
-        split(b, e, '=', [&](const char* b, const char* e) {
+        detail::split(b, e, '=', [&](const char* b, const char* e) {
             if (key.empty()) {
             if (key.empty()) {
                 key.assign(b, e);
                 key.assign(b, e);
             } else {
             } else {
@@ -34,7 +34,7 @@ TEST(ParseQueryTest, ParseQueryString)
     string s = "key1=val1&key2=val2&key3=val3";
     string s = "key1=val1&key2=val2&key3=val3";
     map<string, string> dic;
     map<string, string> dic;
 
 
-    parse_query_text(&s[0], &s[s.size()], dic);
+    detail::parse_query_text(&s[0], &s[s.size()], dic);
 
 
     EXPECT_EQ("val1", dic["key1"]);
     EXPECT_EQ("val1", dic["key1"]);
     EXPECT_EQ("val2", dic["key2"]);
     EXPECT_EQ("val2", dic["key2"]);
@@ -43,44 +43,44 @@ TEST(ParseQueryTest, ParseQueryString)
 
 
 TEST(SocketTest, OpenClose)
 TEST(SocketTest, OpenClose)
 {
 {
-    socket_t sock = create_server_socket("localhost", 1914);
+    socket_t sock = detail::create_server_socket("localhost", 1914);
     ASSERT_NE(-1, sock);
     ASSERT_NE(-1, sock);
 
 
-    auto ret = close_socket(sock);
+    auto ret = detail::shutdown_and_close_socket(sock);
     EXPECT_EQ(0, ret);
     EXPECT_EQ(0, ret);
 }
 }
 
 
 TEST(GetHeaderValueTest, DefaultValue)
 TEST(GetHeaderValueTest, DefaultValue)
 {
 {
     MultiMap map = {{"Dummy","Dummy"}};
     MultiMap map = {{"Dummy","Dummy"}};
-    auto val = get_header_value_text(map, "Content-Type", "text/plain");
+    auto val = detail::get_header_value_text(map, "Content-Type", "text/plain");
     ASSERT_STREQ("text/plain", val);
     ASSERT_STREQ("text/plain", val);
 }
 }
 
 
 TEST(GetHeaderValueTest, DefaultValueInt)
 TEST(GetHeaderValueTest, DefaultValueInt)
 {
 {
     MultiMap map = {{"Dummy","Dummy"}};
     MultiMap map = {{"Dummy","Dummy"}};
-    auto val = get_header_value_int(map, "Content-Length", 100);
+    auto val = detail::get_header_value_int(map, "Content-Length", 100);
     EXPECT_EQ(100, val);
     EXPECT_EQ(100, val);
 }
 }
 
 
 TEST(GetHeaderValueTest, RegularValue)
 TEST(GetHeaderValueTest, RegularValue)
 {
 {
     MultiMap map = {{"Content-Type","text/html"}, {"Dummy", "Dummy"}};
     MultiMap map = {{"Content-Type","text/html"}, {"Dummy", "Dummy"}};
-    auto val = get_header_value_text(map, "Content-Type", "text/plain");
+    auto val = detail::get_header_value_text(map, "Content-Type", "text/plain");
     ASSERT_STREQ("text/html", val);
     ASSERT_STREQ("text/html", val);
 }
 }
 
 
 TEST(GetHeaderValueTest, RegularValueInt)
 TEST(GetHeaderValueTest, RegularValueInt)
 {
 {
     MultiMap map = {{"Content-Length","100"}, {"Dummy", "Dummy"}};
     MultiMap map = {{"Content-Length","100"}, {"Dummy", "Dummy"}};
-    auto val = get_header_value_int(map, "Content-Length", 0);
+    auto val = detail::get_header_value_int(map, "Content-Length", 0);
     EXPECT_EQ(100, val);
     EXPECT_EQ(100, val);
 }
 }
 
 
 class ServerTest : public ::testing::Test {
 class ServerTest : public ::testing::Test {
 protected:
 protected:
-    ServerTest() : svr_(host_, port_) {
+    ServerTest() : svr_(HOST, PORT), cli_(HOST, PORT) {
         persons_["john"] = "programmer";
         persons_["john"] = "programmer";
     }
     }
 
 
@@ -117,106 +117,63 @@ protected:
         f_.get();
         f_.get();
     }
     }
 
 
-    const char*                        host_ = "localhost";
-    int                                port_ = 1914;
+    const char* HOST = "localhost";
+    const int   PORT = 1914;
+
     std::map<std::string, std::string> persons_;
     std::map<std::string, std::string> persons_;
     Server                             svr_;
     Server                             svr_;
+    Client                             cli_;
     std::future<void>                  f_;
     std::future<void>                  f_;
 };
 };
 
 
 TEST_F(ServerTest, GetMethod200)
 TEST_F(ServerTest, GetMethod200)
 {
 {
-    Response res;
-    bool ret = Client(host_, port_).get("/hi", res);
-    ASSERT_EQ(true, ret);
-    EXPECT_EQ(200, res.status);
-    EXPECT_EQ("text/plain", res.get_header_value("Content-Type"));
-    EXPECT_EQ("Hello World!", res.body);
+    auto res = cli_.get("/hi");
+    ASSERT_TRUE(res != nullptr);
+    EXPECT_EQ(200, res->status);
+    EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+    EXPECT_EQ("Hello World!", res->body);
 }
 }
 
 
 TEST_F(ServerTest, GetMethod302)
 TEST_F(ServerTest, GetMethod302)
 {
 {
-    Response res;
-    bool ret = Client(host_, port_).get("/", res);
-    ASSERT_EQ(true, ret);
-    EXPECT_EQ(302, res.status);
-    EXPECT_EQ("/hi", res.get_header_value("Location"));
+    auto res = cli_.get("/");
+    ASSERT_TRUE(res != nullptr);
+    EXPECT_EQ(302, res->status);
+    EXPECT_EQ("/hi", res->get_header_value("Location"));
 }
 }
 
 
 TEST_F(ServerTest, GetMethod404)
 TEST_F(ServerTest, GetMethod404)
 {
 {
-    Response res;
-    bool ret = Client(host_, port_).get("/invalid", res);
-    ASSERT_EQ(true, ret);
-    EXPECT_EQ(404, res.status);
+    auto res = cli_.get("/invalid");
+    ASSERT_TRUE(res != nullptr);
+    EXPECT_EQ(404, res->status);
 }
 }
 
 
 TEST_F(ServerTest, GetMethodPersonJohn)
 TEST_F(ServerTest, GetMethodPersonJohn)
 {
 {
-    Response res;
-    bool ret = Client(host_, port_).get("/person/john", res);
-    ASSERT_EQ(true, ret);
-    EXPECT_EQ(200, res.status);
-    EXPECT_EQ("text/plain", res.get_header_value("Content-Type"));
-    EXPECT_EQ("programmer", res.body);
+    auto res = cli_.get("/person/john");
+    ASSERT_TRUE(res != nullptr);
+    EXPECT_EQ(200, res->status);
+    EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
+    EXPECT_EQ("programmer", res->body);
 }
 }
 
 
 TEST_F(ServerTest, PostMethod)
 TEST_F(ServerTest, PostMethod)
 {
 {
-    {
-        Response res;
-        bool ret = Client(host_, port_).get("/person/john2", res);
-        ASSERT_EQ(true, ret);
-        ASSERT_EQ(404, res.status);
-    }
-    {
-        auto content = "name=john2&note=coder";
-        auto content_type = "application/x-www-form-urlencoded";
-        Response res;
-        bool ret = Client(host_, port_).post("/person", content, content_type, res);
-        ASSERT_EQ(true, ret);
-        ASSERT_EQ(200, res.status);
-    }
-    {
-        Response res;
-        bool ret = Client(host_, port_).get("/person/john2", res);
-        ASSERT_EQ(true, ret);
-        ASSERT_EQ(200, res.status);
-        ASSERT_EQ("text/plain", res.get_header_value("Content-Type"));
-        ASSERT_EQ("coder", res.body);
-    }
-}
+    auto res = cli_.get("/person/john3");
+    ASSERT_TRUE(res != nullptr);
+    ASSERT_EQ(404, res->status);
 
 
-TEST_F(ServerTest, GetMethod200Shared)
-{
-    auto res = Client(host_, port_).get("/hi");
+    res = cli_.post("/person", "name=john3&note=coder", "application/x-www-form-urlencoded");
     ASSERT_TRUE(res != nullptr);
     ASSERT_TRUE(res != nullptr);
-    EXPECT_EQ(200, res->status);
-    EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
-    EXPECT_EQ("Hello World!", res->body);
-}
+    ASSERT_EQ(200, res->status);
 
 
-TEST_F(ServerTest, PostMethodShared)
-{
-    {
-        auto res = Client(host_, port_).get("/person/john3");
-        ASSERT_TRUE(res != nullptr);
-        ASSERT_EQ(404, res->status);
-    }
-    {
-        auto content = "name=john3&note=coder";
-        auto content_type = "application/x-www-form-urlencoded";
-        auto res = Client(host_, port_).post("/person", content, content_type);
-        ASSERT_TRUE(res != nullptr);
-        ASSERT_EQ(200, res->status);
-    }
-    {
-        auto res = Client(host_, port_).get("/person/john3");
-        ASSERT_TRUE(res != nullptr);
-        ASSERT_EQ(200, res->status);
-        ASSERT_EQ("text/plain", res->get_header_value("Content-Type"));
-        ASSERT_EQ("coder", res->body);
-    }
+    res = cli_.get("/person/john3");
+    ASSERT_TRUE(res != nullptr);
+    ASSERT_EQ(200, res->status);
+    ASSERT_EQ("text/plain", res->get_header_value("Content-Type"));
+    ASSERT_EQ("coder", res->body);
 }
 }
 
 
 // vim: et ts=4 sw=4 cin cino={1s ff=unix
 // vim: et ts=4 sw=4 cin cino={1s ff=unix