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

version» Context lines:

pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:93:    "error":Protocols.HTTP.HTTP_GONE]));    else    client->onrequest(req);    } else    return Server(req);    return 0;   }      class Transport {    final function(int, void|string|Stdio.Buffer:void) read_cb; -  final ADT.Queue sendq; +  final Thread.Queue sendq;    final protected int pingtimeout; -  final protected Thread.Mutex singleflush = Thread.Mutex(); -  final protected int knock; +        protected void create(Protocols.WebSocket.Request req) {    pingtimeout = options->pingTimeout/1000+1;    kickwatchdog();    }       private void droptimeout() {    remove_call_out(close);    }   
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:123:    call_out(close, pingtimeout);    }       //! Close the transport.    final void close() {    droptimeout();    read_cb(FORCECLOSE);    }       final protected void sendqempty() { +  if (!sendq.size())    read_cb(SENDQEMPTY);    }   }      class Polling {    inherit Transport:t;       private int forceascii;    final protected Stdio.Buffer c = Stdio.Buffer();    Stdio.Buffer ci = Stdio.Buffer();    final mapping headers = ([]);    final Protocols.WebSocket.Request req; -  +  final protected Thread.Mutex getreq = Thread.Mutex(); +  private Thread.Mutex exclpost = Thread.Mutex();   #if constant(Gz.File)    private Gz.File gzfile;   #endif    protected string noop;       protected void getbody(Protocols.WebSocket.Request _req); -  protected void wrapfinish(string body); +  protected void wrapfinish(Protocols.WebSocket.Request req, string body);    -  protected void respfinish(void|string body, void|string mimetype) { -  if (req) { +  protected void respfinish(Protocols.WebSocket.Request req, +  void|string body, void|string mimetype) {    mapping|string comprheads;    if (!body)    body = noop;   #if constant(Gz.File)    if (gzfile && sizeof(body) >= options->compressionThreshold    && (comprheads = req.request_headers["accept-encoding"])    && acceptgzip->match(comprheads)) {    Stdio.FakeFile f = Stdio.FakeFile("", "wb");    gzfile->open(f, "wb");    gzfile->write(body);
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:168: Inside #if constant(Gz.File)
   body = (string)f;    comprheads += (["Content-Encoding":"gzip"]);    }    } else   #endif    comprheads = headers;    req->response_and_finish(([    "data":body,    "type":mimetype||"text/plain;charset=UTF-8",    "extra_heads":comprheads])); -  req = 0; +     } -  } +        protected void create(Protocols.WebSocket.Request _req) {    noop = sprintf("1:%c", NOOP);    forceascii = !zero_type(_req.variables->b64);    ci->set_error_mode(1);    int clevel;   #if constant(Gz.File)    if (clevel = options->compressionLevel)    (gzfile = Gz.File())->setparams(clevel, Gz.DEFAULT_STRATEGY);   #endif
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:208:    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); +  // Strangely enough, EngineIO 3 does not communicate back +  // over the POST request, so wrap it up. +  function ackpost() { +  _req->response_and_finish((["data":"ok","type":"text/plain", +  "extra_heads":headers])); +  }; + #if constant(Thread.Thread) +  // This requires _req to remain unaltered for the remainder of +  // this function. +  Thread.Thread(ackpost); // Lower latency by doing it parallel + #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;
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:241:    }    })    break;    else {    rewind->update();    if (stringp(res))    res = utf8_to_string(res);    read_cb(type, res);    }    } -  // Strangely enough, EngineIO 3 does not communicate back -  // over the POST request, so wrap it up. -  _req->response_and_finish((["data":"ok","type":"text/plain", -  "extra_heads":headers])); +  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"])]));    }    }    -  +  constant forcebinary = 0; +     final void flush(void|int type, void|string|Stdio.Buffer msg) { -  do { -  Thread.MutexKey lock = singleflush->trylock(); -  if (lock) { -  knock = 0; -  if (req && sendq) { -  while (knock = 0, !sendq->is_empty()) { -  array m = sendq->read(); +  Thread.MutexKey lock; +  if (req && sendq && 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; +  if (forcebinary && !forceascii) +  foreach (tosend;; m) +  if (!stringp(m[1])) { +  anybinary = 1; +  break; +  } +  foreach (tosend;; m) {    type = m[0];    msg = m[1]; -  if (stringp(msg)) { +  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) { -  c->add_int8(1); // 0 would be inefficient, since it passes UTF-8 +  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); -  type -= OPEN; +     } 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(c->read()); +  wrapfinish(myreq, c->read());    sendqempty(); -  } +  } else    lock = 0; -  } else { -  knock = 1; -  break; +     } -  } while (knock); +     }   }      class XHR {    inherit Polling:p; -  +  constant forcebinary = 1;       final protected void getbody(Protocols.WebSocket.Request _req) {    ci->add(_req->body_raw);    }    -  final protected void wrapfinish(string body) { -  respfinish(body, String.range(body)[1]==0xff +  final protected +  void wrapfinish(Protocols.WebSocket.Request req, string body) { +  respfinish(req, body, String.range(body)[1]==0xff    ? "application/octet-stream" : 0);    }   }      class JSONP {    inherit Polling:p;       private string head;       protected void create(Protocols.WebSocket.Request req) {
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:326:    noop = head+"\""+::noop+"\");";    }       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(string body) { +  final protected +  void wrapfinish(Protocols.WebSocket.Request req, string body) {    c->add(head)->add(Standards.JSON.encode(body))->add(");"); -  respfinish(c->read()); +  respfinish(req, c->read());    }   }      class WebSocket {    inherit Transport:t;       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:353:    con->onclose = close;    t::create(req);    }       final void flush(void|int type, void|string|Stdio.Buffer msg) {    void sendit() {    con->send_text(sprintf("%c%s",type,stringp(msg) ? msg : msg->read()));    };    if (msg)    sendit(); -  else -  do { -  Thread.MutexKey lock = singleflush->trylock(); -  if (lock) { -  do -  while (knock = 0, !sendq->is_empty()) { -  array m = sendq->read(); +  else { +  array tosend; +  while (sizeof(tosend = sendq.try_read_array())) { +  array m; +  foreach (tosend;; m) {    type = m[0];    msg = m[1];    sendit();    } -  while (knock); +  }    sendqempty(); -  lock = 0; -  } else { -  knock = 1; -  break; +     } -  } while(knock); +     }       private void recv(Protocols.WebSocket.Frame f) {    kickwatchdog();    switch (f.opcode) {    case Protocols.WebSocket.FRAME_TEXT:    sb->add(f.text);    break;    case Protocols.WebSocket.FRAME_BINARY:    bb->add(f.data);
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:414:   class Server {    private Stdio.Buffer ci = Stdio.Buffer();    private function(mixed, string|Stdio.Buffer:void) read_cb;    private function(mixed:void) close_cb;    //! Contains the last request seen on this connection.    //! Can be used to obtain cookies etc.    final Protocols.WebSocket.Request lastrequest;    private mixed id;    //! The unique session identifier.    final string sid; -  private ADT.Queue sendq = ADT.Queue(); +  private Thread.Queue sendq = Thread.Queue();    private ADT.Queue recvq = ADT.Queue();    private string curtransport;    private Transport transport;    private Transport upgtransport;    private enum {RUNNING = 0, PAUSED, SCLOSING, RCLOSING};    private int state = RUNNING;       //! Set initial argument on callbacks.    final void set_id(mixed _id) {    id = _id;
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:509: Inside #if undefined(EIO_DEBUGMORE)
  #ifndef EIO_DEBUGMORE    if (type!=SENDQEMPTY)   #endif    PD("Received %s %c:%O\n", sid, type, (string)msg);    switch (type) {    default: // Protocol error or CLOSE    close();    break;    case CLOSE:    rclose(); -  if (sendq->is_empty()) +  if (!sendq.size())    clearcallback();    break;    case SENDQEMPTY:    if (state == RCLOSING)    clearcallback();    break;    case FORCECLOSE:    rclose();    clearcallback();    break;
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:545:    switch (type) {    default: // Protocol error or CLOSE    upgtransport = 0;    if (state == PAUSED)    state = RUNNING;    if(transport)    flush();    break;    case PING:    state = PAUSED; -  if (!sizeof(sendq)) +  if (!sendq.size())    send(NOOP);    flush();    upgtransport->flush(PONG, msg);    break;    case UPGRADE: {    upgtransport->read_cb = recv;    transport = upgtransport;    curtransport = "websocket";    if (state == PAUSED)    state = RUNNING;
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:622:    upgtransport->read_cb = upgrecv;    upgtransport->sendq = sendq;    }    }       private string _sprintf(int type, void|mapping flags) {    string res=UNDEFINED;    switch (type) {    case 'O':    res = sprintf(DRIVERNAME"(%s.%d,%s,%d,%d,%d,%d)", -  sid, protocol, curtransport, state, sendq->is_empty(), +  sid, protocol, curtransport, state, sendq->size(),    recvq->is_empty(),sizeof(clients));    break;    }    return res;    }   }