/* Notification callback. This routine is called from the Http pipeline on connection state changes. */ static void stateChangeNotifier(HttpConn *conn, int event, int arg) { Ejs *ejs; EjsRequest *req; assert(conn); ejs = 0; if ((req = httpGetConnContext(conn)) != 0) { ejs = req->ejs; } switch (event) { case HTTP_EVENT_STATE: if (arg == HTTP_STATE_BEGIN) { setupConnTrace(conn); } else if (arg == HTTP_STATE_FINALIZED) { if (req) { if (conn->error) { ejsSendRequestErrorEvent(ejs, req); } ejsSendRequestCloseEvent(ejs, req); if (req->cloned) { ejsSendRequestCloseEvent(req->ejs, req->cloned); } } } break; case HTTP_EVENT_READABLE: /* IO event notification for the request. */ if (req && req->emitter) { ejsSendEvent(ejs, req->emitter, "readable", NULL, req); } break; case HTTP_EVENT_WRITABLE: if (req && req->emitter) { ejsSendEvent(ejs, req->emitter, "writable", NULL, req); } break; case HTTP_EVENT_APP_CLOSE: /* Connection close */ if (req && req->conn) { req->conn = 0; } break; } }
static void httpEventChange(HttpConn *conn, int event, int arg) { Ejs *ejs; EjsHttp *hp; HttpTx *tx; MprOff lastWritten; hp = httpGetConnContext(conn); ejs = hp->ejs; tx = conn->tx; switch (event) { case HTTP_EVENT_STATE: switch (arg) { case HTTP_STATE_PARSED: if (hp->emitter) { ejsSendEvent(ejs, hp->emitter, "headers", NULL, hp); } break; case HTTP_STATE_FINALIZED: if (hp->emitter) { if (conn->error) { sendHttpErrorEvent(ejs, hp); } sendHttpCloseEvent(ejs, hp); } break; } break; case HTTP_EVENT_READABLE: if (hp && hp->emitter) { ejsSendEvent(ejs, hp->emitter, "readable", NULL, hp); } break; case HTTP_EVENT_WRITABLE: if (hp && hp->emitter) { do { lastWritten = tx->bytesWritten; ejsSendEvent(ejs, hp->emitter, "writable", NULL, hp); } while (tx->bytesWritten > lastWritten && !tx->writeBlocked); } break; } }
/* function close(): Void */ static EjsObj *hs_close(Ejs *ejs, EjsHttpServer *sp, int argc, EjsObj **argv) { if (sp->endpoint) { ejsSendEvent(ejs, sp->emitter, "close", NULL, sp); httpDestroyEndpoint(sp->endpoint); sp->endpoint = 0; } return 0; }
/* function on(name, observer: function): Http */ static EjsHttp *http_on(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { EjsFunction *observer; HttpConn *conn; observer = (EjsFunction*) argv[1]; if (observer->boundThis == 0 || observer->boundThis == ejs->global) { observer->boundThis = hp; } ejsAddObserver(ejs, &hp->emitter, argv[0], observer); conn = hp->conn; if (conn->readq && conn->readq->count > 0) { ejsSendEvent(ejs, hp->emitter, "readable", NULL, hp); } // TODO - don't need to test finalizedConnector if (!conn->tx->finalizedConnector && !conn->error && HTTP_STATE_CONNECTED <= conn->state && conn->state < HTTP_STATE_FINALIZED && conn->writeq->ioCount == 0) { httpNotify(conn, HTTP_EVENT_WRITABLE, 0); } return hp; }
static void onWebSocketEvent(EjsWebSocket *ws, int event, EjsAny *data, HttpPacket *packet) { Ejs *ejs; EjsAny *eobj; EjsFunction *fn; HttpRx *rx; cchar *eventName, *reason; int slot, status; ejs = ws->ejs; rx = ws->conn->rx; eobj = ejsCreateObj(ejs, ESV(Object), 0); slot = -1; eventName = 0; switch(event) { case HTTP_EVENT_READABLE: slot = ES_WebSocket_onmessage; eventName = "readable"; assert(data); ejsSetPropertyByName(ejs, eobj, EN("data"), data); ejsSetPropertyByName(ejs, eobj, EN("last"), ejsCreateBoolean(ejs, packet->last)); ejsSetPropertyByName(ejs, eobj, EN("type"), ejsCreateNumber(ejs, packet->type)); break; case HTTP_EVENT_ERROR: eventName = "error"; slot = ES_WebSocket_onerror; break; case HTTP_EVENT_APP_OPEN: slot = ES_WebSocket_onopen; eventName = "headers"; if (rx->webSocket) { httpSetWebSocketPreserveFrames(ws->conn, ws->frames); } break; case HTTP_EVENT_DESTROY: if (ws->closed) { break; } ws->closed = 1; /* Fall through to close */ case HTTP_EVENT_APP_CLOSE: eventName = "complete"; slot = ES_WebSocket_onclose; status = rx ? rx->webSocket->closeStatus: WS_STATUS_COMMS_ERROR; reason = rx ? rx->webSocket->closeReason: 0; ejsSetPropertyByName(ejs, eobj, EN("code"), ejsCreateNumber(ejs, status)); ejsSetPropertyByName(ejs, eobj, EN("reason"), ejsCreateStringFromAsc(ejs, reason)); ejsSetPropertyByName(ejs, eobj, EN("wasClean"), ejsCreateBoolean(ejs, status != WS_STATUS_COMMS_ERROR)); break; } if (slot >= 0) { if (ws->emitter) { ejsSendEvent(ejs, ws->emitter, eventName, ws, data); } fn = ejsGetProperty(ejs, ws, slot); if (ejsIsFunction(ejs, fn) && !ejs->exception) { ejsRunFunction(ejs, fn, ws, 1, &eobj); } } }