/* function send(...content): Number */ static EjsNumber *ws_send(Ejs *ejs, EjsWebSocket *ws, int argc, EjsObj **argv) { EjsArray *args; EjsByteArray *ba; EjsAny *arg; ssize nbytes; int i; args = (EjsArray*) argv[0]; if (ws->conn->state < HTTP_STATE_PARSED && !waitForHttpState(ws, HTTP_STATE_PARSED, -1, 1)) { return ESV(null); } nbytes = 0; for (i = 0; i < args->length; i++) { if ((arg = ejsGetProperty(ejs, args, i)) != 0) { if (ejsIs(ejs, arg, ByteArray)) { ba = (EjsByteArray*) arg; nbytes = ejsGetByteArrayAvailableData(ba); nbytes = httpSendBlock(ws->conn, WS_MSG_BINARY, (cchar*) &ba->value[ba->readPosition], nbytes, HTTP_BLOCK); } else { nbytes = httpSend(ws->conn, ejsToMulti(ejs, arg)); } if (nbytes < 0) { return ESV(null); } } } return ejsCreateNumber(ejs, (MprNumber) nbytes); }
/* Write another block of data */ static ssize writeHttpData(Ejs *ejs, EjsHttp *hp) { EjsByteArray *ba; HttpConn *conn; ssize count, nbytes; conn = hp->conn; ba = hp->data; nbytes = 0; if (ba && (count = ejsGetByteArrayAvailableData(ba)) > 0) { if (conn->tx->finalizedOutput) { ejsThrowIOError(ejs, "Cannot write to socket"); return 0; } // MOB - or should this be non-blocking nbytes = httpWriteBlock(conn->writeq, (cchar*) &ba->value[ba->readPosition], count, HTTP_BLOCK); if (nbytes < 0) { ejsThrowIOError(ejs, "Cannot write to socket"); return 0; } ba->readPosition += nbytes; } httpServiceQueues(conn); return nbytes; }
/* uncompressBytes(data: ByteArray): ByteArray */ static EjsObj *zlib_uncompressBytes(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv) { EjsByteArray *in, *out; z_stream zs; uchar outbuf[ZBUFSIZE]; ssize nbytes, size; int rc; in = (EjsByteArray*) argv[0]; if ((out = ejsCreateByteArray(ejs, in->size)) == 0) { return 0; } if ((size = (int) ejsGetByteArrayAvailableData(in)) == 0) { return (EjsObj*) out; } zs.zalloc = Z_NULL; zs.zfree = Z_NULL; zs.opaque = Z_NULL; zs.avail_in = 0; rc = inflateInit(&zs); zs.next_in = &in->value[in->readPosition]; zs.avail_in = (int) size; do { if (zs.avail_in == 0) { break; } do { zs.avail_out = ZBUFSIZE; zs.next_out = (uchar*) outbuf; if ((rc = inflate(&zs, Z_NO_FLUSH)) == Z_NEED_DICT) { inflateEnd(&zs); return 0; } else if (rc == Z_DATA_ERROR || rc == Z_MEM_ERROR) { inflateEnd(&zs); return 0; } else { nbytes = ZBUFSIZE - zs.avail_out; } if (ejsCopyToByteArray(ejs, out, -1, (char*) outbuf, nbytes) != nbytes) { ejsThrowIOError(ejs, "Cannot copy to byte array"); inflateEnd(&zs); return 0; } out->writePosition += nbytes; } while (zs.avail_out == 0); assure(zs.avail_in == 0); } while (rc != Z_STREAM_END); deflateEnd(&zs); return (EjsObj*) out; }
/* function sendBlock(content, options): Number */ static EjsNumber *ws_sendBlock(Ejs *ejs, EjsWebSocket *ws, int argc, EjsObj **argv) { EjsByteArray *ba; EjsAny *content, *vp; ssize nbytes; cchar *str; int last, mode, type, flags; assert(argc == 2); if (ws->conn->state < HTTP_STATE_PARSED && !waitForHttpState(ws, HTTP_STATE_PARSED, -1, 1)) { return ESV(null); } content = argv[0]; last = ejsGetPropertyByName(ejs, argv[1], EN("last")) != ESV(false); if ((vp = ejsGetPropertyByName(ejs, argv[1], EN("mode"))) != 0) { mode = (int) ejsGetNumber(ejs, vp); if (mode != HTTP_BUFFER && mode != HTTP_BLOCK && mode != HTTP_NON_BLOCK) { ejsThrowArgError(ejs, "Bad message mode"); return 0; } } else { mode = HTTP_BUFFER; } if ((vp = ejsGetPropertyByName(ejs, argv[1], EN("type"))) != 0) { type = (int) ejsGetNumber(ejs, vp); if (type != WS_MSG_CONT && type != WS_MSG_TEXT && type != WS_MSG_BINARY) { ejsThrowArgError(ejs, "Bad message type"); return 0; } } else { type = WS_MSG_TEXT; } flags = mode; if (!last) { flags |= HTTP_MORE; } if (ejsIs(ejs, content, ByteArray)) { ba = (EjsByteArray*) content; nbytes = ejsGetByteArrayAvailableData(ba); nbytes = httpSendBlock(ws->conn, type, (cchar*) &ba->value[ba->readPosition], nbytes, flags); } else { str = ejsToMulti(ejs, content); nbytes = httpSendBlock(ws->conn, type, str, slen(str), flags); } if (nbytes < 0) { ejsThrowIOError(ejs, "Cannot send block"); return 0; } return ejsCreateNumber(ejs, (MprNumber) nbytes); }
/* function write(...data): Void */ static EjsNumber *http_write(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { ssize nbytes; hp->data = ejsCreateByteArray(ejs, -1); if (ejsWriteToByteArray(ejs, hp->data, 1, &argv[0]) < 0) { return 0; } if ((nbytes = writeHttpData(ejs, hp)) < 0) { return 0; } hp->writeCount += nbytes; if (hp->conn->async) { if (ejsGetByteArrayAvailableData(hp->data) > 0) { httpEnableConnEvents(hp->conn); } } return ejsCreateNumber(ejs, (MprNumber) nbytes); }
/* compressBytes(data: ByteArray): ByteArray */ static EjsObj *zlib_compressBytes(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv) { EjsByteArray *in, *out; z_stream zs; char outbuf[ZBUFSIZE]; ssize nbytes; int level, flush; in = (EjsByteArray*) argv[0]; if ((out = ejsCreateByteArray(ejs, in->size)) == 0) { return 0; } zs.zalloc = Z_NULL; zs.zfree = Z_NULL; zs.opaque = Z_NULL; level = Z_DEFAULT_COMPRESSION; deflateInit(&zs, level); zs.avail_in = (int) ejsGetByteArrayAvailableData(in); zs.next_in = (uchar*) &in->value[in->readPosition]; do { flush = (zs.avail_in == 0) ? Z_FINISH : Z_NO_FLUSH; do { zs.avail_out = ZBUFSIZE; zs.next_out = (uchar*) outbuf; deflate(&zs, flush); nbytes = ZBUFSIZE - zs.avail_out; if (ejsCopyToByteArray(ejs, out, -1, outbuf, nbytes) != nbytes) { ejsThrowIOError(ejs, "Cannot copy to byte array"); deflateEnd(&zs); return 0; } out->writePosition += nbytes; } while (zs.avail_out == 0); assure(zs.avail_in == 0); } while (flush != Z_FINISH); deflateEnd(&zs); return (EjsObj*) out; }