static HttpUri *toHttpUri(Ejs *ejs, EjsObj *arg, int dup) { HttpUri *uri; if (ejsIs(ejs, arg, String)) { uri = httpCreateUri(ejsToMulti(ejs, arg), 0); } else if (ejsIs(ejs, arg, Uri)) { if (dup) { uri = httpCloneUri(((EjsUri*) arg)->uri, 0); } else { uri = ((EjsUri*) arg)->uri; } } else if (ejsIs(ejs, arg, Path)) { uri = httpCreateUri(((EjsPath*) arg)->value, 0); } else if (ejsGetLength(ejs, arg) > 0) { uri = createHttpUriFromHash(ejs, arg, 0); } else { arg = (EjsObj*) ejsToString(ejs, arg); uri = httpCreateUri(ejsToMulti(ejs, arg), 0); } return uri; }
/* function form(uri: String = null, formData: Object = null): Http Issue a POST method with form data */ static EjsHttp *http_form(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { EjsObj *data; if (argc == 2 && !ejsIs(ejs, argv[1], Null)) { /* Prep here to reset the state. The ensures the current headers will be preserved. Users may have called setHeader to define custom headers. Users must call reset if they want to clear prior headers. */ httpPrepClientConn(hp->conn, 1); mprFlushBuf(hp->requestContent); data = argv[1]; if (ejsGetLength(ejs, data) > 0) { prepForm(ejs, hp, NULL, data); } else { mprPutStringToBuf(hp->requestContent, ejsToMulti(ejs, data)); } mprAddNullToBuf(hp->requestContent); httpSetHeader(hp->conn, "Content-Type", "application/x-www-form-urlencoded"); /* Ensure this gets recomputed */ httpRemoveHeader(hp->conn, "Content-Length"); } return startHttpRequest(ejs, hp, "POST", argc, argv); }
static int process(EjsMod *mp, cchar *output, int argc, char **argv) { Ejs *ejs; EjsModule *module; MprFile *outfile; MprList *depends; int count, i, next, moduleCount; ejs = mp->ejs; if (output) { outfile = mprOpenFile(output, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0664); } else { outfile = 0; } ejs->loaderCallback = (mp->listing) ? emListingLoadCallback : 0; mp->firstGlobal = ejsGetLength(ejs, ejs->global); /* For each module on the command line */ for (i = 0; i < argc && !mp->fatalError; i++) { moduleCount = mprGetListLength(ejs->modules); ejs->loadData = mp; if (!mprPathExists(argv[i], R_OK)) { mprError("Can't access module %s", argv[i]); return EJS_ERR; } if ((ejsLoadModule(ejs, ejsCreateStringFromAsc(ejs, argv[i]), -1, -1, EJS_LOADER_NO_INIT)) < 0) { ejs->loaderCallback = NULL; mprError("Can't load module %s\n%s", argv[i], ejsGetErrorMsg(ejs, 0)); return EJS_ERR; } if (mp->genSlots) { for (next = moduleCount; (module = mprGetNextItem(ejs->modules, &next)) != 0; ) { emCreateSlotFiles(mp, module, outfile); } } if (mp->depends) { depends = mprCreateList(-1, 0); for (next = moduleCount; (module = mprGetNextItem(ejs->modules, &next)) != 0; ) { getDepends(ejs, depends, module); } count = mprGetListLength(depends); for (next = 1; (module = mprGetNextItem(depends, &next)) != 0; ) { int version = module->version; mprPrintf("%@-%d.%d.%d%s", module->name, EJS_MAJOR(version), EJS_MINOR(version), EJS_PATCH(version), (next >= count) ? "" : " "); } printf("\n"); } } if (mp->html || mp->xml) { emCreateDoc(mp); } mprCloseFile(outfile); return 0; }
/* Prepare form data as a series of key-value pairs. Data is formatted according to www-url-encoded specs by mprSetHttpFormData. Objects are flattened into a one level key/value pairs. Keys can have embedded "." separators. E.g. name=value&address=77%20Park%20Lane */ static void prepForm(Ejs *ejs, EjsHttp *hp, cchar *prefix, EjsObj *data) { EjsName qname; EjsObj *vp; EjsString *value; cchar *key, *sep, *vstr; char *encodedKey, *encodedValue, *newPrefix, *newKey; int i, count; count = ejsGetLength(ejs, data); for (i = 0; i < count; i++) { if (ejsIs(ejs, data, Array)) { key = itos(i); } else { qname = ejsGetPropertyName(ejs, data, i); key = ejsToMulti(ejs, qname.name); } vp = ejsGetProperty(ejs, data, i); if (vp == 0) { continue; } if (ejsGetLength(ejs, vp) > 0) { if (prefix) { newPrefix = sfmt("%s.%s", prefix, key); prepForm(ejs, hp, newPrefix, vp); } else { prepForm(ejs, hp, key, vp); } } else { value = ejsToString(ejs, vp); sep = (mprGetBufLength(hp->requestContent) > 0) ? "&" : ""; if (prefix) { newKey = sjoin(prefix, ".", key, NULL); encodedKey = mprUriEncode(newKey, MPR_ENCODE_URI_COMPONENT); } else { encodedKey = mprUriEncode(key, MPR_ENCODE_URI_COMPONENT); } vstr = ejsToMulti(ejs, value); encodedValue = mprUriEncode(vstr, MPR_ENCODE_URI_COMPONENT); mprPutToBuf(hp->requestContent, "%s%s=%s", sep, encodedKey, encodedValue); } } }
/* List a class (type) */ static void lstClass(EjsMod *mp, EjsModule *module, int slotNum, EjsType *klass, int attributes) { Ejs *ejs; ejs = mp->ejs; mprFprintf(mp->file, "\n"); if (klass->baseType) { mprFprintf(mp->file, "CLASS: %sclass %@ extends %@\n", getAttributeString(mp, attributes), klass->qname.name, klass->baseType->qname.name); } else { mprFprintf(mp->file, "CLASS: %sclass %@\n", getAttributeString(mp, attributes), klass->qname.name); } leadin(mp, module, 1, 0); mprFprintf(mp->file, " # Class Details: %d class traits, %d prototype (instance) traits, %s, requested slot %d\n", ejsGetLength(ejs, (EjsObj*) klass), klass->prototype ? ejsGetLength(ejs, klass->prototype) : 0, klass->hasInstanceVars ? "has-state": "", slotNum); }
/* Resolve empty XML list objects to an actual XML object. This is used by SetPropertyByName to find the actual object to update. This method resolves the value of empty XMLLists. If the XMLList is not empty, the list will be returned. If list is empty, this method attempts to create an element based on the list targetObject and targetProperty. */ static EjsXML *resolve(Ejs *ejs, EjsXML *xml) { EjsXML *targetObject, *targetPropertyList; if (!ejsIsXML(ejs, xml) || xml->kind != EJS_XML_LIST) { /* Resolved to an XML object */ return xml; } if (mprGetListLength(xml->elements) > 0) { /* Resolved to a list of items */ return xml; } if (xml->targetObject == 0 || xml->targetProperty.name == NULL || xml->targetProperty.name->value[0] == '*') { /* End of chain an no more target objects */ return 0; } targetObject = resolve(ejs, xml->targetObject); if (targetObject == 0) { return 0; } // TODO - OPT. targetPropertyList is also being created below. targetPropertyList = ejsGetPropertyByName(ejs, (EjsObj*) targetObject, xml->targetProperty); if (targetPropertyList == 0) { return 0; } if (ejsGetLength(ejs, (EjsObj*) targetPropertyList) == 0) { /* Property does not exist in the target. */ if (targetObject->kind == EJS_XML_LIST && ejsGetLength(ejs, (EjsObj*) targetObject) > 1) { return 0; } /* Create the property as an element (The text value will be optimized away). */ ejsSetPropertyByName(ejs, targetObject, xml->targetProperty, ESV(empty)); targetPropertyList = ejsGetPropertyByName(ejs, (EjsObj*) targetObject, xml->targetProperty); } return targetPropertyList; }
/* Set an alpha property by name. */ static int setAlphaPropertyByName(Ejs *ejs, EjsXML *list, EjsName qname, EjsObj *value) { EjsXML *elt, *targetObject; int count; targetObject = 0; count = ejsGetLength(ejs, (EjsObj*) list); if (count > 1) { // TODO - why no error in spec? assure(0); return 0; } if (count == 0) { /* Empty list so resolve the real target object and append it to the list. */ targetObject = resolve(ejs, list); if (targetObject == 0) { return 0; } if (ejsGetLength(ejs, (EjsObj*) targetObject) != 1) { return 0; } ejsAppendToXML(ejs, list, targetObject); } /* Update the element */ assure(ejsGetLength(ejs, (EjsObj*) list) == 1); elt = mprGetItem(list->elements, 0); // TODO OPT - GetFirstItem assure(elt); ejsSetPropertyByName(ejs, elt, qname, value); return 0; }
static EjsUri *completeUri(Ejs *ejs, EjsUri *up, EjsObj *missing, int includeQuery) { EjsUri *missingUri; if (!ejsIsDefined(ejs, missing)) { missingUri = 0; } else if (ejsGetLength(ejs, missing) > 0) { missingUri = ejsCreateObj(ejs, ESV(Uri), 0); missingUri->uri = createHttpUriFromHash(ejs, missing, HTTP_COMPLETE_URI); } else { missingUri = ejsToUri(ejs, missing); } if (missingUri == 0) { if (!includeQuery) { up->uri->query = NULL; } httpCompleteUri(up->uri, NULL); } else { httpCompleteUri(up->uri, missingUri->uri); } return up; }
/* Convert an arg to a URI. Can handle strings, paths, URIs and object hashes. Will cast all else to strings and then parse. */ static EjsUri *castToUri(Ejs *ejs, EjsObj *arg) { EjsUri *up; up = ejsCreateObj(ejs, ESV(Uri), 0); if (ejsIs(ejs, arg, String)) { up->uri = httpCreateUri(up, ejsToMulti(ejs, arg), 0); } else if (ejsIs(ejs, arg, Uri)) { up->uri = httpCloneUri(((EjsUri*) arg)->uri, 0); } else if (ejsIs(ejs, arg, Path)) { ustr = ((EjsPath*) arg)->path; up->uri = httpCreateUri(up, ustr, 0); } else if (ejsGetLength(ejs, arg) > 0) { up->uri = createHttpUriFromHash(ejs, up, arg, 0); } else { arg = (EjsObj) ejsToString(ejs, arg); up->uri = httpCreateUri(up, ejsToMulti(ejs, arg), 0); } return up; }
static EjsString *serialize(Ejs *ejs, EjsAny *vp, Json *json) { EjsName qname; EjsFunction *fn; EjsString *result, *sv; EjsTrait *trait; EjsObj *pp, *obj, *replacerArgs[2]; wchar *cp; cchar *key; int c, isArray, i, count, slotNum, quotes; /* The main code below can handle Arrays, Objects, objects derrived from Object and also native classes with properties. All others just use toString. */ count = ejsIsPot(ejs, vp) ? ejsGetLength(ejs, vp) : 0; if (count == 0 && TYPE(vp) != ESV(Object) && TYPE(vp) != ESV(Array)) { // OPT - need some flag for this test. if (!ejsIsDefined(ejs, vp) || ejsIs(ejs, vp, Boolean) || ejsIs(ejs, vp, Number)) { return ejsToString(ejs, vp); } else if (json->regexp) { return ejsToString(ejs, vp); } else { return ejsToLiteralString(ejs, vp); } } obj = vp; json->nest++; if (json->buf == 0) { json->buf = mprCreateBuf(0, 0); mprAddRoot(json->buf); } isArray = ejsIs(ejs, vp, Array); mprPutCharToWideBuf(json->buf, isArray ? '[' : '{'); if (json->pretty) { mprPutCharToWideBuf(json->buf, '\n'); } if (++ejs->serializeDepth <= json->depth && !VISITED(obj)) { SET_VISITED(obj, 1); for (slotNum = 0; slotNum < count && !ejs->exception; slotNum++) { trait = ejsGetPropertyTraits(ejs, obj, slotNum); if (trait && (trait->attributes & (EJS_TRAIT_HIDDEN | EJS_TRAIT_DELETED | EJS_FUN_INITIALIZER | EJS_FUN_MODULE_INITIALIZER)) && !json->hidden) { continue; } pp = ejsGetProperty(ejs, obj, slotNum); if (ejs->exception) { SET_VISITED(obj, 0); json->nest--; return 0; } if (pp == 0) { continue; } if (isArray) { key = itos(slotNum); qname.name = ejsCreateStringFromAsc(ejs, key); qname.space = ESV(empty); } else { qname = ejsGetPropertyName(ejs, vp, slotNum); } quotes = json->quotes; if (!quotes) { // UNICODE for (cp = qname.name->value; cp < &qname.name->value[qname.name->length]; cp++) { if (!isalnum((uchar) *cp) && *cp != '_') { quotes = 1; break; } } } if (json->pretty) { for (i = 0; i < ejs->serializeDepth; i++) { mprPutStringToWideBuf(json->buf, json->indent); } } if (!isArray) { if (json->namespaces) { if (qname.space != ESV(empty)) { mprPutToBuf(json->buf, "\"%@\"::", qname.space); } } if (quotes) { mprPutCharToWideBuf(json->buf, '"'); } for (cp = qname.name->value; cp && *cp; cp++) { c = *cp; if (c == '"' || c == '\\') { mprPutCharToWideBuf(json->buf, '\\'); mprPutCharToWideBuf(json->buf, c); } else { mprPutCharToWideBuf(json->buf, c); } } if (quotes) { mprPutCharToWideBuf(json->buf, '"'); } mprPutCharToWideBuf(json->buf, ':'); if (json->pretty) { mprPutCharToWideBuf(json->buf, ' '); } } fn = (EjsFunction*) ejsGetPropertyByName(ejs, TYPE(pp)->prototype, N(NULL, "toJSON")); // OPT - check that this is going directly to serialize most of the time if (!ejsIsFunction(ejs, fn) || (fn->isNativeProc && fn->body.proc == (EjsProc) ejsObjToJSON)) { sv = serialize(ejs, pp, json); } else { sv = (EjsString*) ejsRunFunction(ejs, fn, pp, 1, &json->options); } if (sv == 0 || !ejsIs(ejs, sv, String)) { if (ejs->exception) { ejsThrowTypeError(ejs, "Cannot serialize property %@", qname.name); SET_VISITED(obj, 0); return 0; } } else { if (json->replacer) { replacerArgs[0] = (EjsObj*) qname.name; replacerArgs[1] = (EjsObj*) sv; /* function replacer(key: String, value: String): String */ sv = ejsRunFunction(ejs, json->replacer, obj, 2, (EjsObj**) replacerArgs); } mprPutBlockToBuf(json->buf, sv->value, sv->length * sizeof(wchar)); } if ((slotNum + 1) < count || json->commas) { mprPutCharToWideBuf(json->buf, ','); } if (json->pretty) { mprPutCharToWideBuf(json->buf, '\n'); } } SET_VISITED(obj, 0); } --ejs->serializeDepth; if (json->pretty) { for (i = ejs->serializeDepth; i > 0; i--) { mprPutStringToWideBuf(json->buf, json->indent); } } mprPutCharToWideBuf(json->buf, isArray ? ']' : '}'); mprAddNullToWideBuf(json->buf); if (--json->nest == 0) { result = ejsCreateString(ejs, mprGetBufStart(json->buf), mprGetBufLength(json->buf) / sizeof(wchar)); mprRemoveRoot(json->buf); } else { result = 0; } return result; }
/* List the various property slot assignments */ static void lstSlotAssignments(EjsMod *mp, EjsModule *module, EjsObj *parent, int slotNum, EjsObj *obj) { Ejs *ejs; EjsTrait *trait; EjsType *type; EjsObj *vp; EjsPot *prototype; EjsFunction *fun; EjsBlock *block; EjsName qname; int i, numInherited, count; mprAssert(obj); mprAssert(module); ejs = mp->ejs; if (VISITED(obj)) { return; } SET_VISITED(obj, 1); if (obj == ejs->global) { mprFprintf(mp->file, "\n#\n" "# Global slot assignments (Num prop %d)\n" "#\n", ejsGetLength(ejs, obj)); /* List slots for global */ for (i = module->firstGlobal; i < module->lastGlobal; i++) { trait = ejsGetPropertyTraits(ejs, ejs->global, i); qname = ejsGetPropertyName(ejs, ejs->global, i); if (qname.name == 0) { continue; } lstVarSlot(mp, module, &qname, trait, i); } /* List slots for the initializer */ fun = (EjsFunction*) module->initializer; if (fun) { mprFprintf(mp->file, "\n#\n" "# Initializer slot assignments (Num prop %d)\n" "#\n", ejsGetLength(ejs, (EjsObj*) fun)); count = ejsGetLength(ejs, (EjsObj*) fun); for (i = 0; i < count; i++) { trait = ejsGetPropertyTraits(ejs, (EjsObj*) fun, i); qname = ejsGetPropertyName(ejs, (EjsObj*) fun, i); if (qname.name == 0) { continue; } mprAssert(trait); lstVarSlot(mp, module, &qname, trait, i); } } } else if (ejsIsFunction(ejs, obj)) { fun = (EjsFunction*) obj; count = ejsGetLength(ejs, (EjsObj*) obj); if (count > 0) { mprFprintf(mp->file, "\n#\n" "# Local slot assignments for the \"%@\" function (Num slots %d)\n" "#\n", fun->name, count); for (i = 0; i < count; i++) { trait = ejsGetPropertyTraits(ejs, obj, i); mprAssert(trait); qname = ejsGetPropertyName(ejs, obj, i); lstVarSlot(mp, module, &qname, trait, i); } } } else if (ejsIsType(ejs, obj)) { /* Types */ type = (EjsType*) obj; mprFprintf(mp->file, "\n#\n" "# Class slot assignments for the \"%@\" class (Num slots %d)\n" "#\n", type->qname.name, ejsGetLength(ejs, (EjsObj*) type)); count = ejsGetLength(ejs, (EjsObj*) type); for (i = 0; i < count; i++) { trait = ejsGetPropertyTraits(ejs, (EjsObj*) type, i); mprAssert(trait); qname = ejsGetPropertyName(ejs, obj, i); lstVarSlot(mp, module, &qname, trait, i); } prototype = type->prototype; if (type->baseType && type->baseType->prototype) { numInherited = ejsGetLength(ejs, type->baseType->prototype); } else { numInherited = 0; } mprFprintf(mp->file, "\n#\n" "# Instance slot assignments for the \"%@\" class (Num prop %d, num inherited %d)\n" "#\n", type->qname.name, prototype ? ejsGetLength(ejs, prototype): 0, numInherited); if (prototype) { count = ejsGetLength(ejs, prototype); for (i = 0; i < count; i++) { trait = ejsGetPropertyTraits(ejs, prototype, i); mprAssert(trait); qname = ejsGetPropertyName(ejs, prototype, i); if (qname.name) { lstVarSlot(mp, module, &qname, trait, i); } } } } else if (ejsIsBlock(ejs, obj)) { qname = ejsGetPropertyName(ejs, parent, slotNum); block = (EjsBlock*) obj; count = ejsGetLength(ejs, (EjsObj*) block); if (count > 0) { mprFprintf(mp->file, "\n#\n" "# Block slot assignments for the \"%@\" (Num slots %d)\n" "#\n", qname.name, ejsGetLength(ejs, obj)); count = ejsGetLength(ejs, obj); for (i = 0; i < count; i++) { trait = ejsGetPropertyTraits(ejs, obj, i); mprAssert(trait); qname = ejsGetPropertyName(ejs, obj, i); lstVarSlot(mp, module, &qname, trait, i); } } } /* Now recurse on types, functions and blocks */ if (obj == ejs->global) { i = module->firstGlobal; count = module->lastGlobal; } else { i = 0; count = ejsGetLength(ejs, obj); } for (; i < count; i++) { qname = ejsGetPropertyName(ejs, obj, i); vp = ejsGetProperty(ejs, obj, i); if (vp == 0) { continue; } if (ejsIsType(ejs, vp) || ejsIsFunction(ejs, vp) || ejsIsBlock(ejs, vp)) { lstSlotAssignments(mp, module, obj, i, vp); } } SET_VISITED(obj, 0); }
/* Return the length of bytes added to buf */ static void getGlobal(EjsMod *mp, char *buf, int buflen) { Ejs *ejs; EjsName qname; EjsObj *vp; int t, slotNum; ejs = mp->ejs; vp = 0; if ((t = (int) getNum(mp)) < 0) { mprSprintf(buf, buflen, "<can't read code>"); return; } switch (t & EJS_ENCODE_GLOBAL_MASK) { default: mprAssert(0); return; case EJS_ENCODE_GLOBAL_NOREF: return; case EJS_ENCODE_GLOBAL_SLOT: /* Type is a builtin primitive type or we are binding globals. */ slotNum = t >> 2; if (0 <= slotNum && slotNum < ejsGetLength(ejs, ejs->global)) { vp = ejsGetProperty(ejs, ejs->global, slotNum); } if (vp && ejsIsType(ejs, vp)) { mprSprintf(buf, buflen, "<type: 0x%x, %N> ", t, ((EjsType*) vp)->qname); } break; case EJS_ENCODE_GLOBAL_NAME: /* Type was unknown at compile time */ qname.name = ejsCreateStringFromConst(ejs, mp->module, t >> 2); if (qname.name == 0) { mprAssert(0); mprSprintf(buf, buflen, "<var: 0x%x, missing name> ", t); return; } if ((qname.space = getString(mp->ejs, mp)) == 0) { mprSprintf(buf, buflen, "<var: 0x%x, missing namespace> ", t); return; } if (qname.name) { vp = ejsGetPropertyByName(ejs, ejs->global, qname); } mprSprintf(buf, buflen, "<var: 0x%x, %N> ", t, qname); break; } if (vp == 0) { mprSprintf(buf, buflen, "<var: %d, cannot resolve var/typ at slot e> ", t); } }