f69a2b | 2016-09-19 | Stephen R. van den Berg | | |
922d16 | 2016-09-23 | Stephen R. van den Berg | | * Clean-room Engine.IO implementation for Pike.
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | */
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
|
d6f247 | 2016-10-03 | Pontus Östlund | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
|
d6f247 | 2016-10-03 | Pontus Östlund | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
|
d6f247 | 2016-10-03 | Pontus Östlund | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
|
d6f247 | 2016-10-03 | Pontus Östlund | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | #pike __REAL_VERSION__
|
20859d | 2016-09-20 | Stephen R. van den Berg | |
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
20859d | 2016-09-20 | Stephen R. van den Berg | |
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
#define DRIVERNAME "Engine.IO"
#define DERROR(msg ...) ({sprintf(msg),backtrace()})
#define SERROR(msg ...) (sprintf(msg))
#define USERERROR(msg) throw(msg)
#define SUSERERROR(msg ...) USERERROR(SERROR(msg))
|
d75c0e | 2016-09-22 | Stephen R. van den Berg | | #define DUSERERROR(msg ...) USERERROR(DERROR(msg))
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
#ifdef EIO_DEBUG
#define PD(X ...) werror(X)
|
d75c0e | 2016-09-22 | Stephen R. van den Berg | | #define PDT(X ...) (werror(X), \
werror(describe_backtrace(PT(backtrace()))))
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
#define PT(X ...) (lambda(object _this){return (X);}(this))
#else
#undef EIO_DEBUGMORE
#define PD(X ...) 0
|
d75c0e | 2016-09-22 | Stephen R. van den Berg | | #define PDT(X ...) 0
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | #define PT(X ...) (X)
#endif
|
20859d | 2016-09-20 | Stephen R. van den Berg | | #define SIDBYTES 16
#define TIMEBYTES 6
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
|
2ef949 | 2016-09-25 | Stephen R. van den Berg | |
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | final mapping options = ([
"pingTimeout": 64*1000,
"pingInterval": 29*1000,
|
2ef949 | 2016-09-25 | Stephen R. van den Berg | | #if constant(Gz.deflate)
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | "compressionLevel": 3,
|
2ef949 | 2016-09-25 | Stephen R. van den Berg | | "compressionStrategy": Gz.DEFAULT_STRATEGY,
"compressionThreshold": 256,
"compressionWindowSize": 15,
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | "compressionHeuristics": .WebSocket.HEURISTICS_COMPRESS,
|
2ef949 | 2016-09-25 | Stephen R. van den Berg | | #endif
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | "allowUpgrades": 1,
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | ]);
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
|
20859d | 2016-09-20 | Stephen R. van den Berg | | constant protocol = 3;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
private enum {
BASE64='b', OPEN='0', CLOSE, PING, PONG, MESSAGE, UPGRADE, NOOP,
SENDQEMPTY, FORCECLOSE
};
|
583640 | 2016-09-22 | Stephen R. van den Berg | | private mapping(string:Socket) clients = ([]);
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
private Regexp acceptgzip = Regexp("(^|,)gzip(,|$)");
private Regexp xxsua = Regexp(";MSIE|Trident/");
|
2ef8e7 | 2016-09-26 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
d6f247 | 2016-10-03 | Pontus Östlund | |
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
d6f247 | 2016-10-03 | Pontus Östlund | |
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
d6f247 | 2016-10-03 | Pontus Östlund | |
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
d6f247 | 2016-10-03 | Pontus Östlund | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
|
2ef8e7 | 2016-09-26 | Stephen R. van den Berg | | final Socket farm(Protocols.WebSocket.Request req, void|mapping options) {
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | string sid;
PD("Request %O\n", req.query);
if (sid = req.variables.sid) {
|
583640 | 2016-09-22 | Stephen R. van den Berg | | Socket client;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | if (!(client = clients[sid]))
|
d75c0e | 2016-09-22 | Stephen R. van den Berg | | req.response_and_finish((["data":"Unknown sid",
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | "error":Protocols.HTTP.HTTP_GONE]));
else
|
d75c0e | 2016-09-22 | Stephen R. van den Berg | | client.onrequest(req);
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | } else
|
2ef8e7 | 2016-09-26 | Stephen R. van den Berg | | return Socket(req, options);
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | return 0;
}
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
class Socket {
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
final Protocols.WebSocket.Request request;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
final string sid;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | private mixed id;
|
2ef8e7 | 2016-09-26 | Stephen R. van den Berg | | final mapping _options;
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | private Stdio.Buffer ci = Stdio.Buffer();
private function(mixed, string|Stdio.Buffer:void) read_cb;
private function(mixed:void) close_cb;
private Thread.Queue sendq = Thread.Queue();
private ADT.Queue recvq = ADT.Queue();
private string curtransport;
private Transport conn;
private Transport upgtransport;
private enum {RUNNING = 0, PAUSED, SCLOSING, RCLOSING};
private int state = RUNNING;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | class Transport {
final function(int, void|string|Stdio.Buffer:void) read_cb;
final protected int pingtimeout;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | protected void create(Protocols.WebSocket.Request req) {
|
2ef8e7 | 2016-09-26 | Stephen R. van den Berg | | pingtimeout = _options->pingTimeout/1000+1;
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | kickwatchdog();
}
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | private void droptimeout() {
remove_call_out(close);
}
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | protected void destroy() {
droptimeout();
}
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | final protected void kickwatchdog() {
droptimeout();
call_out(close, pingtimeout);
}
|
7cac5c | 2016-09-24 | Stephen R. van den Berg | | void close() {
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | droptimeout();
read_cb(FORCECLOSE);
}
final protected void sendqempty() {
if (!sendq.size())
read_cb(SENDQEMPTY);
}
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | class Polling {
|
a5bde7 | 2016-09-27 | Stephen R. van den Berg | | inherit Transport;
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
private int forceascii;
final protected Stdio.Buffer c = Stdio.Buffer();
final protected Stdio.Buffer ci = Stdio.Buffer();
final protected Protocols.WebSocket.Request req;
private mapping headers = ([]);
private Thread.Mutex getreq = Thread.Mutex();
private Thread.Mutex exclpost = Thread.Mutex();
|
2ef949 | 2016-09-25 | Stephen R. van den Berg | | #if constant(Gz.deflate)
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | private Gz.File gzfile;
#endif
protected string noop;
protected void getbody(Protocols.WebSocket.Request _req);
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | protected void wrapfinish(Protocols.WebSocket.Request req, string body,
mapping(string:mixed) options);
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | protected void respfinish(Protocols.WebSocket.Request req, string body,
int isbin, mapping(string:mixed) options) {
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | mapping|string comprheads;
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | if (!sizeof(body))
body = noop;
|
2ef949 | 2016-09-25 | Stephen R. van den Berg | | #if constant(Gz.deflate)
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | if (gzfile
&& options->compressionLevel>0
&& sizeof(body) >= options->compressionThreshold
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | && (comprheads = req.request_headers["accept-encoding"])
&& acceptgzip.match(comprheads)) {
Stdio.FakeFile f = Stdio.FakeFile("", "wb");
gzfile.open(f, "wb");
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | gzfile.setparams(options->compressionLevel,
options->compressionStrategy, options->compressionWindowSize);
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | gzfile.write(body);
gzfile.close();
comprheads = headers;
if (sizeof(body)>f.stat().size) {
body = (string)f;
comprheads += (["Content-Encoding":"gzip"]);
}
} else
#endif
comprheads = headers;
req.response_and_finish(([
"data":body,
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | "type":isbin ? "application/octet-stream" : "text/plain;charset=UTF-8",
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | "extra_heads":comprheads]));
}
protected void create(Protocols.WebSocket.Request _req) {
noop = sprintf("1:%c", NOOP);
forceascii = !zero_type(_req.variables->b64);
ci->set_error_mode(1);
|
2ef949 | 2016-09-25 | Stephen R. van den Berg | | #if constant(Gz.deflate)
|
2ef8e7 | 2016-09-26 | Stephen R. van den Berg | | if (_options->compressionLevel)
|
2ef949 | 2016-09-25 | Stephen R. van den Berg | | gzfile = Gz.File();
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | #endif
|
a5bde7 | 2016-09-27 | Stephen R. van den Berg | | ::create(_req);
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | if (_req.request_headers.origin) {
headers["Access-Control-Allow-Credentials"] = "true";
headers["Access-Control-Allow-Origin"] = _req.request_headers.origin;
} else
headers["Access-Control-Allow-Origin"] = "*";
string ua = _req.request_headers["user-agent"];
if (ua && xxsua.match(ua))
headers["X-XSS-Protection"] = "0";
onrequest(_req);
}
final void onrequest(Protocols.WebSocket.Request _req) {
kickwatchdog();
switch (_req.request_type) {
case "GET":
flush();
req = _req;
flush();
break;
case "OPTIONS":
headers["Access-Control-Allow-Headers"] = "Content-Type";
_req.response_and_finish((["data":"ok","extra_heads":headers]));
break;
case "POST": {
getbody(_req);
function ackpost() {
_req.response_and_finish((["data":"ok","type":"text/plain",
"extra_heads":headers]));
};
#if constant(Thread.Thread)
Thread.Thread(ackpost);
#else
ackpost();
#endif
do {
Thread.MutexKey lock;
if (lock = exclpost.trylock()) {
int type;
string|Stdio.Buffer res;
Stdio.Buffer.RewindKey rewind;
rewind = ci->rewind_on_error();
while (sizeof(ci)) {
if (catch {
int len, isbin;
if ((isbin = ci->read_int8()) <= 1) {
for (len = 0;
(type = ci->read_int8())!=0xff;
len=len*10+type);
len--;
type = ci->read_int8() + (isbin ? OPEN : 0);
res = isbin ? ci->read_buffer(len): ci->read(len);
} else {
ci->unread(1);
len = ci->sscanf("%d:")[0]-1;
|
2bc397 | 2016-09-22 | Stephen R. van den Berg | | type = ci->read_int8();
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | if (type == BASE64) {
type = ci->read_int8();
res = Stdio.Buffer(MIME.decode_base64(ci->read(len)));
} else
res = ci->read(len);
}
})
break;
else {
rewind.update();
if (stringp(res))
res = utf8_to_string(res);
read_cb(type, res);
}
|
2bc397 | 2016-09-22 | Stephen R. van den Berg | | }
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | lock = 0;
} else
break;
} while (sizeof(ci));
break;
}
default:
_req.response_and_finish((["data":"Unsupported method",
"error":Protocols.HTTP.HTTP_METHOD_INVALID,
"extra_heads":(["Allow":"GET,POST,OPTIONS"])]));
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
}
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | constant forcebinary = 0;
final void flush(void|int type, void|string|Stdio.Buffer msg) {
Thread.MutexKey lock;
if (req && sendq.size() && (lock = getreq.trylock())) {
Protocols.WebSocket.Request myreq;
array tosend;
if ((myreq = req) && sizeof(tosend = sendq.try_read_array())) {
req = 0;
lock = 0;
array m;
int anybinary = 0;
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | mapping(string:mixed) options = _options;
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | if (forcebinary && !forceascii)
foreach (tosend;; m)
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | if (sizeof(m)>=2 && !stringp(m[1])) {
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | anybinary = 1;
break;
}
foreach (tosend;; m) {
type = m[0];
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | msg = "";
switch(sizeof(m)) {
case 3:
if (m[2])
options += m[2];
case 2:
msg = m[1] || "";
}
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | if (!anybinary && stringp(msg)) {
if (String.width(msg) > 8)
msg = string_to_utf8(msg);
c->add((string)(1+sizeof(msg)))->add_int8(':');
} else if (!forceascii) {
if (stringp(msg))
c->add_int8(0);
else {
type -= OPEN;
c->add_int8(1);
}
foreach ((string)(1+sizeof(msg));; int i)
c->add_int8(i-'0');
c->add_int8(0xff);
} else {
msg = MIME.encode_base64(msg->read(), 1);
c->add((string)(1+1+sizeof(msg)))
->add_int8(':')->add_int8(BASE64);
|
44d5b3 | 2016-09-22 | Stephen R. van den Berg | | }
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | c->add_int8(type)->add(msg);
|
44d5b3 | 2016-09-22 | Stephen R. van den Berg | | }
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | if (sizeof(c))
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | wrapfinish(myreq, c->read(), options);
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | sendqempty();
} else
lock = 0;
}
|
2bc397 | 2016-09-22 | Stephen R. van den Berg | | }
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | class XHR {
|
a5bde7 | 2016-09-27 | Stephen R. van den Berg | | inherit Polling;
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | constant forcebinary = 1;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | final protected void getbody(Protocols.WebSocket.Request _req) {
ci->add(_req.body_raw);
}
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | final protected
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | void wrapfinish(Protocols.WebSocket.Request req, string body,
mapping(string:mixed) options) {
respfinish(req, body, String.range(body)[1]==0xff, options);
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | }
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | class JSONP {
|
a5bde7 | 2016-09-27 | Stephen R. van den Berg | | inherit Polling;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | private string head;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | protected void create(Protocols.WebSocket.Request req) {
|
a5bde7 | 2016-09-27 | Stephen R. van den Berg | | ::create(req);
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | head = "___eio[" + (int)req.variables->j + "](";
noop = head+"\""+::noop+"\");";
}
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | final protected void getbody(Protocols.WebSocket.Request _req) {
string d;
if (d = _req.variables->d)
ci->add(replace(d,({"\r\n","\\n"}),({"\r","\n"})));
}
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | final protected
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | void wrapfinish(Protocols.WebSocket.Request req, string body,
mapping(string:mixed) options) {
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | c->add(head)->add(Standards.JSON.encode(body))->add(");");
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | respfinish(req, c->read(), 0, options);
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | }
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | class WebSocket {
|
a5bde7 | 2016-09-27 | Stephen R. van den Berg | | inherit Transport;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | private Protocols.WebSocket.Connection con;
private Stdio.Buffer bb = Stdio.Buffer();
private String.Buffer sb = String.Buffer();
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
7cac5c | 2016-09-24 | Stephen R. van den Berg | | final void close() {
if (con)
catch(con.close());
}
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | protected void create(Protocols.WebSocket.Request req,
Protocols.WebSocket.Connection _con) {
con = _con;
con.onmessage = recv;
|
7cac5c | 2016-09-24 | Stephen R. van den Berg | | con.onclose = ::close;
|
a5bde7 | 2016-09-27 | Stephen R. van den Berg | | ::create(req);
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | }
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | final void flush(void|int type, void|string|Stdio.Buffer msg) {
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | mapping(string:mixed) options;
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | void sendit() {
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | .WebSocket.Frame f = stringp(msg)
? .WebSocket.Frame(.WebSocket.FRAME_TEXT, sprintf("%c%s", type, msg))
: .WebSocket.Frame(.WebSocket.FRAME_BINARY,
sprintf("%c%s", type - OPEN, msg->read()));
f.options += options;
con.send(f);
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | };
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | if (msg) {
options = _options;
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | sendit();
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | } else {
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | array tosend;
while (sizeof(tosend = sendq.try_read_array())) {
array m;
foreach (tosend;; m) {
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | options = _options;
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | type = m[0];
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | msg = "";
switch(sizeof(m)) {
case 3:
if (m[2])
options += m[2];
case 2:
msg = m[1] || "";
}
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | sendit();
}
|
44d5b3 | 2016-09-22 | Stephen R. van den Berg | | }
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | sendqempty();
|
2bc397 | 2016-09-22 | Stephen R. van den Berg | | }
}
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | private void recv(Protocols.WebSocket.Frame f) {
kickwatchdog();
switch (f.opcode) {
case Protocols.WebSocket.FRAME_TEXT:
|
d75c0e | 2016-09-22 | Stephen R. van den Berg | | sb.add(f.text);
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | break;
case Protocols.WebSocket.FRAME_BINARY:
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | bb->add(f.data);
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | break;
case Protocols.WebSocket.FRAME_CONTINUATION:
if (sizeof(sb))
sb.add(f.text);
else
bb->add(f.data);
break;
default:
return;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | if (f.fin)
if (sizeof(sb)) {
string s = sb.get();
read_cb(s[0], s[1..]);
} else {
int type = bb->read_int8();
|
689cc1 | 2016-09-27 | Stephen R. van den Berg | | read_cb(type + OPEN, bb->read_buffer(sizeof(bb)));
|
922d16 | 2016-09-23 | Stephen R. van den Berg | | }
}
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
final void set_id(mixed _id) {
id = _id;
}
|
583640 | 2016-09-22 | Stephen R. van den Berg | |
|
20859d | 2016-09-20 | Stephen R. van den Berg | |
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | final mixed query_id() {
|
20859d | 2016-09-20 | Stephen R. van den Berg | | return id || this;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
|
20859d | 2016-09-20 | Stephen R. van den Berg | |
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
|
20859d | 2016-09-20 | Stephen R. van den Berg | | final void set_callbacks(
void|function(mixed, string|Stdio.Buffer:void) _read_cb,
void|function(mixed:void) _close_cb) {
close_cb = _close_cb;
read_cb = _read_cb;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | flushrecvq();
}
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | final void write(mapping(string:mixed) options,
string|Stdio.Buffer ... msgs) {
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | if (state >= SCLOSING)
|
d75c0e | 2016-09-22 | Stephen R. van den Berg | | DUSERERROR("Socket already shutting down");
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | foreach (msgs;; string|Stdio.Buffer msg) {
PD("Queue %s %c:%O\n", sid, MESSAGE, (string)msg);
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | sendq.write(({MESSAGE, msg, options}));
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
if (state == RUNNING)
|
44d5b3 | 2016-09-22 | Stephen R. van den Berg | | flush();
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
private void send(int type, void|string|Stdio.Buffer msg) {
PD("Queue %s %c:%O\n", sid, type, (string)(msg || ""));
|
79c557 | 2016-09-29 | Stephen R. van den Berg | | sendq.write(({type, msg}));
|
20859d | 2016-09-20 | Stephen R. van den Berg | | switch (state) {
case RUNNING:
case SCLOSING:
|
44d5b3 | 2016-09-22 | Stephen R. van den Berg | | flush();
|
20859d | 2016-09-20 | Stephen R. van den Berg | | }
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
|
44d5b3 | 2016-09-22 | Stephen R. van den Berg | | private void flush() {
|
7cac5c | 2016-09-24 | Stephen R. van den Berg | | if(catch(conn.flush())) {
|
bcd079 | 2016-09-23 | Stephen R. van den Berg | | catch(conn.close());
|
7cac5c | 2016-09-24 | Stephen R. van den Berg | | if (upgtransport)
catch(upgtransport.close());
}
|
44d5b3 | 2016-09-22 | Stephen R. van den Berg | | }
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | private void flushrecvq() {
|
d75c0e | 2016-09-22 | Stephen R. van den Berg | | while (read_cb && !recvq.is_empty())
|
47c5bf | 2016-09-26 | Stephen R. van den Berg | | read_cb(query_id(), recvq.get());
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
|
20859d | 2016-09-20 | Stephen R. van den Berg | |
final void close() {
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | if (state < SCLOSING) {
|
20859d | 2016-09-20 | Stephen R. van den Berg | | if (close_cb)
close_cb(query_id());
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | PT("Send close, state %O\n", state);
state = SCLOSING;
|
20859d | 2016-09-20 | Stephen R. van den Berg | | catch(send(CLOSE));
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
}
|
20859d | 2016-09-20 | Stephen R. van den Berg | | private void rclose() {
close();
state = RCLOSING;
m_delete(clients, sid);
}
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | private void clearcallback() {
close_cb = 0;
read_cb = 0;
|
583640 | 2016-09-22 | Stephen R. van den Berg | | id = 0;
|
b6ae97 | 2016-09-23 | Stephen R. van den Berg | | upgtransport = conn = 0;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
|
20859d | 2016-09-20 | Stephen R. van den Berg | | private void recv(int type, void|string|Stdio.Buffer msg) {
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | #ifndef EIO_DEBUGMORE
if (type!=SENDQEMPTY)
#endif
PD("Received %s %c:%O\n", sid, type, (string)msg);
switch (type) {
default:
|
20859d | 2016-09-20 | Stephen R. van den Berg | | close();
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | break;
case CLOSE:
|
20859d | 2016-09-20 | Stephen R. van den Berg | | rclose();
|
2bc397 | 2016-09-22 | Stephen R. van den Berg | | if (!sendq.size())
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | clearcallback();
break;
case SENDQEMPTY:
if (state == RCLOSING)
clearcallback();
break;
case FORCECLOSE:
|
20859d | 2016-09-20 | Stephen R. van den Berg | | rclose();
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | clearcallback();
break;
case PING:
send(PONG, msg);
break;
case MESSAGE:
|
d75c0e | 2016-09-22 | Stephen R. van den Berg | | if (read_cb && recvq.is_empty())
|
20859d | 2016-09-20 | Stephen R. van den Berg | | read_cb(query_id(), msg);
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | else {
|
47c5bf | 2016-09-26 | Stephen R. van den Berg | | recvq.put(msg);
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | flushrecvq();
}
break;
}
}
private void upgrecv(int type, string|Stdio.Buffer msg) {
switch (type) {
default:
upgtransport = 0;
if (state == PAUSED)
state = RUNNING;
|
583640 | 2016-09-22 | Stephen R. van den Berg | | if(conn)
|
44d5b3 | 2016-09-22 | Stephen R. van den Berg | | flush();
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | break;
case PING:
state = PAUSED;
|
2bc397 | 2016-09-22 | Stephen R. van den Berg | | if (!sendq.size())
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | send(NOOP);
|
44d5b3 | 2016-09-22 | Stephen R. van den Berg | | flush();
|
d75c0e | 2016-09-22 | Stephen R. van den Berg | | upgtransport.flush(PONG, msg);
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | break;
case UPGRADE: {
|
d75c0e | 2016-09-22 | Stephen R. van den Berg | | upgtransport.read_cb = recv;
|
583640 | 2016-09-22 | Stephen R. van den Berg | | conn = upgtransport;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | curtransport = "websocket";
if (state == PAUSED)
state = RUNNING;
upgtransport = 0;
|
44d5b3 | 2016-09-22 | Stephen R. van den Berg | | flush();
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | break;
}
}
}
protected void destroy() {
|
20859d | 2016-09-20 | Stephen R. van den Berg | | close();
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
|
2ef8e7 | 2016-09-26 | Stephen R. van den Berg | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
|
d6f247 | 2016-10-03 | Pontus Östlund | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
|
d6f247 | 2016-10-03 | Pontus Östlund | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
|
d6f247 | 2016-10-03 | Pontus Östlund | |
|
922d16 | 2016-09-23 | Stephen R. van den Berg | |
protected void create(Protocols.WebSocket.Request req,
|
2ef8e7 | 2016-09-26 | Stephen R. van den Berg | | void|mapping options) {
|
583640 | 2016-09-22 | Stephen R. van den Berg | | request = req;
|
2ef8e7 | 2016-09-26 | Stephen R. van den Berg | | _options = .EngineIO.options;
if (options && sizeof(options))
_options += options;
|
583640 | 2016-09-22 | Stephen R. van den Berg | | switch (curtransport = req.variables->transport) {
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | default:
|
d75c0e | 2016-09-22 | Stephen R. van den Berg | | req.response_and_finish((["data":"Unsupported transport",
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | "error":Protocols.HTTP.HTTP_UNSUPP_MEDIA]));
return;
case "websocket":
|
5c68e8 | 2016-10-26 | Henrik Grubbström (Grubba) | | conn = WebSocket(req, req.websocket_accept(0, UNDEFINED, _options));
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | break;
case "polling":
|
583640 | 2016-09-22 | Stephen R. van den Berg | | conn = req.variables.j ? JSONP(req) : XHR(req);
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | break;
}
|
583640 | 2016-09-22 | Stephen R. van den Berg | | conn.read_cb = recv;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | ci->add(Crypto.Random.random_string(SIDBYTES-TIMEBYTES));
ci->add_hint(gethrtime(), TIMEBYTES);
sid = MIME.encode_base64(ci->read());
|
20859d | 2016-09-20 | Stephen R. van den Berg | | clients[sid] = this;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | send(OPEN, Standards.JSON.encode(
(["sid":sid,
"upgrades":
|
2ef8e7 | 2016-09-26 | Stephen R. van den Berg | | _options->allowUpgrades ? ({"websocket"}) : ({}),
"pingInterval":_options->pingInterval,
"pingTimeout":_options->pingTimeout
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | ])));
PD("New EngineIO sid: %O\n", sid);
}
|
583640 | 2016-09-22 | Stephen R. van den Berg | |
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | |
final void onrequest(Protocols.WebSocket.Request req) {
string s;
|
583640 | 2016-09-22 | Stephen R. van den Berg | | request = req;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | if ((s = req.variables->transport) == curtransport)
|
583640 | 2016-09-22 | Stephen R. van den Berg | | conn.onrequest(req);
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | else
switch (s) {
default:
|
d75c0e | 2016-09-22 | Stephen R. van den Berg | | req.response_and_finish((["data":"Invalid transport",
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | "error":Protocols.HTTP.HTTP_UNSUPP_MEDIA]));
return 0;
case "websocket":
|
cbb6c0 | 2016-10-26 | Henrik Grubbström (Grubba) | | upgtransport =
WebSocket(req, req.websocket_accept(0, UNDEFINED, _options));
|
d75c0e | 2016-09-22 | Stephen R. van den Berg | | upgtransport.read_cb = upgrecv;
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | }
}
private string _sprintf(int type, void|mapping flags) {
string res=UNDEFINED;
|
20859d | 2016-09-20 | Stephen R. van den Berg | | switch (type) {
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | case 'O':
|
20859d | 2016-09-20 | Stephen R. van den Berg | | res = sprintf(DRIVERNAME"(%s.%d,%s,%d,%d,%d,%d)",
|
d75c0e | 2016-09-22 | Stephen R. van den Berg | | sid, protocol, curtransport, state, sendq.size(),
recvq.is_empty(),sizeof(clients));
|
f69a2b | 2016-09-19 | Stephen R. van den Berg | | break;
}
return res;
}
}
|