/* 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; }
/* Read data bytes from a file function readBytes(count: Number = -1): ByteArray */ static EjsObj *readFileBytes(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsByteArray *result; MprPath info; ssize count, totalRead; if (argc == 0) { count = -1; } else if (argc != 1) { count = 0; ejsThrowArgError(ejs, "Bad args"); return 0; } else { assert(argc == 1 && ejsIs(ejs, argv[0], Number)); count = ejsGetInt(ejs, argv[0]); } if (fp->file == 0) { ejsThrowStateError(ejs, "File not open"); return 0; } if (!(fp->mode & EJS_FILE_READ)) { ejsThrowStateError(ejs, "File not opened for reading"); return 0; } if (count < 0) { // TODO OPT could this be cached in fp->info if (mprGetPathInfo(fp->path, &info) == 0) { count = (int) info.size; count -= (int) mprGetFilePosition(fp->file); } else { count = ME_MAX_BUFFER; } assert(count >= 0); } result = ejsCreateByteArray(ejs, count); if (result == 0) { ejsThrowMemoryError(ejs); return 0; } totalRead = readData(ejs, fp, result, 0, count); if (totalRead < 0) { ejsThrowIOError(ejs, "Cannot read from file: %s", fp->path); return 0; } else if (totalRead == 0) { return ESV(null); } ejsSetByteArrayPositions(ejs, result, 0, totalRead); return (EjsObj*) result; }
/* 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; }
/* Connection callback */ static void webSocketNotify(HttpConn *conn, int event, int arg) { Ejs *ejs; EjsWebSocket *ws; EjsByteArray *ba; EjsAny *data; HttpPacket *packet; MprBuf *content; ssize len; if ((ws = httpGetConnContext(conn)) == 0) { return; } ejs = ws->ejs; if (!ejs->service) { /* Shutting down */ return; } switch (event) { case HTTP_EVENT_STATE: if (arg == HTTP_STATE_CONTENT) { ws->protocol = (char*) httpGetHeader(conn, "Sec-WebSocket-Protocol"); mprTrace(3, "Web socket protocol %s", ws->protocol); onWebSocketEvent(ws, HTTP_EVENT_APP_OPEN, 0, 0); } break; case HTTP_EVENT_READABLE: packet = httpGetPacket(conn->readq); content = packet->content; if (packet->type == WS_MSG_TEXT) { data = ejsCreateStringFromBytes(ejs, mprGetBufStart(content), mprGetBufLength(content)); } else { len = httpGetPacketLength(packet); assert(len > 0); if ((ba = ejsCreateByteArray(ejs, len)) == 0) { return; } memcpy(ba->value, mprGetBufStart(content), len); ejsSetByteArrayPositions(ejs, ba, -1, len); data = ba; } onWebSocketEvent(ws, event, data, packet); break; case HTTP_EVENT_ERROR: if (!ws->error && !ws->closed) { ws->error = 1; onWebSocketEvent(ws, event, 0, 0); ws->closed = 1; onWebSocketEvent(ws, HTTP_EVENT_APP_CLOSE, 0, 0); } break; case HTTP_EVENT_APP_CLOSE: if (!ws->closed) { ws->closed = 1; onWebSocketEvent(ws, event, 0, 0); } break; } }
/* function [get|put|delete|post...](uri = null, ...data): Http */ static EjsHttp *startHttpRequest(Ejs *ejs, EjsHttp *hp, char *method, int argc, EjsObj **argv) { EjsArray *args; EjsByteArray *data; EjsNumber *written; EjsUri *uriObj; HttpConn *conn; ssize nbytes; conn = hp->conn; hp->responseCache = 0; hp->requestContentCount = 0; mprFlushBuf(hp->responseContent); if (argc >= 1 && !ejsIs(ejs, argv[0], Null)) { uriObj = (EjsUri*) argv[0]; hp->uri = httpUriToString(uriObj->uri, HTTP_COMPLETE_URI); } if (argc == 2 && ejsIs(ejs, argv[1], Array)) { args = (EjsArray*) argv[1]; if (args->length > 0) { data = ejsCreateByteArray(ejs, -1); written = ejsWriteToByteArray(ejs, data, 1, &argv[1]); mprPutBlockToBuf(hp->requestContent, (char*) data->value, (int) written->value); mprAddNullToBuf(hp->requestContent); assert(written > 0); } } if (hp->uri == 0) { ejsThrowArgError(ejs, "URL is not defined"); return 0; } if (method && strcmp(hp->method, method) != 0) { hp->method = sclone(method); } if (hp->method == 0) { ejsThrowArgError(ejs, "HTTP Method is not defined"); return 0; } if (hp->certFile) { if (!hp->ssl) { hp->ssl = mprCreateSsl(0); } mprSetSslCertFile(hp->ssl, hp->certFile); if (!hp->keyFile) { ejsThrowStateError(ejs, "Must define a Http.key to use with a certificate"); } mprSetSslKeyFile(hp->ssl, hp->keyFile); } if (hp->caFile) { if (!hp->ssl) { hp->ssl = mprCreateSsl(0); } mprSetSslCaFile(hp->ssl, hp->caFile); } if (httpConnect(conn, hp->method, hp->uri, hp->ssl) < 0) { ejsThrowIOError(ejs, "Cannot issue request for \"%s\"", hp->uri); return 0; } if (mprGetBufLength(hp->requestContent) > 0) { nbytes = httpWriteBlock(conn->writeq, mprGetBufStart(hp->requestContent), mprGetBufLength(hp->requestContent), HTTP_BLOCK); if (nbytes < 0) { ejsThrowIOError(ejs, "Cannot write request data for \"%s\"", hp->uri); return 0; } else if (nbytes > 0) { assert(nbytes == mprGetBufLength(hp->requestContent)); mprAdjustBufStart(hp->requestContent, nbytes); hp->requestContentCount += nbytes; } httpFinalize(conn); } httpNotify(conn, HTTP_EVENT_WRITABLE, 0); if (conn->async) { httpEnableConnEvents(hp->conn); } return hp; }