Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 42 additions & 10 deletions examples/minimal_deferred.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,65 @@
USA
*/

#include <atomic>
#include <httpserver.hpp>

using namespace httpserver;

static int counter = 0;
std::atomic<int> reqid;

ssize_t test_callback (char* buf, size_t max) {
if (counter == 2) {
typedef struct {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for typedefs - we can just have a named 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<connection*>(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<connection*>(*data);
}
data = nullptr;
}

class deferred_resource : public http_resource {
public:
const std::shared_ptr<http_response> render_GET(const http_request& req) {
return std::shared_ptr<deferred_response>(new deferred_response(test_callback, "cycle callback response"));
// private data of new connections
auto priv_data = new connection();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, refrain from using "auto" for now

priv_data->reqid = reqid++;

auto response = std::make_shared<deferred_response>(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;
Expand All @@ -52,4 +85,3 @@ int main(int argc, char** argv) {

return 0;
}

3 changes: 2 additions & 1 deletion src/deferred_response.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ namespace details

ssize_t cb(void* cls, uint64_t pos, char* buf, size_t max)
{
ssize_t val = static_cast<deferred_response*>(cls)->cycle_callback(buf, max);
ssize_t val = static_cast<deferred_response*>(cls)->cycle_callback(
static_cast<deferred_response*>(cls)->priv_data, buf, max);
if(val == -1)
{
static_cast<deferred_response*>(cls)->completed = true;
Expand Down
18 changes: 17 additions & 1 deletion src/httpserver/deferred_response.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,33 @@ 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);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I was thinking about this feature, I tried to figure how we could avoid the "void*" for the type.

To be honest this is probably one of those cases where "seeing it after it is written might help".

I was thinking we could use a template type to define the first parameter and a "shared_ptr" to pass it through. This would save us from having to use the "void*" and, ideally, from having the cleanup function entirely.

To be honest, I would convert the currently existing "char*" into a shared_ptr if we are perturbing the interface.

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)
{
}

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)
{
}
Expand All @@ -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;
}
Expand All @@ -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);
Expand Down
5 changes: 3 additions & 2 deletions test/integ/deferred.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -67,7 +67,8 @@ class deferred_resource : public http_resource
public:
const shared_ptr<http_response> render_GET(const http_request& req)
{
return shared_ptr<deferred_response>(new deferred_response(test_callback, "cycle callback response"));
return shared_ptr<deferred_response>(new deferred_response(test_callback, nullptr, nullptr,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have a separate resource and a separate that is used to verify that the new functionality is working fine.

"cycle callback response"));
}
};

Expand Down