From 0ccc4eec64ce471a5dec55e97249dfad717b8256 Mon Sep 17 00:00:00 2001 From: Qibin Lin Date: Tue, 29 Jan 2019 17:30:07 +0800 Subject: [PATCH 1/2] Add private data support for deferred_response --- examples/minimal_deferred.cpp | 52 ++++++++++++++++++++++------ src/deferred_response.cpp | 3 +- src/httpserver/deferred_response.hpp | 18 +++++++++- 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/examples/minimal_deferred.cpp b/examples/minimal_deferred.cpp index a08599c2..7e60fdde 100644 --- a/examples/minimal_deferred.cpp +++ b/examples/minimal_deferred.cpp @@ -18,32 +18,65 @@ USA */ +#include #include using namespace httpserver; -static int counter = 0; +std::atomic reqid; -ssize_t test_callback (char* buf, size_t max) { - if (counter == 2) { +typedef struct { + int reqid; +} connection; + +ssize_t test_callback (void* data, char* buf, size_t max) { + int reqid; + if (data == nullptr) { + reqid = -1; + } else { + reqid = static_cast(data)->reqid; + } + + // only first 5 connections can be established + if (reqid >= 5) { return -1; } - else { - memset(buf, 0, max); - strcat(buf, " test "); - counter++; - return std::string(buf).size(); + + // respond corresponding request IDs to the clients + std::string str = ""; + str += std::to_string(reqid) + " "; + memset(buf, 0, max); + std::copy(str.begin(), str.end(), buf); + + // keep sending reqid + sleep(1); + return (ssize_t)max; +} + +void test_cleanup (void** data) +{ + if (*data != nullptr) { + delete static_cast(*data); } + data = nullptr; } class deferred_resource : public http_resource { public: const std::shared_ptr render_GET(const http_request& req) { - return std::shared_ptr(new deferred_response(test_callback, "cycle callback response")); + // private data of new connections + auto priv_data = new connection(); + priv_data->reqid = reqid++; + + auto response = std::make_shared(test_callback, priv_data, test_cleanup, + "cycle callback response"); + return response; } }; int main(int argc, char** argv) { + reqid.store(0); + webserver ws = create_webserver(8080); deferred_resource hwr; @@ -52,4 +85,3 @@ int main(int argc, char** argv) { return 0; } - diff --git a/src/deferred_response.cpp b/src/deferred_response.cpp index fe17cb29..fc9e1e37 100644 --- a/src/deferred_response.cpp +++ b/src/deferred_response.cpp @@ -30,7 +30,8 @@ namespace details ssize_t cb(void* cls, uint64_t pos, char* buf, size_t max) { - ssize_t val = static_cast(cls)->cycle_callback(buf, max); + ssize_t val = static_cast(cls)->cycle_callback( + static_cast(cls)->priv_data, buf, max); if(val == -1) { static_cast(cls)->completed = true; diff --git a/src/httpserver/deferred_response.hpp b/src/httpserver/deferred_response.hpp index c5a9f1ff..1484b259 100644 --- a/src/httpserver/deferred_response.hpp +++ b/src/httpserver/deferred_response.hpp @@ -35,19 +35,24 @@ namespace details ssize_t cb(void*, uint64_t, char*, size_t); }; -typedef ssize_t(*cycle_callback_ptr)(char*, size_t); +typedef ssize_t(*cycle_callback_ptr)(void*, char*, size_t); +typedef void(*cleanup_callback_ptr)(void**); class deferred_response : public string_response { public: explicit deferred_response( cycle_callback_ptr cycle_callback, + void* priv_data = nullptr, + cleanup_callback_ptr cleanup_callback = nullptr, const std::string& content = "", int response_code = http::http_utils::http_ok, const std::string& content_type = http::http_utils::text_plain ): string_response(content, response_code, content_type), cycle_callback(cycle_callback), + priv_data(priv_data), + cleanup_callback(cleanup_callback), completed(false) { } @@ -55,6 +60,8 @@ class deferred_response : public string_response deferred_response(const deferred_response& other): string_response(other), cycle_callback(other.cycle_callback), + priv_data(other.priv_data), + cleanup_callback(other.cleanup_callback), completed(other.completed) { } @@ -73,6 +80,8 @@ class deferred_response : public string_response (string_response&) (*this) = b; this->cycle_callback = b.cycle_callback; this->completed = b.completed; + this->priv_data = b.priv_data; + this->cleanup_callback = b.cleanup_callback; return *this; } @@ -84,18 +93,25 @@ class deferred_response : public string_response (string_response&) (*this) = std::move(b); this->cycle_callback = std::move(b.cycle_callback); this->completed = b.completed; + this->priv_data = b.priv_data; + this->cleanup_callback = b.cleanup_callback; return *this; } ~deferred_response() { + if (priv_data != nullptr) { + cleanup_callback(&priv_data); + } } MHD_Response* get_raw_response(); void decorate_response(MHD_Response* response); private: cycle_callback_ptr cycle_callback; + void* priv_data; + cleanup_callback_ptr cleanup_callback; bool completed; friend ssize_t details::cb(void* cls, uint64_t pos, char* buf, size_t max); From 8987567f83c40b8bb14c2397c38f6516014bbd9e Mon Sep 17 00:00:00 2001 From: Qibin Lin Date: Wed, 30 Jan 2019 11:58:30 +0800 Subject: [PATCH 2/2] Fix integration test --- test/integ/deferred.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/integ/deferred.cpp b/test/integ/deferred.cpp index c853ab06..a11630b5 100644 --- a/test/integ/deferred.cpp +++ b/test/integ/deferred.cpp @@ -47,7 +47,7 @@ size_t writefunc(void *ptr, size_t size, size_t nmemb, std::string *s) static int counter = 0; -ssize_t test_callback (char* buf, size_t max) +ssize_t test_callback (void*, char* buf, size_t max) { if (counter == 2) { @@ -67,7 +67,8 @@ class deferred_resource : public http_resource public: const shared_ptr render_GET(const http_request& req) { - return shared_ptr(new deferred_response(test_callback, "cycle callback response")); + return shared_ptr(new deferred_response(test_callback, nullptr, nullptr, + "cycle callback response")); } };