Skip to content

Commit b4209eb

Browse files
author
Sebastiano Merlino
committed
Modified webserver in order to accept comet calls
Added ignored patters in gitignore
1 parent 3ecb7b5 commit b4209eb

File tree

8 files changed

+188
-15
lines changed

8 files changed

+188
-15
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
*.pm
66
*.py
77
*_wrap.*
8+
*.gcov
9+
*.gcno
10+
*.gcda
811
build/*
912
aclocal.m4
1013
autom4te.cache/

src/http_response.cpp

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ using namespace std;
2929
namespace httpserver
3030
{
3131

32+
struct data_closure
33+
{
34+
webserver* ws;
35+
string connection_id;
36+
string topic;
37+
};
38+
3239
const std::vector<std::pair<std::string, std::string> > http_response::get_headers()
3340
{
3441
std::vector<std::pair<std::string, std::string> > to_ret;
@@ -82,13 +89,13 @@ shoutCAST_response::shoutCAST_response
8289
{
8390
}
8491

85-
void http_response::get_raw_response(MHD_Response** response, bool* found)
92+
void http_response::get_raw_response(MHD_Response** response, bool* found, webserver* ws)
8693
{
8794
size_t size = &(*content.end()) - &(*content.begin());
8895
*response = MHD_create_response_from_buffer(size, (void*) content.c_str(), MHD_RESPMEM_PERSISTENT);
8996
}
9097

91-
void http_file_response::get_raw_response(MHD_Response** response, bool* found)
98+
void http_file_response::get_raw_response(MHD_Response** response, bool* found, webserver* ws)
9299
{
93100
char* page = NULL;
94101
size_t size = http::load_file(filename.c_str(), &page);
@@ -98,6 +105,42 @@ void http_file_response::get_raw_response(MHD_Response** response, bool* found)
98105
*found = false;
99106
}
100107

108+
void long_polling_receive_response::get_raw_response(MHD_Response** response, bool* found, webserver* ws)
109+
{
110+
data_closure* dc = new data_closure();
111+
dc->ws = ws;
112+
dc->topic = topic;
113+
generate_random_uuid(dc->connection_id);
114+
*response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 80,
115+
&long_polling_receive_response::data_generator, (void*) dc, &long_polling_receive_response::free_callback);
116+
ws->register_to_topic(dc->topic, dc->connection_id);
117+
}
118+
119+
ssize_t long_polling_receive_response::data_generator (void* cls, uint64_t pos, char* buf, size_t max)
120+
{
121+
data_closure* dc = static_cast<data_closure*>(cls);
122+
if(dc->ws->pop_signaled(dc->connection_id))
123+
{
124+
string message;
125+
int size = dc->ws->read_message_from_topic(dc->topic, message);
126+
memcpy(buf, message.c_str(), size);
127+
return size;
128+
}
129+
else
130+
return 0;
131+
}
132+
133+
void long_polling_receive_response::free_callback(void* cls)
134+
{
135+
delete static_cast<data_closure*>(cls);
136+
}
137+
138+
void long_polling_send_response::get_raw_response(MHD_Response** response, bool* found, webserver* ws)
139+
{
140+
http_response::get_raw_response(response, found, ws);
141+
ws->send_message_to_topic(topic, content);
142+
}
143+
101144
void clone_response(const http_response& hr, http_response** dhrs)
102145
{
103146
switch(hr.response_type)
@@ -120,6 +163,12 @@ void clone_response(const http_response& hr, http_response** dhrs)
120163
case(http_response::SWITCH_PROTOCOL):
121164
*dhrs = new switch_protocol_response(hr);
122165
return;
166+
case(http_response::LONG_POLLING_RECEIVE):
167+
*dhrs = new long_polling_receive_response(hr);
168+
return;
169+
case(http_response::LONG_POLLING_SEND):
170+
*dhrs = new long_polling_send_response(hr);
171+
return;
123172
}
124173
}
125174

src/http_utils.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <sstream>
2626
#include <iomanip>
2727
#include <fstream>
28+
#include <uuid/uuid.h>
2829
#include "string_utilities.hpp"
2930
#include "http_utils.hpp"
3031

@@ -447,5 +448,16 @@ char* load_file (const char *filename)
447448
return content;
448449
}
449450

451+
void generate_random_uuid(string& result)
452+
{
453+
uuid_t out;
454+
uuid_generate(out);
455+
std::string ret;
456+
ret.assign((const char*) out, 16);
457+
char unparsed[37];
458+
uuid_unparse((const unsigned char*) ret.c_str(), unparsed);
459+
result.assign((const char*) unparsed, 37);
460+
}
461+
450462
};
451463
};

src/httpserver/http_response.hpp

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ class http_response
5757
SHOUTCAST_CONTENT,
5858
DIGEST_AUTH_FAIL,
5959
BASIC_AUTH_FAIL,
60-
SWITCH_PROTOCOL
60+
SWITCH_PROTOCOL,
61+
LONG_POLLING_RECEIVE,
62+
LONG_POLLING_SEND
6163
};
6264

6365
/**
@@ -74,7 +76,8 @@ class http_response
7476
const std::string& content_type = "text/plain",
7577
const std::string& realm = "",
7678
const std::string& opaque = "",
77-
bool reload_nonce = false
79+
bool reload_nonce = false,
80+
const std::string& topic = ""
7881
):
7982
response_type(response_type),
8083
content(content),
@@ -83,7 +86,8 @@ class http_response
8386
opaque(opaque),
8487
reload_nonce(reload_nonce),
8588
fp(-1),
86-
filename(content)
89+
filename(content),
90+
topic(topic)
8791
{
8892
set_header(http_utils::http_header_content_type, content_type);
8993
}
@@ -101,7 +105,8 @@ class http_response
101105
fp(b.fp),
102106
filename(b.filename),
103107
headers(b.headers),
104-
footers(b.footers)
108+
footers(b.footers),
109+
topic(b.topic)
105110
{
106111
}
107112
virtual ~http_response()
@@ -265,6 +270,10 @@ class http_response
265270
{
266271
return 0;
267272
}
273+
const std::string get_topic() const
274+
{
275+
return this->topic;
276+
}
268277
protected:
269278
response_type_T response_type;
270279
std::string content;
@@ -276,8 +285,9 @@ class http_response
276285
std::string filename;
277286
std::map<std::string, std::string, header_comparator> headers;
278287
std::map<std::string, std::string, header_comparator> footers;
288+
std::string topic;
279289

280-
virtual void get_raw_response(MHD_Response** res, bool* found);
290+
virtual void get_raw_response(MHD_Response** res, bool* found, webserver* ws = 0x0);
281291

282292
friend class webserver;
283293
friend void clone_response(const http_response& hr, http_response** dhr);
@@ -310,7 +320,7 @@ class http_file_response : public http_response
310320

311321
http_file_response(const http_response& b) : http_response(b) { }
312322
protected:
313-
virtual void get_raw_response(MHD_Response** res, bool* found);
323+
virtual void get_raw_response(MHD_Response** res, bool* found, webserver* ws = 0x0);
314324
};
315325

316326
class http_basic_auth_fail_response : public http_response
@@ -372,9 +382,44 @@ class switch_protocol_response : public http_response
372382
{
373383
}
374384
protected:
375-
virtual void get_raw_response(MHD_Response** res, bool* found)
385+
virtual void get_raw_response(MHD_Response** res, bool* found, webserver* ws = 0x0) {}
386+
};
387+
388+
class long_polling_receive_response : public http_response
389+
{
390+
public:
391+
long_polling_receive_response
392+
(
393+
const std::string& content,
394+
int response_code,
395+
const std::string& content_type,
396+
const std::string& topic
397+
) : http_response(http_response::LONG_POLLING_RECEIVE, content, response_code, content_type, "", "", false, topic)
398+
{
399+
}
400+
401+
long_polling_receive_response(const http_response& b) : http_response(b) { }
402+
protected:
403+
virtual void get_raw_response(MHD_Response** res, bool* found, webserver* ws = 0x0);
404+
private:
405+
static ssize_t data_generator (void* cls, uint64_t pos, char* buf, size_t max);
406+
static void free_callback(void* cls);
407+
};
408+
409+
class long_polling_send_response : public http_response
410+
{
411+
public:
412+
long_polling_send_response
413+
(
414+
const std::string& content,
415+
const std::string& topic
416+
) : http_response(http_response::LONG_POLLING_SEND, content, 200, "", "", "", false, topic)
376417
{
377418
}
419+
420+
long_polling_send_response(const http_response& b) : http_response(b) { }
421+
protected:
422+
virtual void get_raw_response(MHD_Response** res, bool* found, webserver* ws = 0x0);
378423
};
379424

380425
void clone_response(http_response* hr, http_response** dhr);

src/httpserver/http_utils.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ char* load_file (const char *filename);
342342

343343
size_t load_file (const char* filename, char** content);
344344

345+
void generate_random_uuid(std::string& uuid);
346+
345347
};
346348
};
347349
#endif

src/httpserver/webserver.hpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class http_resource;
5252
class http_response;
5353
class http_request;
5454
struct modded_request;
55+
class long_polling_receive_response;
56+
class long_polling_send_response;
5557

5658
namespace details
5759
{
@@ -234,6 +236,44 @@ class webserver
234236
void allow_ip(const std::string& ip);
235237
void unban_ip(const std::string& ip);
236238
void disallow_ip(const std::string& ip);
239+
240+
void send_message_to_topic(const std::string& topic, const std::string& message)
241+
{
242+
q_messages[topic] = message;
243+
for(std::set<std::string>::const_iterator it = q_waitings[topic].begin(); it != q_waitings[topic].end(); ++it)
244+
q_signal.insert((*it));
245+
}
246+
247+
void register_to_topic(const std::string& topic, const std::string& connection_id)
248+
{
249+
q_waitings[topic].insert(connection_id);
250+
}
251+
252+
size_t read_message_from_topic(const std::string& topic, std::string& message)
253+
{
254+
message = q_messages[topic];
255+
return message.size();
256+
}
257+
258+
size_t get_topic_consumers(const std::string& topic, std::set<std::string>& consumers)
259+
{
260+
for(std::set<std::string>::const_iterator it = q_waitings[topic].begin(); it != q_waitings[topic].end(); ++it)
261+
consumers.insert((*it));
262+
return consumers.size();
263+
}
264+
265+
bool pop_signaled(const std::string& consumer)
266+
{
267+
std::set<std::string>::iterator it = q_signal.find(consumer);
268+
if(it != q_signal.end())
269+
{
270+
q_signal.erase(it);
271+
return true;
272+
}
273+
else
274+
return false;
275+
}
276+
237277
/**
238278
* Method used to kill the webserver waiting for it to terminate
239279
**/
@@ -282,9 +322,15 @@ class webserver
282322
#ifdef USE_CPP_ZEROX
283323
std::unordered_set<ip_representation> bans;
284324
std::unordered_set<ip_representation> allowances;
325+
std::unordered_map<std::string, std::string> q_messages;
326+
std::unordered_map<std::string, std::unordered_set<std::string> > q_waitings;
327+
std::unordered_set<std::string> q_signal;
285328
#else
286329
std::set<ip_representation> bans;
287330
std::set<ip_representation> allowances;
331+
std::map<std::string, std::string> q_messages;
332+
std::map<std::string, std::set<std::string> > q_waitings;
333+
std::set<std::string> q_signal;
288334
#endif
289335
struct MHD_Daemon *daemon;
290336

src/webserver.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,7 @@ int webserver::finalize_answer(MHD_Connection* connection, struct modded_request
815815
}
816816
#endif
817817
mr->dhrs = dhrs;
818-
dhrs->get_raw_response(&response, &found);
818+
dhrs->get_raw_response(&response, &found, this);
819819
vector<pair<string,string> > response_headers;
820820
dhrs->get_headers(response_headers);
821821
vector<pair<string,string> > response_footers;

test/Test.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
#include "Test.hpp"
2+
#include <signal.h>
23
#include <string>
34
#include <vector>
45
#include <unistd.h>
5-
#include <boost/thread.hpp>
66
#include <iostream>
77
#include <fstream>
88
#include <stdio.h>
99
using namespace std;
1010

11+
webserver* ws_ptr;
12+
13+
void signal_callback_handler(int signum)
14+
{
15+
cout << "bye!" << endl;
16+
ws_ptr->stop();
17+
}
18+
1119
Test::Test() : http_resource()
1220
{
1321
}
@@ -24,8 +32,13 @@ http_response Test::render_GET(const http_request& r)
2432
cout << "PROVA: " << r.get_arg("prova") << endl;
2533
cout << "ALTRO: " << r.get_arg("altro") << endl;
2634
cout << "THUMB: " << r.get_arg("thumbId") << endl;
35+
cout << "COOKIE: " << r.get_cookie("auth") << endl;
36+
std::map<std::string, std::string, header_comparator> head;
37+
r.get_headers(head);
38+
for(std::map<std::string, std::string, header_comparator>::const_iterator it = head.begin(); it != head.end(); ++it)
39+
cout << (*it).first << "-> " << (*it).second << endl;
2740
string pp = r.get_arg("prova");
28-
return http_file_response("/home/etr/progs/libhttpserver/test/readme", 200);
41+
return http_file_response("/home/etr/progs/libhttpserver/test/noimg.png", 200, "image/png");
2942
}
3043

3144
http_response Test::render_POST(const http_request& r)
@@ -56,12 +69,15 @@ http_response Test::render_PUT(const http_request& r)
5669

5770
int main()
5871
{
59-
webserver ws = create_webserver(9898);
72+
signal(SIGINT, &signal_callback_handler);
73+
webserver ws = create_webserver(8080);
74+
ws_ptr = &ws;
6075
Test dt = Test();
6176
Test2 dt2 = Test2();
6277
ws.register_resource(string("base/{var1}/{var2}/drop_test/{var3}/tail"), &dt2, true);
6378
ws.register_resource(string("other/side/{thumbId|[0-9]*}"), &dt, true);
64-
boost::thread* t1 = new boost::thread(boost::bind(&webserver::start, ws, true));
65-
t1->join();
79+
ws.register_resource(string("another/{thumbId|[0-9]*}"), &dt, true);
80+
ws.register_resource(string("edge/thumbnail"), &dt, true);
81+
ws.start(true);
6682
return 0;
6783
}

0 commit comments

Comments
 (0)