pike.git / lib / modules / Protocols.pmod / EngineIO.pmod

version» Context lines:

pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:62:   #define TIMEBYTES 6      //! Global options for all EngineIO instances.   //!   //! @seealso   //! @[Socket.create()], @[Gz.compress()]   final mapping options = ([    "pingTimeout": 64*1000, // Safe for NAT    "pingInterval": 29*1000, // Allows for jitter   #if constant(Gz.deflate) -  "compressionLevel": 3, +  "compressionLevel": 3, // Setting to zero disables.    "compressionStrategy": Gz.DEFAULT_STRATEGY,    "compressionThreshold": 256, // Compress when size>=    "compressionWindowSize": 15, // LZ77 window 2^x (8..15) -  +  "compressionHeuristics": .WebSocket.HEURISTICS_COMPRESS,   #endif -  "allowUpgrades": 1 +  "allowUpgrades": 1,   ]);      //! Engine.IO protocol version.   constant protocol = 3; // EIO Protocol version      private enum {    // 0 1 2 3 4 5 6    BASE64='b', OPEN='0', CLOSE, PING, PONG, MESSAGE, UPGRADE, NOOP,    SENDQEMPTY, FORCECLOSE   };
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:159:    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;    -  //! Set to any of @expr{Protocols.WebSocket.OVERRIDE_COMPRESS@} -  //! or @expr{Protocols.WebSocket.OVERRIDE_SKIPCOMPRESS@} -  //! to bypass of the compression heuristics on binary -  //! frames in a WebSocket connection only. -  final int skip_compression = .WebSocket.HEURISTICS_COMPRESS; -  +     class Transport {    final function(int, void|string|Stdio.Buffer:void) read_cb;    final protected int pingtimeout;       protected void create(Protocols.WebSocket.Request req) {    pingtimeout = _options->pingTimeout/1000+1;    kickwatchdog();    }       private void droptimeout() {
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:215:    final protected Protocols.WebSocket.Request req;    private mapping headers = ([]);    private Thread.Mutex getreq = Thread.Mutex();    private Thread.Mutex exclpost = Thread.Mutex();    #if constant(Gz.deflate)    private Gz.File gzfile;    #endif    protected string noop;       protected void getbody(Protocols.WebSocket.Request _req); -  protected void wrapfinish(Protocols.WebSocket.Request req, string body); +  protected void wrapfinish(Protocols.WebSocket.Request req, string body, +  mapping(string:mixed) options);    -  protected void respfinish(Protocols.WebSocket.Request req, -  void|string body, void|string mimetype) { +  protected void respfinish(Protocols.WebSocket.Request req, string body, +  int isbin, mapping(string:mixed) options) {    mapping|string comprheads; -  if (!body) -  body = noop; +  if (!sizeof(body)) +  body = noop; // Engine.IO does not like empty frames    #if constant(Gz.deflate) -  if (gzfile && sizeof(body) >= _options->compressionThreshold +  if (gzfile +  && options->compressionLevel>0 +  && sizeof(body) >= options->compressionThreshold    && (comprheads = req.request_headers["accept-encoding"])    && acceptgzip.match(comprheads)) {    Stdio.FakeFile f = Stdio.FakeFile("", "wb");    gzfile.open(f, "wb"); -  gzfile.setparams(_options->compressionLevel, -  _options->compressionStrategy, _options->compressionWindowSize); +  gzfile.setparams(options->compressionLevel, +  options->compressionStrategy, options->compressionWindowSize);    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, -  "type":mimetype||"text/plain;charset=UTF-8", +  "type":isbin ? "application/octet-stream" : "text/plain;charset=UTF-8",    "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);    #if constant(Gz.deflate)    if (_options->compressionLevel)    gzfile = Gz.File();
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:355:    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; +  mapping(string:mixed) options = _options;    if (forcebinary && !forceascii)    foreach (tosend;; m) -  if (!stringp(m[1])) { +  if (sizeof(m)>=2 && !stringp(m[1])) {    anybinary = 1;    break;    }    foreach (tosend;; m) {    type = m[0]; -  msg = m[1]; +  msg = ""; +  switch(sizeof(m)) { +  case 3: +  if (m[2]) +  options += m[2]; +  case 2: +  msg = m[1] || ""; +  }    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);
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:386:    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);    }    c->add_int8(type)->add(msg);    }    if (sizeof(c)) -  wrapfinish(myreq, c->read()); +  wrapfinish(myreq, c->read(), options);    sendqempty();    } else    lock = 0;    }    }    }       class XHR {    inherit Polling;    constant forcebinary = 1;       final protected void getbody(Protocols.WebSocket.Request _req) {    ci->add(_req.body_raw);    }       final protected -  void wrapfinish(Protocols.WebSocket.Request req, string body) { -  respfinish(req, body, String.range(body)[1]==0xff -  ? "application/octet-stream" : 0); +  void wrapfinish(Protocols.WebSocket.Request req, string body, +  mapping(string:mixed) options) { +  respfinish(req, body, String.range(body)[1]==0xff, options);    }    }       class JSONP {    inherit Polling;       private string head;       protected void create(Protocols.WebSocket.Request req) {    ::create(req);
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:428:    }       final protected void getbody(Protocols.WebSocket.Request _req) {    string d;    if (d = _req.variables->d)    // Reverse-map some braindead escape mechanisms    ci->add(replace(d,({"\r\n","\\n"}),({"\r","\n"})));    }       final protected -  void wrapfinish(Protocols.WebSocket.Request req, string body) { +  void wrapfinish(Protocols.WebSocket.Request req, string body, +  mapping(string:mixed) options) {    c->add(head)->add(Standards.JSON.encode(body))->add(");"); -  respfinish(req, c->read()); +  respfinish(req, c->read(), 0, options);    }    }       class WebSocket {    inherit Transport;       private Protocols.WebSocket.Connection con;    private Stdio.Buffer bb = Stdio.Buffer();    private String.Buffer sb = String.Buffer();   
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:455:       protected void create(Protocols.WebSocket.Request req,    Protocols.WebSocket.Connection _con) {    con = _con;    con.onmessage = recv;    con.onclose = ::close;    ::create(req);    }       final void flush(void|int type, void|string|Stdio.Buffer msg) { +  mapping(string:mixed) options;    void sendit() { -  if (stringp(msg)) -  con.send_text(sprintf("%c%s", type, msg)); -  else { -  .WebSocket.Frame f = .WebSocket.Frame(.WebSocket.FRAME_BINARY, +  .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.skip_compression = skip_compression; +  f.options += options;    con.send(f); -  } +     }; -  if (msg) +  if (msg) { +  options = _options;    sendit(); -  else { +  } else {    array tosend;    while (sizeof(tosend = sendq.try_read_array())) {    array m;    foreach (tosend;; m) { -  +  options = _options;    type = m[0]; -  msg = m[1]; +  msg = ""; +  switch(sizeof(m)) { +  case 3: +  if (m[2]) +  options += m[2]; +  case 2: +  msg = m[1] || ""; +  }    sendit();    }    }    sendqempty();    }    }       private void recv(Protocols.WebSocket.Frame f) {    kickwatchdog();    switch (f.opcode) {
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:532:    //! will be buffered.    final void set_callbacks(    void|function(mixed, string|Stdio.Buffer:void) _read_cb,    void|function(mixed:void) _close_cb) {    close_cb = _close_cb; // Set close callback first    read_cb = _read_cb; // to avoid losing the close event    flushrecvq();    }       //! Send text @[string] or binary @[Stdio.Buffer] messages. -  final void write(string|Stdio.Buffer ... msgs) { +  final void write(mapping(string:mixed) options, +  string|Stdio.Buffer ... msgs) {    if (state >= SCLOSING)    DUSERERROR("Socket already shutting down");    foreach (msgs;; string|Stdio.Buffer msg) {    PD("Queue %s %c:%O\n", sid, MESSAGE, (string)msg); -  sendq.write(({MESSAGE, msg})); +  sendq.write(({MESSAGE, msg, options}));    }    if (state == RUNNING)    flush();    }       private void send(int type, void|string|Stdio.Buffer msg) {    PD("Queue %s %c:%O\n", sid, type, (string)(msg || "")); -  sendq.write(({type, msg || ""})); +  sendq.write(({type, msg}));    switch (state) {    case RUNNING:    case SCLOSING:    flush();    }    }       private void flush() {    if(catch(conn.flush())) {    catch(conn.close());