diff options
Diffstat (limited to 'source4/lib/appweb/esp')
-rw-r--r-- | source4/lib/appweb/esp/esp.c | 1042 | ||||
-rw-r--r-- | source4/lib/appweb/esp/esp.h | 279 | ||||
-rw-r--r-- | source4/lib/appweb/esp/espEnv.h | 128 | ||||
-rw-r--r-- | source4/lib/appweb/esp/espProcs.c | 246 |
4 files changed, 1695 insertions, 0 deletions
diff --git a/source4/lib/appweb/esp/esp.c b/source4/lib/appweb/esp/esp.c new file mode 100644 index 0000000000..ef20557f93 --- /dev/null +++ b/source4/lib/appweb/esp/esp.c @@ -0,0 +1,1042 @@ +/* + * @file esp.c + * @brief Embedded Server Pages (ESP) core processing. + * @overview The ESP handler provides an efficient way to generate + * dynamic pages using server-side Javascript. This code provides + * core processing, and should be called by an associated web + * server URL handler. + */ +/********************************* Copyright **********************************/ +/* + * @copy default + * + * Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved. + * + * This software is distributed under commercial and open source licenses. + * You may use the GPL open source license described below or you may acquire + * a commercial license from Mbedthis Software. You agree to be fully bound + * by the terms of either license. Consult the LICENSE.TXT distributed with + * this software for full details. + * + * This software is open source; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See the GNU General Public License for more + * details at: http://www.mbedthis.com/downloads/gplLicense.html + * + * This program is distributed WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * This GPL license does NOT permit incorporating this software into + * proprietary programs. If you are unable to comply with the GPL, you must + * acquire a commercial license to use this software. Commercial licenses + * for this software and support services are available from Mbedthis + * Software at http://www.mbedthis.com + * + * @end + */ +/********************************** Includes **********************************/ + +#include "esp.h" + +#if BLD_FEATURE_ESP_MODULE + +/*********************************** Locals ***********************************/ +/* + * Master ESP control interface with the web server + */ + +static const Esp *esp; + +/***************************** Forward Declarations ***************************/ + +static int buildScript(EspRequest *ep, char **jsBuf, char *input, char + **errMsg); + +/************************************ Code ************************************/ +/* + * Called at server initialization + */ + +int espOpen(const Esp *control) +{ + mprAssert(control); + +#if BLD_FEATURE_MULTITHREAD + ejsOpen(control->lock, control->unlock, control->lockData); +#else + ejsOpen(0, 0, 0); +#endif + + /* + * Register the standard procedures + */ + espRegisterProcs(); + + /* + * Just for brain dead systems that don't zero global memory + */ + esp = control; + return 0; +} + +/******************************************************************************/ +/* + * Called at server termination + */ + +void espClose() +{ + ejsClose(); +} + +/******************************************************************************/ +/* + * Create for new ESP request. Assumed that this is called after all the + * HTTP headers have been read but before POST data has been read. It is + * expected that any session cookies have been read and that "variables" + * contains references to all the environment objects including "session". + * requestHandle is the web server request handle. + */ + +EspRequest *espCreateRequest(EspHandle webServerRequestHandle, char *uri, + MprVar *variables) +{ + EspRequest *ep; + MprVar *global; +#if BLD_FEATURE_LEGACY_API + MprVar *np; + char keyBuf[ESP_MAX_HEADER]; + int i; +#endif + + mprAssert(variables); + + ep = mprMalloc(sizeof(EspRequest)); + if (ep == 0) { + return 0; + } + memset(ep, 0, sizeof(EspRequest)); + ep->requestHandle = webServerRequestHandle; + ep->esp = esp; + ep->uri = mprStrdup(uri); + ep->docPath = 0; + ep->variables = variables; + + /* + * The handle passed to ejsOpenEngine is passed to every C function + * called by JavaScript. + */ + ep->eid = ejsOpenEngine((EjsHandle) ep, (EjsHandle) webServerRequestHandle); + if (ep->eid < 0) { + mprFree(ep); + return 0; + } + + /* + * All these copies and SetProperties will only copy references + * They will increments the object ref counts. + */ + mprCopyVar(&variables[ESP_GLOBAL_OBJ], ejsGetGlobalObject(ep->eid), + MPR_SHALLOW_COPY); + mprCopyVar(&variables[ESP_LOCAL_OBJ], ejsGetLocalObject(ep->eid), + MPR_SHALLOW_COPY); + + global = &variables[ESP_GLOBAL_OBJ]; + mprCreateProperty(global, "application", &variables[ESP_APPLICATION_OBJ]); + mprCreateProperty(global, "cookies", &variables[ESP_COOKIES_OBJ]); + mprCreateProperty(global, "files", &variables[ESP_FILES_OBJ]); + mprCreateProperty(global, "form", &variables[ESP_FORM_OBJ]); + mprCreateProperty(global, "headers", &variables[ESP_HEADERS_OBJ]); + mprCreateProperty(global, "request", &variables[ESP_REQUEST_OBJ]); + + /* + * FUTURE -- could server be shared across all requests for a given host + * and be made read-only. + */ + mprCreateProperty(global, "server", &variables[ESP_SERVER_OBJ]); + +#if BLD_FEATURE_SESSION + mprCreateProperty(global, "session", &variables[ESP_SESSION_OBJ]); +#endif + +#if BLD_FEATURE_LEGACY_API + /* + * DEPRECATED: 2.0 + * Define variables as globals. headers[] are prefixed with "HTTP_". + * NOTE: MaRequest::setVar does not copy into globals, whereas espSetVar + * does if legacy_api is defined. So variables pre-defined by MaRequest + * must be copied here into globals[].
+ * + * NOTE: if a variable is in session[] and in form[], the form[] will + * override being later in the variables[] list. Use mprSetProperty + * instead of mprCreateProperty to cover for this case. + */ + for (i = 0; i < ESP_OBJ_MAX; i++) { + if (i == ESP_GLOBAL_OBJ || i == ESP_LOCAL_OBJ) { + continue; + } + if (variables[i].type != MPR_TYPE_OBJECT) { + continue; + } + np = mprGetFirstProperty(&variables[i], MPR_ENUM_DATA); + while (np) { + if (i == ESP_HEADERS_OBJ) { + mprSprintf(keyBuf, sizeof(keyBuf) - 1, "HTTP_%s", np->name); + mprSetProperty(global, keyBuf, np); + } else { + mprSetProperty(global, np->name, np); + } + np = mprGetNextProperty(&variables[i], np, MPR_ENUM_DATA); + } + } +#endif + return ep; +} + +/******************************************************************************/ + +void espDestroyRequest(EspRequest *ep) +{ + mprAssert(ep); + mprAssert(ep->eid >= 0); + + mprFree(ep->uri); + mprFree(ep->docPath); + ejsCloseEngine(ep->eid); + mprFree(ep); +} + +/******************************************************************************/ +/* + * The callback function will be called: + * + * (fn)(EjsId eid, EspRequest *ep, argc, argv); + * + * Callers can get their web server handle by calling: + * + * rq = (requiredCast) espGetHandle(ep); + */ + +void espDefineCFunction(EspRequest *ep, const char *functionName, EspCFunction fn, + void *thisPtr) +{ + mprAssert(functionName && *functionName); + mprAssert(fn); + + if (ep) { + ejsDefineCFunction(ep->eid, functionName, (MprCFunction) fn, + thisPtr, 0); + } else { + ejsDefineCFunction(-1, functionName, (MprCFunction) fn, thisPtr, 0); + } +} + +/******************************************************************************/ + +void espDefineStringCFunction(EspRequest *ep, const char *functionName, + EspStringCFunction fn, void *thisPtr) +{ + mprAssert(functionName && *functionName); + mprAssert(fn); + + if (ep) { + ejsDefineStringCFunction(ep->eid, functionName, (MprStringCFunction) fn, + thisPtr, 0); + } else { + ejsDefineStringCFunction(-1, functionName, (MprStringCFunction) fn, + thisPtr, 0); + } +} + +/******************************************************************************/ + +void *espGetRequestHandle(EspRequest *ep) +{ + return ep->requestHandle; +} + +/******************************************************************************/ + +EjsId espGetScriptHandle(EspRequest *ep) +{ + return ep->eid; +} + +/******************************************************************************/ + +char *espGetStringVar(EspRequest *ep, EspEnvType oType, char *var, + char *defaultValue) +{ + MprVar value; + + if (espGetVar(ep, oType, var, &value) < 0 || + value.type != MPR_TYPE_STRING) { + return defaultValue; + } + return value.string; +} + +/******************************************************************************/ + +int espGetVar(EspRequest *ep, EspEnvType oType, char *var, MprVar *value) +{ + MprVar *vp; + + mprAssert(ep); + mprAssert(var); + + vp = mprGetProperty(&ep->variables[oType], var, 0); + if (vp == 0) { + return -1; + } + *value = *vp; + return 0; +} + +/******************************************************************************/ +/* + * Process the ESP page. docBuf holds the page already. We expect that + * ep->variables holds all the pertinent environment variables. + */ + +int espProcessRequest(EspRequest *ep, const char *docPath, char *docBuf, + char **errMsg) +{ + char *jsBuf; + + mprAssert(ep); + + ep->docPath = mprStrdup(docPath); + + jsBuf = 0; + if (buildScript(ep, &jsBuf, docBuf, errMsg) < 0) { + return MPR_ERR_CANT_COMPLETE; + } + + if (jsBuf) { + mprLog(7, "esp: script is:\n%s\n", jsBuf); + + /* + * Now evaluate the entire escript + * MOB could cache the script + */ + if (ejsEvalScript(ep->eid, jsBuf, 0, errMsg) < 0) { + return MPR_ERR_ABORTED; + } + + mprFree(jsBuf); + } + return 0; +} + +/******************************************************************************/ + +void espRedirect(EspRequest *ep, int code, char *url) +{ + mprAssert(ep); + mprAssert(url); + + ep->esp->redirect(ep->requestHandle, code, url); +} + +/******************************************************************************/ + +void espError(EspRequest *ep, const char *fmt, ...) +{ + va_list args; + char *buf; + + mprAssert(ep); + mprAssert(fmt); + + va_start(args, fmt); + mprAllocVsprintf(&buf, MPR_MAX_HEAP_SIZE, fmt, args); + ejsSetErrorMsg(ep->eid, buf); + mprFree(buf); + va_end(args); +} + +/******************************************************************************/ + +void espSetHeader(EspRequest *ep, char *header, bool allowMultiple) +{ + mprAssert(ep); + + ep->esp->setHeader(ep->requestHandle, header, allowMultiple); +} + +/******************************************************************************/ +/* + * Caller does not need to destroy the var + */ + +MprVar *espGetResult(EspRequest *ep) +{ + mprAssert(ep); + + return ejsGetReturnValue(ep->eid); +} + +/******************************************************************************/ + +void espSetReturn(EspRequest *ep, MprVar value) +{ + mprAssert(ep); + + ejsSetReturnValue(ep->eid, value); +} + +/******************************************************************************/ + +void espSetReturnString(EspRequest *ep, const char *str) +{ + mprAssert(ep); + + ejsSetReturnValue(ep->eid, mprCreateStringVar(str, 0)); +} + +/******************************************************************************/ + +void espSetResponseCode(EspRequest *ep, int code) +{ + mprAssert(ep); + + ep->esp->setResponseCode(ep->requestHandle, code); +} + +/******************************************************************************/ + +void espSetVar(EspRequest *ep, EspEnvType oType, char *var, MprVar value) +{ + mprCreatePropertyValue(&ep->variables[oType], var, value); +} + +/******************************************************************************/ + +void espSetStringVar(EspRequest *ep, EspEnvType oType, + const char *var, const char *value) +{ + /* + * Will create or update if already existing + */ + mprCreatePropertyValue(&ep->variables[oType], var, + mprCreateStringVar(value, 0)); +} + +/******************************************************************************/ + +int espUnsetVar(EspRequest *ep, EspEnvType oType, char *var) +{ + return mprDeleteProperty(&ep->variables[oType], var); +} + +/******************************************************************************/ + +int espWrite(EspRequest *ep, char *buf, int size) +{ + mprAssert(ep); + mprAssert(buf); + mprAssert(size >= 0); + + return ep->esp->writeBlock(ep->requestHandle, buf, size); +} + +/******************************************************************************/ + +int espWriteString(EspRequest *ep, char *buf) +{ + mprAssert(ep); + mprAssert(buf); + + return ep->esp->writeBlock(ep->requestHandle, buf, strlen(buf)); +} + +/******************************************************************************/ + +int espWriteFmt(EspRequest *ep, char *fmt, ...) +{ + va_list args; + char *buf; + int rc, len; + + mprAssert(ep); + mprAssert(fmt); + + va_start(args, fmt); + len = mprAllocVsprintf(&buf, MPR_MAX_HEAP_SIZE, fmt, args); + rc = ep->esp->writeBlock(ep->requestHandle, buf, len); + mprFree(buf); + va_end(args); + return rc; +} + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ +/* + * Get a javascript identifier. Must allow x.y['abc'] or x.y["abc"]. + * Must be careful about quoting and only allow quotes inside []. + */ + +static int getIdentifier(EspParse *parse) +{ + int atQuote, prevC, c; + + mprAssert(parse); + + atQuote = 0; + prevC = 0; + c = *parse->inp++; + + while (isalnum(c) || c == '_' || c == '.' || c == '[' || + c == ']' || c == '\'' || c == '\"') { + if (c == '\'' || c == '\"') { + if (c == atQuote) { + atQuote = 0; + } else if (prevC == '[') { + atQuote = c; + } else { + break; + } + } + if (parse->tokp >= parse->endp) { + parse->token = (char*) mprRealloc(parse->token, + parse->tokLen + ESP_TOK_INCR); + if (parse->token == 0) { + return MPR_ERR_CANT_ALLOCATE; + } + parse->token[parse->tokLen] = '\0'; + parse->tokLen += ESP_TOK_INCR; + parse->endp = &parse->token[parse->tokLen - 1]; + } + *parse->tokp++ = c; + prevC = c; + c = *parse->inp++; + } + + parse->inp--; + *parse->tokp = '\0'; + + return 0; +} + +/******************************************************************************/ +/* + * Get the next ESP input token. input points to the next input token. + * parse->token will hold the parsed token. The function returns the token id. + */ + +static int getEspToken(int state, EspParse *parse) +{ + char *cp; + int tid, done, c, quoted; + + tid = ESP_TOK_LITERAL; + parse->tokp = parse->token; + parse->tokp[0] = '\0'; + quoted = 0; + + c = *parse->inp++; + for (done = 0; !done; c = *parse->inp++) { + + /* + * Get room for more characters in the token buffer + */ + if (parse->tokp >= parse->endp) { + parse->token = (char*) mprRealloc(parse->token, + parse->tokLen + ESP_TOK_INCR); + if (parse->token == 0) { + return ESP_TOK_ERR; + } + parse->token[parse->tokLen] = '\0';
+ parse->tokp = &parse->token[parse->tokLen - 1]; + parse->tokLen += ESP_TOK_INCR; + parse->endp = &parse->token[parse->tokLen - 1]; + } + + switch (c) { + case 0: + if (*parse->token) { + done++; + parse->inp--; + break; + } + return ESP_TOK_EOF; + + default: + if (c == '\"' && state != ESP_STATE_IN_ESP_TAG) { + *parse->tokp++ = '\\'; + } + *parse->tokp++ = c; + quoted = 0; + break; + + case '\\': + quoted = 1; + *parse->tokp++ = c; + break; + + case '@': + if (*parse->inp == '@' && state != ESP_STATE_IN_ESP_TAG) { + if (quoted) { + parse->tokp--; + quoted = 0; + } else { + if (*parse->token) { + parse->inp--; + } else { + parse->inp++; + tid = ESP_TOK_ATAT; + if (getIdentifier(parse) < 0) { + return ESP_TOK_ERR; + } + } + done++; + break; + } + } + *parse->tokp++ = c; + break; + + case '<': + if (*parse->inp == '%' && state != ESP_STATE_IN_ESP_TAG) { + if (quoted) { + parse->tokp--; + quoted = 0; + *parse->tokp++ = c; + break; + } + if (*parse->token) { + parse->inp--; + done++; + break; + } + parse->inp++; + while (isspace((int) *parse->inp)) { + parse->inp++; + } + if (*parse->inp == '=') { + parse->inp++; + while (isspace((int) *parse->inp)) { + parse->inp++; + } + tid = ESP_TOK_EQUALS; + if (getIdentifier(parse) < 0) { + return ESP_TOK_ERR; + } + done++; + break; + } + if (*parse->inp == 'i' && + strncmp(parse->inp, "include", 7) == 0 && + isspace((int) parse->inp[7])) { + tid = ESP_TOK_INCLUDE; + parse->inp += 7; + while (isspace((int) *parse->inp)) { + parse->inp++; + } + while (*parse->inp && !isspace((int) *parse->inp) && + *parse->inp != '%' && parse->tokp < parse->endp) { + *parse->tokp++ = *parse->inp++; + } + *parse->tokp = '\0'; + if (parse->token[0] == '"') { + parse->tokp = parse->token; + for (cp = &parse->token[1]; *cp; ) { + *parse->tokp++ = *cp++; + } + if (cp[-1] == '"') { + parse->tokp--; + } + *parse->tokp = '\0'; + } + + } else { + tid = ESP_TOK_START_ESP; + } + done++; + break; + } + *parse->tokp++ = c; + break; + + case '%': + if (*parse->inp == '>' && state == ESP_STATE_IN_ESP_TAG) { + if (quoted) { + parse->tokp--; + quoted = 0; + } else { + if (*parse->token) { + parse->inp--; + } else { + tid = ESP_TOK_END_ESP; + parse->inp++; + } + done++; + break; + } + } + *parse->tokp++ = c; + break; + } + } + + *parse->tokp = '\0'; + parse->inp--; + return tid; +} + +/******************************************************************************/ +/* + * Convert an ESP page into a JavaScript. We also expand include files. + */ + +static int buildScript(EspRequest *ep, char **jsBuf, char *input, char **errMsg) +{ + EspParse parse; + char path[MPR_MAX_FNAME], dir[MPR_MAX_FNAME], incPath[MPR_MAX_FNAME]; + char *incBuf, *incText; + int state, tid, len, rc, maxScriptSize, incSize; + + mprAssert(ep); + mprAssert(jsBuf); + mprAssert(input); + + rc = 0; + len = 0; + state = ESP_STATE_BEGIN; + if (errMsg) { + *errMsg = 0; + } + + memset(&parse, 0, sizeof(parse)); + parse.token = (char*) mprMalloc(ESP_TOK_INCR); + if (parse.token == 0) { + return MPR_ERR_CANT_ALLOCATE; + } + parse.token[0] = '\0'; + parse.tokLen = ESP_TOK_INCR; + parse.endp = &parse.token[parse.tokLen - 1]; + parse.tokp = parse.token; + parse.inBuf = input; + parse.inp = parse.inBuf; + + maxScriptSize = esp->maxScriptSize; + + tid = getEspToken(state, &parse); + while (tid != ESP_TOK_EOF && len >= 0) { + + switch (tid) { + default: + case ESP_TOK_ERR: + mprFree(parse.token); + return MPR_ERR_BAD_SYNTAX; + + case ESP_TOK_LITERAL: + len = mprReallocStrcat(jsBuf, maxScriptSize, len, 0, + "write(\"", parse.token, "\");\n", 0); + break; + + case ESP_TOK_ATAT: + /* + * Trick to get undefined variables to evaluate to "". + * Catenate with "" to cause toString to run. + */ + len = mprReallocStrcat(jsBuf, maxScriptSize, len, 0, + "write(\"\" + ", parse.token, ");\n", 0); + break; + + case ESP_TOK_EQUALS: + len = mprReallocStrcat(jsBuf, maxScriptSize, len, 0, + "write(\"\" + ", parse.token, ");\n", 0); + state = ESP_STATE_IN_ESP_TAG; + break; + + case ESP_TOK_START_ESP: + state = ESP_STATE_IN_ESP_TAG; + tid = getEspToken(state, &parse); + while (tid != ESP_TOK_EOF && tid != ESP_TOK_EOF && + tid != ESP_TOK_END_ESP && len >= 0) { + len = mprReallocStrcat(jsBuf, maxScriptSize, len, 0, + parse.token, 0); + tid = getEspToken(state, &parse); + } + state = ESP_STATE_BEGIN; + break; + + case ESP_TOK_END_ESP: + state = ESP_STATE_BEGIN; + break; + + case ESP_TOK_INCLUDE: + if (parse.token[0] == '/') { + mprStrcpy(incPath, sizeof(incPath), parse.token); + } else { + mprGetDirName(dir, sizeof(dir), ep->uri); + mprSprintf(incPath, sizeof(incPath), "%s/%s", + dir, parse.token); + } + if (esp->mapToStorage(ep->requestHandle, path, sizeof(path), + incPath, 0) < 0) { + mprAllocSprintf(errMsg, MPR_MAX_STRING, + "Can't find include file: %s", path); + rc = MPR_ERR_CANT_OPEN; + break; + } + if (esp->readFile(ep->requestHandle, &incText, &incSize, path) < 0){ + mprAllocSprintf(errMsg, MPR_MAX_STRING, + "Can't read include file: %s", path); + rc = MPR_ERR_CANT_READ; + break; + } + incText[incSize] = '\0'; + + /* + * Recurse and process the include script + */ + incBuf = 0; + if ((rc = buildScript(ep, &incBuf, incText, errMsg)) < 0) { + mprFree(incText); + mprFree(parse.token); + return rc; + } + + len = mprReallocStrcat(jsBuf, maxScriptSize, len, 0, incBuf, 0); + mprFree(incText); + mprFree(incBuf); + state = ESP_STATE_IN_ESP_TAG; + break; + } + tid = getEspToken(state, &parse); + } + mprFree(parse.token); + if (len < 0) { + mprAllocSprintf(errMsg, MPR_MAX_STRING, + "Script token is too big in %s.\nConfigured maximum is %d.", + path, maxScriptSize); + return MPR_ERR_WONT_FIT; + } + return rc; +} + +/******************************************************************************/ +/******************************* Wrapped Routines *****************************/ +/******************************************************************************/ + +int espCopyVar(EspRequest *ep, char *var, MprVar *value, int copyDepth) +{ + return ejsCopyVar(ep->eid, var, value, copyDepth); +} + +/******************************************************************************/ + +MprVar espCreateObjVar(char *name, int hashSize) +{ + return ejsCreateObj(name, hashSize); +} + +/******************************************************************************/ + +MprVar espCreateArrayVar(char *name, int size) +{ + return ejsCreateArray(name, size); +} + +/******************************************************************************/ + +bool espDestroyVar(MprVar *obj) +{ + return ejsDestroyVar(obj); +} + +/******************************************************************************/ + +MprVar *espCreateProperty(MprVar *obj, char *property, MprVar *newValue) +{ + return mprCreateProperty(obj, property, newValue); +} + +/******************************************************************************/ + +MprVar *espCreatePropertyValue(MprVar *obj, char *property, MprVar newValue) +{ + return mprCreatePropertyValue(obj, property, newValue); +} + +/******************************************************************************/ + +void espDefineFunction(EspRequest *ep, const char *functionName, char *args, char *body) +{ + ejsDefineFunction(ep->eid, functionName, args, body); +} + +/******************************************************************************/ + +int espDeleteProperty(MprVar *obj, char *property) +{ + return mprDeleteProperty(obj, property); +} + +/******************************************************************************/ + +int espDeleteVar(EspRequest *ep, char *var) +{ + return ejsDeleteVar(ep->eid, var); +} + +/******************************************************************************/ +int espEvalFile(EspRequest *ep, char *path, MprVar *result, char **emsg) +{ + return ejsEvalFile(ep->eid, path, result, emsg); +} + +/******************************************************************************/ + +int espEvalScript(EspRequest *ep, char *script, MprVar *result, char **emsg) +{ + return ejsEvalScript(ep->eid, script, result, emsg); +} + +/******************************************************************************/ + +int espGetPropertyCount(MprVar *obj, int includeFlags) +{ + if (obj->type != MPR_TYPE_OBJECT) { + return MPR_ERR_BAD_STATE; + } + return mprGetPropertyCount(obj, includeFlags); +} + +/******************************************************************************/ + +MprVar *espGetFirstProperty(MprVar *obj, int includeFlags) +{ + return mprGetFirstProperty(obj, includeFlags); +} + +/******************************************************************************/ + +MprVar *espGetGlobalObject(EspRequest *ep) +{ + return ejsGetGlobalObject(ep->eid); +} + +/******************************************************************************/ + +MprVar *espGetLocalObject(EspRequest *ep) +{ + return ejsGetLocalObject(ep->eid); +} + +/******************************************************************************/ + +MprVar *espGetNextProperty(MprVar *obj, MprVar *currentProperty, + int includeFlags) +{ + return mprGetNextProperty(obj, currentProperty, includeFlags); +} + +/******************************************************************************/ + +MprVar *espGetProperty(MprVar *obj, char *property, MprVar *value) +{ + return mprGetProperty(obj, property, value); +} + +/******************************************************************************/ + +void *espGetThisPtr(EspRequest *ep) +{ + return ejsGetThisPtr(ep->eid); +} + +/******************************************************************************/ +#if XX_UNUSED_XX + +int espReadProperty(MprVar *dest, MprVar *prop) +{ + mprAssert(prop); + mprAssert(dest); + + *dest = *prop; + return 0; +} + +#endif +/******************************************************************************/ + +int espReadVar(EspRequest *ep, char *var, MprVar *value) +{ + return ejsReadVar(ep->eid, var, value); +} + +/******************************************************************************/ + +int espRunFunction(EspRequest *ep, MprVar *obj, char *functionName, + MprArray *args) +{ + return ejsRunFunction(ep->eid, obj, functionName, args); +} + +/******************************************************************************/ + +MprVar *espSetProperty(MprVar *obj, char *property, MprVar *newValue) +{ + return mprSetProperty(obj, property, newValue); +} + +/******************************************************************************/ + +MprVar *espSetPropertyValue(MprVar *obj, char *property, MprVar newValue) +{ + return mprSetPropertyValue(obj, property, newValue); +} + +/******************************************************************************/ + +int espWriteVar(EspRequest *ep, char *var, MprVar *value) +{ + return ejsWriteVar(ep->eid, var, value); +} + +/******************************************************************************/ + +int espWriteVarValue(EspRequest *ep, char *var, MprVar value) +{ + return ejsWriteVarValue(ep->eid, var, value); +} + +/******************************************************************************/ +#if XX_UNUSED_XX + +int espWriteProperty(MprVar *prop, MprVar *newValue) +{ + return mprWriteProperty(prop, newValue); +} + +/******************************************************************************/ + +int espWritePropertyValue(MprVar *prop, MprVar newValue) +{ + return mprWritePropertyValue(prop, newValue); +} + +#endif +/******************************************************************************/ + +#else /* !BLD_FEATURE_ESP_MODULE */ +void espDummy() {} + +/******************************************************************************/ +#endif /* BLD_FEATURE_ESP_MODULE */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim:tw=78 + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/source4/lib/appweb/esp/esp.h b/source4/lib/appweb/esp/esp.h new file mode 100644 index 0000000000..ee86e8d345 --- /dev/null +++ b/source4/lib/appweb/esp/esp.h @@ -0,0 +1,279 @@ +/** + * @file esp.h + * @brief Header for Embedded Server Pages (ESP) + */ +/********************************* Copyright **********************************/ +/* + * @copy default + * + * Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved. + * + * This software is distributed under commercial and open source licenses. + * You may use the GPL open source license described below or you may acquire + * a commercial license from Mbedthis Software. You agree to be fully bound + * by the terms of either license. Consult the LICENSE.TXT distributed with + * this software for full details. + * + * This software is open source; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See the GNU General Public License for more + * details at: http://www.mbedthis.com/downloads/gplLicense.html + * + * This program is distributed WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * This GPL license does NOT permit incorporating this software into + * proprietary programs. If you are unable to comply with the GPL, you must + * acquire a commercial license to use this software. Commercial licenses + * for this software and support services are available from Mbedthis + * Software at http://www.mbedthis.com + * + * @end + */ +/********************************** Includes **********************************/ + +#ifndef _h_ESP_h +#define _h_ESP_h 1 + +#include "lib/appweb/ejs/ejs.h" +#include "lib/appweb/esp/espEnv.h" +#include "lib/appweb/ejs/var.h" +#include "lib/appweb/ejs/miniMpr.h" + +/*********************************** Defines **********************************/ + +#define ESP_STRING_ARGS MPR_TYPE_STRING_ARGS + +#if BLD_FEATURE_SQUEEZE +#define ESP_TOK_INCR 1024 +#define ESP_MAX_HEADER 1024 +#else +#define ESP_TOK_INCR 4096 +#define ESP_MAX_HEADER 4096 +#endif + +/* + * ESP lexical analyser tokens + */ +#define ESP_TOK_ERR -1 /* Any input error */ +#define ESP_TOK_EOF 0 /* End of file */ +#define ESP_TOK_START_ESP 1 /* <% */ +#define ESP_TOK_END_ESP 2 /* %> */ +#define ESP_TOK_ATAT 3 /* @@var */ +#define ESP_TOK_LITERAL 4 /* literal HTML */ +#define ESP_TOK_INCLUDE 5 /* include file.esp */ +#define ESP_TOK_EQUALS 6 /* = var */ + +/* + * ESP parser states + */ +#define ESP_STATE_BEGIN 1 /* Starting state */ +#define ESP_STATE_IN_ESP_TAG 2 /* Inside a <% %> group */ + +/*********************************** Types ************************************/ + +typedef void* EspHandle; /* Opaque Web server handle type */ + +/* + * Per request control block + */ +typedef struct EspRequest { + MprStr docPath; /* Physical path for ESP page */ + EjsId eid; /* EJS instance handle */ + const struct Esp *esp; /* Pointer to ESP control block */ + EspHandle requestHandle; /* Per request web server handle */ + MprStr uri; /* Request URI */ + MprVar *variables; /* Pointer to variables */ +} EspRequest; + +/* + * Master ESP control block. This defines the function callbacks for a + * web server handler to implement. ESP will call these functions as + * required. + */ +typedef struct Esp { + int maxScriptSize; + void (*createSession)(EspHandle handle, int timeout); + void (*destroySession)(EspHandle handle); + const char *(*getSessionId)(EspHandle handle); + int (*mapToStorage)(EspHandle handle, char *path, int len, const char *uri, + int flags); + int (*readFile)(EspHandle handle, char **buf, int *len, const char *path); + void (*redirect)(EspHandle handle, int code, char *url); + void (*setCookie)(EspHandle handle, const char *name, const char *value, + int lifetime, const char *path, bool secure); + void (*setHeader)(EspHandle handle, const char *value, bool allowMultiple); + void (*setResponseCode)(EspHandle handle, int code); + int (*writeBlock)(EspHandle handle, char *buf, int size); + int (*writeFmt)(EspHandle handle, char *fmt, ...); +#if BLD_FEATURE_MULTITHREAD + void (*lock)(void *lockData); + void (*unlock)(void *lockData); + void *lockData; +#endif +} Esp; + + +/* + * ESP parse context + */ +typedef struct { + char *inBuf; /* Input data to parse */ + char *inp; /* Next character for input */ + char *endp; /* End of storage (allow for null) */ + char *tokp; /* Pointer to current parsed token */ + char *token; /* Storage buffer for token */ + int tokLen; /* Length of buffer */ +} EspParse; + + +/******************************** Private APIs ********************************/ + +extern void espRegisterProcs(void); + +/******************************** Published API *******************************/ +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Function callback signatures + */ +typedef int (*EspCFunction)(EspRequest *ep, int argc, + struct MprVar **argv); +typedef int (*EspStringCFunction)(EspRequest *ep, int argc, + char **argv); + +/* + * APIs for those hosting the ESP module + */ +extern int espOpen(const Esp *control); +extern void espClose(void); +extern EspRequest *espCreateRequest(EspHandle webServerRequestHandle, + char *uri, MprVar *envObj); +extern void espDestroyRequest(EspRequest *ep); +extern int espProcessRequest(EspRequest *ep, const char *docPath, + char *docBuf, char **errMsg); + +/* + * Method invocation + */ +extern void espDefineCFunction(EspRequest *ep, const char *functionName, + EspCFunction fn, void *thisPtr); +extern void espDefineFunction(EspRequest *ep, const char *functionName, + char *args, char *body); +extern void espDefineStringCFunction(EspRequest *ep, + const char *functionName, EspStringCFunction fn, + void *thisPtr); +extern int espRunFunction(EspRequest *ep, MprVar *obj, + char *functionName, MprArray *args); +extern void espSetResponseCode(EspRequest *ep, int code); +extern void espSetReturn(EspRequest *ep, MprVar value); +extern void *espGetThisPtr(EspRequest *ep); + +/* + * Utility routines to use in C methods + */ +extern void espError(EspRequest *ep, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); +extern int espEvalFile(EspRequest *ep, char *path, MprVar *result, + char **emsg); +extern int espEvalScript(EspRequest *ep, char *script, MprVar *result, + char **emsg); +extern MprVar *espGetLocalObject(EspRequest *ep); +extern MprVar *espGetGlobalObject(EspRequest *ep); +extern EspHandle espGetRequestHandle(EspRequest *ep); +extern MprVar *espGetResult(EspRequest *ep); +extern EjsId espGetScriptHandle(EspRequest *ep); +extern void espRedirect(EspRequest *ep, int code, char *url); +extern void espSetHeader(EspRequest *ep, char *header, + bool allowMultiple); +extern void espSetReturnString(EspRequest *ep, const char *str); +extern int espWrite(EspRequest *ep, char *buf, int size); +extern int espWriteString(EspRequest *ep, char *buf); +extern int espWriteFmt(EspRequest *ep, char *fmt, ...) PRINTF_ATTRIBUTE(2,3); + +/* + * ESP array[] variable access (set will update/create) + */ +extern int espGetVar(EspRequest *ep, EspEnvType oType, char *var, + MprVar *value); +extern char *espGetStringVar(EspRequest *ep, EspEnvType oType, + char *var, char *defaultValue); +extern void espSetVar(EspRequest *ep, EspEnvType oType, char *var, + MprVar value); +extern void espSetStringVar(EspRequest *ep, EspEnvType oType, + const char *var, const char *value); +extern int espUnsetVar(EspRequest *ep, EspEnvType oType, char *var); + +/* + * Object creation and management + */ +extern MprVar espCreateObjVar(char *name, int hashSize); +extern MprVar espCreateArrayVar(char *name, int size); +extern bool espDestroyVar(MprVar *var); +extern MprVar *espCreateProperty(MprVar *obj, char *property, + MprVar *newValue); +extern MprVar *espCreatePropertyValue(MprVar *obj, char *property, + MprVar newValue); +extern int espDeleteProperty(MprVar *obj, char *property); + +/* + * JavaScript variable management. Set will create/update a property. + * All return a property reference. GetProperty will optionally return the + * property in value. + */ +extern MprVar *espGetProperty(MprVar *obj, char *property, + MprVar *value); +extern MprVar *espSetProperty(MprVar *obj, char *property, + MprVar *newValue); +extern MprVar *espSetPropertyValue(MprVar *obj, char *property, + MprVar newValue); + +#if 0 +/* + * Low-level direct read and write of properties. + * FUTURE: -- Read is not (dest, src). MUST WARN IN DOC ABOUT COPY/READ + * Will still cause triggers to run. + */ +extern int espReadProperty(MprVar *dest, MprVar *prop); +extern int espWriteProperty(MprVar *prop, MprVar *newValue); +extern int espWritePropertyValue(MprVar *prop, MprVar newValue); +#endif + + +/* + * Access JavaScript variables by their full name. Can use "." or "[]". For + * example: "global.request['REQUEST_URI']" + * For Read/write, the variables must exist. + */ +extern int espCopyVar(EspRequest *ep, char *var, MprVar *value, + int copyDepth); +extern int espDeleteVar(EspRequest *ep, char *var); +extern int espReadVar(EspRequest *ep, char *var, MprVar *value); +extern int espWriteVar(EspRequest *ep, char *var, MprVar *value); +extern int espWriteVarValue(EspRequest *ep, char *var, MprVar value); + +/* + * Object property enumeration + */ +extern MprVar *espGetFirstProperty(MprVar *obj, int includeFlags); +extern MprVar *espGetNextProperty(MprVar *obj, MprVar *currentProperty, + int includeFlags); +extern int espGetPropertyCount(MprVar *obj, int includeFlags); + +#ifdef __cplusplus +} +#endif +/******************************************************************************/ +#endif /* _h_ESP_h */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim:tw=78 + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/source4/lib/appweb/esp/espEnv.h b/source4/lib/appweb/esp/espEnv.h new file mode 100644 index 0000000000..a3c9d9f5c7 --- /dev/null +++ b/source4/lib/appweb/esp/espEnv.h @@ -0,0 +1,128 @@ +/* + * @file espEnv.h + * @brief ESP Environment Variables + */ +/********************************* Copyright **********************************/ +/* + * @copy default + * + * Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved. + * + * This software is distributed under commercial and open source licenses. + * You may use the GPL open source license described below or you may acquire + * a commercial license from Mbedthis Software. You agree to be fully bound + * by the terms of either license. Consult the LICENSE.TXT distributed with + * this software for full details. + * + * This software is open source; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See the GNU General Public License for more + * details at: http://www.mbedthis.com/downloads/gplLicense.html + * + * This program is distributed WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * This GPL license does NOT permit incorporating this software into + * proprietary programs. If you are unable to comply with the GPL, you must + * acquire a commercial license to use this software. Commercial licenses + * for this software and support services are available from Mbedthis + * Software at http://www.mbedthis.com + * + * @end + */ + +/******************************************************************************/ + +#ifndef _h_ESP_ENV_h +#define _h_ESP_ENV_h 1 + +/* + * @brief Scripting environment variable array types + */ +typedef enum EspEnvType { + ESP_UNDEFINED_OBJ = -1, + + /** + * Elements for server[]: + * DOCUMENT_ROOT GATEWAY_INTERFACE SERVER_ADDR SERVER_PORT SERVER_NAME + * SERVER_PROTOCOL SERVER_SOFTWARE SERVER_URL UPLOAD_DIR + * FUTURE: SERVER_ADMIN + * FUTURE: this could be shared across all hosts and be made read-only. + */ + ESP_SERVER_OBJ = 0, /*! server[] data */ + + /** + * Elements for session[]: are user defined + */ + ESP_SESSION_OBJ = 1, /*! session[] data */ + + /** + * Elements for request[]: + * AUTH_TYPE CONTENT_LENGTH CONTENT_TYPE QUERY_STRING PATH_INFO + * PATH_TRANSLATED REMOTE_ADDR REMOTE_HOST REMOTE_USER REQUEST_METHOD + * REQUEST_URI SCRIPT_FILENAME SCRIPT_NAME + * FUTURE: FILEPATH_INFO REDIRECT_URL SELF REMOTE_PORT AUTH_USER + * AUTH_GROUP AUTH_ACL + */ + ESP_REQUEST_OBJ = 2, /*! request[] data */ + + /** + * Elements for headers[]: + * HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_CONNECTION HTTP_HOST + * HTTP_REFERER HTTP_USER_AGENT and any other custom headers + */ + ESP_HEADERS_OBJ = 3, /*! header [] data */ + + /** + * Elements for cookies[]: are defined by the HTTP request + */ + ESP_COOKIES_OBJ = 4, /*! cookies[] data */ + + /** + * Elements for files[]: are defined by the HTTP request + * CLIENT_FILENAME CONTENT_TYPE FILENAME SIZE + */ + ESP_FILES_OBJ = 5, /*! files[] data */ + + /** + * Elements for form[]: are defined by the HTTP request + */ + ESP_FORM_OBJ = 6, /*! form[] data */ + + /** + * Elements for application[]: are user defined + */ + ESP_APPLICATION_OBJ = 7, /*! application[] data */ + + /** + * Elements for global[]: are defined by ESP/EJS + */ + ESP_GLOBAL_OBJ = 8, /*! global [] data */ + + /* + * Elements for local[]: are defined by ESP/EJS + */ + ESP_LOCAL_OBJ = 9, /*! local [] data */ +} EspEnvType; + +#define ESP_OBJ_MAX 10 /* Total objects */ + +#if BLD_SQUEEZE +#define ESP_HASH_SIZE 19 /* Size of hash tables */ +#else +#define ESP_HASH_SIZE 37 +#endif + +/******************************************************************************/ +#endif /* _h_ESP_ENV_h */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim:tw=78 + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/source4/lib/appweb/esp/espProcs.c b/source4/lib/appweb/esp/espProcs.c new file mode 100644 index 0000000000..28b69a8a6f --- /dev/null +++ b/source4/lib/appweb/esp/espProcs.c @@ -0,0 +1,246 @@ +/* + * @file espProcs.c + * @brief Embedded Server Pages (ESP) Procedures. + * @overview These ESP procedures can be used in ESP pages for common tasks. + */ +/********************************* Copyright **********************************/ +/* + * @copy default + * + * Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved. + * + * This software is distributed under commercial and open source licenses. + * You may use the GPL open source license described below or you may acquire + * a commercial license from Mbedthis Software. You agree to be fully bound + * by the terms of either license. Consult the LICENSE.TXT distributed with + * this software for full details. + * + * This software is open source; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See the GNU General Public License for more + * details at: http://www.mbedthis.com/downloads/gplLicense.html + * + * This program is distributed WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * This GPL license does NOT permit incorporating this software into + * proprietary programs. If you are unable to comply with the GPL, you must + * acquire a commercial license to use this software. Commercial licenses + * for this software and support services are available from Mbedthis + * Software at http://www.mbedthis.com + * + * @end + */ +/********************************** Includes **********************************/ + +#include "esp.h" + +/************************************ Code ************************************/ +#if BLD_FEATURE_ESP_MODULE +#if BLD_FEATURE_SESSION +/* + * destroySession + */ + +static int destroySessionProc(EspRequest *ep, int argc, char **argv) +{ + ep->esp->destroySession(ep->requestHandle); + return 0; +} + +#endif /* BLD_FEATURE_SESSION */ + +/******************************************************************************/ +/* + * include + * + * This includes javascript libraries. For example: + * + * <% include("file", ...); %> + * + * Don't confuse with ESP includes: + * + * <% include file.esp %> + * + * Filenames are relative to the base document including the file. + * FUTURE -- move back to EJS. Only here now because we need ep->readFile. + */ + +static int includeProc(EspRequest *ep, int argc, char **argv) +{ + const Esp *esp; + char path[MPR_MAX_FNAME], dir[MPR_MAX_FNAME]; + char *emsg=NULL, *buf; + int size, i; + + esp = ep->esp; + mprAssert(argv); + for (i = 0; i < argc; i++) { + const char *extension; + + if (argv[i][0] != '/') { + mprGetDirName(dir, sizeof(dir), ep->docPath); + mprSprintf(path, sizeof(path), "%s/%s", dir, argv[i]); + } else { + mprSprintf(path, sizeof(path), "%s", argv[i]); + } + + if (esp->readFile(ep->requestHandle, &buf, &size, path) < 0) { + espError(ep, "Can't read include file: %s", path); + return MPR_ERR_CANT_ACCESS; + } + buf[size] = '\0'; + + extension = strrchr(argv[i], '.'); + /* this makes handling include files in esp scripts much more convenient */ + if (extension && strcasecmp(extension, ".esp") == 0) { + if (espProcessRequest(ep, path, buf, &emsg) != 0) { + espError(ep, "Cant evaluate script - %s", emsg?emsg:""); + mprFree(buf); + return -1; + } + } else { + if (ejsEvalScript(espGetScriptHandle(ep), buf, 0, &emsg) < 0) { + espError(ep, "Cant evaluate script - %s", emsg?emsg:""); + mprFree(buf); + return -1; + } + } + mprFree(buf); + } + return 0; +} + +/******************************************************************************/ +/* + * redirect + * + * This implemements <% redirect(url, code); %> command. The redirection + * code is optional. + */ + +static int redirectProc(EspRequest *ep, int argc, char **argv) +{ + char *url; + int code; + + if (argc < 1) { + espError(ep, "Bad args"); + return MPR_ERR_BAD_ARGS; + } + url = argv[0]; + if (argc == 2) { + code = atoi(argv[1]); + } else { + code = 302; + } + espRedirect(ep, code, url); + return 0; +} + +/******************************************************************************/ +#if BLD_FEATURE_SESSION +/* + * useSession + */ + +static int useSessionProc(EspRequest *ep, int argc, char **argv) +{ + int timeout; + + if (argc > 1) { + espError(ep, "Bad args"); + return MPR_ERR_BAD_ARGS; + + } else if (argc == 1) { + timeout = atoi(argv[0]); + } else { + timeout = 0; + } + + ep->esp->createSession(ep->requestHandle, timeout); + espSetReturnString(ep, ep->esp->getSessionId(ep->requestHandle)); + return 0; +} + +#endif /* BLD_FEATURE_SESSION */ +/******************************************************************************/ +/* + * setHeader + * + * This implemements <% setHeader("key: value", allowMultiple); %> command. + */ + +static int setHeaderProc(EspRequest *ep, int argc, char **argv) +{ + mprAssert(argv); + if (argc != 2) { + espError(ep, "Bad args"); + return MPR_ERR_BAD_ARGS; + } + ep->esp->setHeader(ep->requestHandle, argv[0], atoi(argv[1])); + return 0; +} + +/******************************************************************************/ +/* + * write + * + * This implemements <% write("text"); %> command. + */ + +static int writeProc(EspRequest *ep, int argc, char **argv) +{ + char *s; + int i, len; + + mprAssert(argv); + for (i = 0; i < argc; i++) { + s = argv[i]; + len = strlen(s); + if (len > 0) { + if (espWrite(ep, s, len) != len) { + espError(ep, "Can't write to client"); + return -1; + } + } + } + return 0; +} + +/******************************************************************************/ + +void espRegisterProcs() +{ + espDefineStringCFunction(0, "write", writeProc, 0); + espDefineStringCFunction(0, "setHeader", setHeaderProc, 0); + espDefineStringCFunction(0, "redirect", redirectProc, 0); + espDefineStringCFunction(0, "include", includeProc, 0); + +#if BLD_FEATURE_SESSION + /* + * Create and use are synonomous + */ + espDefineStringCFunction(0, "useSession", useSessionProc, 0); + espDefineStringCFunction(0, "createSession", useSessionProc, 0); + espDefineStringCFunction(0, "destroySession", destroySessionProc, 0); +#endif +} + +/******************************************************************************/ + +#else +void mprEspControlsDummy() {} + +#endif /* BLD_FEATURE_ESP_MODULE */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim:tw=78 + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ |