diff options
Diffstat (limited to 'cethcan/http.c')
| -rw-r--r-- | cethcan/http.c | 143 | 
1 files changed, 143 insertions, 0 deletions
diff --git a/cethcan/http.c b/cethcan/http.c new file mode 100644 index 0000000..8316abc --- /dev/null +++ b/cethcan/http.c @@ -0,0 +1,143 @@ +#include "cethcan.h" + +#include <event2/http.h> +#include <event2/buffer.h> +#include <openssl/sha.h> + +static struct evhttp *evhttp; + +static int evb_json_add(const char *data, size_t size, void *arg) +{ +	struct evbuffer *buf = arg; +	return evbuffer_add(buf, data, size); +} + +static void http_json_basic(struct evhttp_request *req, void *arg) +{ +	struct evkeyvalq *outhdr = evhttp_request_get_output_headers(req); +	struct evbuffer *out = evbuffer_new(); + +	evhttp_add_header(outhdr, "Content-Type", "application/json; charset=utf-8"); + +	json_t *jsout = json_object(); +	can_json(jsout, JSON_NORMAL); +	json_dump_callback(jsout, evb_json_add, out, JSON_SORT_KEYS | JSON_INDENT(4)); +	json_decref(jsout); + +	evhttp_send_reply(req, 200, "OK", out); +	evbuffer_free(out); +} + +static void http_json_bump(struct evhttp_request *req, void *arg) +{ +	struct evkeyvalq *outhdr = evhttp_request_get_output_headers(req); +	struct evbuffer *out = evbuffer_new(); + +	evhttp_add_header(outhdr, "Content-Type", "text/plain; charset=utf-8"); +	evbuffer_add_printf(out, "OK"); +	evhttp_send_reply(req, 200, "OK", out); +	evbuffer_free(out); + +	json_bump_longpoll(); +} + +struct longpoll { +	struct longpoll *next; +	struct evhttp_request *req; +}; +static struct longpoll *longpolls = NULL, **plongpoll = &longpolls; +static size_t longpoll_count = 0; + +static char *longpollbuf = NULL; +static size_t longpollbuflen = 0; +static char longpollhash[SHA_DIGEST_LENGTH * 2 + 1] = ""; + +static void http_json_longpoll(struct evhttp_request *req, void *arg) +{ +	struct evkeyvalq *outhdr = evhttp_request_get_output_headers(req); +	struct evbuffer *out; +	struct longpoll *lp; +	const char *query; +	 +	evhttp_add_header(outhdr, "Content-Type", "application/json; charset=utf-8"); + +	query = evhttp_uri_get_query(evhttp_request_get_evhttp_uri(req)); +	if (query && !strcmp(query, longpollhash)) { +		lprintf("long poll"); +		evhttp_send_reply_start(req, 200, "OK Long Poll"); +		evhttp_request_own(req); + +		lp = calloc(sizeof(*lp), 1); +		lp->req = req; +		*plongpoll = lp; +		plongpoll = &lp->next; +		longpoll_count++; +		return; +	} + +	out = evbuffer_new(); +	evbuffer_add(out, longpollbuf, longpollbuflen); +	evhttp_send_reply(req, 200, "OK Short Poll", out); +	evbuffer_free(out); +} + +static void longpoll_updatedata(void) +{ +	json_t *jsout, *jswrap; +	char *data; +	unsigned char digest[SHA_DIGEST_LENGTH]; + +	if (longpollbuf) +		free(longpollbuf); +	 +	jsout = json_object(); +	can_json(jsout, JSON_LONGPOLL); +	data = json_dumps(jsout, JSON_SORT_KEYS | JSON_INDENT(4)); +	SHA1((unsigned char *)data, strlen(data), digest); +	free(data); + +	for (size_t i = 0; i < SHA_DIGEST_LENGTH; i++) +		sprintf(longpollhash + i * 2, "%02x", digest[i]); + +	jswrap = json_object(); +	json_object_set_new(jswrap, "data", jsout); +	json_object_set_new(jswrap, "ref", json_string(longpollhash)); +	longpollbuf = json_dumps(jswrap, JSON_SORT_KEYS | JSON_INDENT(4)); +	longpollbuflen = strlen(longpollbuf); +	json_decref(jswrap); +} + +void json_bump_longpoll(void) +{ +	struct longpoll *lp, *lpnext; +	struct evbuffer *out; + +	longpoll_updatedata(); + +	out = evbuffer_new(); +	for (lp = longpolls; lp; lp = lpnext) { +		lpnext = lp->next; + +		evbuffer_add(out, longpollbuf, longpollbuflen); +		evhttp_send_reply_chunk(lp->req, out); +		/* send_reply_end calls request_free() */ +		evhttp_send_reply_end(lp->req); +		free(lp); +	} +	evbuffer_free(out); + +	longpolls = NULL; +	plongpoll = &longpolls; +	longpoll_count = 0; +} + +void http_init(void) +{ +	evhttp = evhttp_new(ev_base); +	evhttp_set_cb(evhttp, "/", http_json_basic, NULL); +	evhttp_set_cb(evhttp, "/longpoll", http_json_longpoll, NULL); +	evhttp_set_cb(evhttp, "/bump", http_json_bump, NULL); +	evhttp_bind_socket(evhttp, "127.0.0.1", 34999); + +	longpoll_updatedata(); +}  | 
