aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosé Bollo <jose.bollo@iot.bzh>2016-04-06 15:26:04 +0200
committerJosé Bollo <jose.bollo@iot.bzh>2016-04-06 15:26:04 +0200
commitb75bbfd9bd96ad8bb7174a768ae70cf3e8c5af7a (patch)
tree0372d90b0db892cbf46caa80e18a12403cf6edc9
parent46fa94d4edd7fa874e334ab51df34f7daca007ce (diff)
websocket first version works
Change-Id: I4db7d432ea5921636bb5033b8d31e91475cecc52 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
-rw-r--r--src/afb-hreq.c40
-rw-r--r--src/afb-hsrv.c7
-rw-r--r--src/afb-websock.c13
-rw-r--r--src/websock.c11
-rw-r--r--src/websock.h1
-rw-r--r--test/websock.html62
-rw-r--r--test/websock.js111
7 files changed, 188 insertions, 57 deletions
diff --git a/src/afb-hreq.c b/src/afb-hreq.c
index ece9b399..474b90e8 100644
--- a/src/afb-hreq.c
+++ b/src/afb-hreq.c
@@ -184,7 +184,34 @@ static const char *magic_mimetype_fd(int fd)
#endif
-
+static const char *mimetype_fd_name(int fd, const char *filename)
+{
+ const char *result = NULL;
+
+#if defined(INFER_EXTENSION)
+ const char *extension = strrchr(filename, '.');
+ if (extension) {
+ static const char *const known[][2] = {
+ { ".js", "text/javascript" },
+ { ".html", "text/html" },
+ { NULL, NULL }
+ };
+ int i = 0;
+ while (known[i][0]) {
+ if (!strcasecmp(extension, known[i][0])) {
+ result = known[i][1];
+ break;
+ }
+ i++;
+ }
+ }
+#endif
+#if defined(USE_MAGIC_MIME_TYPE)
+ if (result == NULL)
+ result = magic_mimetype_fd(fd);
+#endif
+ return result;
+}
void afb_hreq_free(struct afb_hreq *hreq)
{
@@ -257,6 +284,7 @@ int afb_hreq_reply_file_if_exist(struct afb_hreq *hreq, int dirfd, const char *f
char etag[1 + 2 * sizeof(int)];
const char *inm;
struct MHD_Response *response;
+ const char *mimetype;
/* Opens the file or directory */
if (filename[0]) {
@@ -336,14 +364,10 @@ int afb_hreq_reply_file_if_exist(struct afb_hreq *hreq, int dirfd, const char *f
response = MHD_create_response_from_fd((size_t) st.st_size, fd);
status = MHD_HTTP_OK;
-#if defined(USE_MAGIC_MIME_TYPE)
/* set the type */
- {
- const char *mimetype = magic_mimetype_fd(fd);
- if (mimetype != NULL)
- MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, mimetype);
- }
-#endif
+ mimetype = mimetype_fd_name(fd, filename);
+ if (mimetype != NULL)
+ MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, mimetype);
}
/* fills the value and send */
diff --git a/src/afb-hsrv.c b/src/afb-hsrv.c
index 64cea9d5..977aea63 100644
--- a/src/afb-hsrv.c
+++ b/src/afb-hsrv.c
@@ -152,11 +152,8 @@ static int afb_hreq_websocket_switch(struct afb_hreq *hreq, void *data)
if (!later) {
struct afb_websock *ws = afb_websock_create(hreq);
- if (ws == NULL) {
- /* TODO */
- } else {
- /* TODO */
- }
+ if (ws != NULL)
+ hreq->upgrade = 1;
}
return 1;
}
diff --git a/src/afb-websock.c b/src/afb-websock.c
index dab4aa09..797724ce 100644
--- a/src/afb-websock.c
+++ b/src/afb-websock.c
@@ -220,15 +220,21 @@ static const struct afb_req_itf wsreq_itf = {
struct afb_websock *afb_websock_create(struct afb_hreq *hreq)
{
+ int fd;
struct afb_websock *result;
+ fd = MHD_get_connection_info(hreq->connection,
+ MHD_CONNECTION_INFO_CONNECTION_FD)->connect_fd;
+ fd = dup(fd);
+ if (fd < 0)
+ return NULL;
+
result = malloc(sizeof * result);
if (result == NULL)
goto error;
result->connection = hreq->connection;
- result->fd = MHD_get_connection_info(hreq->connection,
- MHD_CONNECTION_INFO_CONNECTION_FD)->connect_fd;
+ result->fd = fd;
result->context = ctxClientGet(afb_hreq_context(hreq));
if (result->context == NULL)
goto error2;
@@ -255,6 +261,7 @@ error3:
error2:
free(result);
error:
+ close(fd);
return NULL;
}
@@ -346,7 +353,7 @@ static int aws_handle_json(struct afb_websock *aws, struct json_object *obj)
goto error;
verb = &api[lenapi+1];
for (lenverb = 0 ; verb[lenverb] && verb[lenverb] != '/' ; lenverb++);
- if (!lenverb || !verb[lenverb])
+ if (!lenverb || verb[lenverb])
goto error;
/* allocates the request data */
diff --git a/src/websock.c b/src/websock.c
index 41e47a0a..22e91be9 100644
--- a/src/websock.c
+++ b/src/websock.c
@@ -170,12 +170,12 @@ void websock_pong(struct websock *ws)
void websock_text(struct websock *ws, const char *text, size_t length)
{
- websock_send(ws, OPCODE_TEXT, NULL, 0);
+ websock_send(ws, OPCODE_TEXT, text, length);
}
void websock_binary(struct websock *ws, const void *data, size_t length)
{
- websock_send(ws, OPCODE_BINARY, NULL, 0);
+ websock_send(ws, OPCODE_BINARY, data, length);
}
static int read_header(struct websock *ws)
@@ -192,7 +192,7 @@ static int read_header(struct websock *ws)
int websock_dispatch(struct websock *ws)
{
- loop:
+loop:
switch (ws->state) {
case STATE_INIT:
ws->lenhead = 0;
@@ -201,7 +201,7 @@ int websock_dispatch(struct websock *ws)
case STATE_START:
/* read the header */
- if (!read_header(ws))
+ if (read_header(ws))
return -1;
else if (ws->lenhead < ws->szhead)
return 0;
@@ -262,7 +262,7 @@ int websock_dispatch(struct websock *ws)
case STATE_LENGTH:
/* continue to read the header */
- if (!read_header(ws))
+ if (read_header(ws))
return -1;
else if (ws->lenhead < ws->szhead)
return 0;
@@ -409,6 +409,7 @@ struct websock *websock_create(const struct websock_itf *itf, void *closure)
if (result) {
result->itf = itf;
result->closure = closure;
+ result->maxlength = 65000;
}
return result;
}
diff --git a/src/websock.h b/src/websock.h
index b67f36e1..235f9910 100644
--- a/src/websock.h
+++ b/src/websock.h
@@ -63,3 +63,4 @@ int websock_dispatch(struct websock *ws);
struct websock *websock_create(const struct websock_itf *itf, void *closure);
void websock_destroy(struct websock *ws);
+
diff --git a/test/websock.html b/test/websock.html
index 1db33b2a..dd38e74a 100644
--- a/test/websock.html
+++ b/test/websock.html
@@ -1,47 +1,37 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
- <head>
+<head>
<title>WebSocket Echo</title>
+ <script type="text/javascript" src="websock.js"></script>
<script type="text/javascript">
- <!--
- var ws;
+ var ws;
- if ((typeof(WebSocket) == 'undefined') &&
- (typeof(MozWebSocket) != 'undefined')) {
- WebSocket = MozWebSocket;
- }
-
- function init() {
- ws = new WebSocket("ws://localhost:1234/api/");
- ws.onopen = function(event) {
- document.getElementById("main").style.visibility = "visible";
- document.getElementById("connected").innerHTML = "Connected to WebSocket server";
- };
- ws.onmessage = function(event) {
- document.getElementById("output").innerHTML = event.data;
- };
- ws.onerror = function(event) { alert("Received error"); };
- ws.onclose = function(event) {
- ws = null;
- document.getElementById("main").style.visibility = "hidden";
- document.getElementById("connected").innerHTML = "Connection Closed";
- }
- }
-
- function send(message) {
- if (ws) {
- ws.send(message);
- }
- }
- // -->
+ function onopen() {
+ document.getElementById("main").style.visibility = "visible";
+ document.getElementById("connected").innerHTML = "Connected to WebSocket server";
+ }
+ function onabort() {
+ document.getElementById("main").style.visibility = "hidden";
+ document.getElementById("connected").innerHTML = "Connected Closed";
+ }
+ function init() {
+ ws = new AfbWsItf("api", onopen, onabort, new AfbCtxItf("hello"));
+ }
+ function replyok(obj) {
+ document.getElementById("output").innerHTML = "OK: "+JSON.stringify(obj);
+ }
+ function replyerr(obj) {
+ document.getElementById("output").innerHTML = "ERROR: "+JSON.stringify(obj);
+ }
+ function send(message) {
+ ws.call("hello", "ping", {data:message}, replyok, replyerr);
+ }
</script>
- </head>
- <body onload="init();">
+
+<body onload="init();">
<h1>WebSocket Echo</h1>
<div id="connected">Not Connected</div>
<div id="main" style="visibility:hidden">
Enter Message: <input type="text" name="message" value="" size="80" onchange="send(this.value)"/><br/>
Server says... <div id="output"></div>
</div>
- </body>
-</html>
+
diff --git a/test/websock.js b/test/websock.js
new file mode 100644
index 00000000..1ba136b4
--- /dev/null
+++ b/test/websock.js
@@ -0,0 +1,111 @@
+
+AfbCtxItf = (function(){
+
+ var UUID = undefined;
+ var TOKEN = undefined;
+
+ function AfbCtxItf(token, uuid) {
+ this.token = token;
+ this.uuid = uuid;
+ }
+
+ AfbCtxItf.prototype = {
+ get token() {return TOKEN;},
+ set token(tok) {if(tok) TOKEN=tok;},
+ get uuid() {return UUID;},
+ set uuid(id) {if(id) UUID=id;}
+ };
+
+ return AfbCtxItf;
+})();
+
+
+AfbWsItf = (function(){
+
+ var CALL = 2;
+ var RETOK = 3;
+ var RETERR = 4;
+
+ function AfbWsItf(base, onopen, onabort, ctx) {
+ var wl = window.location;
+ var u = "ws://"+wl.host+"/"+base;
+ this.ws = new (WebSocket || MozWebSocket)(u, [ "afb1", "afb2" ]);
+ this.pendings = {};
+ this.counter = 0;
+ this.ctx = ctx || new AfbCtxItf();
+ this.ws.onopen = onopen.bind(this);
+ this.ws.onerror = onerror.bind(this);
+ this.ws.onclose = onclose.bind(this);
+ this.ws.onmessage = onmessage.bind(this);
+ this.onopen = onopen;
+ this.onabort = onabort;
+ }
+
+ function onerror(event) {
+ var f = this.onabort;
+ if (f) {
+ delete this.onopen;
+ delete this.onabort;
+ f && f(this);
+ }
+ this.onerror && this.onerror(this);
+ }
+
+ function onopen(event) {
+ var f = this.onopen;
+ delete this.onopen;
+ delete this.onabort;
+ f && f(this);
+ }
+
+ function onclose(event) {
+ for (var id in this.pendings) {
+ var ferr = this.pendings[id].onerror;
+ ferr && ferr(null, this);
+ }
+ this.pendings = {};
+ this.onclose && this.onclose();
+ }
+
+ function onmessage(event) {
+ var obj = JSON.parse(event.data);
+ var code = obj[0];
+ var id = obj[1];
+ var ans = obj[2];
+ this.ctx.token = obj[3];
+ var pend;
+ if (id && id in this.pendings) {
+ pend = this.pendings[id];
+ delete this.pendings[id];
+ }
+ switch (code) {
+ case RETOK:
+ pend && pend.onsuccess && pend.onsuccess(ans, this);
+ break;
+ case RETERR:
+ default:
+ pend && pend.onerror && pend.onerror(ans, this);
+ break;
+ }
+ }
+
+ function close() {
+ this.ws.close();
+ }
+
+ function call(api, verb, request, onsuccess, onerror) {
+ var id = String(++this.counter);
+ this.pendings[id] = { onsuccess: onsuccess, onerror: onerror };
+ var arr = [CALL, id, api+"/"+verb, request ];
+ if (this.ctx.token) arr.push(this.ctx.token);
+ this.ws.send(JSON.stringify(arr));
+ }
+
+ AfbWsItf.prototype = {
+ close: close,
+ call: call
+ };
+
+ return AfbWsItf;
+})();
+