1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-12 20:58:37 +03:00

r6981: first version of the builtin web server for Samba4

This includes an embedded server side scripting system called 'esp'
(see http://www.appwebserver.org/products/esp/esp.html) and javascript
based scripting language called 'esj' (see
http://www.appwebserver.org/products/ejs/ejs.html)

The justification for including this scripting language is that it
should make it much easier to write a high quality web interface for
Samba4. The scripting language can call into any Samba4 library code
(so for example it will be able to make ldb and loadparm calls), plus
it provides easy support for forms, cookies, sessions etc.

There is still quite a bit more work to do on the web server, but
there is enough here now for people to look at and comment. I will be
committing some sample web pages that test esp functionality shortly.
This commit is contained in:
Andrew Tridgell 2005-05-26 01:06:32 +00:00 committed by Gerald (Jerry) Carter
parent 822e2e5abe
commit 26f0ba92c0
25 changed files with 14596 additions and 1 deletions

View File

@ -41,6 +41,7 @@ sub smb_build_main($)
"smb_server/config.mk",
"rpc_server/config.mk",
"ldap_server/config.mk",
"web_server/config.mk",
"winbind/config.mk",
"nbt_server/config.mk",
"cldap_server/config.mk",

View File

@ -211,3 +211,4 @@ struct wrepl_pull_names;
struct arcfour_state;
union libnet_SamDump;
struct websrv_context;

View File

@ -211,6 +211,7 @@ typedef struct
BOOL bWinbindUseDefaultDomain;
char *szIDMapBackend;
char *szGuestaccount;
char *swat_directory;
int max_mux;
int max_xmit;
int pwordlevel;
@ -238,6 +239,7 @@ typedef struct
int nbt_port;
int dgram_port;
int cldap_port;
int swat_port;
char *socket_options;
BOOL bDNSproxy;
BOOL bWINSsupport;
@ -621,6 +623,8 @@ static struct parm_struct parm_table[] = {
{"nbt port", P_INTEGER, P_GLOBAL, &Globals.nbt_port, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
{"dgram port", P_INTEGER, P_GLOBAL, &Globals.dgram_port, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
{"cldap port", P_INTEGER, P_GLOBAL, &Globals.cldap_port, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
{"swat port", P_INTEGER, P_GLOBAL, &Globals.swat_port, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
{"swat directory", P_STRING, P_GLOBAL, &Globals.swat_directory, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
{"large readwrite", P_BOOL, P_GLOBAL, &Globals.bLargeReadwrite, NULL, NULL, FLAG_DEVELOPER},
{"max protocol", P_ENUM, P_GLOBAL, &Globals.maxprotocol, NULL, enum_protocol, FLAG_DEVELOPER},
{"min protocol", P_ENUM, P_GLOBAL, &Globals.minprotocol, NULL, enum_protocol, FLAG_DEVELOPER},
@ -938,7 +942,7 @@ static void init_globals(void)
do_parameter("max connections", "-1");
do_parameter("dcerpc endpoint servers", "epmapper srvsvc wkssvc rpcecho samr netlogon lsarpc spoolss drsuapi winreg dssetup");
do_parameter("server services", "smb rpc nbt ldap cldap");
do_parameter("server services", "smb rpc nbt ldap cldap web");
do_parameter("auth methods", "anonymous sam_ignoredomain");
do_parameter("smb passwd file", dyn_SMB_PASSWD_FILE);
do_parameter("private dir", dyn_PRIVATE_DIR);
@ -1057,6 +1061,8 @@ static void init_globals(void)
do_parameter("nbt port", "137");
do_parameter("dgram port", "138");
do_parameter("cldap port", "389");
do_parameter("swat port", "901");
do_parameter_var("swat directory", "%s%s", dyn_LIBDIR, "/swat");
do_parameter("nt status support", "True");
@ -1160,7 +1166,9 @@ FN_GLOBAL_LIST(lp_smb_ports, &Globals.smb_ports)
FN_GLOBAL_INTEGER(lp_nbt_port, &Globals.nbt_port)
FN_GLOBAL_INTEGER(lp_dgram_port, &Globals.dgram_port)
FN_GLOBAL_INTEGER(lp_cldap_port, &Globals.cldap_port)
FN_GLOBAL_INTEGER(lp_swat_port, &Globals.swat_port)
FN_GLOBAL_STRING(lp_dos_charset, &Globals.dos_charset)
FN_GLOBAL_STRING(lp_swat_directory, &Globals.swat_directory)
FN_GLOBAL_STRING(lp_unix_charset, &Globals.unix_charset)
FN_GLOBAL_STRING(lp_display_charset, &Globals.display_charset)
FN_GLOBAL_STRING(lp_logfile, &Globals.szLogFile)

View File

@ -60,6 +60,16 @@ REQUIRED_SUBSYSTEMS = \
# End MODULE server_service_cldapd
################################################
################################################
# Start MODULE server_service_web
[MODULE::server_service_web]
INIT_FUNCTION = server_service_web_init
SUBSYSTEM = SERVER_SERVICE
REQUIRED_SUBSYSTEMS = \
WEB
# End MODULE server_service_web
################################################
#######################
# Start SUBSYSTEM SERVICE
[SUBSYSTEM::SERVER_SERVICE]

View File

@ -0,0 +1,39 @@
# web server subsystem
#######################
# Start SUBSYSTEM EJS
[SUBSYSTEM::EJS]
ADD_OBJ_FILES = \
web_server/ejs/ejs.o \
web_server/ejs/ejsLex.o \
web_server/ejs/ejsParser.o \
web_server/ejs/ejsProcs.o \
web_server/ejs/miniMpr.o \
web_server/ejs/var.o
NOPROTO=YES
# End SUBSYSTEM EJS
#######################
#######################
# Start SUBSYSTEM ESP
[SUBSYSTEM::ESP]
ADD_OBJ_FILES = \
web_server/esp/esp.o \
web_server/esp/espProcs.o
REQUIRED_SUBSYSTEMS = EJS
NOPROTO=YES
# End SUBSYSTEM ESP
#######################
#######################
# Start SUBSYSTEM WEB
[SUBSYSTEM::WEB]
INIT_OBJ_FILES = \
web_server/web_server.o
ADD_OBJ_FILES = \
web_server/http.o
REQUIRED_SUBSYSTEMS = ESP
# End SUBSYSTEM WEB
#######################

View File

@ -0,0 +1,147 @@
//
// config.h -- Build configuration file.
//
// WARNING: DO NOT EDIT. This file is generated by configure.
//
// If you wish to modify the defaults, then edit conf/config.defaults.* and
// then run "configure --reset".
//
////////////////////////////////////////////////////////////////////////////////
#define BLD_PRODUCT "Samba4"
#define BLD_NAME "Samba4 SWAT"
#define BLD_VERSION "4"
#define BLD_NUMBER "1"
#define BLD_TYPE "DEBUG"
#define BLD_DEFAULTS "normal"
#define BLD_PACKAGES ""
#define BLD_APPWEB_CONFIG "normal.conf"
#define BLD_APPWEB 0
#define BLD_COMPANY "Mbedthis"
#define BLD_DEBUG 1
#define BLD_DIRS "bootstrap include obj bin mpr ejs esp http doc appWeb appWebSamples images"
#define BLD_HTTP_PORT 7777
#define BLD_LIB_VERSION "1.0.0"
#define BLD_SSL_PORT 4443
#define BLD_CLEAN_INSTALL "0"
#define BLD_LICENSE "gpl"
#define BLD_HOST_SYSTEM "i686-pc-linux-gnu"
#define BLD_BUILD_SYSTEM "i686-pc-linux-gnu"
#define BLD_HOST_OS "LINUX"
#define BLD_HOST_CPU_ARCH MPR_CPU_IX86
#define BLD_HOST_CPU "i686"
#define BLD_HOST_UNIX 1
#define BLD_BUILD_OS "LINUX"
#define BLD_BUILD_CPU_ARCH MPR_CPU_IX86
#define BLD_BUILD_CPU i686
#define BLD_BUILD_UNIX 1
#define BLD_ROOT_PREFIX "/"
#define BLD_FEATURE_ACCESS_LOG 0
#define BLD_FEATURE_ADMIN_MODULE 0
#define BLD_FEATURE_ASPNET_MODULE 0
#define BLD_FEATURE_ASSERT 1
#define BLD_FEATURE_AUTH_MODULE 0
#define BLD_FEATURE_C_API_MODULE 1
#define BLD_FEATURE_C_API_CLIENT 0
#define BLD_FEATURE_CGI_MODULE 0
#define BLD_FEATURE_COMPAT_MODULE 0
#define BLD_FEATURE_CONFIG_PARSE 0
#define BLD_FEATURE_CONFIG_SAVE 0
#define BLD_FEATURE_COOKIE 0
#define BLD_FEATURE_COPY_MODULE 0
#define BLD_FEATURE_DIGEST 0
#define BLD_FEATURE_DLL 0
#define BLD_FEATURE_EGI_MODULE 0
#define BLD_FEATURE_EJS 1
#define BLD_FEATURE_ESP_MODULE 1
#define BLD_FEATURE_EVAL_PERIOD 30
#define BLD_FEATURE_FLOATING_POINT 0
#define BLD_FEATURE_IF_MODIFIED 0
#define BLD_FEATURE_INT64 0
#define BLD_FEATURE_KEEP_ALIVE 0
#define BLD_FEATURE_LEGACY_API 0
#define BLD_FEATURE_LIB_STDCPP 0
#define BLD_FEATURE_LICENSE 0
#define BLD_FEATURE_LOG 0
#define BLD_FEATURE_MULTITHREAD 0
#define BLD_FEATURE_MALLOC 0
#define BLD_FEATURE_MALLOC_STATS 0
#define BLD_FEATURE_MALLOC_LEAK 0
#define BLD_FEATURE_MALLOC_HOOK 0
#define BLD_FEATURE_NUM_TYPE int
#define BLD_FEATURE_NUM_TYPE_ID MPR_TYPE_INT
#define BLD_FEATURE_ROMFS 0
#define BLD_FEATURE_RUN_AS_SERVICE 0
#define BLD_FEATURE_SAFE_STRINGS 0
#define BLD_FEATURE_SAMPLES 0
#define BLD_FEATURE_SESSION 1
#define BLD_FEATURE_SHARED 0
#define BLD_FEATURE_SQUEEZE 0
#define BLD_FEATURE_SSL_MODULE 0
#define BLD_FEATURE_STATIC 1
#define BLD_FEATURE_STATIC_LINK_LIBC 0
#define BLD_FEATURE_TEST 0
#define BLD_FEATURE_UPLOAD_MODULE 0
#define BLD_FEATURE_XDB_MODULE 0
#define BLD_FEATURE_ADMIN_MODULE_BUILTIN 0
#define BLD_FEATURE_ASPNET_MODULE_BUILTIN 0
#define BLD_FEATURE_AUTH_MODULE_BUILTIN 0
#define BLD_FEATURE_C_API_MODULE_BUILTIN 0
#define BLD_FEATURE_CGI_MODULE_BUILTIN 0
#define BLD_FEATURE_COMPAT_MODULE_BUILTIN 0
#define BLD_FEATURE_COPY_MODULE_BUILTIN 0
#define BLD_FEATURE_EGI_MODULE_BUILTIN 0
#define BLD_FEATURE_ESP_MODULE_BUILTIN 0
#define BLD_FEATURE_SSL_MODULE_BUILTIN 0
#define BLD_FEATURE_UPLOAD_MODULE_BUILTIN 0
#define BLD_FEATURE_XDB_MODULE_BUILTIN 0
#define BLD_FEATURE_ADMIN_MODULE_LOADABLE 0
#define BLD_FEATURE_ASPNET_MODULE_LOADABLE 0
#define BLD_FEATURE_AUTH_MODULE_LOADABLE 0
#define BLD_FEATURE_C_API_MODULE_LOADABLE 0
#define BLD_FEATURE_CGI_MODULE_LOADABLE 0
#define BLD_FEATURE_COMPAT_MODULE_LOADABLE 0
#define BLD_FEATURE_COPY_MODULE_LOADABLE 0
#define BLD_FEATURE_EGI_MODULE_LOADABLE 0
#define BLD_FEATURE_ESP_MODULE_LOADABLE 0
#define BLD_FEATURE_SSL_MODULE_LOADABLE 0
#define BLD_FEATURE_UPLOAD_MODULE_LOADABLE 0
#define BLD_FEATURE_XDB_MODULE_LOADABLE 0
#define BLD_AR_FOR_BUILD "ar"
#define BLD_CC_FOR_BUILD "cc"
#define BLD_CSC_FOR_BUILD ""
#define BLD_JAVAC_FOR_BUILD ""
#define BLD_LD_FOR_BUILD "ld"
#define BLD_RANLIB_FOR_BUILD ""
#define BLD_NM_FOR_BUILD "nm"
#define BLD_CFLAGS_FOR_BUILD ""
#define BLD_IFLAGS_FOR_BUILD ""
#define BLD_LDFLAGS_FOR_BUILD ""
#define BLD_ARCHIVE_FOR_BUILD ".a"
#define BLD_EXE_FOR_BUILD ""
#define BLD_OBJ_FOR_BUILD ".o"
#define BLD_PIOBJ_FOR_BUILD ".lo"
#define BLD_CLASS_FOR_BUILD ".class"
#define BLD_SHLIB_FOR_BUILD ""
#define BLD_SHOBJ_FOR_BUILD ".so"
#define BLD_AR_FOR_HOST "ar"
#define BLD_CC_FOR_HOST "cc"
#define BLD_CSC_FOR_HOST "csc"
#define BLD_JAVAC_FOR_HOST "javac"
#define BLD_LD_FOR_HOST "ld"
#define BLD_RANLIB_FOR_HOST "true"
#define BLD_NM_FOR_HOST "nm"
#define BLD_CFLAGS_FOR_HOST ""
#define BLD_IFLAGS_FOR_HOST ""
#define BLD_LDFLAGS_FOR_HOST ""
#define BLD_ARCHIVE_FOR_HOST ".a"
#define BLD_EXE_FOR_HOST ""
#define BLD_OBJ_FOR_HOST ".o"
#define BLD_PIOBJ_FOR_HOST ".lo"
#define BLD_CLASS_FOR_HOST ".class"
#define BLD_SHLIB_FOR_HOST ""
#define BLD_SHOBJ_FOR_HOST ".so"
#define BLD_TOOLS_DIR "${BLD_TOP}/bin"
#define BLD_BIN_DIR "${BLD_TOP}/bin"
#define BLD_INC_DIR "/usr/include/${BLD_PRODUCT}"
#define BLD_EXP_OBJ_DIR "${BLD_TOP}/obj"

1058
source/web_server/ejs/ejs.c Normal file

File diff suppressed because it is too large Load Diff

131
source/web_server/ejs/ejs.h Normal file
View File

@ -0,0 +1,131 @@
/*
* @file ejs.h
* @brief Primary Embedded Javascript (ECMAScript) header.
* @overview This Embedded Javascript (EJS) header defines the
* public API. This API should only be used by those directly
* using EJS without using Embedded Server Pages (ESP). ESP
* wraps all relevant APIs to expose a single consistent API.
* \n\n
* This API requires the mpr/var.h facilities to create and
* manage objects and properties.
*/
/********************************* Copyright **********************************/
/*
* @copy default.g
*
* Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
* Portions Copyright (c) GoAhead Software, 1995-2000. 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_EJS
#define _h_EJS 1
#include "web_server/ejs/miniMpr.h"
#include "web_server/ejs/var.h"
#ifdef __cplusplus
extern "C" {
#endif
/********************************* Prototypes *********************************/
typedef MprVarHandle EjsId;
typedef MprVarHandle EjsHandle;
/*
* Multithreaded lock routines
*/
typedef void (*EjsLock)(void *lockData);
typedef void (*EjsUnlock)(void *lockData);
/********************************* Prototypes *********************************/
/*
* Module management
*/
extern int ejsOpen(EjsLock lock, EjsUnlock unlock, void *lockData);
extern void ejsClose(void);
extern EjsId ejsOpenEngine(EjsHandle primaryHandle, EjsHandle altHandle);
extern void ejsCloseEngine(EjsId eid);
/*
* Evaluation functions
*/
extern int ejsEvalFile(EjsId eid, char *path, MprVar *result, char **emsg);
extern int ejsEvalScript(EjsId eid, char *script, MprVar *result,
char **emsg);
extern int ejsRunFunction(int eid, MprVar *obj, const char *functionName,
MprArray *args);
/*
* Composite variable get / set routines. Can also use the MPR property
* routines on an object variable.
*/
extern MprVar ejsCreateObj(const char *name, int hashSize);
extern MprVar ejsCreateArray(const char *name, int hashSize);
extern bool ejsDestroyVar(MprVar *obj);
extern int ejsCopyVar(EjsId eid, const char *var, MprVar *value, bool copyRef);
extern int ejsReadVar(EjsId eid, const char *var, MprVar *value);
extern int ejsWriteVar(EjsId eid, const char *var, MprVar *value);
extern int ejsWriteVarValue(EjsId eid, const char *var, MprVar value);
extern int ejsDeleteVar(EjsId eid, const char *var);
extern MprVar *ejsGetLocalObject(EjsId eid);
extern MprVar *ejsGetGlobalObject(EjsId eid);
/*
* Function routines
*/
extern void ejsDefineFunction(EjsId eid, char *functionName, char *args,
char *body);
extern void ejsDefineCFunction(EjsId eid, char *functionName,
MprCFunction fn, void *thisPtr, int flags);
extern void ejsDefineStringCFunction(EjsId eid, const char *functionName,
MprStringCFunction fn, void *thisPtr, int flags);
extern void *ejsGetThisPtr(EjsId eid);
extern MprVar *ejsGetReturnValue(EjsId eid);
extern int ejsGetLineNumber(EjsId eid);
extern int ejsParseArgs(int argc, char **argv, char *fmt, ...);
extern void ejsSetErrorMsg(EjsId eid, const char* fmt, ...);
extern void ejsSetReturnValue(EjsId eid, MprVar value);
extern void ejsSetReturnString(EjsId eid, const char *str);
#ifdef __cplusplus
}
#endif
#endif /* _h_EJS */
/*****************************************************************************/
/*
* 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
*/

View File

@ -0,0 +1,292 @@
/*
* @file ejsInternal.h
* @brief Private header for Embedded Javascript (ECMAScript)
* @overview This Embedded Javascript header defines the private Embedded
* Javascript internal structures.
*/
/********************************* Copyright **********************************/
/*
* @copy default.g
*
* Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
* Portions Copyright (c) GoAhead Software, 1995-2000. 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_EJS_INTERNAL
#define _h_EJS_INTERNAL 1
#include "web_server/ejs/ejs.h"
/********************************** Defines ***********************************/
#ifdef __cplusplus
extern "C" {
#endif
/*
* Constants
*/
#if BLD_FEATURE_SQUEEZE
#define EJS_PARSE_INCR 256 /* Growth factor */
#define EJS_MAX_RECURSE 25 /* Sanity for maximum recursion */
#define EJS_MAX_ID 128 /* Maximum ID length */
#define EJS_OBJ_HASH_SIZE 13 /* Object hash table size */
#define EJS_SMALL_OBJ_HASH_SIZE 11 /* Small object hash size */
#define EJS_LIST_INCR 8 /* Growth increment for lists */
#else
#define EJS_PARSE_INCR 1024 /* Growth factor */
#define EJS_MAX_RECURSE 100 /* Sanity for maximum recursion */
#define EJS_MAX_ID 256 /* Maximum ID length */
#define EJS_OBJ_HASH_SIZE 29 /* Object hash table size */
#define EJS_SMALL_OBJ_HASH_SIZE 11 /* Small object hash size */
#define EJS_LIST_INCR 16 /* Growth increment for lists */
#endif
#define EJS_TOKEN_STACK 4 /* Put back token stack */
/*
* Lexical analyser tokens
*/
#define EJS_TOK_ERR -1 /* Any error */
#define EJS_TOK_LPAREN 1 /* ( */
#define EJS_TOK_RPAREN 2 /* ) */
#define EJS_TOK_IF 3 /* if */
#define EJS_TOK_ELSE 4 /* else */
#define EJS_TOK_LBRACE 5 /* { */
#define EJS_TOK_RBRACE 6 /* } */
#define EJS_TOK_LOGICAL 7 /* ||, &&, ! */
#define EJS_TOK_EXPR 8 /* +, -, /, % */
#define EJS_TOK_SEMI 9 /* ; */
#define EJS_TOK_LITERAL 10 /* literal string */
#define EJS_TOK_FUNCTION_NAME 11 /* functionName */
#define EJS_TOK_NEWLINE 12 /* newline white space */
#define EJS_TOK_ID 13 /* Identifier */
#define EJS_TOK_EOF 14 /* End of script */
#define EJS_TOK_COMMA 15 /* Comma */
#define EJS_TOK_VAR 16 /* var */
#define EJS_TOK_ASSIGNMENT 17 /* = */
#define EJS_TOK_FOR 18 /* for */
#define EJS_TOK_INC_DEC 19 /* ++, -- */
#define EJS_TOK_RETURN 20 /* return */
#define EJS_TOK_PERIOD 21 /* . */
#define EJS_TOK_LBRACKET 22 /* [ */
#define EJS_TOK_RBRACKET 23 /* ] */
#define EJS_TOK_NEW 24 /* new */
#define EJS_TOK_DELETE 25 /* delete */
#define EJS_TOK_IN 26 /* in */
#define EJS_TOK_FUNCTION 27 /* function */
#define EJS_TOK_NUMBER 28 /* Number */
/*
* Expression operators
*/
#define EJS_EXPR_LESS 1 /* < */
#define EJS_EXPR_LESSEQ 2 /* <= */
#define EJS_EXPR_GREATER 3 /* > */
#define EJS_EXPR_GREATEREQ 4 /* >= */
#define EJS_EXPR_EQ 5 /* == */
#define EJS_EXPR_NOTEQ 6 /* != */
#define EJS_EXPR_PLUS 7 /* + */
#define EJS_EXPR_MINUS 8 /* - */
#define EJS_EXPR_DIV 9 /* / */
#define EJS_EXPR_MOD 10 /* % */
#define EJS_EXPR_LSHIFT 11 /* << */
#define EJS_EXPR_RSHIFT 12 /* >> */
#define EJS_EXPR_MUL 13 /* * */
#define EJS_EXPR_ASSIGNMENT 14 /* = */
#define EJS_EXPR_INC 15 /* ++ */
#define EJS_EXPR_DEC 16 /* -- */
#define EJS_EXPR_BOOL_COMP 17 /* ! */
/*
* Conditional operators
*/
#define EJS_COND_AND 1 /* && */
#define EJS_COND_OR 2 /* || */
#define EJS_COND_NOT 3 /* ! */
/*
* States
*/
#define EJS_STATE_ERR -1 /* Error state */
#define EJS_STATE_EOF 1 /* End of file */
#define EJS_STATE_COND 2 /* Parsing a "(conditional)" stmt */
#define EJS_STATE_COND_DONE 3
#define EJS_STATE_RELEXP 4 /* Parsing a relational expr */
#define EJS_STATE_RELEXP_DONE 5
#define EJS_STATE_EXPR 6 /* Parsing an expression */
#define EJS_STATE_EXPR_DONE 7
#define EJS_STATE_STMT 8 /* Parsing General statement */
#define EJS_STATE_STMT_DONE 9
#define EJS_STATE_STMT_BLOCK_DONE 10 /* End of block "}" */
#define EJS_STATE_ARG_LIST 11 /* Function arg list */
#define EJS_STATE_ARG_LIST_DONE 12
#define EJS_STATE_DEC_LIST 16 /* Declaration list */
#define EJS_STATE_DEC_LIST_DONE 17
#define EJS_STATE_DEC 18 /* Declaration statement */
#define EJS_STATE_DEC_DONE 19
#define EJS_STATE_RET 20 /* Return statement */
#define EJS_STATE_BEGIN EJS_STATE_STMT
/*
* General parsing flags.
*/
#define EJS_FLAGS_EXE 0x1 /* Execute statements */
#define EJS_FLAGS_LOCAL 0x2 /* Get local vars only */
#define EJS_FLAGS_GLOBAL 0x4 /* Get global vars only */
#define EJS_FLAGS_CREATE 0x8 /* Create var */
#define EJS_FLAGS_ASSIGNMENT 0x10 /* In assignment stmt */
#define EJS_FLAGS_DELETE 0x20 /* Deleting a variable */
#define EJS_FLAGS_FOREACH 0x40 /* In foreach */
#define EJS_FLAGS_NEW 0x80 /* In a new stmt() */
#define EJS_FLAGS_EXIT 0x100 /* Must exit */
/*
* Putback token
*/
typedef struct EjsToken {
char *token; /* Token string */
int id; /* Token ID */
} EjsToken;
/*
* EJ evaluation block structure
*/
typedef struct ejEval {
EjsToken putBack[EJS_TOKEN_STACK]; /* Put back token stack */
int putBackIndex; /* Top of stack index */
MprStr line; /* Current line */
int lineLength; /* Current line length */
int lineNumber; /* Parse line number */
int lineColumn; /* Column in line */
MprStr script; /* Input script for parsing */
char *scriptServp; /* Next token in the script */
int scriptSize; /* Length of script */
MprStr tokbuf; /* Current token */
char *tokEndp; /* Pointer past end of token */
char *tokServp; /* Pointer to next token char */
int tokSize; /* Size of token buffer */
} EjsInput;
/*
* Function call structure
*/
typedef struct {
MprArray *args; /* Args for function */
MprVar *fn; /* Function definition */
char *procName; /* Function name */
} EjsProc;
/*
* Per EJS structure
*/
typedef struct ej {
EjsHandle altHandle; /* alternate callback handle */
MprVar *currentObj; /* Ptr to current object */
MprVar *currentProperty; /* Ptr to current property */
EjsId eid; /* Halloc handle */
char *error; /* Error message */
int exitStatus; /* Status to exit() */
int flags; /* Flags */
MprArray *frames; /* List of variable frames */
MprVar *global; /* Global object */
EjsInput *input; /* Input evaluation block */
MprVar *local; /* Local object */
EjsHandle primaryHandle; /* primary callback handle */
EjsProc *proc; /* Current function */
MprVar result; /* Variable result */
void *thisPtr; /* C++ ptr for functions */
int tid; /* Current token id */
char *token; /* Pointer to token string */
MprVar tokenNumber; /* Parsed number */
} Ejs;
typedef int EjsBlock; /* Scope block id */
/*
* Function callback when using Alternate handles.
*/
typedef int (*EjsAltStringCFunction)(EjsHandle userHandle, EjsHandle altHandle,
int argc, char **argv);
typedef int (*EjsAltCFunction)(EjsHandle userHandle, EjsHandle altHandle,
int argc, MprVar **argv);
/******************************** Prototypes **********************************/
/*
* Ejs Lex
*/
extern int ejsLexOpenScript(Ejs* ep, char *script);
extern void ejsLexCloseScript(Ejs* ep);
extern int ejsInitInputState(EjsInput *ip);
extern void ejsLexSaveInputState(Ejs* ep, EjsInput* state);
extern void ejsLexFreeInputState(Ejs* ep, EjsInput* state);
extern void ejsLexRestoreInputState(Ejs* ep, EjsInput* state);
extern int ejsLexGetToken(Ejs* ep, int state);
extern void ejsLexPutbackToken(Ejs* ep, int tid, char *string);
/*
* Parsing
*/
extern MprVar *ejsFindObj(Ejs *ep, int state, const char *property, int flags);
extern MprVar *ejsFindProperty(Ejs *ep, int state, MprVar *obj,
char *property, int flags);
extern int ejsGetVarCore(Ejs *ep, const char *var, MprVar **obj,
MprVar **varValue, int flags);
extern int ejsParse(Ejs *ep, int state, int flags);
extern Ejs *ejsPtr(EjsId eid);
extern void ejsSetExitStatus(int eid, int status);
extern void ejsSetFlags(int orFlags, int andFlags);
/*
* Create variable scope blocks
*/
extern EjsBlock ejsOpenBlock(EjsId eid);
extern int ejsCloseBlock(EjsId eid, EjsBlock vid);
extern int ejsEvalBlock(EjsId eid, char *script, MprVar *v, char **err);
extern int ejsDefineStandardProperties(MprVar *objVar);
/*
* Error handling
*/
extern void ejsError(Ejs *ep, const char *fmt, ...);
#ifdef __cplusplus
}
#endif
#endif /* _h_EJS_INTERNAL */
/*
* 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
*/

View File

@ -0,0 +1,910 @@
/*
* @file ejsLex.c
* @brief EJS Lexical Analyser
* @overview EJS lexical analyser. This implementes a lexical analyser
* for a subset of the JavaScript language.
*/
/********************************* Copyright **********************************/
/*
* @copy default.g
*
* Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
* Portions Copyright (c) GoAhead Software, 1995-2000. 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 "web_server/ejs/ejsInternal.h"
#if BLD_FEATURE_EJS
/****************************** Forward Declarations **************************/
static int getLexicalToken(Ejs *ep, int state);
static int tokenAddChar(Ejs *ep, int c);
static int inputGetc(Ejs *ep);
static void inputPutback(Ejs *ep, int c);
static int charConvert(Ejs *ep, int base, int maxDig);
/************************************* Code ***********************************/
/*
* Open a new input script
*/
int ejsLexOpenScript(Ejs *ep, char *script)
{
EjsInput *ip;
mprAssert(ep);
mprAssert(script);
if ((ep->input = mprMalloc(sizeof(EjsInput))) == NULL) {
return -1;
}
ip = ep->input;
memset(ip, 0, sizeof(*ip));
/*
* Create the parse token buffer and script buffer
*/
ip->tokbuf = mprMalloc(EJS_PARSE_INCR);
ip->tokSize = EJS_PARSE_INCR;
ip->tokServp = ip->tokbuf;
ip->tokEndp = ip->tokbuf;
ip->script = mprStrdup(script);
ip->scriptSize = strlen(script);
ip->scriptServp = ip->script;
ip->lineNumber = 1;
ip->lineLength = 0;
ip->lineColumn = 0;
ip->line = NULL;
ip->putBackIndex = -1;
return 0;
}
/******************************************************************************/
/*
* Close the input script
*/
void ejsLexCloseScript(Ejs *ep)
{
EjsInput *ip;
int i;
mprAssert(ep);
ip = ep->input;
mprAssert(ip);
for (i = 0; i < EJS_TOKEN_STACK; i++) {
mprFree(ip->putBack[i].token);
ip->putBack[i].token = 0;
}
mprFree(ip->line);
mprFree(ip->tokbuf);
mprFree(ip->script);
mprFree(ip);
}
/******************************************************************************/
/*
* Initialize an input state structure
*/
int ejsInitInputState(EjsInput *ip)
{
mprAssert(ip);
memset(ip, 0, sizeof(*ip));
ip->putBackIndex = -1;
return 0;
}
/******************************************************************************/
/*
* Save the input state
*/
void ejsLexSaveInputState(Ejs *ep, EjsInput *state)
{
EjsInput *ip;
int i;
mprAssert(ep);
ip = ep->input;
mprAssert(ip);
*state = *ip;
for (i = 0; i < ip->putBackIndex; i++) {
state->putBack[i].token = mprStrdup(ip->putBack[i].token);
state->putBack[i].id = ip->putBack[i].id;
}
for (; i < EJS_TOKEN_STACK; i++) {
state->putBack[i].token = 0;
}
state->line = mprMalloc(ip->lineLength);
mprStrcpy(state->line, ip->lineLength, ip->line);
state->lineColumn = ip->lineColumn;
state->lineNumber = ip->lineNumber;
state->lineLength = ip->lineLength;
}
/******************************************************************************/
/*
* Restore the input state
*/
void ejsLexRestoreInputState(Ejs *ep, EjsInput *state)
{
EjsInput *ip;
int i;
mprAssert(ep);
mprAssert(state);
ip = ep->input;
mprAssert(ip);
ip->tokbuf = state->tokbuf;
ip->tokServp = state->tokServp;
ip->tokEndp = state->tokEndp;
ip->tokSize = state->tokSize;
ip->script = state->script;
ip->scriptServp = state->scriptServp;
ip->scriptSize = state->scriptSize;
ip->putBackIndex = state->putBackIndex;
for (i = 0; i < ip->putBackIndex; i++) {
mprFree(ip->putBack[i].token);
ip->putBack[i].id = state->putBack[i].id;
ip->putBack[i].token = mprStrdup(state->putBack[i].token);
}
mprFree(ip->line);
ip->line = mprMalloc(state->lineLength);
mprStrcpy(ip->line, state->lineLength, state->line);
ip->lineColumn = state->lineColumn;
ip->lineNumber = state->lineNumber;
ip->lineLength = state->lineLength;
}
/******************************************************************************/
/*
* Free a saved input state
*/
void ejsLexFreeInputState(Ejs *ep, EjsInput *state)
{
int i;
mprAssert(ep);
mprAssert(state);
for (i = 0; i < EJS_TOKEN_STACK; i++) {
mprFree(state->putBack[i].token);
}
state->putBackIndex = -1;
mprFree(state->line);
state->lineLength = 0;
state->lineColumn = 0;
}
/******************************************************************************/
/*
* Get the next EJS token
*/
int ejsLexGetToken(Ejs *ep, int state)
{
mprAssert(ep);
ep->tid = getLexicalToken(ep, state);
return ep->tid;
}
/******************************************************************************/
/*
* Check for reserved words "if", "else", "var", "for", "foreach",
* "delete", "function", and "return". "new", "in" and "function"
* done below. "true", "false", "null", "undefined" are handled
* as global objects.
*
* Other reserved words not supported:
* "break", "case", "catch", "continue", "default", "do",
* "finally", "instanceof", "switch", "this", "throw", "try",
* "typeof", "while", "with"
*
* ECMA extensions reserved words (not supported):
* "abstract", "boolean", "byte", "char", "class", "const",
* "debugger", "double", "enum", "export", "extends",
* "final", "float", "goto", "implements", "import", "int",
* "interface", "long", "native", "package", "private",
* "protected", "public", "short", "static", "super",
* "synchronized", "throws", "transient", "volatile"
*/
static int checkReservedWord(Ejs *ep, int state, int c, int tid)
{
if (state == EJS_STATE_STMT) {
if (strcmp(ep->token, "if") == 0) {
inputPutback(ep, c);
return EJS_TOK_IF;
} else if (strcmp(ep->token, "else") == 0) {
inputPutback(ep, c);
return EJS_TOK_ELSE;
} else if (strcmp(ep->token, "var") == 0) {
inputPutback(ep, c);
return EJS_TOK_VAR;
} else if (strcmp(ep->token, "for") == 0) {
inputPutback(ep, c);
return EJS_TOK_FOR;
} else if (strcmp(ep->token, "delete") == 0) {
inputPutback(ep, c);
return EJS_TOK_DELETE;
} else if (strcmp(ep->token, "function") == 0) {
inputPutback(ep, c);
return EJS_TOK_FUNCTION;
} else if (strcmp(ep->token, "return") == 0) {
if ((c == ';') || (c == '(')) {
inputPutback(ep, c);
}
return EJS_TOK_RETURN;
}
} else if (state == EJS_STATE_EXPR) {
if (strcmp(ep->token, "new") == 0) {
inputPutback(ep, c);
return EJS_TOK_NEW;
} else if (strcmp(ep->token, "in") == 0) {
inputPutback(ep, c);
return EJS_TOK_IN;
} else if (strcmp(ep->token, "function") == 0) {
inputPutback(ep, c);
return EJS_TOK_FUNCTION;
}
}
return tid;
}
/******************************************************************************/
/*
* Get the next EJS token
*/
static int getLexicalToken(Ejs *ep, int state)
{
MprType type;
EjsInput *ip;
int done, tid, c, quote, style, idx;
mprAssert(ep);
ip = ep->input;
mprAssert(ip);
ep->tid = -1;
tid = -1;
type = BLD_FEATURE_NUM_TYPE_ID;
/*
* Use a putback tokens first. Don't free strings as caller needs access.
*/
if (ip->putBackIndex >= 0) {
idx = ip->putBackIndex;
tid = ip->putBack[idx].id;
ep->token = (char*) ip->putBack[idx].token;
tid = checkReservedWord(ep, state, 0, tid);
ip->putBackIndex--;
return tid;
}
ep->token = ip->tokServp = ip->tokEndp = ip->tokbuf;
*ip->tokServp = '\0';
if ((c = inputGetc(ep)) < 0) {
return EJS_TOK_EOF;
}
/*
* Main lexical analyser
*/
for (done = 0; !done; ) {
switch (c) {
case -1:
return EJS_TOK_EOF;
case ' ':
case '\t':
case '\r':
do {
if ((c = inputGetc(ep)) < 0)
break;
} while (c == ' ' || c == '\t' || c == '\r');
break;
case '\n':
return EJS_TOK_NEWLINE;
case '(':
tokenAddChar(ep, c);
return EJS_TOK_LPAREN;
case ')':
tokenAddChar(ep, c);
return EJS_TOK_RPAREN;
case '[':
tokenAddChar(ep, c);
return EJS_TOK_LBRACKET;
case ']':
tokenAddChar(ep, c);
return EJS_TOK_RBRACKET;
case '.':
tokenAddChar(ep, c);
return EJS_TOK_PERIOD;
case '{':
tokenAddChar(ep, c);
return EJS_TOK_LBRACE;
case '}':
tokenAddChar(ep, c);
return EJS_TOK_RBRACE;
case '+':
if ((c = inputGetc(ep)) < 0) {
ejsError(ep, "Syntax Error");
return EJS_TOK_ERR;
}
if (c != '+' ) {
inputPutback(ep, c);
tokenAddChar(ep, EJS_EXPR_PLUS);
return EJS_TOK_EXPR;
}
tokenAddChar(ep, EJS_EXPR_INC);
return EJS_TOK_INC_DEC;
case '-':
if ((c = inputGetc(ep)) < 0) {
ejsError(ep, "Syntax Error");
return EJS_TOK_ERR;
}
if (c != '-' ) {
inputPutback(ep, c);
tokenAddChar(ep, EJS_EXPR_MINUS);
return EJS_TOK_EXPR;
}
tokenAddChar(ep, EJS_EXPR_DEC);
return EJS_TOK_INC_DEC;
case '*':
tokenAddChar(ep, EJS_EXPR_MUL);
return EJS_TOK_EXPR;
case '%':
tokenAddChar(ep, EJS_EXPR_MOD);
return EJS_TOK_EXPR;
case '/':
/*
* Handle the division operator and comments
*/
if ((c = inputGetc(ep)) < 0) {
ejsError(ep, "Syntax Error");
return EJS_TOK_ERR;
}
if (c != '*' && c != '/') {
inputPutback(ep, c);
tokenAddChar(ep, EJS_EXPR_DIV);
return EJS_TOK_EXPR;
}
style = c;
/*
* Eat comments. Both C and C++ comment styles are supported.
*/
while (1) {
if ((c = inputGetc(ep)) < 0) {
ejsError(ep, "Syntax Error");
return EJS_TOK_ERR;
}
if (c == '\n' && style == '/') {
break;
} else if (c == '*') {
c = inputGetc(ep);
if (style == '/') {
if (c == '\n') {
break;
}
} else {
if (c == '/') {
break;
}
}
}
}
/*
* Continue looking for a token, so get the next character
*/
if ((c = inputGetc(ep)) < 0) {
return EJS_TOK_EOF;
}
break;
case '<': /* < and <= */
if ((c = inputGetc(ep)) < 0) {
ejsError(ep, "Syntax Error");
return EJS_TOK_ERR;
}
if (c == '<') {
tokenAddChar(ep, EJS_EXPR_LSHIFT);
return EJS_TOK_EXPR;
} else if (c == '=') {
tokenAddChar(ep, EJS_EXPR_LESSEQ);
return EJS_TOK_EXPR;
}
tokenAddChar(ep, EJS_EXPR_LESS);
inputPutback(ep, c);
return EJS_TOK_EXPR;
case '>': /* > and >= */
if ((c = inputGetc(ep)) < 0) {
ejsError(ep, "Syntax Error");
return EJS_TOK_ERR;
}
if (c == '>') {
tokenAddChar(ep, EJS_EXPR_RSHIFT);
return EJS_TOK_EXPR;
} else if (c == '=') {
tokenAddChar(ep, EJS_EXPR_GREATEREQ);
return EJS_TOK_EXPR;
}
tokenAddChar(ep, EJS_EXPR_GREATER);
inputPutback(ep, c);
return EJS_TOK_EXPR;
case '=': /* "==" */
if ((c = inputGetc(ep)) < 0) {
ejsError(ep, "Syntax Error");
return EJS_TOK_ERR;
}
if (c == '=') {
tokenAddChar(ep, EJS_EXPR_EQ);
return EJS_TOK_EXPR;
}
inputPutback(ep, c);
return EJS_TOK_ASSIGNMENT;
case '!': /* "!=" or "!"*/
if ((c = inputGetc(ep)) < 0) {
ejsError(ep, "Syntax Error");
return EJS_TOK_ERR;
}
if (c == '=') {
tokenAddChar(ep, EJS_EXPR_NOTEQ);
return EJS_TOK_EXPR;
}
inputPutback(ep, c);
tokenAddChar(ep, EJS_EXPR_BOOL_COMP);
return EJS_TOK_EXPR;
case ';':
tokenAddChar(ep, c);
return EJS_TOK_SEMI;
case ',':
tokenAddChar(ep, c);
return EJS_TOK_COMMA;
case '|': /* "||" */
if ((c = inputGetc(ep)) < 0 || c != '|') {
ejsError(ep, "Syntax Error");
return EJS_TOK_ERR;
}
tokenAddChar(ep, EJS_COND_OR);
return EJS_TOK_LOGICAL;
case '&': /* "&&" */
if ((c = inputGetc(ep)) < 0 || c != '&') {
ejsError(ep, "Syntax Error");
return EJS_TOK_ERR;
}
tokenAddChar(ep, EJS_COND_AND);
return EJS_TOK_LOGICAL;
case '\"': /* String quote */
case '\'':
quote = c;
if ((c = inputGetc(ep)) < 0) {
ejsError(ep, "Syntax Error");
return EJS_TOK_ERR;
}
while (c != quote) {
/*
* Check for escape sequence characters
*/
if (c == '\\') {
c = inputGetc(ep);
if (isdigit(c)) {
/*
* Octal support, \101 maps to 65 = 'A'. Put first
* char back so converter will work properly.
*/
inputPutback(ep, c);
c = charConvert(ep, 8, 3);
} else {
switch (c) {
case 'n':
c = '\n'; break;
case 'b':
c = '\b'; break;
case 'f':
c = '\f'; break;
case 'r':
c = '\r'; break;
case 't':
c = '\t'; break;
case 'x':
/*
* Hex support, \x41 maps to 65 = 'A'
*/
c = charConvert(ep, 16, 2);
break;
case 'u':
/*
* Unicode support, \x0401 maps to 65 = 'A'
*/
c = charConvert(ep, 16, 2);
c = c*16 + charConvert(ep, 16, 2);
break;
case '\'':
case '\"':
case '\\':
break;
default:
ejsError(ep, "Invalid Escape Sequence");
return EJS_TOK_ERR;
}
}
if (tokenAddChar(ep, c) < 0) {
return EJS_TOK_ERR;
}
} else {
if (tokenAddChar(ep, c) < 0) {
return EJS_TOK_ERR;
}
}
if ((c = inputGetc(ep)) < 0) {
ejsError(ep, "Unmatched Quote");
return EJS_TOK_ERR;
}
}
return EJS_TOK_LITERAL;
case '0':
if (tokenAddChar(ep, c) < 0) {
return EJS_TOK_ERR;
}
if ((c = inputGetc(ep)) < 0) {
break;
}
if (tolower(c) == 'x') {
if (tokenAddChar(ep, c) < 0) {
return EJS_TOK_ERR;
}
if ((c = inputGetc(ep)) < 0) {
break;
}
}
if (! isdigit(c)) {
#if BLD_FEATURE_FLOATING_POINT
if (c == '.' || tolower(c) == 'e' || c == '+' || c == '-') {
/* Fall through */
type = MPR_TYPE_FLOAT;
} else
#endif
{
mprDestroyVar(&ep->tokenNumber);
ep->tokenNumber = mprParseVar(ep->token, type);
inputPutback(ep, c);
return EJS_TOK_NUMBER;
}
}
/* Fall through to get more digits */
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
do {
if (tokenAddChar(ep, c) < 0) {
return EJS_TOK_ERR;
}
if ((c = inputGetc(ep)) < 0) {
break;
}
#if BLD_FEATURE_FLOATING_POINT
if (c == '.' || tolower(c) == 'e' || c == '+' || c == '-') {
type = MPR_TYPE_FLOAT;
}
} while (isdigit(c) || c == '.' || tolower(c) == 'e' ||
c == '+' || c == '-');
#else
} while (isdigit(c));
#endif
mprDestroyVar(&ep->tokenNumber);
ep->tokenNumber = mprParseVar(ep->token, type);
inputPutback(ep, c);
return EJS_TOK_NUMBER;
default:
/*
* Identifiers or a function names
*/
while (1) {
if (c == '\\') {
if ((c = inputGetc(ep)) < 0) {
break;
}
if (c == '\n' || c == '\r') {
break;
}
} else if (tokenAddChar(ep, c) < 0) {
break;
}
if ((c = inputGetc(ep)) < 0) {
break;
}
if (!isalnum(c) && c != '$' && c != '_' && c != '\\') {
break;
}
}
if (*ep->token == '\0') {
c = inputGetc(ep);
break;
}
if (! isalpha((int) *ep->token) && *ep->token != '$' &&
*ep->token != '_') {
ejsError(ep, "Invalid identifier %s", ep->token);
return EJS_TOK_ERR;
}
tid = checkReservedWord(ep, state, c, EJS_TOK_ID);
if (tid != EJS_TOK_ID) {
return tid;
}
/*
* Skip white space after token to find out whether this is
* a function or not.
*/
while (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
if ((c = inputGetc(ep)) < 0)
break;
}
tid = EJS_TOK_ID;
done++;
}
}
/*
* Putback the last extra character for next time
*/
inputPutback(ep, c);
return tid;
}
/******************************************************************************/
/*
* Convert a hex or octal character back to binary, return original char if
* not a hex digit
*/
static int charConvert(Ejs *ep, int base, int maxDig)
{
int i, c, lval, convChar;
lval = 0;
for (i = 0; i < maxDig; i++) {
if ((c = inputGetc(ep)) < 0) {
break;
}
/*
* Initialize to out of range value
*/
convChar = base;
if (isdigit(c)) {
convChar = c - '0';
} else if (c >= 'a' && c <= 'f') {
convChar = c - 'a' + 10;
} else if (c >= 'A' && c <= 'F') {
convChar = c - 'A' + 10;
}
/*
* If unexpected character then return it to buffer.
*/
if (convChar >= base) {
inputPutback(ep, c);
break;
}
lval = (lval * base) + convChar;
}
return lval;
}
/******************************************************************************/
/*
* Putback the last token read. Accept at most one push back token.
*/
void ejsLexPutbackToken(Ejs *ep, int tid, char *string)
{
EjsInput *ip;
int idx;
mprAssert(ep);
ip = ep->input;
mprAssert(ip);
ip->putBackIndex += 1;
idx = ip->putBackIndex;
ip->putBack[idx].id = tid;
if (ip->putBack[idx].token) {
if (ip->putBack[idx].token == string) {
return;
}
mprFree(ip->putBack[idx].token);
}
ip->putBack[idx].token = mprStrdup(string);
}
/******************************************************************************/
/*
* Add a character to the token buffer
*/
static int tokenAddChar(Ejs *ep, int c)
{
EjsInput *ip;
uchar *oldbuf;
mprAssert(ep);
ip = ep->input;
mprAssert(ip);
if (ip->tokEndp >= &ip->tokbuf[ip->tokSize - 1]) {
ip->tokSize += EJS_PARSE_INCR;
oldbuf = ip->tokbuf;
ip->tokbuf = mprRealloc(ip->tokbuf, ip->tokSize);
if (ip->tokbuf == 0) {
ejsError(ep, "Token too big");
return -1;
}
ip->tokEndp += (int) ((uchar*) ip->tokbuf - oldbuf);
ip->tokServp += (int) ((uchar*) ip->tokbuf - oldbuf);
ep->token += (int) ((uchar*) ip->tokbuf - oldbuf);
}
*ip->tokEndp++ = c;
*ip->tokEndp = '\0';
return 0;
}
/******************************************************************************/
/*
* Get another input character
*/
static int inputGetc(Ejs *ep)
{
EjsInput *ip;
int c;
mprAssert(ep);
ip = ep->input;
if (ip->scriptSize <= 0) {
return -1;
}
c = (uchar) (*ip->scriptServp++);
ip->scriptSize--;
/*
* For debugging, accumulate the line number and the currenly parsed line
*/
if (c == '\n') {
#if BLD_DEBUG && 0
if (ip->lineColumn > 0) {
printf("PARSED: %s\n", ip->line);
}
#endif
ip->lineNumber++;
ip->lineColumn = 0;
} else {
if ((ip->lineColumn + 2) >= ip->lineLength) {
ip->lineLength += 80;
ip->line = mprRealloc(ip->line, ip->lineLength * sizeof(char));
}
ip->line[ip->lineColumn++] = c;
ip->line[ip->lineColumn] = '\0';
}
return c;
}
/******************************************************************************/
/*
* Putback a character onto the input queue
*/
static void inputPutback(Ejs *ep, int c)
{
EjsInput *ip;
mprAssert(ep);
if (c != 0) {
ip = ep->input;
*--ip->scriptServp = c;
ip->scriptSize++;
ip->lineColumn--;
ip->line[ip->lineColumn] = '\0';
}
}
/******************************************************************************/
#else
void ejsLexDummy() {}
/******************************************************************************/
#endif /* BLD_FEATURE_EJS */
/*
* 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
*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,705 @@
/*
* @file ejsProc.c
* @brief EJS support functions
*/
/********************************* Copyright **********************************/
/*
* @copy default.g
*
* Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
* Portions Copyright (c) GoAhead Software, 1995-2000. 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 "web_server/ejs/ejsInternal.h"
#if BLD_FEATURE_EJS
/****************************** Forward Declarations **************************/
/*
* Object constructors
*/
static int objectConsProc(EjsHandle eid, int argc, MprVar **argv);
static int arrayConsProc(EjsHandle eid, int argc, MprVar **argv);
static int booleanConsProc(EjsHandle eid, int argc, MprVar **agv);
static int numberConsProc(EjsHandle eid, int argc, MprVar **argv);
static int stringConsProc(EjsHandle eid, int argc, MprVar **argv);
/*
* Core functions
*/
static int toStringProc(EjsHandle eid, int argc, MprVar **argv);
static int valueOfProc(EjsHandle eid, int argc, MprVar **argv);
/*
* Triggers
*/
static MprVarTriggerStatus lengthTrigger(MprVarTriggerOp op,
MprProperties *parentProperties, MprVar *prop, MprVar *newValue,
bool copyRef);
/******************************************************************************/
/*
* Routine to create the base common to all object types
*/
MprVar ejsCreateObj(const char *name, int hashSize)
{
MprVar o;
o = mprCreateObjVar(name, hashSize);
if (o.type == MPR_TYPE_UNDEFINED) {
mprAssert(0);
return o;
}
mprCreatePropertyValue(&o, "toString",
mprCreateCFunctionVar(toStringProc, 0, MPR_VAR_SCRIPT_HANDLE));
mprCreatePropertyValue(&o, "valueOf",
mprCreateCFunctionVar(valueOfProc, 0, MPR_VAR_SCRIPT_HANDLE));
return o;
}
/******************************************************************************/
/*
* Routine to destroy a variable
*/
bool ejsDestroyVar(MprVar *obj)
{
return mprDestroyVar(obj);
}
/******************************************************************************/
/*
* Routine to create the base array type
*/
MprVar ejsCreateArray(const char *name, int size)
{
MprVar obj, *lp, undef;
char idx[16];
int i;
/* Sanity limit for size of hash table */
obj = ejsCreateObj(name, max(size, 503));
if (obj.type == MPR_TYPE_UNDEFINED) {
mprAssert(0);
return obj;
}
undef = mprCreateUndefinedVar();
for (i = 0; i < size; i++) {
mprItoa(i, idx, sizeof(idx));
mprCreateProperty(&obj, idx, &undef);
}
lp = mprCreatePropertyValue(&obj, "length", mprCreateIntegerVar(size));
mprAssert(lp);
mprSetVarReadonly(lp, 1);
mprAddVarTrigger(lp, lengthTrigger);
return obj;
}
/******************************************************************************/
/******************************** Constructors ********************************/
/******************************************************************************/
/*
* Object constructor. Nothing really done here. For future expansion.
*/
static int objectConsProc(EjsHandle eid, int argc, MprVar **argv)
{
#if UNUSED
MprVar *obj;
Ejs *ep;
if((ep = ejsPtr(eid)) == NULL) {
return -1;
}
obj = mprGetProperty(ep->local, "this", 0);
mprAssert(obj);
#endif
return 0;
}
/******************************************************************************/
/*
* Array constructor
*/
static int arrayConsProc(EjsHandle eid, int argc, MprVar **argv)
{
MprVar *obj, *lp, undef;
Ejs *ep;
char idx[16];
int i, max;
objectConsProc(eid, argc, argv);
if((ep = ejsPtr(eid)) == NULL) {
return -1;
}
obj = mprGetProperty(ep->local, "this", 0);
mprAssert(obj);
if (argc == 1) {
/*
* x = new Array(size);
*/
undef = mprCreateUndefinedVar();
max = (int) mprVarToInteger(argv[0]);
for (i = 0; i < max; i++) {
mprItoa(i, idx, sizeof(idx));
mprCreateProperty(obj, idx, &undef);
}
} else if (argc > 1) {
/*
* x = new Array(element0, element1, ..., elementN):
*/
max = argc;
for (i = 0; i < max; i++) {
mprItoa(i, idx, sizeof(idx));
mprCreateProperty(obj, idx, argv[i]);
}
} else {
max = 0;
}
lp = mprCreatePropertyValue(obj, "length", mprCreateIntegerVar(max));
mprAssert(lp);
mprSetVarReadonly(lp, 1);
mprAddVarTrigger(lp, lengthTrigger);
return 0;
}
/******************************************************************************/
/*
* Boolean constructor
*/
static int booleanConsProc(EjsHandle eid, int argc, MprVar **argv)
{
objectConsProc(eid, argc, argv);
return 0;
}
/******************************************************************************/
#if FUTURE
/*
* Date constructor
*/
static int dateConsProc(EjsHandle eid, int argc, MprVar **argv)
{
objectConsProc(eid, argc, argv);
return 0;
}
#endif
/******************************************************************************/
/*
* Number constructor
*/
static int numberConsProc(EjsHandle eid, int argc, MprVar **argv)
{
objectConsProc(eid, argc, argv);
return 0;
}
/******************************************************************************/
/*
* String constructor
*/
static int stringConsProc(EjsHandle eid, int argc, MprVar **argv)
{
objectConsProc(eid, argc, argv);
return 0;
}
/******************************************************************************/
/********************************** Functions *********************************/
/******************************************************************************/
static int toStringProc(EjsHandle eid, int argc, MprVar **argv)
{
MprVar *obj;
Ejs *ep;
char *buf;
int radix;
if (argc == 0) {
radix = 10;
} else if (argc == 1) {
radix = (int) mprVarToInteger(argv[0]);
} else {
mprAssert(0);
return -1;
}
if((ep = ejsPtr(eid)) == NULL) {
return -1;
}
obj = mprGetProperty(ep->local, "this", 0);
mprAssert(obj);
mprVarToString(&buf, MPR_MAX_STRING, 0, obj);
mprCopyVarValue(&ep->result, mprCreateStringVar(buf, 0), MPR_SHALLOW_COPY);
mprFree(buf);
return 0;
}
/******************************************************************************/
static int valueOfProc(EjsHandle eid, int argc, MprVar **argv)
{
MprVar *obj;
Ejs *ep;
if (argc != 0) {
mprAssert(0);
return -1;
}
if((ep = ejsPtr(eid)) == NULL) {
return -1;
}
obj = mprGetProperty(ep->local, "this", 0);
mprAssert(obj);
switch (obj->type) {
default:
case MPR_TYPE_UNDEFINED:
case MPR_TYPE_NULL:
case MPR_TYPE_CFUNCTION:
case MPR_TYPE_OBJECT:
case MPR_TYPE_FUNCTION:
case MPR_TYPE_STRING_CFUNCTION:
mprCopyVar(&ep->result, obj, MPR_SHALLOW_COPY);
break;
case MPR_TYPE_STRING:
mprCopyVarValue(&ep->result, mprCreateIntegerVar(atoi(obj->string)), 0);
break;
case MPR_TYPE_BOOL:
case MPR_TYPE_INT:
#if BLD_FEATURE_INT64
case MPR_TYPE_INT64:
#endif
#if BLD_FEATURE_FLOATING_POINT
case MPR_TYPE_FLOAT:
#endif
mprCopyVar(&ep->result, obj, 0);
break;
}
return 0;
}
/******************************************************************************/
/*
* Var access trigger on the Array.length property. Return the count of
* enumerable properties (don't count functions).
*/
static MprVarTriggerStatus lengthTrigger(MprVarTriggerOp op,
MprProperties *parentProperties, MprVar *prop, MprVar *newValue,
bool copyRef)
{
switch (op) {
case MPR_VAR_READ:
/*
* Subtract one for the length property
* FUTURE -- need an API to access parentProperties
* FUTURE -- contradiction to be read-only yet allow USE_NEW_VALUE.
* API needs finer control.
*/
*newValue = mprCreateIntegerVar(parentProperties->numDataItems - 1);
return MPR_TRIGGER_USE_NEW_VALUE;
case MPR_VAR_WRITE:
return MPR_TRIGGER_ABORT;
case MPR_VAR_CREATE_PROPERTY:
case MPR_VAR_DELETE_PROPERTY:
case MPR_VAR_DELETE:
default:
break;
}
return MPR_TRIGGER_PROCEED;
}
/******************************************************************************/
/**************************** Extension Functions *****************************/
/******************************************************************************/
/*
* Assert
*/
static int assertProc(EjsHandle eid, int argc, MprVar **argv)
{
bool b;
if (argc < 1) {
ejsSetErrorMsg(eid, "usage: assert(condition)\n");
return -1;
}
b = mprVarToBool(argv[0]);
if (b == 0) {
ejsSetErrorMsg(eid, "Assertion failure\n");
return -1;
}
ejsSetReturnValue(eid, mprCreateBoolVar(b));
return 0;
}
/******************************************************************************/
/*
* Exit
*/
static int exitProc(EjsHandle eid, int argc, MprVar **argv)
{
int status;
if (argc < 1) {
ejsSetErrorMsg(eid, "usage: exit(status)\n");
return -1;
}
status = (int) mprVarToInteger(argv[0]);
ejsSetExitStatus(eid, status);
ejsSetReturnValue(eid, mprCreateStringVar("", 0));
return 0;
}
/******************************************************************************/
static void printVar(MprVar *vp, int recurseCount, int indent)
{
MprVar *np;
char *buf;
int i;
if (recurseCount > 5) {
write(1, "Skipping - recursion too deep\n", 29);
return;
}
for (i = 0; i < indent; i++) {
write(1, " ", 2);
}
if (vp->type == MPR_TYPE_OBJECT) {
if (vp->name) {
write(1, vp->name, strlen(vp->name));
} else {
write(1, "unknown", 7);
}
write(1, ": {\n", 4);
np = mprGetFirstProperty(vp, MPR_ENUM_DATA);
while (np) {
if (strcmp(np->name, "local") == 0 ||
strcmp(np->name, "global") == 0 ||
strcmp(np->name, "this") == 0) {
np = mprGetNextProperty(vp, np, MPR_ENUM_DATA);
continue;
}
printVar(np, recurseCount + 1, indent + 1);
np = mprGetNextProperty(vp, np, MPR_ENUM_DATA);
if (np) {
write(1, ",\n", 2);
}
}
write(1, "\n", 1);
for (i = 0; i < indent; i++) {
write(1, " ", 2);
}
write(1, "}", 1);
} else {
if (vp->name) {
write(1, vp->name, strlen(vp->name));
} else {
write(1, "unknown", 7);
}
write(1, ": ", 2);
/* FUTURE -- other types ? */
mprVarToString(&buf, MPR_MAX_STRING, 0, vp);
if (vp->type == MPR_TYPE_STRING) {
write(1, "\"", 1);
}
write(1, buf, strlen(buf));
if (vp->type == MPR_TYPE_STRING) {
write(1, "\"", 1);
}
mprFree(buf);
}
}
/******************************************************************************/
/*
* Print the args to stdout
*/
static int printVarsProc(EjsHandle eid, int argc, MprVar **argv)
{
MprVar *vp;
char *buf;
int i;
for (i = 0; i < argc; i++) {
vp = argv[i];
switch (vp->type) {
case MPR_TYPE_OBJECT:
printVar(vp, 0, 0);
break;
default:
mprVarToString(&buf, MPR_MAX_STRING, 0, vp);
write(1, buf, strlen(buf));
mprFree(buf);
break;
}
}
write(1, "\n", 1);
ejsSetReturnValue(eid, mprCreateStringVar("", 0));
return 0;
}
/******************************************************************************/
/*
* Print the args to stdout
*/
static int printProc(EjsHandle eid, int argc, MprVar **argv)
{
char *buf;
int i;
for (i = 0; i < argc; i++) {
mprVarToString(&buf, MPR_MAX_STRING, 0, argv[i]);
write(1, buf, strlen(buf));
mprFree(buf);
}
return 0;
}
/******************************************************************************/
/*
* println
*/
static int printlnProc(EjsHandle eid, int argc, MprVar **argv)
{
printProc(eid, argc, argv);
write(1, "\n", 1);
return 0;
}
/******************************************************************************/
/*
* Trace
*/
static int traceProc(EjsHandle eid, int argc, char **argv)
{
if (argc == 1) {
mprLog(0, argv[0]);
} else if (argc == 2) {
mprLog(atoi(argv[0]), argv[1]);
} else {
ejsSetErrorMsg(eid, "Usage: trace([level], message)");
return -1;
}
ejsSetReturnString(eid, "");
return 0;
}
/******************************************************************************/
/*
* Return the object reference count
*/
static int refCountProc(EjsHandle eid, int argc, MprVar **argv)
{
MprVar *vp;
int count;
vp = argv[0];
if (vp->type == MPR_TYPE_OBJECT) {
count = mprGetVarRefCount(vp);
ejsSetReturnValue(eid, mprCreateIntegerVar(count));
} else {
ejsSetReturnValue(eid, mprCreateIntegerVar(0));
}
return 0;
}
/******************************************************************************/
/*
* Evaluate a sub-script. It is evaluated in the same variable scope as
* the calling script / function.
*/
static int evalScriptProc(EjsHandle eid, int argc, MprVar **argv)
{
MprVar *arg;
char *emsg;
int i;
ejsSetReturnValue(eid, mprCreateUndefinedVar());
for (i = 0; i < argc; i++) {
arg = argv[i];
if (arg->type != MPR_TYPE_STRING) {
continue;
}
if (ejsEvalScript(eid, arg->string, 0, &emsg) < 0) {
ejsSetErrorMsg(eid, "%s", emsg);
mprFree(emsg);
return -1;
}
}
/*
* Return with the value of the last expression
*/
return 0;
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/*
* Define the standard properties and functions inherited by all script engines.
*/
int ejsDefineStandardProperties(MprVar *obj)
{
#if BLD_FEATURE_FLOATING_POINT
double d = 0.0;
/* FUTURE - this generates warnings on some systems. This is okay. */
mprCreatePropertyValue(obj, "NaN", mprCreateFloatVar(0.0 / d));
d = MAX_FLOAT;
mprCreatePropertyValue(obj, "Infinity", mprCreateFloatVar(d * d));
#endif
mprCreatePropertyValue(obj, "null", mprCreateNullVar());
mprCreatePropertyValue(obj, "undefined", mprCreateUndefinedVar());
mprCreatePropertyValue(obj, "true", mprCreateBoolVar(1));
mprCreatePropertyValue(obj, "false", mprCreateBoolVar(0));
#if BLD_FEATURE_LEGACY_API
/*
* DEPRECATED: 2.0.
* So that ESP/ASP can ignore "language=javascript" statements
*/
mprCreatePropertyValue(obj, "javascript", mprCreateIntegerVar(0));
#endif
/*
* Extension functions
*/
mprCreatePropertyValue(obj, "assert",
mprCreateCFunctionVar(assertProc, 0, MPR_VAR_SCRIPT_HANDLE));
mprCreatePropertyValue(obj, "eval",
mprCreateCFunctionVar(evalScriptProc, 0, MPR_VAR_SCRIPT_HANDLE));
mprCreatePropertyValue(obj, "exit",
mprCreateCFunctionVar(exitProc, 0, MPR_VAR_SCRIPT_HANDLE));
mprCreatePropertyValue(obj, "refCount",
mprCreateCFunctionVar(refCountProc, 0, MPR_VAR_SCRIPT_HANDLE));
mprCreatePropertyValue(obj, "print",
mprCreateCFunctionVar(printProc, 0, MPR_VAR_SCRIPT_HANDLE));
mprCreatePropertyValue(obj, "println",
mprCreateCFunctionVar(printlnProc, 0, MPR_VAR_SCRIPT_HANDLE));
mprCreatePropertyValue(obj, "printVars",
mprCreateCFunctionVar(printVarsProc,0, MPR_VAR_SCRIPT_HANDLE));
mprCreatePropertyValue(obj, "trace",
mprCreateStringCFunctionVar(traceProc, 0, MPR_VAR_SCRIPT_HANDLE));
/*
* Constructors
*/
mprCreatePropertyValue(obj, "Array",
mprCreateCFunctionVar(arrayConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
mprCreatePropertyValue(obj, "Boolean",
mprCreateCFunctionVar(booleanConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
mprCreatePropertyValue(obj, "Object",
mprCreateCFunctionVar(objectConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
mprCreatePropertyValue(obj, "Number",
mprCreateCFunctionVar(numberConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
mprCreatePropertyValue(obj, "String",
mprCreateCFunctionVar(stringConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
/* mprCreatePropertyValue(obj, "Date",
* mprCreateCFunctionVar(dateConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
* mprCreatePropertyValue(obj, "Regexp",
* mprCreateCFunctionVar(regexpConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
*/
/*
* Can we use on var x = "string text";
*/
return 0;
}
/******************************************************************************/
#else
void ejsProcsDummy() {}
/******************************************************************************/
#endif /* BLD_FEATURE_EJS */
/*
* 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
*/

View File

@ -0,0 +1,512 @@
/*
* @file miniMpr.cpp
* @brief Mini Mbedthis Portable Runtime (MPR)
* @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
*/
#include "web_server/ejs/miniMpr.h"
/************************************ Code ************************************/
#if !BLD_APPWEB
#if !BLD_GOAHEAD_WEBSERVER
static TALLOC_CTX *mpr_ctx;
void mprFreeAll(void)
{
talloc_free(mpr_ctx);
mpr_ctx = NULL;
}
void mprSetCtx(TALLOC_CTX *ctx)
{
talloc_free(mpr_ctx);
mpr_ctx = talloc_new(ctx);
}
void mprFree(void *ptr)
{
talloc_free(ptr);
}
void *mprMalloc(uint size)
{
return talloc_size(mpr_ctx, size);
}
/******************************************************************************/
void *mprRealloc(void *ptr, uint size)
{
return talloc_realloc_size(mpr_ctx, ptr, size);
}
/******************************************************************************/
char *mprStrdup(const char *str)
{
if (str == 0) {
str = "";
}
return talloc_strdup(mpr_ctx, str);
}
/*****************************************************************************/
int mprAllocSprintf(char **msgbuf, int maxSize, const char *fmt, ...)
{
va_list args;
char *buf;
int count;
va_start(args, fmt);
buf = mprMalloc(maxSize + 1);
count = mtVsprintf(buf, maxSize, fmt, args);
*msgbuf = buf;
va_end(args);
return count;
}
/*****************************************************************************/
int mprAllocVsprintf(char **msgbuf, int maxSize, const char *fmt, va_list args)
{
char *buf;
int count;
buf = mprMalloc(maxSize + 1);
count = mtVsprintf(buf, maxSize, fmt, args);
*msgbuf = buf;
return count;
}
/*****************************************************************************/
/*
* Format a number as a string. FUTURE -- reverse args to be standard.
* ie. mprItoa(char *userBuf, int bufsize, int value);
*/
char *mprItoa(int value, char *buf, int width)
{
char numBuf[16];
char *cp, *dp, *endp;
int negative;
cp = &numBuf[sizeof(numBuf)];
*--cp = '\0';
if (value < 0) {
negative = 1;
value = -value;
width--;
} else {
negative = 0;
}
do {
*--cp = '0' + (value % 10);
value /= 10;
} while (value > 0);
if (negative) {
*--cp = '-';
}
dp = buf;
endp = &buf[width];
while (dp < endp && *cp) {
*dp++ = *cp++;
}
*dp++ = '\0';
return buf;
}
/*****************************************************************************/
void mprLog(int level, const char *fmt, ...)
{
va_list args;
char *buf;
if (DEBUGLVL(level)) {
va_start(args, fmt);
mprAllocVsprintf(&buf, MPR_MAX_STRING, fmt, args);
va_end(args);
DEBUG(level, ("mprLog: %s", buf));
mprFree(buf);
}
}
/*****************************************************************************/
void mprBreakpoint(const char *file, int line, const char *cond)
{
/*
* Optionally break into the debugger here
*/
mprLog(0, "ASSERT at %s:%d, %s\n", file, line, cond);
}
#endif /* !BLD_GOAHEAD_WEBSERVER */
/*****************************************************************************/
/*
* Create a general growable array structure
*/
MprArray *mprCreateArray()
{
MprArray *array;
int size;
array = (MprArray*) mprMalloc(sizeof(MprArray));
if (array == 0) {
return 0;
}
memset(array, 0, sizeof(MprArray));
size = MPR_ARRAY_INCR * sizeof(void*);
array->handles = (void**) mprMalloc(size);
if (array->handles == 0) {
mprFree(array);
return 0;
}
memset(array->handles, 0, size);
array->max = MPR_ARRAY_INCR;
array->used = 0;
return array;
}
/*****************************************************************************/
/*
* Dispose of the array. Callers responsibility to dispose of handle entries.
*/
void mprDestroyArray(MprArray *array)
{
mprAssert(array);
mprAssert(array->max >= 0);
mprAssert(array->used >= 0);
mprFree(array->handles);
mprFree(array);
}
/*****************************************************************************/
/*
* Add an item to the array
*/
int mprAddToArray(MprArray *array, void *item)
{
int memsize, idx, len;
mprAssert(array);
mprAssert(array->max >= 0);
mprAssert(array->used >= 0);
if (array->used < array->max) {
idx = array->used++;
mprAssert(idx >= 0 && idx < array->max);
mprAssert(array->handles[idx] == 0);
array->handles[idx] = item;
return idx;
}
for (idx = array->used; idx < array->max; idx++) {
if (array->handles[idx] == 0) {
array->used++;
mprAssert(array->handles[idx] == 0);
array->handles[idx] = item;
return idx;
}
}
len = array->max + MPR_ARRAY_INCR;
memsize = len * sizeof(void*);
array->handles = (void**) mprRealloc((void*) array->handles, memsize);
if (array->handles == NULL) {
return -1;
}
memset(&array->handles[array->max], 0, sizeof(void*) * MPR_ARRAY_INCR);
array->max = len;
array->used++;
mprAssert(idx >= 0 && idx < array->max);
mprAssert(array->handles[idx] == 0);
array->handles[idx] = item;
return idx;
}
/*****************************************************************************/
/*
* Remove from the array
*/
int mprRemoveFromArray(MprArray *array, int idx)
{
mprAssert(array);
mprAssert(array->max > 0);
mprAssert(idx >= 0 && idx < array->max);
mprAssert(array->handles[idx] != 0);
mprAssert(array->used > 0);
array->handles[idx] = 0;
return --array->used;
}
/*****************************************************************************/
/*
* Thread-safe wrapping of strtok. Note "str" is modifed as per strtok()
*/
char *mprStrTok(char *str, const char *delim, char **tok)
{
char *start, *end;
int i;
start = str ? str : *tok;
if (start == 0) {
return 0;
}
i = strspn(start, delim);
start += i;
if (*start == '\0') {
*tok = 0;
return 0;
}
end = strpbrk(start, delim);
if (end) {
*end++ = '\0';
i = strspn(end, delim);
end += i;
}
*tok = end;
return start;
}
/*****************************************************************************/
static int mprCoreStrcat(int alloc, char **destp, int destMax, int existingLen,
const char *delim, const char *src, va_list args)
{
va_list ap;
char *dest, *dp;
const char *str;
int sepLen, addBytes, required;
mprAssert(destp);
mprAssert(destMax > 0);
mprAssert(src);
dest = *destp;
sepLen = (delim) ? strlen(delim) : 0;
#ifdef __va_copy
__va_copy(ap, args);
#else
ap = args;
#endif
addBytes = 0;
str = src;
while (str) {
addBytes += strlen(str) + sepLen;
str = va_arg(ap, const char*);
}
if (existingLen > 0) {
addBytes += sepLen;
}
required = existingLen + addBytes + 1;
if (required >= destMax) {
mprAssert(0);
return MPR_ERR_WONT_FIT;
}
if (alloc) {
if (dest == 0) {
dest = (char*) mprMalloc(required);
} else {
dest = (char*) mprRealloc(dest, required);
}
} else {
dest = (char*) *destp;
}
dp = &dest[existingLen];
if (delim) {
strcpy(dp, delim);
dp += sepLen;
}
if (addBytes > 0) {
#ifdef __va_copy
__va_copy(ap, args);
#else
ap = args;
#endif
str = src;
while (str) {
strcpy(dp, str);
dp += strlen(str);
str = va_arg(ap, char*);
if (delim && str) {
strcpy(dp, delim);
dp += sepLen;
}
}
} else if (dest == 0) {
dest = (char*) mprMalloc(1);
}
*dp = '\0';
*destp = dest;
mprAssert(dp < &dest[required]);
return required - 1;
}
/*****************************************************************************/
int mprReallocStrcat(char **destp, int destMax, int existingLen,
const char *delim, const char *src,...)
{
va_list ap;
int rc;
va_start(ap, src);
rc = mprCoreStrcat(1, destp, destMax, existingLen, delim, src, ap);
va_end(ap);
return rc;
}
/*****************************************************************************/
/*
* Return the directory portion of a pathname into the users buffer.
*/
int mprGetDirName(char *buf, int bufsize, char *path)
{
char *cp;
int dlen;
mprAssert(path);
mprAssert(buf);
mprAssert(bufsize > 0);
cp = strrchr(path, '/');
if (cp == 0) {
#if WIN
cp = strrchr(path, '\\');
if (cp == 0)
#endif
{
buf[0] = '\0';
return 0;
}
}
if (cp == path && cp[1] == '\0') {
strcpy(buf, ".");
return 0;
}
dlen = cp - path;
if (dlen < bufsize) {
if (dlen == 0) {
dlen++;
}
mprMemcpy(buf, bufsize, path, dlen);
buf[dlen] = '\0';
return 0;
}
return MPR_ERR_WONT_FIT;
}
/*****************************************************************************/
int mprStrcpy(char *dest, int destMax, const char *src)
{
int len;
mprAssert(dest);
mprAssert(destMax > 0);
mprAssert(src);
len = strlen(src);
if (len >= destMax && len > 0) {
mprAssert(0);
return MPR_ERR_WONT_FIT;
}
if (len > 0) {
memcpy(dest, src, len);
dest[len] = '\0';
} else {
*dest = '\0';
len = 0;
}
return len;
}
/*****************************************************************************/
int mprMemcpy(char *dest, int destMax, const char *src, int nbytes)
{
mprAssert(dest);
mprAssert(destMax > nbytes);
mprAssert(src);
mprAssert(nbytes > 0);
if (nbytes > destMax) {
mprAssert(0);
return MPR_ERR_WONT_FIT;
}
if (nbytes > 0) {
memcpy(dest, src, nbytes);
return nbytes;
} else {
return 0;
}
}
/*****************************************************************************/
#else
void miniMprDummy() {}
#endif // !BLD_APPWEB && !BLD_GOAHEAD_WEBSERVER
/*
* 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
*/

View File

@ -0,0 +1,287 @@
/*
* @file miniMpr.h
* @brief Mini Mbedthis Portable Runtime (MPR) Environment.
* @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_MINI_MPR
#define _h_MINI_MPR 1
/********************************** Includes **********************************/
/*
* Find out about our configuration
*/
#include "includes.h"
/* allow this library to use strcpy() */
#undef strcpy
#include "config.h"
#if BLD_APPWEB
/*
* If building within AppWeb, use the full MPR
*/
#include "mpr.h"
#else
#include <ctype.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#if !WIN
#include <unistd.h>
#endif
#if CE
#include <io.h>
#include "CE/wincompat.h"
#endif
#if LYNX
#include <unistd.h>
#endif
#if QNX4
#include <dirent.h>
#endif
/********************************** Defines ***********************************/
#ifdef __cplusplus
extern "C" {
#endif
#if BLD_FEATURE_SQUEEZE
///
/// Reasonable length of a file path name to use in most cases where you know
/// the expected file name and it is certain to be less than this limit.
///
#define MPR_MAX_FNAME 128
#define MPR_MAX_STRING 512
#define MPR_DEFAULT_HASH_SIZE 23 // Default size of hash table index
#define MPR_MAX_HEAP_SIZE (32 * 1024)
#else
#define MPR_MAX_FNAME 256
#define MPR_MAX_STRING 4096
#define MPR_DEFAULT_HASH_SIZE 43 // Default size of hash table index
#define MPR_MAX_HEAP_SIZE (64 * 1024)
#endif
/*
* Useful for debugging
*/
#define MPR_L __FILE__, __LINE__
#if BLD_FEATURE_ASSERT
#define mprAssert(C) \
if (C) ; else mprBreakpoint(__FILE__, __LINE__, #C)
#else
#define mprAssert(C) if (1) ; else
#endif
///
/// Standard MPR return and error codes
///
#define MPR_ERR_BASE (-200) ///< Error code
#define MPR_ERR_GENERAL (MPR_ERR_BASE - 1) ///< Error code
#define MPR_ERR_ABORTED (MPR_ERR_BASE - 2) ///< Error code
#define MPR_ERR_ALREADY_EXISTS (MPR_ERR_BASE - 3) ///< Error code
#define MPR_ERR_BAD_ARGS (MPR_ERR_BASE - 4) ///< Error code
#define MPR_ERR_BAD_FORMAT (MPR_ERR_BASE - 5) ///< Error code
#define MPR_ERR_BAD_HANDLE (MPR_ERR_BASE - 6) ///< Error code
#define MPR_ERR_BAD_STATE (MPR_ERR_BASE - 7) ///< Error code
#define MPR_ERR_BAD_SYNTAX (MPR_ERR_BASE - 8) ///< Error code
#define MPR_ERR_BAD_TYPE (MPR_ERR_BASE - 9) ///< Error code
#define MPR_ERR_BAD_VALUE (MPR_ERR_BASE - 10) ///< Error code
#define MPR_ERR_BUSY (MPR_ERR_BASE - 11) ///< Error code
#define MPR_ERR_CANT_ACCESS (MPR_ERR_BASE - 12) ///< Error code
#define MPR_ERR_CANT_COMPLETE (MPR_ERR_BASE - 13) ///< Error code
#define MPR_ERR_CANT_CREATE (MPR_ERR_BASE - 14) ///< Error code
#define MPR_ERR_CANT_INITIALIZE (MPR_ERR_BASE - 15) ///< Error code
#define MPR_ERR_CANT_OPEN (MPR_ERR_BASE - 16) ///< Error code
#define MPR_ERR_CANT_READ (MPR_ERR_BASE - 17) ///< Error code
#define MPR_ERR_CANT_WRITE (MPR_ERR_BASE - 18) ///< Error code
#define MPR_ERR_DELETED (MPR_ERR_BASE - 19) ///< Error code
#define MPR_ERR_NETWORK (MPR_ERR_BASE - 20) ///< Error code
#define MPR_ERR_NOT_FOUND (MPR_ERR_BASE - 21) ///< Error code
#define MPR_ERR_NOT_INITIALIZED (MPR_ERR_BASE - 22) ///< Error code
#define MPR_ERR_NOT_READY (MPR_ERR_BASE - 23) ///< Error code
#define MPR_ERR_READ_ONLY (MPR_ERR_BASE - 24) ///< Error code
#define MPR_ERR_TIMEOUT (MPR_ERR_BASE - 25) ///< Error code
#define MPR_ERR_TOO_MANY (MPR_ERR_BASE - 26) ///< Error code
#define MPR_ERR_WONT_FIT (MPR_ERR_BASE - 27) ///< Error code
#define MPR_ERR_WOULD_BLOCK (MPR_ERR_BASE - 28) ///< Error code
#define MPR_ERR_CANT_ALLOCATE (MPR_ERR_BASE - 29) ///< Error code
#define MPR_ERR_MAX (MPR_ERR_BASE - 30) ///< Error code
//
// Standard error severity and trace levels. These are ored with the error
// severities below. The MPR_LOG_MASK is used to extract the trace level
// from a flags word. We expect most apps to run with level 2 trace.
//
#define MPR_FATAL 0 ///< Fatal error. Cant continue.
#define MPR_ERROR 1 ///< Hard error
#define MPR_WARN 2 ///< Soft warning
#define MPR_CONFIG 2 ///< Essential configuration settings
#define MPR_INFO 3 ///< Informational only
#define MPR_DEBUG 4 ///< Debug information
#define MPR_VERBOSE 9 ///< Highest level of trace
#define MPR_LOG_MASK 0xf ///< Level mask
//
// Error flags. Specify where the error should be sent to. Note that the
// product.xml setting "headless" will modify how errors are reported.
// Assert errors are trapped when in DEV mode. Otherwise ignored.
//
#define MPR_TRAP 0x10 ///< Assert error -- trap in debugger
#define MPR_LOG 0x20 ///< Log the error in the O/S event log
#define MPR_USER 0x40 ///< Display to the user
#define MPR_ALERT 0x80 ///< Send a management alert
#define MPR_TRACE 0x100 ///< Trace
//
// Error format flags
//
#define MPR_RAW 0x200 // Raw trace output
//
// Error line number information
//
#define MPR_L __FILE__, __LINE__
typedef char* MprStr;
#ifndef __cplusplus
typedef unsigned char uchar;
typedef int bool;
#endif
/*
* Porters: put other operating system type defines here
*/
#if WIN
typedef unsigned int uint;
typedef __int64 int64;
typedef unsigned __int64 uint64;
#else
#define O_BINARY 0
typedef unsigned int uint;
__extension__ typedef long long int int64;
__extension__ typedef unsigned long long int uint64;
#endif
/*
* Flexible array data type
*/
typedef struct {
int max; /* Size of the handles array */
int used; /* Count of used entries in handles */
void **handles;
} MprArray;
#if BLD_FEATURE_SQUEEZE
#define MPR_ARRAY_INCR 8
#else
#define MPR_ARRAY_INCR 16
#endif
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
/********************************* Prototypes *********************************/
/*
* If running in the GoAhead WebServer, map some MPR routines to WebServer
* equivalents.
*/
#if BLD_GOAHEAD_WEBSERVER
#include "uemf.h"
#define mprMalloc(size) balloc(B_L, size)
#define mprFree(ptr) bfreeSafe(B_L, ptr)
#define mprRealloc(ptr, size) brealloc(B_L, ptr, size)
#define mprStrdup(ptr) bstrdup(B_L, ptr)
#define mprAllocSprintf fmtAlloc
#define mprAllocVsprintf fmtValloc
#define mprSprintf fmtStatic
#define mprItoa stritoa
#define mprLog trace
#define mprBreakpoint(file, line, cond) \
error(file, line, E_BLD_FEATURE_ASSERT, T("%s"), cond)
#else /* !BLD_GOAHEAD_WEBSERVER */
//#define mprMalloc malloc
#define mprSprintf snprintf
#define mtVsprintf vsnprintf
extern void *mprMalloc(uint size);
extern void *mprRealloc(void *ptr, uint size);
extern void mprFree(void *ptr);
extern char *mprStrdup(const char *str);
extern int mprAllocVsprintf(char **msgbuf, int maxSize, const char *fmt,
va_list args);
extern int mprAllocSprintf(char **msgbuf, int maxSize, const char *fmt, ...);
extern char *mprItoa(int num, char *buf, int width);
extern void mprLog(int level, const char *fmt, ...);
extern void mprBreakpoint(const char *file, int line, const char *msg);
#endif /* BLD_GOAHEAD_WEBSERVER */
extern MprArray *mprCreateArray(void);
extern void mprDestroyArray(MprArray *array);
extern int mprAddToArray(MprArray *array, void *item);
extern int mprRemoveFromArray(MprArray *array, int idx);
extern char *mprStrTok(char *str, const char *delim, char **tok);
extern int mprGetDirName(char *buf, int bufsize, char *path);
extern int mprReallocStrcat(char **dest, int max, int existingLen,
const char *delim, const char *src, ...);
extern int mprStrcpy(char *dest, int destMax, const char *src);
extern int mprMemcpy(char *dest, int destMax, const char *src, int nbytes);
extern void mprFreeAll(void);
extern void mprSetCtx(TALLOC_CTX *ctx);
#ifdef __cplusplus
}
#endif
#endif /* !BLD_APPWEB */
#endif /* _h_MINI_MPR */
/*****************************************************************************/
/*
* 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
*/

2259
source/web_server/ejs/mpr.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,627 @@
///
/// @file mprOs.h
/// @brief Include O/S headers and smooth out per-O/S differences
// @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
//////////////////////////////// Documentation /////////////////////////////////
///
/// This header is part of the Mbedthis Portable Runtime and aims to include
/// all necessary O/S headers and to unify the constants and declarations
/// required by Mbedthis products. It can be included by C or C++ programs.
///
////////////////////////////////////////////////////////////////////////////////
#error foo
blah blah;
#ifndef _h_MPR_OS_HDRS
#define _h_MPR_OS_HDRS 1
#include "web_server/ejs/config.h"
////////////////////////////////// CPU Families ////////////////////////////////
//
// Porters, add your CPU families here and update configure code.
//
#define MPR_CPU_UNKNOWN 0
#define MPR_CPU_IX86 1
#define MPR_CPU_PPC 2
#define MPR_CPU_SPARC 3
#define MPR_CPU_XSCALE 4
#define MPR_CPU_ARM 5
#define MPR_CPU_MIPS 6
#define MPR_CPU_68K 7
#define MPR_CPU_SIMNT 8 // VxWorks NT simulator
#define MPR_CPU_SIMSPARC 9 // VxWorks sparc simulator
////////////////////////////////// O/S Includes ////////////////////////////////
#if LINUX || SOLARIS
#include <sys/types.h>
#include <time.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <grp.h>
#include <errno.h>
#include <libgen.h>
#include <limits.h>
#include <netdb.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <pthread.h>
#include <pwd.h>
#include <resolv.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <unistd.h>
#if LINUX
#include <stdint.h>
#endif
#if SOLARIS
#include <netinet/in_systm.h>
#endif
#if BLD_FEATURE_FLOATING_POINT
#define __USE_ISOC99 1
#include <math.h>
#include <values.h>
#endif
#endif // LINUX || SOLARIS
#if VXWORKS
#include <vxWorks.h>
#include <envLib.h>
#include <sys/types.h>
#include <time.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <loadLib.h>
#include <netdb.h>
#include <net/if.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysSymTbl.h>
#include <sys/fcntlcom.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/times.h>
#include <sys/wait.h>
#include <unistd.h>
#include <unldLib.h>
#if BLD_FEATURE_FLOATING_POINT
#include <float.h>
#define __USE_ISOC99 1
#include <math.h>
#endif
#include <sockLib.h>
#include <inetLib.h>
#include <ioLib.h>
#include <pipeDrv.h>
#include <hostLib.h>
#include <netdb.h>
#include <tickLib.h>
#include <taskHookLib.h>
#endif // VXWORKS
#if MACOSX
#include <time.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <fcntl.h>
#include <grp.h>
#include <errno.h>
#include <libgen.h>
#include <limits.h>
#include <mach-o/dyld.h>
#include <netdb.h>
#include <net/if.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <pthread.h>
#include <pwd.h>
#include <resolv.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <syslog.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <unistd.h>
#endif // MACOSX
#if WIN
#include <ctype.h>
#include <conio.h>
#include <direct.h>
#include <errno.h>
#include <fcntl.h>
#include <io.h>
#include <limits.h>
#include <malloc.h>
#include <process.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
#include <winbase.h>
#if BLD_FEATURE_FLOATING_POINT
#include <float.h>
#endif
#include <shlobj.h>
#include <shellapi.h>
#include <wincrypt.h>
#endif // WIN
#ifdef __cplusplus
extern "C" {
#endif
////////////////////////////////////////////////////////////////////////////////
//////////////////////////////// General Defines ///////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#define MAXINT INT_MAX
#define BITS(type) (BITSPERBYTE * (int) sizeof(type))
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
//
// Set FD_SETSIZE to the maximum number of files (sockets) that you want to
// support. It is used in select.cpp.
//
// #ifdef FD_SETSIZE
// #undef FD_SETSIZE
// #endif
// #define FD_SETSIZE 128
//
typedef char *MprStr; // Used for dynamic strings
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// Linux Defines ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#if LINUX
typedef unsigned char uchar;
#if BLD_FEATURE_INT64
__extension__ typedef long long int int64;
__extension__ typedef unsigned long long int uint64;
#define INT64(x) (x##LL)
#endif
#define closesocket(x) close(x)
#define MPR_BINARY ""
#define MPR_TEXT ""
#define O_BINARY 0
#define O_TEXT 0
#define SOCKET_ERROR -1
#define MPR_DLL_EXT ".so"
#if BLD_FEATURE_FLOATING_POINT
#define MAX_FLOAT MAXFLOAT
#endif
#if BLD_FEATURE_MALLOC
//
// PORTERS: You will need add assembler code for your architecture here
// only if you want to use the fast malloc (BLD_FEATURE_MALLOC)
//
#if UNUSED
#define MPR_GET_RETURN(ip) __builtin_return_address(0)
#else
#if BLD_HOST_CPU_ARCH == MPR_CPU_IX86
#define MPR_GET_RETURN(ip) \
asm("movl 4(%%ebp),%%eax ; movl %%eax,%0" : \
"=g" (ip) : \
: "eax")
#endif
#endif // UNUSED
#endif // BLD_FEATURE_MALLOC
#if FUTURE
// #define mprGetHiResTime(x) __asm__ __volatile__ ("rdtsc" : "=A" (x))
// extern char *inet_ntoa_r(const struct in_addr in, char *buffer, int buflen);
//
// Atomic functions
//
typedef struct { volatile int counter; } mprAtomic_t;
#if BLD_FEATURE_MULTITHREAD
#define LOCK "lock ; "
#else
#define LOCK ""
#endif
static __inline__ void mprAtomicInc(mprAtomic_t* v) {
__asm__ __volatile__(
LOCK "incl %0"
:"=m" (v->counter)
:"m" (v->counter));
}
static __inline__ void mprAtomicDec(mprAtomic_t* v) {
__asm__ __volatile__(
LOCK "decl %0"
:"=m" (v->counter)
:"m" (v->counter));
}
#endif // FUTURE
#endif // LINUX
////////////////////////////////////////////////////////////////////////////////
//////////////////////////////// VxWorks Defines ///////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#if VXWORKS
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
#define HAVE_SOCKLEN_T
typedef int socklen_t;
#if BLD_FEATURE_INT64
typedef long long int int64;
typedef unsigned long long int uint64;
#define INT64(x) (x##LL)
#endif
#define closesocket(x) close(x)
#define getpid() taskIdSelf()
#define MPR_BINARY ""
#define MPR_TEXT ""
#define O_BINARY 0
#define O_TEXT 0
#define SOCKET_ERROR -1
#define MPR_DLL_EXT ".so"
#if BLD_FEATURE_FLOATING_POINT
#define MAX_FLOAT FLT_MAX
#endif
#undef R_OK
#define R_OK 4
#undef W_OK
#define W_OK 2
#undef X_OK
#define X_OK 1
#undef F_OK
#define F_OK 0
#define MSG_NOSIGNAL 0
extern int access(char *path, int mode);
extern int sysClkRateGet();
#if BLD_FEATURE_MALLOC
//
// PORTERS: You will need add assembler code for your architecture here
// only if you want to use the fast malloc (BLD_FEATURE_MALLOC)
//
#if UNUSED
#define MPR_GET_RETURN(ip) __builtin_return_address(0)
#else
#if BLD_HOST_CPU_ARCH == MPR_CPU_IX86
#define MPR_GET_RETURN(ip) \
asm("movl 4(%%ebp),%%eax ; movl %%eax,%0" : \
"=g" (ip) : \
: "eax")
#endif
#endif // UNUSED
#endif // BLD_FEATURE_MALLOC
#endif // VXWORKS
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// MacOsx Defines ///////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#if MACOSX
typedef unsigned long ulong;
typedef unsigned char uchar;
#if BLD_FEATURE_INT64
__extension__ typedef long long int int64;
__extension__ typedef unsigned long long int uint64;
#define INT64(x) (x##LL)
#endif
#define closesocket(x) close(x)
#define MPR_BINARY ""
#define MPR_TEXT ""
#define O_BINARY 0
#define O_TEXT 0
#define SOCKET_ERROR -1
#define MPR_DLL_EXT ".dylib"
#define MSG_NOSIGNAL 0
#define __WALL 0x40000000
#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
#if BLD_FEATURE_FLOATING_POINT
#define MAX_FLOAT MAXFLOAT
#endif
#if MPR_FEATURE_MALLOC
//
// PORTERS: You will need add assembler code for your architecture here
// only if you want to use the fast malloc (MPR_FEATURE_MALLOC)
//
#define MPR_GET_RETURN(ip) __builtin_return_address
#endif
#if FUTURE
// #define mprGetHiResTime(x) __asm__ __volatile__ ("rdtsc" : "=A" (x))
// extern char *inet_ntoa_r(const struct in_addr in, char *buffer, int buflen);
//
// Atomic functions
//
typedef struct { volatile int counter; } mprAtomic_t;
#if MPR_FEATURE_MULTITHREAD
#define LOCK "lock ; "
#else
#define LOCK ""
#endif
static __inline__ void mprAtomicInc(mprAtomic_t* v) {
__asm__ __volatile__(
LOCK "incl %0"
:"=m" (v->counter)
:"m" (v->counter));
}
static __inline__ void mprAtomicDec(mprAtomic_t* v) {
__asm__ __volatile__(
LOCK "decl %0"
:"=m" (v->counter)
:"m" (v->counter));
}
#endif
#endif // MACOSX
////////////////////////////////////////////////////////////////////////////////
//////////////////////////////// Windows Defines ///////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#if WIN
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned short ushort;
#if BLD_FEATURE_INT64
typedef __int64 int64;
typedef unsigned __int64 uint64;
#define INT64(x) (x##i64)
#endif
typedef int uid_t;
typedef void *handle;
typedef char *caddr_t;
typedef long pid_t;
typedef int gid_t;
typedef ushort mode_t;
typedef void *siginfo_t;
#define HAVE_SOCKLEN_T
typedef int socklen_t;
#undef R_OK
#define R_OK 4
#undef W_OK
#define W_OK 2
#undef X_OK
#define X_OK 1
#undef F_OK
#define F_OK 0
#ifndef EADDRINUSE
#define EADDRINUSE 46
#endif
#ifndef EWOULDBLOCK
#define EWOULDBLOCK EAGAIN
#endif
#ifndef ENETDOWN
#define ENETDOWN 43
#endif
#ifndef ECONNRESET
#define ECONNRESET 44
#endif
#ifndef ECONNREFUSED
#define ECONNREFUSED 45
#endif
#define MSG_NOSIGNAL 0
#define MPR_BINARY "b"
#define MPR_TEXT "t"
#if BLD_FEATURE_FLOATING_POINT
#define MAX_FLOAT DBL_MAX
#endif
#ifndef FILE_FLAG_FIRST_PIPE_INSTANCE
#define FILE_FLAG_FIRST_PIPE_INSTANCE 0x00080000
#endif
#define access _access
#define close _close
#define fileno _fileno
#define fstat _fstat
#define getpid _getpid
#define open _open
#define putenv _putenv
#define read _read
#define stat _stat
#define umask _umask
#define unlink _unlink
#define write _write
#define strdup _strdup
#define lseek _lseek
#define mkdir(a,b) _mkdir(a)
#define rmdir(a) _rmdir(a)
#if BLD_FEATURE_MALLOC
//
// PORTERS: You will need add assembler code for your architecture here
// only if you want to use the fast malloc (BLD_FEATURE_MALLOC)
//
#if MPR_CPU_IX86
#define MPR_GET_RETURN(ip) \
__asm { mov eax, 4[ebp] } \
__asm { mov ip, eax }
#endif
#endif
#define MPR_DLL_EXT ".dll"
extern void srand48(long);
extern long lrand48(void);
extern long ulimit(int, ...);
extern long nap(long);
extern uint sleep(unsigned int secs);
extern uid_t getuid(void);
extern uid_t geteuid(void);
#endif // WIN
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////// Solaris Defines ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#if SOLARIS
typedef unsigned char uchar;
#if BLD_FEATURE_INT64
typedef long long int int64;
typedef unsigned long long int uint64;
#define INT64(x) (x##LL)
#endif
#define closesocket(x) close(x)
#define MPR_BINARY ""
#define MPR_TEXT ""
#define O_BINARY 0
#define O_TEXT 0
#define SOCKET_ERROR -1
#define MPR_DLL_EXT ".so"
#define MSG_NOSIGNAL 0
#define INADDR_NONE ((in_addr_t) 0xffffffff)
#define __WALL 0
#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
#if BLD_FEATURE_FLOATING_POINT
#define MAX_FLOAT MAXFLOAT
#endif
#endif // SOLARIS
////////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
}
#endif
#endif // _h_MPR_OS_HDRS
//
// 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
//

2161
source/web_server/ejs/var.c Normal file

File diff suppressed because it is too large Load Diff

482
source/web_server/ejs/var.h Normal file
View File

@ -0,0 +1,482 @@
/*
* @file var.h
* @brief MPR Universal Variable Type
* @copy default.m
*
* Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
* Copyright (c) Michael O'Brien, 1994-1995. 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
*/
/******************************* Documentation ********************************/
/*
* Variables can efficiently store primitive types and can hold references to
* objects. Objects can store properties which are themselves variables.
* Properties can be primitive data types, other objects or functions.
* Properties are indexed by a character name. A variable may store one of
* the following types:
*
* string, integer, integer-64bit, C function, C function with string args,
* Javascript function, Floating point number, boolean value, Undefined
* value and the Null value.
*
* Variables have names while objects may be referenced by multiple variables.
* Objects use reference counting for garbage collection.
*
* This module is not thread safe for performance and compactness. It relies
* on upper modules to provide thread synchronization as required. The API
* provides primitives to get variable/object references or to get copies of
* variables which will help minimize required lock times.
*/
#ifndef _h_MPR_VAR
#define _h_MPR_VAR 1
/********************************* Includes ***********************************/
#include "web_server/ejs/miniMpr.h"
/********************************** Defines ***********************************/
/*
* Define VAR_DEBUG if you want to track objects. However, this code is not
* thread safe and you need to run the server single threaded.
*
* #define VAR_DEBUG 1
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
* Forward declare types
*/
struct MprProperties;
struct MprVar;
/*
* Possible variable types. Don't use enum because we need to be able to
* do compile time conditional compilation on BLD_FEATURE_NUM_TYPE_ID.
*/
typedef int MprType;
#define MPR_TYPE_UNDEFINED 0 ///< Undefined. No value has been set.
#define MPR_TYPE_NULL 1 ///< Value defined to be null.
#define MPR_TYPE_BOOL 2 ///< Boolean type.
#define MPR_TYPE_CFUNCTION 3 ///< C function or C++ method
#define MPR_TYPE_FLOAT 4 ///< Floating point number
#define MPR_TYPE_INT 5 ///< Integer number
#define MPR_TYPE_INT64 6 ///< 64-bit Integer number
#define MPR_TYPE_OBJECT 7 ///< Object reference
#define MPR_TYPE_FUNCTION 8 ///< JavaScript function
#define MPR_TYPE_STRING 9 ///< String (immutable)
#define MPR_TYPE_STRING_CFUNCTION 10 ///< C/C++ function with string args
/*
* Create a type for the default number type
* Config.h will define the default number type. For example:
*
* BLD_FEATURE_NUM_TYPE=int
* BLD_FEATURE_NUM_TYPE_ID=MPR_TYPE_INT
*/
/**
* Set to the type used for MPR numeric variables. Will equate to int, int64
* or double.
*/
typedef BLD_FEATURE_NUM_TYPE MprNum;
/**
* Set to the MPR_TYPE used for MPR numeric variables. Will equate to
* MPR_TYPE_INT, MPR_TYPE_INT64 or MPR_TYPE_FLOAT.
*/
#define MPR_NUM_VAR BLD_FEATURE_NUM_TYPE_ID
#define MPR_TYPE_NUM BLD_FEATURE_NUM_TYPE_ID
/*
* Return TRUE if a variable is a function type
*/
#define mprVarIsFunction(type) \
(type == MPR_TYPE_FUNCTION || type == MPR_TYPE_STRING_CFUNCTION || \
type == MPR_TYPE_CFUNCTION)
/*
* Return TRUE if a variable is a numeric type
*/
#define mprVarIsNumber(type) \
(type == MPR_TYPE_INT || type == MPR_TYPE_INT64 || type == MPR_TYPE_FLOAT)
/*
* Return TRUE if a variable is a boolean
*/
#define mprVarIsBoolean(type) \
(type == MPR_TYPE_BOOL)
#define mprVarIsString(type) \
(type == MPR_TYPE_STRING)
#define mprVarIsObject(type) \
(type == MPR_TYPE_OBJECT)
#define mprVarIsFloating(type) \
(type == MPR_TYPE_FLOAT)
#define mprVarIsUndefined(var) \
((var)->type == MPR_TYPE_UNDEFINED)
#define mprVarIsNull(var) \
((var)->type == MPR_TYPE_NULL)
#define mprVarIsValid(var) \
(((var)->type != MPR_TYPE_NULL) && ((var)->type != MPR_TYPE_UNDEFINED))
#define MPR_VAR_MAX_RECURSE 5 /* Max object loops */
#if BLD_FEATURE_SQUEEZE
#define MPR_MAX_VAR 64 /* Max var full name */
#else
#define MPR_MAX_VAR 512
#endif
#ifndef __NO_PACK
#pragma pack(2)
#endif /* _NO_PACK */
/*
* Function signatures
*/
typedef int MprVarHandle;
typedef int (*MprCFunction)(MprVarHandle userHandle, int argc,
struct MprVar **argv);
typedef int (*MprStringCFunction)(MprVarHandle userHandle, int argc,
char **argv);
/*
* Triggers
*/
typedef enum {
MPR_VAR_WRITE, /* This property is being updated */
MPR_VAR_READ, /* This property is being read */
MPR_VAR_CREATE_PROPERTY, /* A property is being created */
MPR_VAR_DELETE_PROPERTY, /* A property is being deleted */
MPR_VAR_DELETE /* This object is being deleted */
} MprVarTriggerOp;
/*
* Trigger function return codes.
*/
typedef enum {
MPR_TRIGGER_ABORT, /* Abort the current operation */
MPR_TRIGGER_USE_NEW_VALUE, /* Proceed and use the newValue */
MPR_TRIGGER_PROCEED /* Proceed with the operation */
} MprVarTriggerStatus;
/*
* The MprVarTrigger arguments have the following meaning:
*
* op The operation being performed. See MprVarTriggerOp.
* parentProperties Pointer to the MprProperties structure.
* vp Pointer to the property that registered the trigger.
* newValue New value (see below for more details).
* copyDepth Specify what data items to copy.
*
* For VAR_READ, newVar is set to a temporary variable that the trigger
* function may assign a value to be returned instead of the actual
* property value.
* For VAR_WRITE, newValue holds the new value. The old existing value may be
* accessed via vp.
* For DELETE_PROPERTY, vp is the property being deleted. newValue is null.
* For ADD_PROPERTY, vp is set to the property being added and newValue holds
* the new value.
*/
typedef MprVarTriggerStatus (*MprVarTrigger)(MprVarTriggerOp op,
struct MprProperties *parentProperties, struct MprVar *vp,
struct MprVar *newValue, int copyDepth);
/*
* mprCreateFunctionVar flags
*/
/** Use the alternate handle on function callbacks */
#define MPR_VAR_ALT_HANDLE 0x1
/** Use the script handle on function callbacks */
#define MPR_VAR_SCRIPT_HANDLE 0x2
/*
* Useful define for the copyDepth argument
*/
/** Don't copy any data. Copy only the variable name */
#define MPR_NO_COPY 0
/** Copy strings. Increment object reference counts. */
#define MPR_SHALLOW_COPY 1
/** Copy strings and do complete object copies. */
#define MPR_DEEP_COPY 2
/*
* GetFirst / GetNext flags
*/
/** Step into data properties. */
#define MPR_ENUM_DATA 0x1
/** Step into functions properties. */
#define MPR_ENUM_FUNCTIONS 0x2
/*
* Collection type to hold properties in an object
*/
typedef struct MprProperties { /* Collection of properties */
#if VAR_DEBUG
struct MprProperties *next; /* Linked list */
struct MprProperties *prev; /* Linked list */
char name[32]; /* Debug name */
#endif
struct MprVar **buckets; /* Hash chains */
int numItems; /* Total count of items */
int numDataItems; /* Enumerable data items */
uint hashSize : 8; /* Size of the hash table */
uint refCount : 8; /* References to this property*/
uint deleteProtect : 8; /* Don't recursively delete */
uint visited : 8; /* Node has been processed */
} MprProperties;
/*
* Universal Variable Type
*/
typedef struct MprVar {
MprStr name; /* Property name */
MprStr fullName; /* Full object name */
MprProperties *properties; /* Pointer to properties */
/*
* Packed bit field
*/
MprType type : 8; /* Selector into union */
uint bucketIndex : 8; /* Copy of bucket index */
uint flags : 5; /* Type specific flags */
uint allocatedData : 1; /* Data needs freeing */
uint readonly : 1; /* Unmodifiable */
uint deleteProtect : 1; /* Don't recursively delete */
uint visited : 1; /* Node has been processed */
uint allocatedVar : 1; /* Var needs freeing */
uint spare : 6; /* Unused */
struct MprVar *forw; /* Hash table linkage */
MprVarTrigger trigger; /* Trigger function */
#if UNUSED && KEEP
struct MprVar *baseClass; /* Pointer to class object */
#endif
MprProperties *parentProperties; /* Pointer to parent object */
/*
* Union of primitive types. When debugging on Linux, don't use unions
* as the gdb debugger can't display them.
*/
#if !BLD_DEBUG && !LINUX && !VXWORKS
union {
#endif
int boolean; /* Use int for speed */
#if BLD_FEATURE_FLOATING_POINT
double floating;
#endif
int integer;
#if BLD_FEATURE_INT64
int64 integer64;
#endif
struct { /* Javascript functions */
MprArray *args; /* Null terminated */
char *body;
} function;
struct { /* Function with MprVar args */
MprCFunction fn;
void *thisPtr;
} cFunction;
struct { /* Function with string args */
MprStringCFunction fn;
void *thisPtr;
} cFunctionWithStrings;
MprStr string; /* Allocated string */
#if !BLD_DEBUG && !LINUX && !VXWORKS
};
#endif
} MprVar;
/*
* Define a field macro so code an use numbers in a "generic" fashion.
*/
#if MPR_NUM_VAR == MPR_TYPE_INT || DOXYGEN
//* Default numeric type */
#define mprNumber integer
#endif
#if MPR_NUM_VAR == MPR_TYPE_INT64
//* Default numeric type */
#define mprNumber integer64
#endif
#if MPR_NUM_VAR == MPR_TYPE_FLOAT
//* Default numeric type */
#define mprNumber floating
#endif
typedef BLD_FEATURE_NUM_TYPE MprNumber;
#ifndef __NO_PACK
#pragma pack()
#endif /* __NO_PACK */
/********************************* Prototypes *********************************/
/*
* Variable constructors and destructors
*/
extern MprVar mprCreateObjVar(const char *name, int hashSize);
extern MprVar mprCreateBoolVar(bool value);
extern MprVar mprCreateCFunctionVar(MprCFunction fn, void *thisPtr,
int flags);
#if BLD_FEATURE_FLOATING_POINT
extern MprVar mprCreateFloatVar(double value);
#endif
extern MprVar mprCreateIntegerVar(int value);
#if BLD_FEATURE_INT64
extern MprVar mprCreateInteger64Var(int64 value);
#endif
extern MprVar mprCreateFunctionVar(char *args, char *body, int flags);
extern MprVar mprCreateNullVar(void);
extern MprVar mprCreateNumberVar(MprNumber value);
extern MprVar mprCreateStringCFunctionVar(MprStringCFunction fn,
void *thisPtr, int flags);
extern MprVar mprCreateStringVar(const char *value, bool allocate);
extern MprVar mprCreateUndefinedVar(void);
extern bool mprDestroyVar(MprVar *vp);
extern bool mprDestroyAllVars(MprVar* vp);
extern MprType mprGetVarType(MprVar *vp);
/*
* Copy
*/
extern void mprCopyVar(MprVar *dest, MprVar *src, int copyDepth);
extern void mprCopyVarValue(MprVar *dest, MprVar src, int copyDepth);
extern MprVar *mprDupVar(MprVar *src, int copyDepth);
/*
* Manage vars
*/
extern MprVarTrigger
mprAddVarTrigger(MprVar *vp, MprVarTrigger fn);
extern int mprGetVarRefCount(MprVar *vp);
extern void mprSetVarDeleteProtect(MprVar *vp, int deleteProtect);
extern void mprSetVarFullName(MprVar *vp, char *name);
extern void mprSetVarReadonly(MprVar *vp, int readonly);
extern void mprSetVarName(MprVar *vp, char *name);
/*
* Create properties and return a reference to the property.
*/
extern MprVar *mprCreateProperty(MprVar *obj, const char *property,
MprVar *newValue);
extern MprVar *mprCreatePropertyValue(MprVar *obj, const char *property,
MprVar newValue);
extern int mprDeleteProperty(MprVar *obj, const char *property);
/*
* Get/Set properties. Set will update/create.
*/
extern MprVar *mprGetProperty(MprVar *obj, const char *property, MprVar *value);
extern MprVar *mprSetProperty(MprVar *obj, const char *property, MprVar *value);
extern MprVar *mprSetPropertyValue(MprVar *obj, const char *property, MprVar value);
/*
* Directly read/write property values (the property must already exist)
* For mprCopyProperty, mprDestroyVar must always called on the var.
*/
extern int mprReadProperty(MprVar *prop, MprVar *value);
extern int mprWriteProperty(MprVar *prop, MprVar *newValue);
extern int mprWritePropertyValue(MprVar *prop, MprVar newValue);
/*
* Copy a property. NOTE: reverse of most other args: (dest, src)
*/
extern int mprCopyProperty(MprVar *dest, MprVar *prop, int copyDepth);
/*
* Enumerate properties
*/
extern MprVar *mprGetFirstProperty(MprVar *obj, int includeFlags);
extern MprVar *mprGetNextProperty(MprVar *obj, MprVar *currentProperty,
int includeFlags);
/*
* Query properties characteristics
*/
extern int mprGetPropertyCount(MprVar *obj, int includeFlags);
/*
* Conversion routines
*/
extern MprVar mprParseVar(char *str, MprType prefType);
extern MprNum mprVarToNumber(MprVar *vp);
extern int mprVarToInteger(MprVar *vp);
#if BLD_FEATURE_INT64
extern int64 mprVarToInteger64(MprVar *vp);
#endif
extern bool mprVarToBool(MprVar *vp);
#if BLD_FEATURE_FLOATING_POINT
extern double mprVarToFloat(MprVar *vp);
#endif
extern void mprVarToString(char** buf, int size, char *fmt, MprVar *vp);
/*
* Parsing and utility routines
*/
extern MprNum mprParseNumber(char *str);
extern int mprParseInteger(char *str);
#if BLD_FEATURE_INT64
extern int64 mprParseInteger64(char *str);
#endif
#if BLD_FEATURE_FLOATING_POINT
extern double mprParseFloat(char *str);
extern bool mprIsInfinite(double f);
extern bool mprIsNan(double f);
#endif
#if VAR_DEBUG
extern void mprPrintObjects(char *msg);
extern void mprPrintObjRefCount(MprVar *vp);
#endif
#ifdef __cplusplus
}
#endif
/*****************************************************************************/
#endif /* _h_MPR_VAR */
/*
* 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
*/

1042
source/web_server/esp/esp.c Normal file

File diff suppressed because it is too large Load Diff

279
source/web_server/esp/esp.h Normal file
View File

@ -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 "web_server/ejs/ejs.h"
#include "web_server/esp/espEnv.h"
#include "web_server/ejs/var.h"
#include "web_server/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 */
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);
char *(*getSessionId)(EspHandle handle);
int (*mapToStorage)(EspHandle handle, char *path, int len, char *uri,
int flags);
int (*readFile)(EspHandle handle, char **buf, int *len, char *path);
void (*redirect)(EspHandle handle, int code, char *url);
void (*setCookie)(EspHandle handle, char *name, char *value,
int lifetime, 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(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, char *functionName,
EspCFunction fn, void *thisPtr);
extern void espDefineFunction(EspRequest *ep, 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, ...);
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, 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, ...);
/*
* 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
*/

View File

@ -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
*/

View File

@ -0,0 +1,230 @@
/*
* @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)
{
Esp *esp;
char path[MPR_MAX_FNAME], dir[MPR_MAX_FNAME];
char *emsg, *buf;
int size, i;
esp = ep->esp;
mprAssert(argv);
for (i = 0; i < argc; i++) {
mprGetDirName(dir, sizeof(dir), ep->docPath);
mprSprintf(path, sizeof(path), "%s/%s", dir, 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';
if (ejsEvalScript(espGetScriptHandle(ep), buf, 0, &emsg) < 0) {
espError(ep, "Cant evaluate script");
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
*/

627
source/web_server/http.c Normal file
View File

@ -0,0 +1,627 @@
/*
Unix SMB/CIFS implementation.
http handling code
Copyright (C) Andrew Tridgell 2005
This program is free software; 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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "web_server/web_server.h"
#include "smbd/service_stream.h"
#include "lib/events/events.h"
#include "system/filesys.h"
#include "system/iconv.h"
#include "system/time.h"
#include "web_server/esp/esp.h"
/* state of the esp subsystem */
struct esp_state {
struct websrv_context *web;
struct MprVar variables[ESP_OBJ_MAX];
struct EspRequest *req;
};
/* destroy a esp session */
static int esp_destructor(void *ptr)
{
struct esp_state *esp = talloc_get_type(ptr, struct esp_state);
if (esp->req) {
espDestroyRequest(esp->req);
}
espClose();
mprFreeAll();
return 0;
}
/*
output the http headers
*/
static void http_output_headers(struct websrv_context *web)
{
int i;
char *s;
DATA_BLOB b;
const char *response_string = "Unknown Code";
const struct {
unsigned code;
const char *response_string;
} codes[] = {
{ 200, "OK" },
{ 301, "Moved" },
{ 302, "Found" },
{ 303, "Method" },
{ 304, "Not Modified" },
{ 400, "Bad request" },
{ 401, "Unauthorized" },
{ 403, "Forbidden" },
{ 404, "Not Found" },
{ 500, "Internal Server Error" },
{ 501, "Not implemented" }
};
for (i=0;i<ARRAY_SIZE(codes);i++) {
if (codes[i].code == web->output.response_code) {
response_string = codes[i].response_string;
}
}
if (web->output.headers == NULL) return;
s = talloc_asprintf(web, "HTTP/1.0 %u %s\r\n",
web->output.response_code, response_string);
if (s == NULL) return;
for (i=0;web->output.headers[i];i++) {
s = talloc_asprintf_append(s, "%s\r\n", web->output.headers[i]);
}
s = talloc_asprintf_append(s, "\r\n");
if (s == NULL) return;
b = web->output.content;
web->output.content.data = s;
web->output.content.length = strlen(s);
data_blob_append(web, &web->output.content, b.data, b.length);
data_blob_free(&b);
}
/*
called when esp wants to output something
*/
static int http_writeBlock(EspHandle handle, char *buf, int size)
{
struct websrv_context *web = talloc_get_type(handle, struct websrv_context);
NTSTATUS status;
status = data_blob_append(web, &web->output.content, buf, size);
if (!NT_STATUS_IS_OK(status)) return -1;
return size;
}
/*
set a http header
*/
static void http_setHeader(EspHandle handle, const char *value, bool allowMultiple)
{
struct websrv_context *web = talloc_get_type(handle, struct websrv_context);
char *p = strchr(value, ':');
if (p && !allowMultiple && web->output.headers) {
int i;
for (i=0;web->output.headers[i];i++) {
if (strncmp(web->output.headers[i], value, (p+1)-value) == 0) {
web->output.headers[i] = talloc_strdup(web, value);
return;
}
}
}
web->output.headers = str_list_add(web->output.headers, value);
}
/*
set a http response code
*/
static void http_setResponseCode(EspHandle handle, int code)
{
struct websrv_context *web = talloc_get_type(handle, struct websrv_context);
web->output.response_code = code;
}
/*
redirect to another web page
*/
static void http_redirect(EspHandle handle, int code, char *url)
{
struct websrv_context *web = talloc_get_type(handle, struct websrv_context);
const char *host = web->input.host;
/* form the full url, unless it already looks like a url */
if (strchr(url, ':') == NULL) {
if (host == NULL) {
host = talloc_asprintf(web, "%s:%u",
socket_get_my_addr(web->conn->socket, web),
socket_get_my_port(web->conn->socket));
}
if (host == NULL) goto internal_error;
if (url[0] != '/') {
char *p = strrchr(web->input.url, '/');
if (p == web->input.url) {
url = talloc_asprintf(web, "http://%s/%s", host, url);
} else {
int dirlen = p - web->input.url;
url = talloc_asprintf(web, "http://%s%*.*s/%s",
host,
dirlen, dirlen, web->input.url,
url);
}
if (url == NULL) goto internal_error;
}
}
http_setHeader(handle, talloc_asprintf(web, "Location: %s", url), 0);
/* make sure we give a valid redirect code */
if (code >= 300 && code < 400) {
http_setResponseCode(handle, code);
} else {
http_setResponseCode(handle, 302);
}
return;
internal_error:
http_error(web, 500, "Internal server error");
}
/* callbacks for esp processing */
static const struct Esp esp_control = {
.maxScriptSize = 60000,
.writeBlock = http_writeBlock,
.setHeader = http_setHeader,
.redirect = http_redirect,
.setResponseCode = http_setResponseCode
};
/*
setup for a raw http level error
*/
void http_error(struct websrv_context *web, int code, const char *info)
{
char *s;
s = talloc_asprintf(web,"<HTML><HEAD><TITLE>Error %u</TITLE></HEAD><BODY><H1>Error %u</H1>%s<p></BODY></HTML>\r\n\r\n",
code, code, info);
if (s == NULL) {
stream_terminate_connection(web->conn, "http_error: out of memory");
return;
}
http_writeBlock(web, s, strlen(s));
http_setResponseCode(web, code);
http_output_headers(web);
EVENT_FD_NOT_READABLE(web->conn->event.fde);
EVENT_FD_WRITEABLE(web->conn->event.fde);
}
/*
map a unix error code to a http error
*/
void http_error_unix(struct websrv_context *web, const char *info)
{
int code = 500;
switch (errno) {
case ENOENT:
case EISDIR:
code = 404;
break;
case EACCES:
code = 403;
break;
}
http_error(web, code, info);
}
/*
return the local path for a URL
*/
static const char *http_local_path(struct websrv_context *web, const char *url)
{
int i;
char *path;
/* check that the url is OK */
if (url[0] != '/') return NULL;
for (i=0;url[i];i++) {
if ((!isalnum(url[i]) && !strchr("./", url[i])) ||
(url[i] == '.' && strchr("/.", url[i+1]))) {
return NULL;
}
}
path = talloc_asprintf(web, "%s/%s", lp_swat_directory(), url+1);
if (path == NULL) return NULL;
if (directory_exist(path)) {
path = talloc_asprintf_append(path, "/index.html");
}
return path;
}
/*
a simple file request
*/
static void http_simple_request(struct websrv_context *web)
{
const char *url = web->input.url;
const char *path;
struct stat st;
path = http_local_path(web, url);
if (path == NULL) goto invalid;
/* looks ok */
web->output.fd = open(path, O_RDONLY);
if (web->output.fd == -1) {
http_error_unix(web, url);
return;
}
if (fstat(web->output.fd, &st) != 0 || !S_ISREG(st.st_mode)) {
close(web->output.fd);
goto invalid;
}
http_output_headers(web);
EVENT_FD_WRITEABLE(web->conn->event.fde);
return;
invalid:
http_error(web, 400, "Malformed URL");
}
/*
setup the standard ESP arrays
*/
static void http_setup_arrays(struct esp_state *esp)
{
struct websrv_context *web = esp->web;
struct EspRequest *req = esp->req;
char *p;
espSetStringVar(req, ESP_REQUEST_OBJ, "CONTENT_LENGTH",
talloc_asprintf(esp, "%u", web->input.content_length));
if (web->input.query_string) {
espSetStringVar(req, ESP_REQUEST_OBJ, "QUERY_STRING",
web->input.query_string);
}
espSetStringVar(req, ESP_REQUEST_OBJ, "REQUEST_METHOD",
web->input.post_request?"POST":"GET");
espSetStringVar(req, ESP_REQUEST_OBJ, "REQUEST_URI", web->input.url);
p = strrchr(web->input.url, '/');
espSetStringVar(req, ESP_REQUEST_OBJ, "SCRIPT_NAME", p+1);
if (web->input.referer) {
espSetStringVar(req, ESP_HEADERS_OBJ, "HTT_REFERER", web->input.referer);
}
if (web->input.user_agent) {
espSetStringVar(req, ESP_HEADERS_OBJ, "USER_AGENT", web->input.user_agent);
}
espSetStringVar(req, ESP_SERVER_OBJ, "SERVER_ADDR",
socket_get_my_addr(web->conn->socket, esp));
espSetStringVar(req, ESP_SERVER_OBJ, "SERVER_PORT",
talloc_asprintf(esp, "%u", socket_get_my_port(web->conn->socket)));
espSetStringVar(req, ESP_SERVER_OBJ, "SERVER_PROTOCOL", "http");
}
/*
process a esp request
*/
static void esp_request(struct esp_state *esp)
{
struct websrv_context *web = esp->web;
const char *url = web->input.url;
char *buf;
const char *path;
struct stat st;
int fd, res;
char *emsg = NULL;
http_setup_arrays(esp);
path = http_local_path(web, url);
if (path == NULL) goto invalid;
espSetStringVar(esp->req, ESP_REQUEST_OBJ, "SCRIPT_FILENAME", path);
/* looks ok */
fd = open(path, O_RDONLY);
if (fd == -1) {
http_error_unix(web, url);
return;
}
if (fstat(fd, &st) != 0 || !S_ISREG(st.st_mode)) {
close(fd);
goto invalid;
}
buf = talloc_size(esp, st.st_size+1);
if (buf == NULL) goto invalid;
if (read(fd, buf, st.st_size) != st.st_size) {
goto invalid;
}
buf[st.st_size] = 0;
close(fd);
res = espProcessRequest(esp->req, path, buf, &emsg);
if (res != 0 && emsg) {
http_writeBlock(esp, emsg, strlen(emsg));
}
http_output_headers(web);
EVENT_FD_WRITEABLE(web->conn->event.fde);
return;
invalid:
http_error(web, 400, "Malformed URL");
}
/*
handling of + and % escapes in http variables
*/
static const char *http_unescape(TALLOC_CTX *mem_ctx, const char *p)
{
char *s0 = talloc_strdup(mem_ctx, p);
char *s = s0;
if (s == NULL) return NULL;
while (*s) {
unsigned v;
if (*s == '+') *s = ' ';
if (*s == '%' && sscanf(s+1, "%02x", &v) == 1) {
*s = (char)v;
memmove(s+1, s+3, strlen(s+3)+1);
}
s++;
}
return s0;
}
/*
set a form or GET variable
*/
static void esp_putvar(struct esp_state *esp, const char *var, const char *value)
{
espSetStringVar(esp->req, ESP_FORM_OBJ,
http_unescape(esp, var),
http_unescape(esp, value));
}
/*
parse the variables in a POST style request
*/
static NTSTATUS http_parse_post(struct esp_state *esp)
{
DATA_BLOB b = esp->web->input.partial;
while (b.length) {
char *p, *line;
size_t len;
p = memchr(b.data, '&', b.length);
if (p == NULL) {
len = b.length;
} else {
len = p - (char *)b.data;
}
line = talloc_strndup(esp, b.data, len);
NT_STATUS_HAVE_NO_MEMORY(line);
p = strchr(line,'=');
if (p) {
*p = 0;
esp_putvar(esp, line, p+1);
}
talloc_free(line);
b.length -= len;
b.data += len;
if (b.length > 0) {
b.length--;
b.data++;
}
}
return NT_STATUS_OK;
}
/*
parse the variables in a GET style request
*/
static NTSTATUS http_parse_get(struct esp_state *esp)
{
struct websrv_context *web = esp->web;
char *p, *s, *tok;
char *pp;
p = strchr(web->input.url, '?');
web->input.query_string = p+1;
*p = 0;
s = talloc_strdup(esp, esp->web->input.query_string);
NT_STATUS_HAVE_NO_MEMORY(s);
for (tok=strtok_r(s,"&;", &pp);tok;tok=strtok_r(NULL,"&;", &pp)) {
p = strchr(tok,'=');
if (p) {
*p = 0;
esp_putvar(esp, tok, p+1);
}
}
return NT_STATUS_OK;
}
/*
setup some standard variables
*/
static void http_setup_vars(struct esp_state *esp)
{
int i;
for (i = 0; i < ESP_OBJ_MAX; i++) {
esp->variables[i] = mprCreateUndefinedVar();
}
esp->variables[ESP_HEADERS_OBJ] = mprCreateObjVar("headers", ESP_HASH_SIZE);
esp->variables[ESP_FORM_OBJ] = mprCreateObjVar("form", ESP_HASH_SIZE);
esp->variables[ESP_APPLICATION_OBJ] = mprCreateObjVar("application", ESP_HASH_SIZE);
esp->variables[ESP_COOKIES_OBJ] = mprCreateObjVar("cookies", ESP_HASH_SIZE);
esp->variables[ESP_FILES_OBJ] = mprCreateObjVar("files", ESP_HASH_SIZE);
esp->variables[ESP_REQUEST_OBJ] = mprCreateObjVar("request", ESP_HASH_SIZE);
esp->variables[ESP_SERVER_OBJ] = mprCreateObjVar("server", ESP_HASH_SIZE);
esp->variables[ESP_SESSION_OBJ] = mprCreateObjVar("session", ESP_HASH_SIZE);
}
/*
process a complete http request
*/
void http_process_input(struct websrv_context *web)
{
NTSTATUS status;
struct esp_state *esp;
char *p;
int i;
const char *file_type = NULL;
const struct {
const char *extension;
const char *mime_type;
} mime_types[] = {
{"gif", "image/gif"},
{"png", "image/png"},
{"jpg", "image/jpeg"},
{"txt", "text/plain"}
};
esp = talloc_zero(web, struct esp_state);
if (esp == NULL) goto internal_error;
esp->web = web;
mprSetCtx(esp);
talloc_set_destructor(esp, esp_destructor);
if (espOpen(&esp_control) != 0) goto internal_error;
http_setup_vars(esp);
esp->req = espCreateRequest(web, web->input.url, esp->variables);
if (esp->req == NULL) goto internal_error;
if (web->input.url == NULL) {
http_error(web, 400, "You must specify a GET or POST request");
return;
}
if (web->input.post_request) {
status = http_parse_post(esp);
if (!NT_STATUS_IS_OK(status)) {
http_error(web, 400, "Malformed POST data");
return;
}
} else if (strchr(web->input.url, '?')) {
status = http_parse_get(esp);
if (!NT_STATUS_IS_OK(status)) {
http_error(web, 400, "Malformed GET data");
return;
}
}
/* process all html files as ESP */
p = strrchr(web->input.url, '.');
for (i=0;p && i<ARRAY_SIZE(mime_types);i++) {
if (strcmp(mime_types[i].extension, p+1) == 0) {
file_type = mime_types[i].mime_type;
}
}
if (file_type == NULL) {
file_type = "text/html";
}
/* setup basic headers */
http_setResponseCode(web, 200);
http_setHeader(web, talloc_asprintf(esp, "Date: %s",
http_timestring(esp, time(NULL))), 0);
http_setHeader(web, "Server: Samba", 0);
http_setHeader(web, "Connection: close", 0);
http_setHeader(web, talloc_asprintf(esp, "Content-Type: %s", file_type), 0);
if (strcmp(file_type, "text/html") == 0) {
esp_request(esp);
} else {
http_simple_request(web);
}
talloc_free(esp);
return;
internal_error:
talloc_free(esp);
http_error(web, 500, "Internal server error");
}
/*
parse one line of header input
*/
NTSTATUS http_parse_header(struct websrv_context *web, const char *line)
{
if (line[0] == 0) {
web->input.end_of_headers = True;
} else if (strncasecmp(line,"GET ", 4)==0) {
web->input.url = talloc_strndup(web, &line[4], strcspn(&line[4], " \t"));
} else if (strncasecmp(line,"POST ", 5)==0) {
web->input.post_request = True;
web->input.url = talloc_strndup(web, &line[5], strcspn(&line[5], " \t"));
} else if (strchr(line, ':') == NULL) {
http_error(web, 400, "This server only accepts GET and POST requests");
return NT_STATUS_INVALID_PARAMETER;
} else if (strncasecmp(line,"Content-Length: ", 16)==0) {
web->input.content_length = strtoul(&line[16], NULL, 10);
} else {
#define PULL_HEADER(v, s) do { \
if (strncmp(line, s, strlen(s)) == 0) { \
web->input.v = talloc_strdup(web, &line[strlen(s)]); \
return NT_STATUS_OK; \
} \
} while (0)
PULL_HEADER(content_type, "Content-Type: ");
PULL_HEADER(user_agent, "User-Agent: ");
PULL_HEADER(referer, "Referer: ");
PULL_HEADER(host, "Host: ");
PULL_HEADER(accept_encoding, "Accept-Encoding: ");
}
/* ignore all other headers for now */
return NT_STATUS_OK;
}

View File

@ -0,0 +1,252 @@
/*
Unix SMB/CIFS implementation.
web server startup
Copyright (C) Andrew Tridgell 2005
This program is free software; 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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "smbd/service_task.h"
#include "smbd/service_stream.h"
#include "web_server/web_server.h"
#include "lib/events/events.h"
#include "system/filesys.h"
/* don't allow connections to hang around forever */
#define HTTP_TIMEOUT 30
/*
destroy a web connection
*/
static int websrv_destructor(void *ptr)
{
struct websrv_context *web = talloc_get_type(ptr, struct websrv_context);
if (web->output.fd != -1) {
close(web->output.fd);
}
return 0;
}
/*
called when a connection times out. This prevents a stuck connection
from hanging around forever
*/
static void websrv_timeout(struct event_context *event_context,
struct timed_event *te,
struct timeval t, void *private)
{
struct websrv_context *web = talloc_get_type(private, struct websrv_context);
stream_terminate_connection(web->conn, "websrv_context: timeout");
}
/*
called when a web connection becomes readable
*/
static void websrv_recv(struct stream_connection *conn, uint16_t flags)
{
struct websrv_context *web = talloc_get_type(conn->private,
struct websrv_context);
NTSTATUS status;
uint8_t buf[1024];
size_t nread;
uint8_t *p;
DATA_BLOB b;
/* not the most efficient http parser ever, but good enough for us */
status = socket_recv(conn->socket, buf, sizeof(buf), &nread, 0);
if (NT_STATUS_IS_ERR(status)) goto failed;
if (!NT_STATUS_IS_OK(status)) return;
status = data_blob_append(web, &web->input.partial, buf, nread);
if (!NT_STATUS_IS_OK(status)) goto failed;
/* parse any lines that are available */
b = web->input.partial;
while (!web->input.end_of_headers &&
(p=memchr(b.data, '\n', b.length))) {
const char *line = b.data;
*p = 0;
if (p != b.data && p[-1] == '\r') {
p[-1] = 0;
}
status = http_parse_header(web, line);
if (!NT_STATUS_IS_OK(status)) return;
b.length -= (p - b.data) + 1;
b.data = p+1;
}
/* keep any remaining bytes in web->input.partial */
if (b.length == 0) {
b.data = NULL;
}
b = data_blob_talloc(web, b.data, b.length);
data_blob_free(&web->input.partial);
web->input.partial = b;
/* we finish when we have both the full headers (terminated by
a blank line) and any post data, as indicated by the
content_length */
if (web->input.end_of_headers &&
web->input.partial.length == web->input.content_length) {
EVENT_FD_NOT_READABLE(web->conn->event.fde);
http_process_input(web);
}
return;
failed:
stream_terminate_connection(conn, "websrv_recv: failed\n");
}
/*
called when a web connection becomes writable
*/
static void websrv_send(struct stream_connection *conn, uint16_t flags)
{
struct websrv_context *web = talloc_get_type(conn->private,
struct websrv_context);
NTSTATUS status;
size_t nsent;
DATA_BLOB b;
b = web->output.content;
b.data += web->output.nsent;
b.length -= web->output.nsent;
status = socket_send(conn->socket, &b, &nsent, 0);
if (NT_STATUS_IS_ERR(status)) {
stream_terminate_connection(web->conn, "socket_send: failed");
return;
}
if (!NT_STATUS_IS_OK(status)) {
return;
}
web->output.nsent += nsent;
/* possibly read some more raw data from a file */
if (web->output.content.length == web->output.nsent &&
web->output.fd != -1) {
uint8_t buf[2048];
ssize_t nread;
data_blob_free(&web->output.content);
web->output.nsent = 0;
nread = read(web->output.fd, buf, sizeof(buf));
if (nread == 0) {
close(web->output.fd);
web->output.fd = -1;
}
if (nread == -1 && errno == EINTR) {
return;
}
web->output.content = data_blob_talloc(web, buf, nread);
}
if (web->output.content.length == web->output.nsent) {
stream_terminate_connection(web->conn, NULL);
}
}
/*
establish a new connection to the web server
*/
static void websrv_accept(struct stream_connection *conn)
{
struct websrv_context *web;
web = talloc_zero(conn, struct websrv_context);
if (web == NULL) goto failed;
web->conn = conn;
conn->private = web;
web->output.fd = -1;
talloc_set_destructor(web, websrv_destructor);
event_add_timed(conn->event.ctx, web,
timeval_current_ofs(HTTP_TIMEOUT, 0),
websrv_timeout, web);
return;
failed:
talloc_free(conn);
}
static const struct stream_server_ops web_stream_ops = {
.name = "web",
.accept_connection = websrv_accept,
.recv_handler = websrv_recv,
.send_handler = websrv_send,
};
/*
startup the web server task
*/
static void websrv_task_init(struct task_server *task)
{
NTSTATUS status;
uint16_t port = lp_swat_port();
const struct model_ops *model_ops;
/* run the web server as a single process */
model_ops = process_model_byname("single");
if (!model_ops) goto failed;
if (lp_interfaces() && lp_bind_interfaces_only()) {
int num_interfaces = iface_count();
int i;
for(i = 0; i < num_interfaces; i++) {
const char *address = iface_n_ip(i);
status = stream_setup_socket(task->event_ctx, model_ops,
&web_stream_ops,
"ipv4", address,
&port, task);
if (!NT_STATUS_IS_OK(status)) goto failed;
}
} else {
status = stream_setup_socket(task->event_ctx, model_ops,
&web_stream_ops,
"ipv4", lp_socket_address(),
&port, task);
if (!NT_STATUS_IS_OK(status)) goto failed;
}
return;
failed:
task_terminate(task, "Failed to startup web server task");
}
/*
called on startup of the web server service It's job is to start
listening on all configured sockets
*/
static NTSTATUS websrv_init(struct event_context *event_context,
const struct model_ops *model_ops)
{
return task_server_startup(event_context, model_ops, websrv_task_init);
}
/* called at smbd startup - register ourselves as a server service */
NTSTATUS server_service_web_init(void)
{
return register_server_service("web", websrv_init);
}

View File

@ -0,0 +1,49 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Andrew Tridgell 2005
This program is free software; 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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "request.h"
#include "smbd/process_model.h"
/*
context of one open web connection
*/
struct websrv_context {
struct stream_connection *conn;
struct {
DATA_BLOB partial;
BOOL end_of_headers;
char *url;
unsigned content_length;
BOOL post_request;
const char *content_type;
const char *query_string;
const char *user_agent;
const char *referer;
const char *host;
const char *accept_encoding;
} input;
struct {
DATA_BLOB content;
int fd;
unsigned nsent;
int response_code;
const char **headers;
} output;
};