/* Create an initialized regular expression object. The pattern should include the slash delimiters. For example: /abc/ or /abc/g */ EjsRegExp *ejsCreateRegExp(Ejs *ejs, EjsString *pattern) { EjsRegExp *rp; cchar *errMsg; MprChar *flags; int column, errCode; if (pattern->length == 0 || pattern->value[0] != '/') { ejsThrowArgError(ejs, "Bad regular expression pattern. Must start with '/'"); return 0; } rp = ejsCreateObj(ejs, ESV(RegExp), 0); if (rp != 0) { /* Strip off flags for passing to pcre_compile2 */ rp->pattern = sclone(&pattern->value[1]); if ((flags = wrchr(rp->pattern, '/')) != 0) { rp->options = parseFlags(rp, &flags[1]); *flags = 0; } // TODO - UNICODE is pattern meant to be rp->compiled = pcre_compile2(rp->pattern, rp->options, &errCode, &errMsg, &column, NULL); if (rp->compiled == NULL) { ejsThrowArgError(ejs, "Can't compile regular expression '%s'. Error %s at column %d", rp->pattern, errMsg, column); return 0; } } return rp; }
/* 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); }
static void setHttpPipeline(Ejs *ejs, EjsHttpServer *sp) { EjsString *vs; HttpHost *host; HttpRoute *route; Http *http; HttpStage *stage; cchar *name; int i; assure(sp->endpoint); http = sp->endpoint->http; host = mprGetFirstItem(sp->endpoint->hosts); route = mprGetFirstItem(host->routes); if (sp->outgoingStages) { httpClearRouteStages(route, HTTP_STAGE_TX); for (i = 0; i < sp->outgoingStages->length; i++) { vs = ejsGetProperty(ejs, sp->outgoingStages, i); if (vs && ejsIs(ejs, vs, String)) { name = vs->value; if (httpLookupStage(http, name) == 0) { ejsThrowArgError(ejs, "Cannot find pipeline stage name %s", name); return; } httpAddRouteFilter(route, name, NULL, HTTP_STAGE_TX); } } } if (sp->incomingStages) { httpClearRouteStages(route, HTTP_STAGE_RX); for (i = 0; i < sp->incomingStages->length; i++) { vs = ejsGetProperty(ejs, sp->incomingStages, i); if (vs && ejsIs(ejs, vs, String)) { name = vs->value; if (httpLookupStage(http, name) == 0) { ejsThrowArgError(ejs, "Cannot find pipeline stage name %s", name); return; } httpAddRouteFilter(route, name, NULL, HTTP_STAGE_RX); } } } if (sp->connector) { if ((stage = httpLookupStage(http, sp->connector)) == 0) { ejsThrowArgError(ejs, "Cannot find pipeline stage name %s", sp->connector); return; } route->connector = stage; } }
/* Parse a regular expression string. The string should include the slash delimiters and may contain appended flags. For example: /abc/ or /abc/g */ PUBLIC EjsRegExp *ejsParseRegExp(Ejs *ejs, EjsString *pattern) { EjsRegExp *rp; cchar *errMsg; char *cp, *dp; wchar *flags; int column, errCode; if (pattern->length == 0 || pattern->value[0] != '/') { ejsThrowArgError(ejs, "Bad regular expression pattern. Must start with '/'"); return 0; } if ((rp = ejsCreateObj(ejs, ESV(RegExp), 0)) == 0) { return 0; } /* Strip off flags for passing to pcre_compile2 */ if (pattern->value[0] == '/') { rp->pattern = sclone(&pattern->value[1]); if ((flags = wrchr(rp->pattern, '/')) != 0) { if (flags == rp->pattern) { ejsThrowArgError(ejs, "Bad regular expression pattern. Must end with '/'"); return 0; } rp->options = parseFlags(rp, &flags[1]); *flags = 0; } /* NOTE: we don't expect backquotes to be quoted. That only happens when interpreting literal js code and JSON */ for (dp = cp = rp->pattern; *cp; ) { if (*cp == '\\' && cp[1] == '/') { cp++; } *dp++ = *cp++; } *dp++ = '\0'; } else { rp->pattern = sclone(&pattern->value[1]); } rp->compiled = pcre_compile2(rp->pattern, rp->options, &errCode, &errMsg, &column, NULL); if (rp->compiled == NULL) { ejsThrowArgError(ejs, "Cannot compile regular expression '%s'. Error %s at column %d", rp->pattern, errMsg, column); return 0; } return rp; }
/* Set the length. TODO - what does this do? public override function set length(value: int): void */ static EjsObj *setLength(Ejs *ejs, EjsXML *xml, int argc, EjsObj **argv) { int length; assert(ejsIsXML(ejs, xml)); if (argc != 1) { ejsThrowArgError(ejs, "usage: obj.length = value"); return 0; } length = ejsVarToInteger(ejs, argv[0]); if (length < ap->length) { for (i = length; i < ap->length; i++) { if (ejsSetProperty(ejs, ap, i, ESV(undefined)) < 0) { // TODO - DIAG return 0; } } } else if (length > ap->length) { if (ejsSetProperty(ejs, ap, length - 1, ESV(undefined)) < 0) { // TODO - DIAG return 0; } } ap->length = length; return 0; }
/* Constructor function File(path: Object, options: Object = null) */ static EjsFile *fileConstructor(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsObj *pp, *options; cchar *path; if (argc < 1 || argc > 2) { ejsThrowArgError(ejs, "Bad args"); return 0; } pp = argv[0]; if (ejsIs(ejs, pp, Path)) { path = ((EjsPath*) pp)->value; } else if (ejsIs(ejs, pp, String)) { path = ejsToMulti(ejs, pp); } else { ejsThrowIOError(ejs, "Bad path"); return 0; } fp->path = mprNormalizePath(path); if (argc == 2) { options = (argc >= 2) ? argv[1] : 0; openFile(ejs, fp, 1, &options); } return fp; }
/* Post a message to this worker. Note: the worker is the destination worker which may be the parent. function postMessage(data: Object, ports: Array = null): Void */ static EjsObj *workerPostMessage(Ejs *ejs, EjsWorker *worker, int argc, EjsObj **argv) { EjsString *data; EjsWorker *target; MprDispatcher *dispatcher; Message *msg; if (worker->state >= EJS_WORKER_CLOSED) { ejsThrowStateError(ejs, "Worker has completed"); return 0; } /* Create the event with serialized data in the originating interpreter. It owns the data. */ ejsBlockGC(ejs); if ((data = ejsToJSON(ejs, argv[0], NULL)) == 0) { ejsThrowArgError(ejs, "Cannot serialize message data"); return 0; } if ((msg = createMessage()) == 0) { ejsThrowMemoryError(ejs); return 0; } target = worker->pair; msg->data = ejsToMulti(ejs, data); msg->worker = target; msg->callback = "onmessage"; msg->callbackSlot = ES_Worker_onmessage; dispatcher = target->ejs->dispatcher; mprCreateEvent(dispatcher, "postMessage", 0, doMessage, msg, 0); return 0; }
static EjsObj *xmlListConstructor(Ejs *ejs, EjsObj *thisObj, int argc, EjsObj **argv) { #if FUTURE EjsObj *vp; cchar *str; if (argc == 1) { vp = argv[0]; if (ejsIsObject(vp)) { /* Convert DOM to XML. Not implemented */; } else if (ejsIs(ejs, vp, String)) { str = ((EjsString*) vp)->value; if (str == 0) { return 0; } if (*str == '<') { /* XML Literal */ return loadXmlString(ejs, (EjsXML*) thisObj, str); } else { /* Load from file */ return load(ejs, (EjsXML*) thisObj, argc, argv); } } else { ejsThrowArgError(ejs, "Bad type passed to XML constructor"); return 0; } } #endif return (EjsObj*) thisObj; }
/* * Post a message to this worker. Note: the worker is the destination worker which may be the parent. * * function postMessage(data: Object, ports: Array = null): Void */ static EjsVar *workerPostMessage(Ejs *ejs, EjsWorker *worker, int argc, EjsVar **argv) { EjsVar *data; EjsWorker *target; MprDispatcher *dispatcher; Message *msg; if (worker->state >= EJS_WORKER_CLOSED) { ejsThrowStateError(ejs, "Worker has completed"); return 0; } /* * Create the event with serialized data in the originating interpreter. It owns the data. */ if ((data = ejsSerialize(ejs, argv[0], -1, 0, 0)) == 0) { ejsThrowArgError(ejs, "Can't serialize message data"); return 0; } if ((msg = mprAllocObjZeroed(ejs, Message)) == 0) { ejsThrowMemoryError(ejs); return 0; } target = worker->pair; msg->data = mprStrdup(target->ejs, ejsGetString(data)); msg->worker = target; msg->callback = "onmessage"; msg->callbackSlot = ES_ejs_sys_Worker_onmessage; dispatcher = target->ejs->dispatcher; mprCreateEvent(dispatcher, (MprEventProc) doMessage, 0, MPR_NORMAL_PRIORITY, msg, 0); mprSignalCond(dispatcher->cond); return 0; }
/* function WebSocket(uri: Uri, protocols = null, options) options = { certificate: Path, verify: Boolean, } */ static EjsWebSocket *wsConstructor(Ejs *ejs, EjsWebSocket *ws, int argc, EjsObj **argv) { EjsAny *certificate; bool verify; assert(ejsIsPot(ejs, ws)); ejsLoadHttpService(ejs); ws->ejs = ejs; verify = 0; ws->uri = httpUriToString(((EjsUri*) argv[0])->uri, 0); if (argc >= 2) { if (ejsIs(ejs, argv[1], Array)) { ws->protocols = sclone((ejsToString(ejs, argv[1]))->value); } else if (ejsIs(ejs, argv[1], String)) { ws->protocols = sclone(((EjsString*) argv[1])->value); } else { ws->protocols = sclone("chat"); } } else { ws->protocols = sclone("chat"); } if (*ws->protocols == '\0') { ejsThrowArgError(ejs, "Bad protocol"); return 0; } if (argc >= 3) { ws->frames = ejsGetPropertyByName(ejs, argv[2], EN("frames")) == ESV(true); verify = ejsGetPropertyByName(ejs, argv[2], EN("verify")) == ESV(true); if ((certificate = ejsGetPropertyByName(ejs, argv[2], EN("certificate"))) != 0) { ws->certFile = ejsToMulti(ejs, argv[0]); } } if ((ws->conn = httpCreateConn(MPR->httpService, NULL, ejs->dispatcher)) == 0) { ejsThrowMemoryError(ejs); return 0; } httpSetAsync(ws->conn, 1); httpPrepClientConn(ws->conn, 0); httpSetConnNotifier(ws->conn, webSocketNotify); httpSetWebSocketProtocols(ws->conn, ws->protocols); httpSetConnContext(ws->conn, ws); if (sstarts(ws->uri, "wss")) { ws->ssl = mprCreateSsl(0); mprVerifySslIssuer(ws->ssl, verify); mprVerifySslPeer(ws->ssl, verify); #if FUTURE if (!hp->caFile) { //MOB - Some define for this. hp->caFile = mprJoinPath(mprGetAppDir(), "http-ca.crt"); } mprSetSslCaFile(hp->ssl, hp->caFile); mprSetSslCaFile(hp->ssl, mprJoinPath(mprGetAppDir(), "http-ca.crt")); #endif } startWebSocketRequest(ejs, ws); return ws; }
static void setupTrace(Ejs *ejs, HttpTrace *trace, int dir, EjsObj *options) { EjsArray *extensions; EjsObj *ext; HttpTrace *tp; int i, level, *levels; tp = &trace[dir]; levels = tp->levels; if ((level = getNumOption(ejs, options, "all")) >= 0) { for (i = 0; i < HTTP_TRACE_MAX_ITEM; i++) { levels[i] = level; } } else { levels[HTTP_TRACE_CONN] = getNumOption(ejs, options, "conn"); levels[HTTP_TRACE_FIRST] = getNumOption(ejs, options, "first"); levels[HTTP_TRACE_HEADER] = getNumOption(ejs, options, "headers"); levels[HTTP_TRACE_BODY] = getNumOption(ejs, options, "body"); } tp->size = getNumOption(ejs, options, "size"); if ((extensions = (EjsArray*) ejsGetPropertyByName(ejs, options, EN("include"))) != 0) { if (!ejsIs(ejs, extensions, Array)) { ejsThrowArgError(ejs, "include is not an array"); return; } tp->include = mprCreateHash(0, 0); for (i = 0; i < extensions->length; i++) { if ((ext = ejsGetProperty(ejs, extensions, i)) != 0) { mprAddKey(tp->include, ejsToMulti(ejs, ejsToString(ejs, ext)), ""); } } } if ((extensions = (EjsArray*) ejsGetPropertyByName(ejs, options, EN("exclude"))) != 0) { if (!ejsIs(ejs, extensions, Array)) { ejsThrowArgError(ejs, "exclude is not an array"); return; } tp->exclude = mprCreateHash(0, 0); for (i = 0; i < extensions->length; i++) { if ((ext = ejsGetProperty(ejs, extensions, i)) != 0) { mprAddKey(tp->exclude, ejsToMulti(ejs, ejsToString(ejs, ext)), MPR->emptyString); } } } }
/* Constructor function open(options: Object = null): File NOTE: options can be an options hash or as mode string */ static EjsObj *openFile(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsObj *options; cchar *mode; int perms, omode; if (argc < 0 || argc > 1) { ejsThrowArgError(ejs, "Bad args"); return 0; } options = argv[0]; if (argc == 0 || !ejsIsDefined(ejs, options)) { omode = O_RDONLY | O_BINARY; perms = EJS_FILE_PERMS; fp->mode = EJS_FILE_READ; mode = "r"; } else { if (ejsIs(ejs, options, String)) { mode = ejsToMulti(ejs, options); perms = EJS_FILE_PERMS; } else { perms = ejsGetNumOption(ejs, options, "permissions", EJS_FILE_PERMS, 1); mode = getStrOption(ejs, options, "mode", "r", 1); if (ejs->exception) { return 0; } } omode = mapMode(mode); if (!(omode & O_WRONLY)) { fp->mode |= EJS_FILE_READ; } if (omode & (O_WRONLY | O_RDWR)) { fp->mode |= EJS_FILE_WRITE; } } fp->modeString = sclone(mode); fp->perms = perms; if (fp->file) { mprCloseFile(fp->file); } fp->file = mprOpenFile(fp->path, omode, perms); if (fp->file == 0) { ejsThrowIOError(ejs, "Cannot open %s", fp->path); return 0; } if (options) { ejsSetPathAttributes(ejs, fp->path, options); } #if ME_CC_MMU && FUTURE mprGetPathInfo(&fp->info); fp->mapped = mapFile(fp, fp->info.size, MPR_MAP_READ | MPR_MAP_WRITE); #endif fp->mode |= EJS_FILE_OPEN; return (EjsObj*) fp; }
static cchar *getStrOption(Ejs *ejs, EjsObj *options, cchar *field, cchar *defaultValue, bool optional) { EjsObj *vp; EjsString *str; vp = ejsGetPropertyByName(ejs, options, EN(field)); if (vp == 0) { if (optional) { return sclone(defaultValue); } ejsThrowArgError(ejs, "Required option %s is missing", field); return 0; } str = ejsToString(ejs, vp); if (!ejsIs(ejs, str, String)) { ejsThrowArgError(ejs, "Bad option type for field \"%s\"", field); return 0; } return ejsToMulti(ejs, str); }
// TODO - rename static int ejsGetNumOption(Ejs *ejs, EjsObj *options, cchar *field, int defaultValue, bool optional) { EjsObj *vp; EjsNumber *num; vp = ejsGetPropertyByName(ejs, options, EN(field)); if (vp == 0) { if (optional) { return defaultValue; } ejsThrowArgError(ejs, "Required option \"%s\" is missing", field); return 0; } num = ejsToNumber(ejs, vp); if (!ejsIs(ejs, num, Number)) { ejsThrowArgError(ejs, "Bad option type for field \"%s\"", field); return 0; } return (int) num->value; }
/* * native static function callback(fn: Function): Void */ static EjsVar *setRedlineCallback(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv) { mprAssert(argc == 1 && ejsIsFunction(argv[0])); if (!ejsIsFunction(argv[0])) { ejsThrowArgError(ejs, "Callaback is not a function"); return 0; } ejs->memoryCallback = (EjsFunction*) argv[0]; return 0; }
/* native function XML(value: Object = null) */ static EjsObj *xmlConstructor(Ejs *ejs, EjsXML *thisObj, int argc, EjsObj **argv) { EjsObj *arg, *vp; wchar *str; // TODO - should be also able to handle a File object if (thisObj == 0) { /* Called as a function - cast the arg */ if (argc > 0) { if ((arg = ejsCast(ejs, argv[0], String)) == 0) { return 0; } } thisObj = ejsCreateXML(ejs, 0, N(NULL, NULL), NULL, NULL); } if (argc == 0) { return (EjsObj*) thisObj; } arg = argv[0]; assert(arg); if (!ejsIsDefined(ejs, arg)) { return (EjsObj*) thisObj; } arg = ejsCast(ejs, argv[0], String); if (arg && ejsIs(ejs, arg, String)) { str = ((EjsString*) arg)->value; if (str == 0) { return 0; } while (isspace((uchar) *str)) str++; if (*str == '<') { /* XML Literal */ ejsLoadXMLString(ejs, thisObj, (EjsString*) arg); } else { /* Load from file */ loadXml(ejs, thisObj, argc, argv); } } else if (arg && ejsIsXML(ejs, arg)) { if ((vp = xmlToString(ejs, argv[0], 0, NULL)) != 0) { ejsLoadXMLString(ejs, thisObj, (EjsString*) vp); } } else { ejsThrowArgError(ejs, "Bad type passed to XML constructor"); return 0; } return (EjsObj*) thisObj; }
/* Constructor to create an iterator using a scripted next(). public function Iterator(obj, f, deep, ...namespaces) */ static EjsObj *iteratorConstructor(Ejs *ejs, EjsIterator *ip, int argc, EjsObj **argv) { if (argc != 2 || !ejsIsFunction(ejs, argv[1])) { ejsThrowArgError(ejs, "usage: Iterator(obj, function)"); return 0; } ip->target = argv[0]; ip->next = (EjsFunction*) argv[1]; mprAssert(ip->nativeNext == 0); return ip; }
/* function close(status: Number = 1000, reason: String? = ""): Void */ static EjsObj *ws_close(Ejs *ejs, EjsWebSocket *ws, int argc, EjsObj **argv) { HttpConn *conn; char *reason; int status; conn = ws->conn; if (conn) { status = argc == 0 ? WS_STATUS_OK : ejsGetInt(ejs, argv[0]); if (status <= 999 || status >= WS_STATUS_MAX || status == WS_STATUS_NO_STATUS || status == WS_STATUS_COMMS_ERROR) { ejsThrowArgError(ejs, "Bad status"); return 0; } reason = (argc >= 1) ? ejsToMulti(ejs, argv[1]): 0; if (slen(reason) >= 124) { ejsThrowArgError(ejs, "Close reason is too long. Must be less than 124 bytes"); return 0; } httpSendClose(conn, status, reason); } return 0; }
/* native static function set newQuota(quota: Number): Void */ static EjsObj *gc_set_newQuota(Ejs *ejs, EjsObj *thisObj, int argc, EjsObj **argv) { int quota; assure(argc == 1 && ejsIs(ejs, argv[0], Number)); quota = ejsGetInt(ejs, argv[0]); if (quota < MPR_NEW_QUOTA && quota != 0) { ejsThrowArgError(ejs, "Bad work quota"); return 0; } mprGetMpr()->heap->newQuota = quota; return 0; }
/* function set method(value: String): Void */ static EjsObj *http_set_method(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { cchar *method; method = ejsToMulti(ejs, argv[0]); if (strcmp(method, "DELETE") != 0 && strcmp(method, "GET") != 0 && strcmp(method, "HEAD") != 0 && strcmp(method, "OPTIONS") != 0 && strcmp(method, "POST") != 0 && strcmp(method, "PUT") != 0 && strcmp(method, "TRACE") != 0) { ejsThrowArgError(ejs, "Unknown HTTP method"); return 0; } hp->method = ejsToMulti(ejs, argv[0]); return 0; }
/* 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; }
/* Read data as a string function readString(count: Number = -1): String */ static EjsString *readFileString(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsString *result; MprPath info; ssize totalRead; int count; 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); } if ((result = ejsCreateBareString(ejs, count)) == NULL) { ejsThrowMemoryError(ejs); return 0; } totalRead = mprReadFile(fp->file, result->value, count); if (totalRead != count) { ejsThrowIOError(ejs, "Cannot read from file: %s", fp->path); return 0; } return ejsInternString(result); }
/* Create an initialized regular expression object. The pattern should NOT include the slash delimiters. */ PUBLIC EjsRegExp *ejsCreateRegExp(Ejs *ejs, cchar *pattern, cchar *flags) { EjsRegExp *rp; cchar *errMsg; int column, errCode; if ((rp = ejsCreateObj(ejs, ESV(RegExp), 0)) == 0) { return 0; } rp->pattern = sclone(pattern); rp->options = parseFlags(rp, (wchar*) flags); rp->compiled = pcre_compile2(rp->pattern, rp->options, &errCode, &errMsg, &column, NULL); if (rp->compiled == NULL) { ejsThrowArgError(ejs, "Cannot compile regular expression '%s'. Error %s at column %d", rp->pattern, errMsg, column); return 0; } return rp; }
static EjsRegExp *regex_Constructor(Ejs *ejs, EjsRegExp *rp, int argc, EjsObj **argv) { cchar *errMsg; int column, errCode; rp->pattern = wclone(ejsToString(ejs, argv[0])->value); rp->options = PCRE_JAVASCRIPT_COMPAT; if (argc == 2) { rp->options |= parseFlags(rp, ejsToString(ejs, argv[1])->value); } if (rp->compiled) { free(rp->compiled); } if ((rp->compiled = pcre_compile2(rp->pattern, rp->options, &errCode, &errMsg, &column, NULL)) == 0) { ejsThrowArgError(ejs, "Cannot compile regular expression '%s'. Error %s at column %d", rp->pattern, errMsg, column); return 0; } return rp; }
/** Sort the array using the supplied compare function function sort(compare: Function = null, direction: Number = 1): Array Where compare is defined as: function compare(a,b): Number */ PUBLIC EjsArray *ejsSortArray(Ejs *ejs, EjsArray *ap, int argc, EjsObj **argv) { EjsFunction *compare; int direction; if (ap->length <= 1) { return ap; } compare = (EjsFunction*) ((argc >= 1) ? argv[0]: NULL); if (compare == ESV(null)) { compare = 0; } if (compare && !ejsIsFunction(ejs, compare)) { ejsThrowArgError(ejs, "Compare argument is not a function"); return 0; } direction = (argc >= 2) ? ejsGetInt(ejs, argv[1]) : 1; quickSort(ejs, ap, compare, direction, 0, ap->length - 1); return ap; }
static EjsObj *saveXml(Ejs *ejs, EjsXML *xml, int argc, EjsObj **argv) { MprBuf *buf; MprFile *file; char *filename; ssize bytes, len; if (argc != 1 || !ejsIs(ejs, argv[0], String)) { ejsThrowArgError(ejs, "Bad args. Usage: save(filename);"); return 0; } filename = awtom(((EjsString*) argv[0])->value, NULL); /* Create a buffer to hold the output. All in memory. */ buf = mprCreateBuf(ME_MAX_BUFFER, -1); mprPutStringToBuf(buf, "<?xml version=\"1.0\"?>\n"); if (ejsXMLToBuf(ejs, buf, xml, 0) < 0) { return 0; } file = mprOpenFile(filename, O_CREAT | O_TRUNC | O_WRONLY | O_TEXT, 0664); if (file == 0) { ejsThrowIOError(ejs, "Cannot open: %s, %d", filename, mprGetOsError(ejs)); return 0; } len = mprGetBufLength(buf); bytes = mprWriteFile(file, buf->start, len); if (bytes != len) { ejsThrowIOError(ejs, "Cannot write to: %s", filename); mprCloseFile(file); return 0; } mprWriteFile(file, "\n", 1); mprCloseFile(file); return 0; }
/* function setHeader(key: String, value: String, overwrite: Boolean = true): Void */ static EjsObj *http_setHeader(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { HttpConn *conn; cchar *key, *value; bool overwrite; assert(argc >= 2); conn = hp->conn; if (conn->state >= HTTP_STATE_CONNECTED) { ejsThrowArgError(ejs, "Cannot update request headers once the request has started"); return 0; } key = ejsToMulti(ejs, argv[0]); value = ejsToMulti(ejs, argv[1]); overwrite = (argc == 3) ? ejsGetBoolean(ejs, argv[2]) : 1; if (overwrite) { httpSetHeaderString(hp->conn, key, value); } else { httpAppendHeaderString(hp->conn, key, value); } return 0; }
/* * Insert, remove or replace array elements. Return the removed elements. * * function splice(start: Number, deleteCount: Number, ...values): Array * */ static EjsVar *spliceArray(Ejs *ejs, EjsArray *ap, int argc, EjsVar **argv) { EjsArray *result, *values; EjsVar **data, **dest, **items; int start, deleteCount, i, delta, endInsert, oldLen; mprAssert(1 <= argc && argc <= 3); start = ejsGetInt(argv[0]); deleteCount = ejsGetInt(argv[1]); values = (EjsArray*) argv[2]; if (ap->length == 0) { if (deleteCount <= 0) { return (EjsVar*) ap; } ejsThrowArgError(ejs, "Array is empty"); return 0; } if (start < 0) { start += ap->length; } if (start < 0) { start = 0; } if (start >= ap->length) { start = ap->length - 1; } if (deleteCount < 0) { deleteCount = ap->length - start + 1; } if (deleteCount > ap->length) { deleteCount = ap->length; } result = ejsCreateArray(ejs, deleteCount); if (result == 0) { ejsThrowMemoryError(ejs); return 0; } data = ap->data; dest = result->data; items = values->data; /* * Copy removed items to the result */ for (i = 0; i < deleteCount; i++) { dest[i] = data[i + start]; } oldLen = ap->length; delta = values->length - deleteCount; if (delta > 0) { /* * Make room for items to insert */ if (growArray(ejs, ap, ap->length + delta) < 0) { return 0; } data = ap->data; endInsert = start + delta; for (i = ap->length - 1; i >= endInsert; i--) { data[i] = data[i - delta]; } } else { ap->length += delta; } /* * Copy in new values */ for (i = 0; i < values->length; i++) { data[start + i] = items[i]; } /* * Remove holes */ if (delta < 0) { for (i = start + values->length; i < oldLen; i++) { data[i] = data[i - delta]; } } return (EjsVar*) result; }
/* 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; }
/* function listen(endpoint): Void An endpoint can be either a "port" or "ip:port", or null. If hosted, this call does little -- just add to the ejs->httpServers list. */ static EjsVoid *hs_listen(Ejs *ejs, EjsHttpServer *sp, int argc, EjsObj **argv) { HttpEndpoint *endpoint; HttpHost *host; HttpRoute *route; EjsString *address; EjsObj *loc; EjsPath *documents; if (!sp->hosted) { loc = (argc >= 1) ? argv[0] : ESV(null); if (loc != ESV(null)) { address = ejsToString(ejs, loc); // TODO should permit https://IP:PORT mprParseSocketAddress(address->value, &sp->ip, &sp->port, NULL, 0); } else { address = 0; } if (address == 0) { ejsThrowArgError(ejs, "Missing listen endpoint"); return 0; } if (sp->endpoint) { httpDestroyEndpoint(sp->endpoint); sp->endpoint = 0; } /* The endpoint uses the ejsDispatcher. This is VERY important. All connections will inherit this also. This serializes all activity on one dispatcher. */ if ((endpoint = httpCreateEndpoint(sp->ip, sp->port, ejs->dispatcher)) == 0) { ejsThrowIOError(ejs, "Cannot create Http endpoint object"); return 0; } sp->endpoint = endpoint; host = httpCreateHost(NULL); httpSetHostName(host, sfmt("%s:%d", sp->ip, sp->port)); route = httpCreateConfiguredRoute(host, 1); httpAddRouteMethods(route, "DELETE, HEAD, OPTIONS, PUT"); httpAddRouteHandler(route, "ejsHandler", ""); httpSetRouteTarget(route, "run", 0); httpFinalizeRoute(route); httpSetHostDefaultRoute(host, route); httpAddHostToEndpoint(endpoint, host); if (sp->limits) { ejsSetHttpLimits(ejs, endpoint->limits, sp->limits, 1); } if (sp->incomingStages || sp->outgoingStages || sp->connector) { setHttpPipeline(ejs, sp); } if (sp->ssl) { httpSecureEndpoint(endpoint, sp->ssl); } if (sp->name) { httpSetHostName(host, sp->name); } httpSetSoftware(EJS_HTTPSERVER_NAME); httpSetEndpointAsync(endpoint, sp->async); httpSetEndpointContext(endpoint, sp); httpSetEndpointNotifier(endpoint, stateChangeNotifier); /* This is only required when http is using non-ejs handlers and/or filters */ documents = ejsGetProperty(ejs, sp, ES_ejs_web_HttpServer_documents); if (ejsIs(ejs, documents, Path)) { httpSetRouteDocuments(route, documents->value); } #if KEEP // TODO -- what to do with home? // TODO - if removed, then the "home" property should be removed? home = ejsGetProperty(ejs, sp, ES_ejs_web_HttpServer_home); if (ejsIs(ejs, home, Path)) { httpSetRoutDir(host, home->value); } #endif if (httpStartEndpoint(endpoint) < 0) { httpDestroyEndpoint(sp->endpoint); sp->endpoint = 0; ejsThrowIOError(ejs, "Cannot listen on %s", address->value); } } if (ejs->httpServers == 0) { ejs->httpServers = mprCreateList(-1, MPR_LIST_STATIC_VALUES); } /* Remove to make sure old listening() registrations are removed */ mprRemoveItem(ejs->httpServers, sp); mprAddItem(ejs->httpServers, sp); return 0; }