MAIN(http, int argc, char **argv, char **envp) { Mpr *mpr; cchar *argp; char *logSpec, *traceSpec; int argind; logSpec = 0; traceSpec = 0; if ((mpr = mprCreate(argc, argv, MPR_USER_EVENTS_THREAD)) == NULL) { exit(1); } if ((app = mprAllocObj(App, manageApp)) == NULL) { exit(2); } mprAddRoot(app); mprAddStandardSignals(); if (httpCreate(HTTP_CLIENT_SIDE | HTTP_SERVER_SIDE) < 0) { exit(2); } app->mpr = mpr; app->home = mprGetCurrentPath(); argc = mpr->argc; argv = (char**) mpr->argv; for (argind = 1; argind < argc; argind++) { argp = argv[argind]; if (*argp != '-') { break; } if (smatch(argp, "--config") || smatch(argp, "--conf")) { if (argind >= argc) { usageError(); } app->configFile = sclone(argv[++argind]); } else if (smatch(argp, "--debugger") || smatch(argp, "-D")) { mprSetDebugMode(1); } else if (smatch(argp, "--log") || smatch(argp, "-l")) { if (argind >= argc) { usageError(); } logSpec = argv[++argind]; } else if (smatch(argp, "--name") || smatch(argp, "-n")) { if (argind >= argc) { usageError(); } mprSetAppName(argv[++argind], 0, 0); } else if (smatch(argp, "--show") || smatch(argp, "-s")) { app->show = 1; } else if (smatch(argp, "--trace") || smatch(argp, "-t")) { if (argind >= argc) { usageError(); } traceSpec = argv[++argind]; } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) { if (!logSpec) { logSpec = sfmt("stderr:2"); } if (!traceSpec) { traceSpec = sfmt("stderr:2"); } } else if (smatch(argp, "--version") || smatch(argp, "-V")) { mprPrintf("%s\n", ME_VERSION); exit(0); } else if (*argp == '-' && isdigit((uchar) argp[1])) { if (!logSpec) { logSpec = sfmt("stderr:%d", (int) stoi(&argp[1])); } if (!traceSpec) { traceSpec = sfmt("stderr:%d", (int) stoi(&argp[1])); } } else if (smatch(argp, "-?") || scontains(argp, "-help")) { usageError(); exit(3); } else if (*argp == '-') { mprLog("error http", 0, "Unknown switch \"%s\"", argp); usageError(); exit(4); } } if (logSpec) { mprStartLogging(logSpec, MPR_LOG_CMDLINE); } if (traceSpec) { httpStartTracing(traceSpec); } if (mprStart() < 0) { mprLog("error http", 0, "Cannot start MPR"); mprDestroy(); return MPR_ERR_CANT_INITIALIZE; } if (argc == argind && !app->configFile) { if (findConfig() < 0) { exit(5); } } if (createEndpoints(argc - argind, &argv[argind]) < 0) { return MPR_ERR_CANT_INITIALIZE; } if (httpStartEndpoints() < 0) { mprLog("error http", 0, "Cannot start HTTP service, exiting."); exit(6); } if (app->show) { httpLogRoutes(0, 0); } mprServiceEvents(-1, 0); mprLog("info http", 1, "Stopping http-server ..."); mprDestroy(); return mprGetExitStatus(); }
/* If the program has a UNIX style "#!/program" string at the start of the file that program will be selected and the original program will be passed as the first arg to that program with argv[] appended after that. If the program is not found, this routine supports a safe intelligent search for the command. If all else fails, we just return in program the fileName we were passed in. script will be set if we are modifying the program to run and we have extracted the name of the file to run as a script. */ static void findExecutable(HttpConn *conn, char **program, char **script, char **bangScript, cchar *fileName) { HttpRx *rx; HttpTx *tx; HttpRoute *route; MprKey *kp; MprFile *file; cchar *actionProgram, *ext, *cmdShell, *cp, *start, *path; char *tok, buf[ME_MAX_FNAME + 1]; rx = conn->rx; tx = conn->tx; route = rx->route; *bangScript = 0; *script = 0; *program = 0; path = 0; actionProgram = mprGetMimeProgram(rx->route->mimeTypes, rx->mimeType); ext = tx->ext; /* If not found, go looking for the fileName with the extensions defined in appweb.conf. NOTE: we don't use PATH deliberately!!! */ if (access(fileName, X_OK) < 0) { for (kp = 0; (kp = mprGetNextKey(route->extensions, kp)) != 0; ) { path = sjoin(fileName, ".", kp->key, NULL); if (access(path, X_OK) == 0) { break; } path = 0; } if (kp) { ext = kp->key; } else { path = fileName; } } else { path = fileName; } assert(path && *path); #if ME_WIN_LIKE if (ext && (strcmp(ext, ".bat") == 0 || strcmp(ext, ".cmd") == 0)) { /* Let a mime action override COMSPEC */ if (actionProgram) { cmdShell = actionProgram; } else { cmdShell = getenv("COMSPEC"); } if (cmdShell == 0) { cmdShell = "cmd.exe"; } *script = sclone(path); *program = sclone(cmdShell); return; } #endif if (actionProgram) { *program = sclone(actionProgram); } else if ((file = mprOpenFile(path, O_RDONLY, 0)) != 0) { if (mprReadFile(file, buf, ME_MAX_FNAME) > 0) { mprCloseFile(file); buf[ME_MAX_FNAME] = '\0'; if (buf[0] == '#' && buf[1] == '!') { cp = start = &buf[2]; cmdShell = stok(&buf[2], "\r\n", &tok); if (!mprIsPathAbs(cmdShell)) { /* If we can't access the command shell and the command is not an absolute path, look in the same directory as the script. */ if (mprPathExists(cmdShell, X_OK)) { cmdShell = mprJoinPath(mprGetPathDir(path), cmdShell); } } *program = sclone(cmdShell); *bangScript = sclone(path); return; } } else { mprCloseFile(file); } } if (actionProgram) { *program = sclone(actionProgram); *bangScript = sclone(path); } else { *program = sclone(path); } return; }
/* Parse address and return the IP address and port components. Handles ipv4 and ipv6 addresses. If the IP portion is absent, *pip is set to null. If the port portion is absent, port is set to the defaultPort. If a ":*" port specifier is used, *pport is set to -1; When an address contains an ipv6 port it should be written as: aaaa:bbbb:cccc:dddd:eeee:ffff:gggg:hhhh:iiii or [aaaa:bbbb:cccc:dddd:eeee:ffff:gggg:hhhh:iiii]:port If supplied an IPv6 address, the backets are stripped in the returned IP address. This routine parses any "https://" prefix. Caller must free *pip */ PUBLIC int socketParseAddress(char *address, char **pip, int *pport, int *secure, int defaultPort) { char *ip, *cp; ip = 0; if (defaultPort < 0) { defaultPort = 80; } *secure = strncmp(address, "https", 5) == 0; if ((cp = strstr(address, "://")) != 0) { address = &cp[3]; } if (ipv6(address)) { /* IPv6. If port is present, it will follow a closing bracket ']' */ if ((cp = strchr(address, ']')) != 0) { cp++; if ((*cp) && (*cp == ':')) { *pport = (*++cp == '*') ? -1 : atoi(cp); /* Set ipAddr to ipv6 address without brackets */ ip = sclone(address + 1); cp = strchr(ip, ']'); *cp = '\0'; } else { /* Handles [a:b:c:d:e:f:g:h:i] case (no port)- should not occur */ ip = sclone(address + 1); if ((cp = strchr(ip, ']')) != 0) { *cp = '\0'; } if (*ip == '\0') { ip = 0; } /* No port present, use callers default */ *pport = defaultPort; } } else { /* Handles a:b:c:d:e:f:g:h:i case (no port) */ ip = sclone(address); /* No port present, use callers default */ *pport = defaultPort; } } else { /* ipv4 */ ip = sclone(address); if ((cp = strchr(ip, ':')) != 0) { *cp++ = '\0'; if (*cp == '*') { *pport = -1; } else { *pport = atoi(cp); } if (*ip == '*' || *ip == '\0') { ip = 0; } } else if (strchr(ip, '.')) { *pport = defaultPort; } else { if (isdigit((uchar) *ip)) { *pport = atoi(ip); ip = 0; } else { /* No port present, use callers default */ *pport = defaultPort; } } } if (pip) { *pip = ip; } return 0; }
/* Convert an ESP web page into C code Directives: <%@ include "file" Include an esp file <%@ layout "file" Specify a layout page to use. Use layout "" to disable layout management <%@ content Mark the location to substitute content in a layout pag <% Begin esp section containing C code <%^ global Put esp code at the global level <%^ start Put esp code at the start of the function <%^ end Put esp code at the end of the function <%= Begin esp section containing an expression to evaluate and substitute <%= [%fmt] Begin a formatted expression to evaluate and substitute. Format is normal printf format. Use %S for safe HTML escaped output. %> End esp section -%> End esp section and trim trailing newline @@var Substitue the value of a variable. Var can also be simple expressions (without spaces) @#field Lookup the current record for the value of the field. */ char *espBuildScript(HttpRoute *route, cchar *page, cchar *path, cchar *cacheName, cchar *layout, char **err) { EspParse parse; char *control, *incBuf, *incText, *global, *token, *body, *where; char *rest, *start, *end, *include, *line, *fmt, *layoutPage, *layoutBuf; ssize len; int tid; mprAssert(page); body = start = end = global = ""; *err = 0; memset(&parse, 0, sizeof(parse)); parse.data = (char*) page; parse.next = parse.data; if ((parse.token = mprCreateBuf(-1, -1)) == 0) { return 0; } tid = getEspToken(&parse); while (tid != ESP_TOK_EOF) { token = mprGetBufStart(parse.token); #if FUTURE if (parse.lineNumber != lastLine) { body = sfmt("\n# %d \"%s\"\n", parse.lineNumber, path); } #endif switch (tid) { case ESP_TOK_CODE: if (*token == '^') { for (token++; *token && isspace((int) *token); token++) ; where = stok(token, " \t\r\n", &rest); if (rest == 0) { ; } else if (scmp(where, "global") == 0) { global = sjoin(global, rest, NULL); } else if (scmp(where, "start") == 0) { if (*start == '\0') { start = " "; } start = sjoin(start, rest, NULL); } else if (scmp(where, "end") == 0) { if (*end == '\0') { end = " "; } end = sjoin(end, rest, NULL); } } else { body = sjoin(body, token, NULL); } break; case ESP_TOK_CONTROL: /* NOTE: layout parsing not supported */ control = stok(token, " \t\r\n", &token); if (scmp(control, "content") == 0) { body = sjoin(body, CONTENT_MARKER, NULL); } else if (scmp(control, "include") == 0) { if (token == 0) { token = ""; } token = strim(token, " \t\r\n\"", MPR_TRIM_BOTH); token = mprNormalizePath(token); if (token[0] == '/') { include = sclone(token); } else { include = mprJoinPath(mprGetPathDir(path), token); } if ((incText = mprReadPathContents(include, &len)) == 0) { *err = sfmt("Can't read include file: %s", include); return 0; } /* Recurse and process the include script */ incBuf = 0; if ((incBuf = espBuildScript(route, incText, include, NULL, NULL, err)) == 0) { return 0; } body = sjoin(body, incBuf, NULL); } else if (scmp(control, "layout") == 0) { token = strim(token, " \t\r\n\"", MPR_TRIM_BOTH); if (*token == '\0') { layout = 0; } else { token = mprNormalizePath(token); if (token[0] == '/') { layout = sclone(token); } else { layout = mprJoinPath(mprGetPathDir(path), token); } if (!mprPathExists(layout, F_OK)) { *err = sfmt("Can't access layout page %s", layout); return 0; } } } else { *err = sfmt("Unknown control %s at line %d", control, parse.lineNumber); return 0; } break; case ESP_TOK_ERR: return 0; case ESP_TOK_EXPR: /* <%= expr %> */ if (*token == '%') { fmt = stok(token, ": \t\r\n", &token); if (token == 0) { token = ""; } } else { fmt = "%s"; } token = strim(token, " \t\r\n;", MPR_TRIM_BOTH); body = sjoin(body, " espRender(conn, \"", fmt, "\", ", token, ");\n", NULL); break; case ESP_TOK_FIELD: /* @#field */ token = strim(token, " \t\r\n;", MPR_TRIM_BOTH); body = sjoin(body, " espRender(conn, getField(\"", token, "\"));\n", NULL); break; case ESP_TOK_LITERAL: line = joinLine(token, &len); body = sfmt("%s espRenderBlock(conn, \"%s\", %d);\n", body, line, len); break; case ESP_TOK_VAR: /* @@var */ token = strim(token, " \t\r\n;", MPR_TRIM_BOTH); /* espRenderParam uses espRenderSafeString */ body = sjoin(body, " espRenderParam(conn, \"", token, "\");\n", NULL); break; default: return 0; } tid = getEspToken(&parse); } if (cacheName) { /* CacheName will only be set for the outermost invocation */ if (layout && mprPathExists(layout, R_OK)) { if ((layoutPage = mprReadPathContents(layout, &len)) == 0) { *err = sfmt("Can't read layout page: %s", layout); return 0; } layoutBuf = 0; if ((layoutBuf = espBuildScript(route, layoutPage, layout, NULL, NULL, err)) == 0) { return 0; } body = sreplace(layoutBuf, CONTENT_MARKER, body); } if (start && start[slen(start) - 1] != '\n') { start = sjoin(start, "\n", NULL); } if (end && end[slen(end) - 1] != '\n') { end = sjoin(end, "\n", NULL); } mprAssert(slen(path) > slen(route->dir)); mprAssert(sncmp(path, route->dir, slen(route->dir)) == 0); if (sncmp(path, route->dir, slen(route->dir)) == 0) { path = &path[slen(route->dir) + 1]; } body = sfmt(\ "/*\n Generated from %s\n */\n"\ "#include \"esp-app.h\"\n"\ "%s\n"\ "static void %s(HttpConn *conn) {\n"\ "%s%s%s"\ "}\n\n"\ "%s int esp_%s(HttpRoute *route, MprModule *module) {\n"\ " espDefineView(route, \"%s\", %s);\n"\ " return 0;\n"\ "}\n", path, global, cacheName, start, body, end, ESP_EXPORT_STRING, cacheName, mprGetPortablePath(path), cacheName); mprLog(6, "Create ESP script: \n%s\n", body); } return body; }
/* Create and initialize an SSL configuration for a route. This configuration is used by all requests for a given route. An application can have different SSL configurations for different routes. There is also a default SSL configuration that is used when a route does not define a configuration and one for clients. */ static OpenConfig *createOpenSslConfig(MprSocket *sp) { MprSsl *ssl; OpenConfig *cfg; X509_STORE *store; SSL_CTX *context; cchar *key; uchar resume[16]; int verifyMode; ssl = sp->ssl; assert(ssl); if ((ssl->config = mprAllocObj(OpenConfig, manageOpenConfig)) == 0) { return 0; } cfg = ssl->config; if ((context = SSL_CTX_new(SSLv23_method())) == 0) { mprLog("error openssl", 0, "Unable to create SSL context"); return 0; } SSL_CTX_set_app_data(context, (void*) ssl); if (ssl->verifyPeer && !(ssl->caFile || ssl->caPath)) { sp->errorMsg = sfmt("Cannot verify peer due to undefined CA certificates"); SSL_CTX_free(context); return 0; } /* Configure the certificates */ if (ssl->certFile) { if (SSL_CTX_use_certificate_chain_file(context, ssl->certFile) <= 0) { if (SSL_CTX_use_certificate_file(context, ssl->certFile, SSL_FILETYPE_ASN1) <= 0) { mprLog("error openssl", 0, "Cannot open certificate file: %s", ssl->certFile); SSL_CTX_free(context); return 0; } } key = (ssl->keyFile == 0) ? ssl->certFile : ssl->keyFile; if (key) { if (SSL_CTX_use_PrivateKey_file(context, key, SSL_FILETYPE_PEM) <= 0) { /* attempt ASN1 for self-signed format */ if (SSL_CTX_use_PrivateKey_file(context, key, SSL_FILETYPE_ASN1) <= 0) { mprLog("error openssl", 0, "Cannot open private key file: %s", key); SSL_CTX_free(context); return 0; } } if (!SSL_CTX_check_private_key(context)) { mprLog("error openssl", 0, "Check of private key file failed: %s", key); SSL_CTX_free(context); return 0; } } } if (ssl->ciphers) { ssl->ciphers = mapCipherNames(ssl->ciphers); } if (!ssl->ciphers && (sp->flags & MPR_SOCKET_SERVER)) { ssl->ciphers = sclone(OPENSSL_DEFAULT_CIPHERS); } if (ssl->ciphers) { mprLog("info openssl", 5, "Using SSL ciphers: %s", ssl->ciphers); if (SSL_CTX_set_cipher_list(context, ssl->ciphers) != 1) { sp->errorMsg = sfmt("Unable to set cipher list \"%s\". %s", ssl->ciphers, getOssError(sp)); SSL_CTX_free(context); return 0; } } verifyMode = ssl->verifyPeer ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE; if (verifyMode != SSL_VERIFY_NONE) { if (!(ssl->caFile || ssl->caPath)) { sp->errorMsg = sclone("No defined certificate authority file"); SSL_CTX_free(context); return 0; } if ((!SSL_CTX_load_verify_locations(context, (char*) ssl->caFile, (char*) ssl->caPath)) || (!SSL_CTX_set_default_verify_paths(context))) { sp->errorMsg = sfmt("Unable to set certificate locations: %s: %s", ssl->caFile, ssl->caPath); SSL_CTX_free(context); return 0; } if (ssl->caFile) { STACK_OF(X509_NAME) *certNames; certNames = SSL_load_client_CA_file(ssl->caFile); if (certNames) { /* Define the list of CA certificates to send to the client before they send their client certificate for validation */ SSL_CTX_set_client_CA_list(context, certNames); } } store = SSL_CTX_get_cert_store(context); if (ssl->revokeList && !X509_STORE_load_locations(store, ssl->revokeList, 0)) { mprLog("error openssl", 0, "Cannot load certificate revoke list: %s", ssl->revokeList); SSL_CTX_free(context); return 0; } if (sp->flags & MPR_SOCKET_SERVER) { SSL_CTX_set_verify_depth(context, ssl->verifyDepth); } } /* Define callbacks */ SSL_CTX_set_verify(context, verifyMode, verifyPeerCertificate); /* Configure DH parameters */ SSL_CTX_set_tmp_dh_callback(context, dhcallback); cfg->dhKey = getDhKey(); /* Define default OpenSSL options */ SSL_CTX_set_options(context, SSL_OP_ALL); /* Ensure we generate a new private key for each connection */ SSL_CTX_set_options(context, SSL_OP_SINGLE_DH_USE); /* Define a session reuse context */ RAND_bytes(resume, sizeof(resume)); SSL_CTX_set_session_id_context(context, resume, sizeof(resume)); /* Elliptic Curve initialization */ #if SSL_OP_SINGLE_ECDH_USE #ifdef SSL_CTX_set_ecdh_auto SSL_CTX_set_ecdh_auto(context, 1); #else { EC_KEY *ecdh; cchar *name; int nid; name = ME_MPR_SSL_CURVE; if ((nid = OBJ_sn2nid(name)) == 0) { sp->errorMsg = sfmt("Unknown curve name \"%s\"", name); SSL_CTX_free(context); return 0; } if ((ecdh = EC_KEY_new_by_curve_name(nid)) == 0) { sp->errorMsg = sfmt("Unable to create curve \"%s\"", name); SSL_CTX_free(context); return 0; } SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE); SSL_CTX_set_tmp_ecdh(context, ecdh); EC_KEY_free(ecdh); } #endif #endif SSL_CTX_set_mode(context, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_AUTO_RETRY | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); #ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING SSL_CTX_set_options(context, SSL_OP_MSIE_SSLV2_RSA_PADDING); #endif #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(context, SSL_MODE_RELEASE_BUFFERS); #endif #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE SSL_CTX_set_mode(context, SSL_OP_CIPHER_SERVER_PREFERENCE); #endif /* Select the required protocols Disable SSLv2 and SSLv3 by default -- they are insecure. */ SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); SSL_CTX_set_options(context, SSL_OP_NO_SSLv3); #ifdef SSL_OP_NO_TLSv1 if (!(ssl->protocols & MPR_PROTO_TLSV1)) { SSL_CTX_set_options(context, SSL_OP_NO_TLSv1); } #endif #ifdef SSL_OP_NO_TLSv1_1 if (!(ssl->protocols & MPR_PROTO_TLSV1_1)) { SSL_CTX_set_options(context, SSL_OP_NO_TLSv1_1); } #endif #ifdef SSL_OP_NO_TLSv1_2 if (!(ssl->protocols & MPR_PROTO_TLSV1_2)) { SSL_CTX_set_options(context, SSL_OP_NO_TLSv1_2); } #endif /* Options set via main.me mpr.ssl.* */ #if defined(SSL_OP_NO_TICKET) /* Ticket based session reuse is enabled by default */ #if defined(ME_MPR_SSL_TICKET) if (ME_MPR_SSL_TICKET) { SSL_CTX_clear_options(context, SSL_OP_NO_TICKET); } else { SSL_CTX_set_options(context, SSL_OP_NO_TICKET); } #else SSL_CTX_clear_options(context, SSL_OP_NO_TICKET); #endif #endif #if defined(SSL_OP_NO_COMPRESSION) /* Use of compression is not secure. Disabled by default. */ #if defined(ME_MPR_SSL_COMPRESSION) if (ME_MPR_SSL_COMPRESSION) { SSL_CTX_clear_options(context, SSL_OP_NO_COMPRESSION); } else { SSL_CTX_set_options(context, SSL_OP_NO_COMPRESSION); } #else /* CRIME attack targets compression */ SSL_CTX_clear_options(context, SSL_OP_NO_COMPRESSION); #endif #endif #if defined(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION) /* Force a new session on renegotiation. Default to true. */ #if defined(ME_MPR_SSL_RENEGOTIATE) if (ME_MPR_SSL_RENEGOTIATE) { SSL_CTX_clear_options(context, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); } else { SSL_CTX_set_options(context, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); } #else SSL_CTX_set_options(context, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); #endif #endif #if defined(SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) /* Disables a countermeasure against a SSL 3.0/TLS 1.0 protocol vulnerability affecting CBC ciphers. Defaults to true. */ #if defined(ME_MPR_SSL_EMPTY_FRAGMENTS) if (ME_MPR_SSL_EMPTY_FRAGMENTS) { /* SSL_OP_ALL disables empty fragments. Only needed for ancient browsers like IE-6 on SSL-3.0/TLS-1.0 */ SSL_CTX_clear_options(context, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); } else { SSL_CTX_set_options(context, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); } #else SSL_CTX_set_options(context, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); #endif #endif #if defined(ME_MPR_SSL_CACHE) /* Set the number of sessions supported. Default in OpenSSL is 20K. */ SSL_CTX_sess_set_cache_size(context, ME_MPR_SSL_CACHE); #else SSL_CTX_sess_set_cache_size(context, 1024); #endif cfg->context = context; return cfg; }
MAIN(appweb, int argc, char **argv, char **envp) { Mpr *mpr; cchar *argp, *jail; char *logSpec; int argind, status, verbose; jail = 0; verbose = 0; logSpec = 0; if ((mpr = mprCreate(argc, argv, MPR_USER_EVENTS_THREAD)) == NULL) { exit(1); } mprSetAppName(BIT_PRODUCT, BIT_TITLE, BIT_VERSION); /* Allocate the top level application object. ManageApp is the GC manager function and is called by the GC to mark references in the app object. */ if ((app = mprAllocObj(AppwebApp, manageApp)) == NULL) { exit(2); } mprAddRoot(app); mprAddStandardSignals(); app->mpr = mpr; app->configFile = sclone("appweb.conf"); app->home = mprGetCurrentPath(); app->documents = app->home; argc = mpr->argc; argv = (char**) mpr->argv; for (argind = 1; argind < argc; argind++) { argp = argv[argind]; if (*argp != '-') { break; } if (smatch(argp, "--config") || smatch(argp, "--conf")) { if (argind >= argc) { usageError(); } app->configFile = sclone(argv[++argind]); #if BIT_UNIX_LIKE } else if (smatch(argp, "--chroot")) { if (argind >= argc) { usageError(); } jail = mprGetAbsPath(argv[++argind]); #endif } else if (smatch(argp, "--debugger") || smatch(argp, "-D")) { mprSetDebugMode(1); } else if (smatch(argp, "--exe")) { if (argind >= argc) { usageError(); } mpr->argv[0] = mprGetAbsPath(argv[++argind]); mprSetAppPath(mpr->argv[0]); mprSetModuleSearchPath(NULL); } else if (smatch(argp, "--home")) { if (argind >= argc) { usageError(); } app->home = mprGetAbsPath(argv[++argind]); if (chdir(app->home) < 0) { mprError("%s: Cannot change directory to %s", mprGetAppName(), app->home); exit(4); } } else if (smatch(argp, "--log") || smatch(argp, "-l")) { if (argind >= argc) { usageError(); } logSpec = argv[++argind]; } else if (smatch(argp, "--name") || smatch(argp, "-n")) { if (argind >= argc) { usageError(); } mprSetAppName(argv[++argind], 0, 0); } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) { verbose++; } else if (smatch(argp, "--version") || smatch(argp, "-V")) { mprPrintf("%s-%s\n", BIT_VERSION, BIT_BUILD_NUMBER); exit(0); } else { if (!smatch(argp, "?")) { mprError("Unknown switch \"%s\"", argp); } usageError(); exit(5); } } if (logSpec) { mprStartLogging(logSpec, 1); mprSetCmdlineLogging(1); } else if (verbose) { mprStartLogging(sfmt("stderr:%d", verbose + 1), 1); mprSetCmdlineLogging(1); } /* Start the multithreaded portable runtime (MPR) */ if (mprStart() < 0) { mprError("Cannot start MPR for %s", mprGetAppName()); mprDestroy(); return MPR_ERR_CANT_INITIALIZE; } if (checkEnvironment(argv[0]) < 0) { exit(6); } if (findAppwebConf() < 0) { exit(7); } if (jail && changeRoot(jail) < 0) { exit(8); } /* Open the sockets to listen on */ if (createEndpoints(argc - argind, &argv[argind]) < 0) { return MPR_ERR_CANT_INITIALIZE; } /* Start HTTP services */ if (maStartAppweb(app->appweb) < 0) { mprError("Cannot start HTTP service, exiting."); exit(9); } /* Service I/O events until instructed to exit */ while (!mprIsStopping()) { mprServiceEvents(-1, 0); } status = mprGetExitStatus(); mprLog(1, "Stopping Appweb ..."); maStopAppweb(app->appweb); mprDestroy(); return status; }
static EjsWorker *initWorker(Ejs *ejs, EjsWorker *worker, Ejs *baseVM, cchar *name, EjsArray *search, cchar *scriptFile) { Ejs *wejs; EjsWorker *self; EjsName sname; static int workerSeqno = 0; ejsBlockGC(ejs); if (worker == 0) { worker = ejsCreateWorker(ejs); } worker->ejs = ejs; worker->state = EJS_WORKER_BEGIN; if (name) { worker->name = sclone(name); } else { lock(ejs); worker->name = sfmt("worker-%d", workerSeqno++); unlock(ejs); } /* Create a new interpreter and an "inside" worker object and pair it with the current "outside" worker. The worker interpreter gets a new dispatcher */ if (baseVM) { if ((wejs = ejsCloneVM(baseVM)) == 0) { ejsThrowMemoryError(ejs); return 0; } } else { if ((wejs = ejsCreateVM(0, 0, ejs->flags)) == 0) { ejsThrowMemoryError(ejs); return 0; } if (ejsLoadModules(wejs, 0, 0) < 0) { return 0; } } worker->pair = self = ejsCreateWorker(wejs); self->state = EJS_WORKER_BEGIN; self->ejs = wejs; self->inside = 1; self->pair = worker; self->name = sjoin("inside-", worker->name, NULL); if (search) { ejsSetSearchPath(ejs, (EjsArray*) search); } // TODO - these should be don't delete ejsSetProperty(ejs, worker, ES_Worker_name, ejsCreateStringFromAsc(ejs, self->name)); ejsSetProperty(wejs, self, ES_Worker_name, ejsCreateStringFromAsc(wejs, self->name)); sname = ejsName(wejs, EJS_WORKER_NAMESPACE, "self"); ejsSetPropertyByName(wejs, wejs->global, sname, self); /* Workers have a dedicated namespace to enable viewing of the worker globals (self, onmessage, postMessage...) */ ejsDefineReservedNamespace(wejs, wejs->global, NULL, EJS_WORKER_NAMESPACE); addWorker(ejs, worker); if (scriptFile) { worker->scriptFile = sclone(scriptFile); worker->state = EJS_WORKER_STARTED; if (mprCreateEvent(wejs->dispatcher, "workerMain", 0, (MprEventProc) workerMain, self, 0) < 0) { mprRemoveItem(ejs->workers, worker); ejsThrowStateError(ejs, "Cannot create worker event"); return 0; } } return worker; }
/* WARNING: may yield */ PUBLIC int espLoadConfig(HttpRoute *route) { EspRoute *eroute; cchar *name, *package; bool modified; eroute = route->eroute; if (!route->update) { return 0; } package = mprJoinPath(mprGetPathDir(eroute->configFile), "package.json"); modified = 0; ifConfigModified(route, eroute->configFile, &modified); ifConfigModified(route, package, &modified); if (modified) { lock(esp); httpInitConfig(route); #if DEPRECATED || 1 /* Don't reload if configFile == package.json */ if (!mprSamePath(package, eroute->configFile)) { #endif if (mprPathExists(package, R_OK)) { if (httpLoadConfig(route, package) < 0) { unlock(esp); return MPR_ERR_CANT_LOAD; } } } if (httpLoadConfig(route, eroute->configFile) < 0) { unlock(esp); return MPR_ERR_CANT_LOAD; } if ((name = espGetConfig(route, "name", 0)) != 0) { eroute->appName = name; } if (espLoadCompilerRules(route) < 0) { return MPR_ERR_CANT_OPEN; } unlock(esp); } if (!route->cookie) { httpSetRouteCookie(route, sfmt("esp-%s", eroute->appName)); } if (route->database && !eroute->edi) { if (espOpenDatabase(route, route->database) < 0) { mprLog("error esp", 0, "Cannot open database %s", route->database); return MPR_ERR_CANT_LOAD; } } #if !ME_STATIC if (!(route->flags & HTTP_ROUTE_NO_LISTEN)) { MprJson *preload, *item; cchar *errMsg, *source; char *kind; int i; /* WARNING: may yield when compiling modules */ if (eroute->combine) { source = mprJoinPaths(route->home, httpGetDir(route, "CACHE"), sfmt("%s.c", eroute->appName), NULL); } else { source = mprJoinPaths(route->home, httpGetDir(route, "SRC"), "app.c", NULL); } lock(esp); if (espLoadModule(route, NULL, "app", source, &errMsg) < 0) { if (eroute->combine) { mprLog("error esp", 0, "%s", errMsg); unlock(esp); return MPR_ERR_CANT_LOAD; } } if (!eroute->combine && (preload = mprGetJsonObj(route->config, "esp.preload")) != 0) { for (ITERATE_JSON(preload, item, i)) { source = ssplit(sclone(item->value), ":", &kind); if (*kind == '\0') { kind = "controller"; } source = mprJoinPaths(route->home, httpGetDir(route, "CONTROLLERS"), source, NULL); if (espLoadModule(route, NULL, kind, source, &errMsg) < 0) { mprLog("error esp", 0, "Cannot preload esp module %s. %s", source, errMsg); unlock(esp); return MPR_ERR_CANT_LOAD; } } } unlock(esp); }
MAIN(goahead, int argc, char **argv, char **envp) { char *argp, *home, *documents, *endpoints, *endpoint, *route, *auth, *tok, *lspec; int argind; #if WINDOWS if (windowsInit() < 0) { return 0; } #endif route = "route.txt"; auth = "auth.txt"; for (argind = 1; argind < argc; argind++) { argp = argv[argind]; if (*argp != '-') { break; } else if (smatch(argp, "--auth") || smatch(argp, "-a")) { auth = argv[++argind]; #if BIT_UNIX_LIKE && !MACOSX } else if (smatch(argp, "--background") || smatch(argp, "-b")) { websSetBackground(1); #endif } else if (smatch(argp, "--debugger") || smatch(argp, "-d") || smatch(argp, "-D")) { websSetDebug(1); } else if (smatch(argp, "--home")) { if (argind >= argc) usage(); home = argv[++argind]; if (chdir(home) < 0) { error("Can't change directory to %s", home); exit(-1); } } else if (smatch(argp, "--log") || smatch(argp, "-l")) { if (argind >= argc) usage(); logSetPath(argv[++argind]); } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) { logSetPath("stdout:2"); } else if (smatch(argp, "--route") || smatch(argp, "-r")) { route = argv[++argind]; } else if (smatch(argp, "--version") || smatch(argp, "-V")) { printf("%s\n", BIT_VERSION); exit(0); } else if (*argp == '-' && isdigit((uchar) argp[1])) { lspec = sfmt("stdout:%s", &argp[1]); logSetPath(lspec); wfree(lspec); } else { usage(); } } documents = BIT_GOAHEAD_DOCUMENTS; if (argc > argind) { documents = argv[argind++]; } initPlatform(); if (websOpen(documents, route) < 0) { error("Can't initialize server. Exiting."); return -1; } if (websLoad(auth) < 0) { error("Can't load %s", auth); return -1; } logHeader(); if (argind < argc) { while (argind < argc) { endpoint = argv[argind++]; if (websListen(endpoint) < 0) { return -1; } } } else { endpoints = sclone(BIT_GOAHEAD_LISTEN); for (endpoint = stok(endpoints, ", \t", &tok); endpoint; endpoint = stok(NULL, ", \t,", &tok)) { #if !BIT_PACK_SSL if (strstr(endpoint, "https")) continue; #endif if (websListen(endpoint) < 0) { return -1; } } wfree(endpoints); } #if BIT_ROM && KEEP /* If not using a route/auth config files, then manually create the routes like this: If custom matching is required, use websSetRouteMatch. If authentication is required, use websSetRouteAuth. */ websAddRoute("/", "file", 0); #endif #if BIT_UNIX_LIKE && !MACOSX /* Service events till terminated */ if (websGetBackground()) { if (daemon(0, 0) < 0) { error("Can't run as daemon"); return -1; } } #endif websServiceEvents(&finished); logmsg(1, "Instructed to exit"); websClose(); #if WINDOWS windowsClose(); #endif return 0; }
/* Redirect the user to another web page. The targetUri may or may not have a scheme. */ PUBLIC void httpRedirect(HttpConn *conn, int status, cchar *targetUri) { HttpTx *tx; HttpRx *rx; HttpUri *target, *base; HttpEndpoint *endpoint; cchar *msg; char *dir, *cp; assert(targetUri); rx = conn->rx; tx = conn->tx; if (tx->finalized) { /* A response has already been formulated */ return; } tx->status = status; if (schr(targetUri, '$')) { targetUri = httpExpandUri(conn, targetUri); } mprLog(3, "redirect %d %s", status, targetUri); msg = httpLookupStatus(conn->http, status); if (300 <= status && status <= 399) { if (targetUri == 0) { targetUri = "/"; } target = httpCreateUri(targetUri, 0); base = rx->parsedUri; /* Support URIs without a host: https:///path. This is used to redirect onto the same host but with a different scheme. So find a suitable local endpoint to supply the port for the scheme. */ if (!target->port && (!target->host || smatch(base->host, target->host)) && (target->scheme && !smatch(target->scheme, base->scheme))) { endpoint = smatch(target->scheme, "https") ? conn->host->secureEndpoint : conn->host->defaultEndpoint; if (endpoint) { target->port = endpoint->port; } else { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot find endpoint for scheme %s", target->scheme); return; } } if (target->path && target->path[0] != '/') { /* Relative file redirection to a file in the same directory as the previous request. */ dir = sclone(rx->pathInfo); if ((cp = strrchr(dir, '/')) != 0) { /* Remove basename */ *cp = '\0'; } target->path = sjoin(dir, "/", target->path, NULL); } target = httpCompleteUri(target, base); targetUri = httpUriToString(target, 0); httpSetHeader(conn, "Location", "%s", targetUri); httpFormatResponse(conn, "<!DOCTYPE html>\r\n" "<html><head><title>%s</title></head>\r\n" "<body><h1>%s</h1>\r\n<p>The document has moved <a href=\"%s\">here</a>.</p></body></html>\r\n", msg, msg, targetUri); } else { httpFormatResponse(conn, "<!DOCTYPE html>\r\n" "<html><head><title>%s</title></head>\r\n" "<body><h1>%s</h1>\r\n</body></html>\r\n", msg, msg); } httpFinalize(conn); }
static int defaultIconDirective(MaState *state, cchar *key, cchar *value) { state->dir->defaultIcon = sclone(value); return 0; }
static bool parseArgs(int argc, char **argv) { char *argp, *key, *value; int i, setWorkers, nextArg; setWorkers = 0; for (nextArg = 1; nextArg < argc; nextArg++) { argp = argv[nextArg]; if (*argp != '-') { break; } if (strcmp(argp, "--benchmark") == 0 || strcmp(argp, "-b") == 0) { app->benchmark++; } else if (strcmp(argp, "--chunk") == 0) { if (nextArg >= argc) { return 0; } else { value = argv[++nextArg]; app->chunkSize = atoi(value); if (app->chunkSize < 0) { mprError("Bad chunksize %d", app->chunkSize); return 0; } } } else if (strcmp(argp, "--continue") == 0) { app->continueOnErrors++; } else if (strcmp(argp, "--cookie") == 0) { if (nextArg >= argc) { return 0; } else { mprAddItem(app->headers, mprCreateKeyPair("Cookie", argv[++nextArg])); } } else if (strcmp(argp, "--data") == 0) { if (nextArg >= argc) { return 0; } else { if (app->bodyData == 0) { app->bodyData = mprCreateBuf(-1, -1); } mprPutStringToBuf(app->bodyData, argv[++nextArg]); } } else if (strcmp(argp, "--debugger") == 0 || strcmp(argp, "-D") == 0) { mprSetDebugMode(1); app->retries = 0; app->timeout = MAXINT; } else if (strcmp(argp, "--delete") == 0) { app->method = "DELETE"; } else if (strcmp(argp, "--form") == 0 || strcmp(argp, "-f") == 0) { if (nextArg >= argc) { return 0; } else { if (app->formData == 0) { app->formData = mprCreateList(-1, 0); } addFormVars(argv[++nextArg]); } } else if (strcmp(argp, "--header") == 0) { if (nextArg >= argc) { return 0; } else { key = argv[++nextArg]; if ((value = strchr(key, ':')) == 0) { mprError("Bad header format. Must be \"key: value\""); return 0; } *value++ = '\0'; while (isspace((int) *value)) { value++; } mprAddItem(app->headers, mprCreateKeyPair(key, value)); } } else if (strcmp(argp, "--host") == 0) { if (nextArg >= argc) { return 0; } else { app->host = argv[++nextArg]; if (*app->host == ':') { app->host = &app->host[1]; } if (isPort(app->host)) { app->host = sfmt("http://127.0.0.1:%s", app->host); } else { app->host = sclone(app->host); } } } else if (strcmp(argp, "--iterations") == 0 || strcmp(argp, "-i") == 0) { if (nextArg >= argc) { return 0; } else { app->iterations = atoi(argv[++nextArg]); } } else if (strcmp(argp, "--log") == 0 || strcmp(argp, "-l") == 0) { if (nextArg >= argc) { return 0; } else { mprStartLogging(argv[++nextArg], 0); } } else if (strcmp(argp, "--method") == 0 || strcmp(argp, "-m") == 0) { if (nextArg >= argc) { return 0; } else { app->method = argv[++nextArg]; } } else if (strcmp(argp, "--out") == 0 || strcmp(argp, "-o") == 0) { if (nextArg >= argc) { return 0; } else { app->outFilename = sclone(argv[++nextArg]); } } else if (strcmp(argp, "--noout") == 0 || strcmp(argp, "-n") == 0 || strcmp(argp, "--quiet") == 0 || strcmp(argp, "-q") == 0) { app->noout++; } else if (strcmp(argp, "--nofollow") == 0) { app->nofollow++; } else if (strcmp(argp, "--password") == 0 || strcmp(argp, "-p") == 0) { if (nextArg >= argc) { return 0; } else { app->password = sclone(argv[++nextArg]); } } else if (strcmp(argp, "--post") == 0) { app->method = "POST"; } else if (strcmp(argp, "--printable") == 0) { app->printable++; } else if (strcmp(argp, "--protocol") == 0) { if (nextArg >= argc) { return 0; } else { app->protocol = supper(argv[++nextArg]); } } else if (strcmp(argp, "--put") == 0) { app->method = "PUT"; } else if (strcmp(argp, "--range") == 0) { if (nextArg >= argc) { return 0; } else { // TODO - should allow multiple ranges if (app->ranges == 0) { app->ranges = sfmt("bytes=%s", argv[++nextArg]); } else { app->ranges = srejoin(app->ranges, ",", argv[++nextArg], NULL); } } } else if (strcmp(argp, "--retries") == 0 || strcmp(argp, "-r") == 0) { if (nextArg >= argc) { return 0; } else { app->retries = atoi(argv[++nextArg]); } } else if (strcmp(argp, "--sequence") == 0) { app->sequence++; } else if (strcmp(argp, "--showHeaders") == 0 || strcmp(argp, "--show") == 0 || strcmp(argp, "-s") == 0) { app->showHeaders++; } else if (strcmp(argp, "--showStatus") == 0 || strcmp(argp, "--showCode") == 0) { app->showStatus++; } else if (strcmp(argp, "--single") == 0 || strcmp(argp, "-s") == 0) { app->singleStep++; } else if (strcmp(argp, "--text") == 0) { app->text++; } else if (strcmp(argp, "--threads") == 0 || strcmp(argp, "-t") == 0) { if (nextArg >= argc) { return 0; } else { app->loadThreads = atoi(argv[++nextArg]); } } else if (strcmp(argp, "--timeout") == 0) { if (nextArg >= argc) { return 0; } else { app->timeout = atoi(argv[++nextArg]) * MPR_TICKS_PER_SEC; } } else if (strcmp(argp, "--upload") == 0 || strcmp(argp, "-u") == 0) { app->upload++; } else if (strcmp(argp, "--user") == 0 || strcmp(argp, "--username") == 0) { if (nextArg >= argc) { return 0; } else { app->username = argv[++nextArg]; } } else if (strcmp(argp, "--verbose") == 0 || strcmp(argp, "-v") == 0) { app->verbose++; } else if (strcmp(argp, "--version") == 0 || strcmp(argp, "-V") == 0) { mprPrintfError("%s %s\n" "Copyright (C) Embedthis Software 2003-2012\n" "Copyright (C) Michael O'Brien 2003-2012\n", BLD_NAME, BLD_VERSION); exit(0); } else if (strcmp(argp, "--workerTheads") == 0 || strcmp(argp, "-w") == 0) { if (nextArg >= argc) { return 0; } else { app->workers = atoi(argv[++nextArg]); } setWorkers++; } else if (strcmp(argp, "--zero") == 0) { app->zeroOnErrors++; } else if (strcmp(argp, "--") == 0) { nextArg++; break; } else if (strcmp(argp, "-") == 0) { break; } else { return 0; break; } } if (argc == nextArg) { return 0; } app->nextArg = nextArg; argc = argc - nextArg; argv = &argv[nextArg]; app->target = argv[argc - 1]; app->iterations *= app->loadThreads; if (--argc > 0) { /* Files present on command line */ app->files = mprCreateList(argc, MPR_LIST_STATIC_VALUES); for (i = 0; i < argc; i++) { mprAddItem(app->files, argv[i]); } } if (!setWorkers) { app->workers = app->loadThreads + 2; } if (app->method == 0) { if (app->bodyData || app->formData || app->upload) { app->method = "POST"; } else if (app->files) { app->method = "PUT"; } else { app->method = "GET"; } } return 1; }
APIENTRY WinMain(HINSTANCE inst, HINSTANCE junk, char *command, int junk2) { char *argv[ME_MAX_ARGC], *argp; int argc, err, nextArg, manage, stop; argv[0] = ME_NAME "Monitor"; argc = mprParseArgs(command, &argv[1], ME_MAX_ARGC - 1) + 1; if (mprCreate(argc, argv, MPR_USER_EVENTS_THREAD | MPR_NO_WINDOW) == NULL) { exit(1); } if ((app = mprAllocObj(App, manageApp)) == NULL) { exit(2); } mprAddRoot(app); err = 0; stop = 0; manage = 0; app->appInst = inst; app->company = sclone(ME_COMPANY); app->serviceName = sclone(ME_NAME); mprSetLogHandler(logHandler); chdir(mprGetAppDir()); /* Parse command line arguments */ for (nextArg = 1; nextArg < argc; nextArg++) { argp = argv[nextArg]; if (*argp != '-') { break; } if (strcmp(argp, "--manage") == 0) { manage++; } else if (strcmp(argp, "--stop") == 0) { stop++; } else { err++; } if (err) { mprError("appweb monitor", "Bad command line: %s\n" " Usage: %s [options]\n" " Switches:\n" " --manage # Launch browser to manage", " --stop # Stop a running monitor", command, mprGetAppName()); return -1; } } if (stop) { stopMonitor(); return 0; } if (findInstance()) { mprError("appweb monitor", "Application %s is already active.", mprGetAppTitle()); return MPR_ERR_BUSY; } app->hwnd = mprSetWindowsThread(0); mprSetWinMsgCallback(msgProc); if (app->taskBarIcon > 0) { ShowWindow(app->hwnd, SW_MINIMIZE); UpdateWindow(app->hwnd); } if (manage) { /* Launch the browser */ runBrowser("/index.html"); } else { if (openMonitorIcon() < 0) { mprError("appweb monitor", "Cannot open %s tray", mprGetAppName()); } else { mprServiceEvents(-1, 0); closeMonitorIcon(); } } mprDestroy(); return 0; }
/* Upgrade a standard socket to use SSL/TLS. Used by both clients and servers to upgrade a socket for SSL. If a client, this may block while connecting. */ static int upgradeOss(MprSocket *sp, MprSsl *ssl, cchar *requiredPeerName) { OpenSocket *osp; OpenConfig *cfg; int rc; assert(sp); if (ssl == 0) { ssl = mprCreateSsl(sp->flags & MPR_SOCKET_SERVER); } if ((osp = (OpenSocket*) mprAllocObj(OpenSocket, manageOpenSocket)) == 0) { return MPR_ERR_MEMORY; } osp->sock = sp; sp->sslSocket = osp; sp->ssl = ssl; if (!ssl->config || ssl->changed) { /* On-demand creation of the SSL configuration */ if ((ssl->config = createOpenSslConfig(sp)) == 0) { return MPR_ERR_CANT_INITIALIZE; } ssl->changed = 0; } /* Create and configure the SSL struct */ cfg = osp->cfg = sp->ssl->config; if ((osp->handle = (SSL*) SSL_new(cfg->context)) == 0) { return MPR_ERR_BAD_STATE; } SSL_set_app_data(osp->handle, (void*) osp); /* Create a socket bio. We don't use the BIO except as storage for the fd */ if ((osp->bio = BIO_new_socket((int) sp->fd, BIO_NOCLOSE)) == 0) { return MPR_ERR_BAD_STATE; } SSL_set_bio(osp->handle, osp->bio, osp->bio); if (sp->flags & MPR_SOCKET_SERVER) { SSL_set_accept_state(osp->handle); } else { if (requiredPeerName) { osp->requiredPeerName = sclone(requiredPeerName); } /* Block while connecting */ mprSetSocketBlockingMode(sp, 1); sp->errorMsg = 0; if ((rc = SSL_connect(osp->handle)) < 1) { if (sp->errorMsg) { mprLog("info mpr ssl openssl", 4, "Connect failed: %s", sp->errorMsg); } else { mprLog("info mpr ssl openssl", 4, "Connect failed: error %s", getOssError(sp)); } return MPR_ERR_CANT_CONNECT; } if (rc > 0 && checkPeerCertName(sp) < 0) { return MPR_ERR_CANT_CONNECT; } setSecured(sp); mprSetSocketBlockingMode(sp, 0); } #if defined(ME_MPR_SSL_RENEGOTIATE) && !ME_MPR_SSL_RENEGOTIATE /* Disable renegotiation after the initial handshake if renegotiate is explicitly set to false (CVE-2009-3555). Note: this really is a bogus CVE as disabling renegotiation is not required nor does it enhance security if used with up-to-date (patched) SSL stacks. */ if (osp->handle->s3) { osp->handle->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS; } #endif return 0; }
/* Tokens: ARCH Build architecture (64) GCC_ARCH ARCH mapped to gcc -arch switches (x86_64) CC Compiler (cc) DEBUG Debug compilation options (-g, -Zi -Od) INC Include directory out/inc LIB Library directory (out/lib, xcode/VS: out/bin) LIBS Libraries required to link with ESP OBJ Name of compiled source (out/lib/view-MD5.o) MOD Output module (view_MD5.dylib) SHLIB Host Shared library (.lib, .so) SHOBJ Host Shared Object (.dll, .so) SRC Source code for view or controller (already templated) TMP Temp directory VS Visual Studio directory WINSDK Windows SDK directory */ PUBLIC char *espExpandCommand(EspRoute *eroute, cchar *command, cchar *source, cchar *module) { MprBuf *buf; MaAppweb *appweb; cchar *cp, *outputModule, *os, *arch, *profile; char *tmp; if (command == 0) { return 0; } appweb = MPR->appwebService; outputModule = mprTrimPathExt(module); maParsePlatform(appweb->platform, &os, &arch, &profile); buf = mprCreateBuf(-1, -1); for (cp = command; *cp; ) { if (*cp == '$') { if (matchToken(&cp, "${ARCH}")) { /* Target architecture (x86|mips|arm|x64) */ mprPutStringToBuf(buf, arch); } else if (matchToken(&cp, "${GCC_ARCH}")) { /* Target architecture mapped to GCC mtune|mcpu values */ mprPutStringToBuf(buf, getMappedArch(arch)); } else if (matchToken(&cp, "${INC}")) { /* Include directory for the configuration */ mprPutStringToBuf(buf, mprJoinPath(appweb->platformDir, "inc")); } else if (matchToken(&cp, "${LIBPATH}")) { /* Library directory for Appweb libraries for the target */ mprPutStringToBuf(buf, mprJoinPath(appweb->platformDir, "bin")); } else if (matchToken(&cp, "${LIBS}")) { /* Required libraries to link. These may have nested ${TOKENS} */ mprPutStringToBuf(buf, espExpandCommand(eroute, getLibs(os), source, module)); } else if (matchToken(&cp, "${MOD}")) { /* Output module path in the cache without extension */ mprPutStringToBuf(buf, outputModule); } else if (matchToken(&cp, "${OBJ}")) { /* Output object with extension (.o) in the cache directory */ mprPutStringToBuf(buf, mprJoinPathExt(outputModule, getObjExt(os))); } else if (matchToken(&cp, "${OS}")) { /* Target architecture (freebsd|linux|macosx|windows|vxworks) */ mprPutStringToBuf(buf, os); } else if (matchToken(&cp, "${SHLIB}")) { /* .dll, .so, .dylib */ mprPutStringToBuf(buf, getShlibExt(os)); } else if (matchToken(&cp, "${SHOBJ}")) { /* .dll, .so, .dylib */ mprPutStringToBuf(buf, getShobjExt(os)); } else if (matchToken(&cp, "${SRC}")) { /* View (already parsed into C code) or controller source */ mprPutStringToBuf(buf, source); } else if (matchToken(&cp, "${TMP}")) { if ((tmp = getenv("TMPDIR")) == 0) { if ((tmp = getenv("TMP")) == 0) { tmp = getenv("TEMP"); } } mprPutStringToBuf(buf, tmp ? tmp : "."); } else if (matchToken(&cp, "${VS}")) { mprPutStringToBuf(buf, getVisualStudio()); } else if (matchToken(&cp, "${VXCPU}")) { mprPutStringToBuf(buf, getVxCPU(arch)); } else if (matchToken(&cp, "${WINSDK}")) { mprPutStringToBuf(buf, getWinSDK()); /* These vars can be configured from environment variables. NOTE: the default esp.conf includes "esp->vxworks.conf" which has EspEnv definitions for the configured VxWorks toolchain */ } else if (matchToken(&cp, "${CC}")) { mprPutStringToBuf(buf, getEnvString(eroute, "CC", getCompilerPath(os, arch))); } else if (matchToken(&cp, "${LINK}")) { mprPutStringToBuf(buf, getEnvString(eroute, "LINK", "")); } else if (matchToken(&cp, "${CFLAGS}")) { mprPutStringToBuf(buf, getEnvString(eroute, "CFLAGS", "")); } else if (matchToken(&cp, "${DEBUG}")) { mprPutStringToBuf(buf, getEnvString(eroute, "DEBUG", getDebug())); } else if (matchToken(&cp, "${LDFLAGS}")) { mprPutStringToBuf(buf, getEnvString(eroute, "LDFLAGS", "")); } else if (matchToken(&cp, "${WIND_BASE}")) { mprPutStringToBuf(buf, getEnvString(eroute, "WIND_BASE", WIND_BASE)); } else if (matchToken(&cp, "${WIND_HOME}")) { mprPutStringToBuf(buf, getEnvString(eroute, "WIND_HOME", WIND_HOME)); } else if (matchToken(&cp, "${WIND_HOST_TYPE}")) { mprPutStringToBuf(buf, getEnvString(eroute, "WIND_HOST_TYPE", WIND_HOST_TYPE)); } else if (matchToken(&cp, "${WIND_PLATFORM}")) { mprPutStringToBuf(buf, getEnvString(eroute, "WIND_PLATFORM", WIND_PLATFORM)); } else if (matchToken(&cp, "${WIND_GNU_PATH}")) { mprPutStringToBuf(buf, getEnvString(eroute, "WIND_GNU_PATH", WIND_GNU_PATH)); } else if (matchToken(&cp, "${WIND_CCNAME}")) { mprPutStringToBuf(buf, getEnvString(eroute, "WIND_CCNAME", getCompilerName(os, arch))); } else { mprPutCharToBuf(buf, *cp++); } } else { mprPutCharToBuf(buf, *cp++); } } mprAddNullToBuf(buf); return sclone(mprGetBufStart(buf)); }
MAIN(goahead, int argc, char **argv, char **envp) { char *argp, *auth, *home, *documents, *endpoints, *endpoint, *route, *tok; int argind; route = "route.txt"; auth = "auth.txt"; for (argind = 1; argind < argc; argind++) { argp = argv[argind]; if (*argp != '-') { break; } else if (smatch(argp, "--auth") || smatch(argp, "-a")) { if (argind >= argc) usage(); auth = argv[++argind]; } else if (smatch(argp, "--background") || smatch(argp, "-b")) { websSetBackground(1); } else if (smatch(argp, "--debugger") || smatch(argp, "-d") || smatch(argp, "-D")) { websSetDebug(1); } else if (smatch(argp, "--home")) { if (argind >= argc) usage(); home = argv[++argind]; if (chdir(home) < 0) { error("Can't change directory to %s", home); exit(-1); } } else if (smatch(argp, "--log") || smatch(argp, "-l")) { if (argind >= argc) usage(); traceSetPath(argv[++argind]); } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) { traceSetPath("stdout:2"); } else if (smatch(argp, "--route") || smatch(argp, "-r")) { route = argv[++argind]; } else if (smatch(argp, "--version") || smatch(argp, "-V")) { printf("%s: %s-%s\n", BIT_PRODUCT, BIT_VERSION, BIT_BUILD_NUMBER); exit(0); } else { usage(); } } documents = BIT_DOCUMENTS; if (argc > argind) { documents = argv[argind++]; } initPlatform(); if (websOpen(documents, route) < 0) { error("Can't initialize server. Exiting."); return -1; } logHeader(); if (websLoad(auth) < 0) { error("Can't load %s", auth); return -1; } if (argind < argc) { while (argind < argc) { endpoint = argv[argind++]; if (websListen(endpoint) < 0) { return -1; } } } else { endpoints = sclone(BIT_LISTEN); for (endpoint = stok(endpoints, ", \t", &tok); endpoint; endpoint = stok(NULL, ", \t,", &tok)) { if (websListen(endpoint) < 0) { return -1; } } wfree(endpoints); } websDefineHandler("test", testHandler, 0, 0); websAddRoute("/test", "test", 0); #if BIT_LEGACY websUrlHandlerDefine("/legacy/", 0, 0, legacyTest, 0); #endif #if BIT_JAVASCRIPT websDefineJst("aspTest", aspTest); websDefineJst("bigTest", bigTest); #endif websDefineAction("test", actionTest); websDefineAction("sessionTest", sessionTest); websDefineAction("showTest", showTest); #if BIT_UPLOAD websDefineAction("uploadTest", uploadTest); #endif #if BIT_UNIX_LIKE /* Service events till terminated */ if (websGetBackground()) { if (daemon(0, 0) < 0) { error("Can't run as daemon"); return -1; } } #endif websServiceEvents(&finished); trace(1, "Instructed to exit\n"); websClose(); return 0; }
static int compileInner(EcCompiler *cp, int argc, char **argv) { Ejs *ejs; EjsModule *mp; MprList *nodes; EjsBlock *block; EcLocation loc; cchar *ext; char *msg; int next, i, j, nextModule, lflags, rc, paused; ejs = cp->ejs; if ((nodes = mprCreateList(-1, 0)) == 0) { return EJS_ERR; } cp->nodes = nodes; /* Warn about source files mentioned multiple times. TODO OPT. This is slow. */ for (i = 0; i < argc; i++) { for (j = 0; j < argc; j++) { if (i == j) { continue; } if (mprSamePath(argv[i], argv[j])) { compileError(cp, "Loading source %s multiple times. Ignoring extra copies.", argv[i]); return EJS_ERR; } } if (cp->outputFile && mprSamePath(cp->outputFile, argv[i])) { compileError(cp, "Output file is the same as input file: %s", argv[i]); return EJS_ERR; } } /* Compile source files and load any module files */ for (i = 0; i < argc && !cp->fatalError; i++) { ext = mprGetPathExt(argv[i]); if (scaselesscmp(ext, "mod") == 0 || scaselesscmp(ext, BIT_SHOBJ) == 0) { nextModule = mprGetListLength(ejs->modules); lflags = cp->strict ? EJS_LOADER_STRICT : 0; if ((rc = ejsLoadModule(cp->ejs, ejsCreateStringFromAsc(ejs, argv[i]), -1, -1, lflags)) < 0) { msg = sfmt("Error initializing module %s\n%s", argv[i], ejsGetErrorMsg(cp->ejs, 1)); memset(&loc, 0, sizeof(EcLocation)); loc.filename = sclone(argv[i]); if (rc == MPR_ERR_CANT_INITIALIZE) { ecError(cp, "Error", &loc, msg); } else { ecError(cp, "Error", &loc, msg); } cp->nodes = NULL; return EJS_ERR; } if (cp->merge) { /* If merging, we must emit the loaded module into the output. So add to the compiled modules list. */ for (next = nextModule; (mp = mprGetNextItem(ejs->modules, &next)) != 0; ) { if (mprLookupItem(cp->modules, mp) < 0 && mprAddItem(cp->modules, mp) < 0) { compileError(cp, "Cannot add module %s", mp->name); } } } mprAddItem(nodes, 0); } else { paused = ejsBlockGC(ejs); mprAddItem(nodes, ecParseFile(cp, argv[i])); ejsUnblockGC(ejs, paused); } } assure(ejs->result == 0 || (MPR_GET_GEN(MPR_GET_MEM(ejs->result)) != MPR->heap->dead)); /* Allocate the eval frame stack. This is used for property lookups. We have one dummy block at the top always. */ block = ejsCreateBlock(ejs, 0); mprSetName(block, "Compiler"); ejsPushBlock(ejs, block); /* Process the internal representation and generate code */ paused = ejsBlockGC(ejs); if (!cp->parseOnly && cp->errorCount == 0) { ecResetParser(cp); if (ecAstProcess(cp) < 0) { ejsPopBlock(ejs); cp->nodes = NULL; ejsUnblockGC(ejs, paused); return EJS_ERR; } if (cp->errorCount == 0) { ecResetParser(cp); if (ecCodeGen(cp) < 0) { ejsPopBlock(ejs); cp->nodes = NULL; ejsUnblockGC(ejs, paused); return EJS_ERR; } } } ejsPopBlock(ejs); assure(ejs->result == 0 || (MPR_GET_GEN(MPR_GET_MEM(ejs->result)) != MPR->heap->dead)); /* Add compiled modules to the interpreter */ for (next = 0; ((mp = (EjsModule*) mprGetNextItem(cp->modules, &next)) != 0); ) { ejsAddModule(cp->ejs, mp); } cp->nodes = NULL; ejsUnblockGC(ejs, paused); if (!paused) { mprYield(0); } assure(ejs->result == 0 || (MPR_GET_GEN(MPR_GET_MEM(ejs->result)) != MPR->heap->dead)); return (cp->errorCount > 0) ? EJS_ERR: 0; }
MAIN(ejsMain, int argc, char **argv, char **envp) { Mpr *mpr; EcCompiler *cp; Ejs *ejs; cchar *cmd, *className, *method, *homeDir, *logSpec, *traceSpec; char *argp, *searchPath, *modules, *name, *tok, *extraFiles; int nextArg, err, ecFlags, stats, merge, bind, noout, debug, optimizeLevel, warnLevel, strict, i, next; /* Initialize Multithreaded Portable Runtime (MPR) */ mpr = mprCreate(argc, argv, 0); app = mprAllocObj(App, manageApp); mprAddRoot(app); mprAddStandardSignals(); if (mprStart(mpr) < 0) { mprLog("ejs", 0, "Cannot start mpr services"); return EJS_ERR; } err = 0; className = 0; cmd = 0; method = 0; searchPath = 0; stats = 0; merge = 0; bind = 1; noout = 1; debug = 1; warnLevel = 1; optimizeLevel = 9; strict = 0; logSpec = 0; traceSpec = 0; app->files = mprCreateList(-1, 0); app->iterations = 1; argc = mpr->argc; argv = (char**) mpr->argv; for (nextArg = 1; nextArg < argc; nextArg++) { argp = argv[nextArg]; if (*argp != '-') { break; } if (smatch(argp, "--bind")) { bind = 1; } else if (smatch(argp, "--class")) { if (nextArg >= argc) { err++; } else { className = argv[++nextArg]; } } else if (smatch(argp, "--chdir") || smatch(argp, "--home") || smatch(argp, "-C")) { if (nextArg >= argc) { err++; } else { homeDir = argv[++nextArg]; if (chdir((char*) homeDir) < 0) { mprLog("ejs", 0, "Cannot change directory to %s", homeDir); } } #if ME_UNIX_LIKE } else if (smatch(argp, "--chroot")) { /* Not documented or supported */ if (nextArg >= argc) { err++; } else { homeDir = mprGetAbsPath(argv[++nextArg]); if (chroot(homeDir) < 0) { if (errno == EPERM) { mprEprintf("%s: Must be super user to use the --chroot option", mprGetAppName(mpr)); } else { mprEprintf("%s: Cannot change change root directory to %s, errno %d", mprGetAppName(), homeDir, errno); } return 4; } } #endif } else if (smatch(argp, "--cmd") || smatch(argp, "-c")) { if (nextArg >= argc) { err++; } else { cmd = argv[++nextArg]; } #if ME_WIN_LIKE } else if (smatch(argp, "--cygroot")) { if (nextArg >= argc) { err++; } else { app->cygroot = sclone(argv[++nextArg]); } #endif } else if (smatch(argp, "--debug")) { debug = 1; } else if (smatch(argp, "--debugger") || smatch(argp, "-D")) { mprSetDebugMode(1); } else if (smatch(argp, "--files") || smatch(argp, "-f")) { /* Compatibility with mozilla shell */ if (nextArg >= argc) { err++; } else { extraFiles = sclone(argv[++nextArg]); name = stok(extraFiles, " \t", &tok); while (name != NULL) { mprAddItem(app->files, sclone(name)); name = stok(NULL, " \t", &tok); } } } else if (smatch(argp, "--iterations") || smatch(argp, "-i")) { if (nextArg >= argc) { err++; } else { app->iterations = atoi(argv[++nextArg]); } } else if (smatch(argp, "--log")) { if (nextArg >= argc) { err++; } else { logSpec = argv[++nextArg]; } } else if (smatch(argp, "--method")) { if (nextArg >= argc) { err++; } else { method = argv[++nextArg]; } } else if (smatch(argp, "--name")) { /* Just ignore. Used to tag commands with a unique command line */ nextArg++; } else if (smatch(argp, "--nobind")) { bind = 0; } else if (smatch(argp, "--nodebug")) { debug = 0; } else if (smatch(argp, "--optimize")) { if (nextArg >= argc) { err++; } else { optimizeLevel = atoi(argv[++nextArg]); } } else if (smatch(argp, "--require")) { if (nextArg >= argc) { err++; } else { if (app->modules == 0) { app->modules = mprCreateList(-1, 0); } modules = sclone(argv[++nextArg]); name = stok(modules, " \t", &tok); while (name != NULL) { require(name); name = stok(NULL, " \t", &tok); } } } else if (smatch(argp, "-s")) { /* Compatibility with mozilla shell. Just ignore */ } else if (smatch(argp, "--search") || smatch(argp, "--searchpath")) { if (nextArg >= argc) { err++; } else { searchPath = argv[++nextArg]; } } else if (smatch(argp, "--standard")) { strict = 0; } else if (smatch(argp, "--stats")) { stats = 1; } else if (smatch(argp, "--strict")) { strict = 1; } else if (smatch(argp, "--trace") || smatch(argp, "-t")) { if (nextArg >= argc) { err++; } else { traceSpec = argv[++nextArg]; } } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) { logSpec = "stderr:2"; } else if (smatch(argp, "--version") || smatch(argp, "-V")) { mprPrintf("%s\n", EJS_VERSION); return 0; } else if (smatch(argp, "--warn")) { if (nextArg >= argc) { err++; } else { warnLevel = atoi(argv[++nextArg]); } } else if (*argp == '-' && isdigit((uchar) argp[1])) { if (!logSpec) { logSpec = sfmt("stderr:%d", (int) stoi(&argp[1])); } if (!traceSpec) { traceSpec = sfmt("stderr:%d", (int) stoi(&argp[1])); } } else { err++; break; } } if (err) { /* If --method or --class is specified, then the named class.method will be run (method defaults to "main", class defaults to first class with a "main"). Examples: ejs ejs script.es arg1 arg2 arg3 ejs --class "Customer" --method "start" --files "script1.es script2.es" main.es */ mprEprintf("Usage: %s [options] script.es [arguments] ...\n" " Ejscript shell program options:\n" " --class className # Name of class containing method to run\n" " --cmd ejscriptCode # Literal ejscript statements to execute\n" " --cygroot path # Set cygwin root for resolving script paths\n" " --debug # Use symbolic debugging information (default)\n" " --debugger # Disable timeouts to make using a debugger easier\n" " --files \"files..\" # Extra source to compile\n" " --log logSpec # Internal compiler diagnostics logging\n" " --method methodName # Name of method to run. Defaults to main\n" " --nodebug # Omit symbolic debugging information\n" " --optimize level # Set the optimization level (0-9 default is 9)\n" " --require 'module,...' # Required list of modules to pre-load\n" " --search ejsPath # Module search path\n" " --standard # Default compilation mode to standard (default)\n" " --stats # Print memory stats on exit\n" " --strict # Default compilation mode to strict\n" " --trace traceSpec # HTTP request tracing\n" " --verbose | -v # Same as --log stderr:2 \n" " --version # Emit the compiler version information\n" " --warn level # Set the warning message level (0-9 default is 0)\n\n", mpr->name); return -1; } if (logSpec) { mprStartLogging(logSpec, MPR_LOG_CMDLINE); } if (traceSpec) { httpCreate(HTTP_CLIENT_SIDE | HTTP_SERVER_SIDE); httpStartTracing(traceSpec); } if ((ejs = ejsCreateVM(argc - nextArg, (cchar **) &argv[nextArg], 0)) == 0) { return MPR_ERR_MEMORY; } mprStartDispatcher(ejs->dispatcher); app->ejs = ejs; if (ejsLoadModules(ejs, searchPath, app->modules) < 0) { return MPR_ERR_CANT_READ; } mprGC(MPR_GC_FORCE); ecFlags = 0; ecFlags |= (merge) ? EC_FLAGS_MERGE: 0; ecFlags |= (bind) ? EC_FLAGS_BIND: 0; ecFlags |= (noout) ? EC_FLAGS_NO_OUT: 0; ecFlags |= (debug) ? EC_FLAGS_DEBUG: 0; cp = app->compiler = ecCreateCompiler(ejs, ecFlags); if (cp == 0) { return MPR_ERR_MEMORY; } ecSetRequire(cp, app->modules); ecSetOptimizeLevel(cp, optimizeLevel); ecSetWarnLevel(cp, warnLevel); ecSetStrictMode(cp, strict); if (nextArg < argc) { mprAddItem(app->files, sclone(argv[nextArg])); } if (app->cygroot) { /* When cygwin invokes a script with shebang, it passes a cygwin path to the script The ejs --cygroot option permits ejscript to conver this to a native path */ for (next = 0; (name = mprGetNextItem(app->files, &next)) != 0; ) { if (*name == '/' || *name == '\\') { mprSetItem(app->files, next - 1, sjoin(app->cygroot, name, NULL)); } } } for (i = 0; !err && i < app->iterations; i++) { if (cmd) { if (interpretCommands(cp, cmd) < 0) { err++; } } else if (mprGetListLength(app->files) > 0) { if (interpretFiles(cp, app->files, argc - nextArg, &argv[nextArg], className, method) < 0) { err++; } } else { /* No args - run as an interactive shell */ if (interpretCommands(cp, NULL) < 0) { err++; } } } if (stats) { #if ME_DEBUG mprSetLogLevel(1); mprPrintMem("Memory Usage", 1); #endif } if (err) { mprSetExitStatus(err); } app->ejs = 0; app->compiler = 0; ejsDestroy(ejs); mprDestroy(); return mprGetExitStatus(); }
static bool parseDigestDetails(Webs *wp) { WebsTime when; char *value, *tok, *key, *dp, *sp, *secret, *realm; int seenComma; assert(wp); key = sclone(wp->authDetails); while (*key) { while (*key && isspace((uchar) *key)) { key++; } tok = key; while (*tok && !isspace((uchar) *tok) && *tok != ',' && *tok != '=') { tok++; } *tok++ = '\0'; while (isspace((uchar) *tok)) { tok++; } seenComma = 0; if (*tok == '\"') { value = ++tok; while (*tok != '\"' && *tok != '\0') { tok++; } } else { value = tok; while (*tok != ',' && *tok != '\0') { tok++; } seenComma++; } *tok++ = '\0'; /* Handle back-quoting */ if (strchr(value, '\\')) { for (dp = sp = value; *sp; sp++) { if (*sp == '\\') { sp++; } *dp++ = *sp++; } *dp = '\0'; } /* user, response, oqaque, uri, realm, nonce, nc, cnonce, qop */ switch (tolower((uchar) *key)) { case 'a': if (scaselesscmp(key, "algorithm") == 0) { break; } else if (scaselesscmp(key, "auth-param") == 0) { break; } break; case 'c': if (scaselesscmp(key, "cnonce") == 0) { wp->cnonce = sclone(value); } break; case 'd': if (scaselesscmp(key, "domain") == 0) { break; } break; case 'n': if (scaselesscmp(key, "nc") == 0) { wp->nc = sclone(value); } else if (scaselesscmp(key, "nonce") == 0) { wp->nonce = sclone(value); } break; case 'o': if (scaselesscmp(key, "opaque") == 0) { wp->opaque = sclone(value); } break; case 'q': if (scaselesscmp(key, "qop") == 0) { wp->qop = sclone(value); } break; case 'r': if (scaselesscmp(key, "realm") == 0) { wp->realm = sclone(value); } else if (scaselesscmp(key, "response") == 0) { /* Store the response digest in the password field. This is MD5(user:realm:password) */ wp->password = sclone(value); wp->encoded = 1; } break; case 's': if (scaselesscmp(key, "stale") == 0) { break; } case 'u': if (scaselesscmp(key, "uri") == 0) { wp->digestUri = sclone(value); } else if (scaselesscmp(key, "username") == 0 || scaselesscmp(key, "user") == 0) { wp->username = sclone(value); } break; default: /* Just ignore keywords we don't understand */ ; } key = tok; if (!seenComma) { while (*key && *key != ',') { key++; } if (*key) { key++; } } } if (wp->username == 0 || wp->realm == 0 || wp->nonce == 0 || wp->route == 0 || wp->password == 0) { return 0; } if (wp->qop && (wp->cnonce == 0 || wp->nc == 0)) { return 0; } if (wp->qop == 0) { wp->qop = sclone(""); } /* Validate the nonce value - prevents replay attacks */ when = 0; secret = 0; realm = 0; parseDigestNonce(wp->nonce, &secret, &realm, &when); if (!smatch(secret, secret)) { trace(2, "Access denied: Nonce mismatch"); return 0; } else if (!smatch(realm, BIT_GOAHEAD_REALM)) { trace(2, "Access denied: Realm mismatch"); return 0; } else if (!smatch(wp->qop, "auth")) { trace(2, "Access denied: Bad qop"); return 0; } else if ((when + (5 * 60)) < time(0)) { trace(2, "Access denied: Nonce is stale"); return 0; } if (!wp->user) { if ((wp->user = websLookupUser(wp->username)) == 0) { trace(2, "Access denied: user is unknown"); return 0; } } wp->digest = calcDigest(wp, 0, wp->user->password); return 1; }
static void require(cchar *name) { if (name && *name) { mprAddItem(app->modules, sclone(name)); } }
static int processUploadHeader(Webs *wp, char *line) { WebsUpload *file; char *key, *headerTok, *rest, *nextPair, *value; if (line[0] == '\0') { wp->uploadState = UPLOAD_CONTENT_DATA; return 0; } trace(7, "Header line: %s", line); headerTok = line; stok(line, ": ", &rest); if (scaselesscmp(headerTok, "Content-Disposition") == 0) { /* The content disposition header describes either a form variable or an uploaded file. Content-Disposition: form-data; name="field1" >>blank line Field Data ---boundary Content-Disposition: form-data; name="field1" filename="user.file" >>blank line File data ---boundary */ key = rest; wp->uploadVar = wp->clientFilename = 0; while (key && stok(key, ";\r\n", &nextPair)) { key = strim(key, " ", WEBS_TRIM_BOTH); ssplit(key, "= ", &value); value = strim(value, "\"", WEBS_TRIM_BOTH); if (scaselesscmp(key, "form-data") == 0) { /* Nothing to do */ } else if (scaselesscmp(key, "name") == 0) { wp->uploadVar = sclone(value); } else if (scaselesscmp(key, "filename") == 0) { if (wp->uploadVar == 0) { websError(wp, HTTP_CODE_BAD_REQUEST, "Bad upload state. Missing name field"); return -1; } value = websNormalizeUriPath(value); if (*value == '.' || !websValidUriChars(value) || strpbrk(value, "\\/:*?<>|~\"'%`^\n\r\t\f")) { websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Bad upload client filename"); return -1; } wfree(wp->clientFilename); wp->clientFilename = sclone(value); /* Create the file to hold the uploaded data */ if ((wp->uploadTmp = websTempFile(uploadDir, "tmp")) == 0) { websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot create upload temp file %s. Check upload temp dir %s", wp->uploadTmp, uploadDir); return -1; } trace(5, "File upload of: %s stored as %s", wp->clientFilename, wp->uploadTmp); if ((wp->upfd = open(wp->uploadTmp, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600)) < 0) { websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot open upload temp file %s", wp->uploadTmp); printf("Cannot open upload temp file %s\n",wp->uploadTmp); return -1; } printf("Open upload temp file %s\n",wp->uploadTmp); /* Create the files[id] */ file = wp->currentFile = walloc(sizeof(WebsUpload)); memset(file, 0, sizeof(WebsUpload)); file->clientFilename = sclone(wp->clientFilename); file->filename = sclone(wp->uploadTmp); } key = nextPair; } } else if (scaselesscmp(headerTok, "Content-Type") == 0) { if (wp->clientFilename) { trace(5, "Set files[%s][CONTENT_TYPE] = %s", wp->uploadVar, rest); wp->currentFile->contentType = sclone(rest); } } return 0; }
/* Build the command arguments. NOTE: argv is untrusted input. */ static void buildArgs(HttpConn *conn, MprCmd *cmd, int *argcp, cchar ***argvp) { HttpRx *rx; HttpTx *tx; char **argv; char *indexQuery, *cp, *tok; cchar *actionProgram, *fileName; size_t len; int argc, argind, i; rx = conn->rx; tx = conn->tx; fileName = tx->filename; assert(fileName); actionProgram = 0; argind = 0; argc = *argcp; if (tx->ext) { actionProgram = mprGetMimeProgram(rx->route->mimeTypes, tx->ext); if (actionProgram != 0) { argc++; } /* This is an Apache compatible hack for PHP 5.3 */ mprAddKey(rx->headers, "REDIRECT_STATUS", itos(HTTP_CODE_MOVED_TEMPORARILY)); } /* Count the args for ISINDEX queries. Only valid if there is not a "=" in the query. If this is so, then we must not have these args in the query env also? */ indexQuery = rx->parsedUri->query; if (indexQuery && !strchr(indexQuery, '=')) { argc++; for (cp = indexQuery; *cp; cp++) { if (*cp == '+') { argc++; } } } else { indexQuery = 0; } #if ME_WIN_LIKE || VXWORKS { char *bangScript, *cmdBuf, *program, *cmdScript; /* On windows we attempt to find an executable matching the fileName. We look for *.exe, *.bat and also do unix style processing "#!/program" */ findExecutable(conn, &program, &cmdScript, &bangScript, fileName); assert(program); if (cmdScript) { /* Cmd/Batch script (.bat | .cmd) Convert the command to the form where there are 4 elements in argv that cmd.exe can interpret. argv[0] = cmd.exe argv[1] = /Q argv[2] = /C argv[3] = ""script" args ..." */ argc = 4; len = (argc + 1) * sizeof(char*); argv = (char**) mprAlloc(len); memset(argv, 0, len); argv[argind++] = program; /* Duped in findExecutable */ argv[argind++] = "/Q"; argv[argind++] = "/C"; len = strlen(cmdScript) + 2 + 1; cmdBuf = mprAlloc(len); fmt(cmdBuf, len, "\"%s\"", cmdScript); argv[argind++] = cmdBuf; mprSetCmdDir(cmd, cmdScript); /* program will get freed when argv[] gets freed */ } else if (bangScript) { /* Script used "#!/program". NOTE: this may be overridden by a mime Action directive. */ argc++; /* Adding bangScript arg */ len = (argc + 1) * sizeof(char*); argv = (char**) mprAlloc(len); memset(argv, 0, len); argv[argind++] = program; /* Will get freed when argv[] is freed */ argv[argind++] = bangScript; /* Will get freed when argv[] is freed */ mprSetCmdDir(cmd, bangScript); } else { /* Either unknown extension or .exe (.out) program. */ len = (argc + 1) * sizeof(char*); argv = (char**) mprAlloc(len); memset(argv, 0, len); if (actionProgram) { argv[argind++] = sclone(actionProgram); } argv[argind++] = program; } } #else len = (argc + 1) * sizeof(char*); argv = mprAlloc(len); memset(argv, 0, len); if (actionProgram) { argv[argind++] = sclone(actionProgram); } // OPT - why clone all these string? argv[argind++] = sclone(fileName); #endif /* ISINDEX queries. Only valid if there is not a "=" in the query. If this is so, then we must not have these args in the query env also? FUTURE - should query vars be set in the env? */ if (indexQuery) { indexQuery = sclone(indexQuery); cp = stok(indexQuery, "+", &tok); while (cp) { argv[argind++] = mprEscapeCmd(mprUriDecode(cp), 0); cp = stok(NULL, "+", &tok); } } assert(argind <= argc); argv[argind] = 0; *argcp = argc; *argvp = (cchar**) argv; mprTrace(5, "CGI: command:"); for (i = 0; i < argind; i++) { mprTrace(5, " argv[%d] = %s", i, argv[i]); } }
/* Tokens: ARCH Build architecture (x86_64) CC Compiler (cc) DEBUG Debug compilation options (-g, -Zi -Od) INC Include directory out/inc LIB Library directory (out/lib, xcode/VS: out/bin) LIBS Libraries required to link with ESP OBJ Name of compiled source (out/lib/view-MD5.o) OUT Output module (view_MD5.dylib) SHLIB Host Shared library (.lib, .so) SHOBJ Host Shared Object (.dll, .so) SRC Source code for view or controller (already templated) TMP Temp directory VS Visual Studio directory WINSDK Windows SDK directory */ char *espExpandCommand(cchar *command, cchar *source, cchar *module) { MprBuf *buf; MaAppweb *appweb; cchar *cp, *out; char *tmp; #if BLD_WIN_LIKE cchar *path; path = 0; #endif if (command == 0) { return 0; } out = mprTrimPathExt(module); buf = mprCreateBuf(-1, -1); appweb = MPR->appwebService; for (cp = command; *cp; ) { if (*cp == '$') { if (matchToken(&cp, "${ARCH}")) { /* Build architecture */ mprPutStringToBuf(buf, appweb->hostArch); #if BLD_WIN_LIKE } else if (matchToken(&cp, "${WINSDK}")) { path = mprReadRegistry("HKLM\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows", "CurrentInstallFolder"); path = strim(path, "\\", MPR_TRIM_END); mprPutStringToBuf(buf, path); } else if (matchToken(&cp, "${VS}")) { path = mprGetPathParent(mprGetPathParent(getenv("VS100COMNTOOLS"))); mprPutStringToBuf(buf, mprGetPortablePath(path)); #endif } else if (matchToken(&cp, "${CC}")) { /* Compiler */ #if BLD_WIN_LIKE // MOB - what about cross compilation path = mprJoinPath(mprGetPathParent(mprGetPathParent(getenv("VS100COMNTOOLS"))), "VC/bin/cl.exe"); mprPutStringToBuf(buf, mprGetPortablePath(path)); #else mprPutStringToBuf(buf, BLD_CC); #endif } else if (matchToken(&cp, "${DEBUG}")) { mprPutStringToBuf(buf, ESP_DEBUG); } else if (matchToken(&cp, "${INC}")) { /* Include directory (out/inc) */ mprPutStringToBuf(buf, mprResolvePath(mprGetAppDir(), "inc")); } else if (matchToken(&cp, "${LIB}")) { /* Library directory. IDE's use bin dir */ mprPutStringToBuf(buf, getOutDir(BLD_LIB_NAME)); } else if (matchToken(&cp, "${LIBS}")) { /* Required libraries to link. These may have nested ${TOKENS} */ mprPutStringToBuf(buf, espExpandCommand(ESP_LIBS, source, module)); } else if (matchToken(&cp, "${OBJ}")) { /* Output object with extension (.o) */ mprPutStringToBuf(buf, mprJoinPathExt(out, BLD_OBJ)); } else if (matchToken(&cp, "${OUT}")) { /* Output modules */ mprPutStringToBuf(buf, out); } else if (matchToken(&cp, "${SHLIB}")) { /* .lib */ mprPutStringToBuf(buf, appweb->hostOs); } else if (matchToken(&cp, "${SHOBJ}")) { /* .dll */ #ifdef BLD_HOST_SHOBJ // MOB - need this for bit mprPutStringToBuf(buf, BLD_HOST_SHOBJ); #else mprPutStringToBuf(buf, BLD_SHOBJ); #endif } else if (matchToken(&cp, "${SRC}")) { /* View (already parsed into C code) or controller source */ mprPutStringToBuf(buf, source); } else if (matchToken(&cp, "${TMP}")) { #if BLD_WIN_LIKE if ((tmp = getenv("TMP")) == 0) { tmp = getenv("TEMP"); } #else tmp = getenv("TMPDIR"); #endif mprPutStringToBuf(buf, tmp ? tmp : "."); #ifdef WIND_BASE } else if (matchToken(&cp, "${WIND_BASE}")) { mprPutStringToBuf(buf, WIND_BASE); #endif #ifdef WIND_HOME } else if (matchToken(&cp, "${WIND_HOME}")) { mprPutStringToBuf(buf, WIND_HOME); #endif #ifdef WIND_HOST_TYPE } else if (matchToken(&cp, "${WIND_HOST_TYPE}")) { mprPutStringToBuf(buf, WIND_HOST_TYPE); #endif #ifdef WIND_PLATFORM } else if (matchToken(&cp, "${WIND_PLATFORM}")) { mprPutStringToBuf(buf, WIND_PLATFORM); #endif #ifdef WIND_GNU_PATH } else if (matchToken(&cp, "${WIND_GNU_PATH}")) { mprPutStringToBuf(buf, WIND_GNU_PATH); #endif } else { mprPutCharToBuf(buf, *cp++); } } else { mprPutCharToBuf(buf, *cp++); } } mprAddNullToBuf(buf); return sclone(mprGetBufStart(buf)); }
static int verifyPeerCertificate(int ok, X509_STORE_CTX *xContext) { X509 *cert; SSL *handle; OpenSocket *osp; MprSocket *sp; MprSsl *ssl; char subject[512], issuer[512], peerName[512]; int error, depth; subject[0] = issuer[0] = '\0'; handle = (SSL*) X509_STORE_CTX_get_app_data(xContext); osp = (OpenSocket*) SSL_get_app_data(handle); sp = osp->sock; ssl = sp->ssl; cert = X509_STORE_CTX_get_current_cert(xContext); depth = X509_STORE_CTX_get_error_depth(xContext); error = X509_STORE_CTX_get_error(xContext); ok = 1; if (X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject) - 1) < 0) { sp->errorMsg = sclone("Cannot get subject name"); ok = 0; } if (X509_NAME_oneline(X509_get_issuer_name(cert), issuer, sizeof(issuer) - 1) < 0) { sp->errorMsg = sclone("Cannot get issuer name"); ok = 0; } if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, peerName, sizeof(peerName) - 1) == 0) { sp->errorMsg = sclone("Cannot get peer name"); ok = 0; } if (ok && ssl->verifyDepth < depth) { if (error == 0) { error = X509_V_ERR_CERT_CHAIN_TOO_LONG; } } switch (error) { case X509_V_OK: break; case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: /* Normal self signed certificate */ if (ssl->verifyIssuer) { sp->errorMsg = sclone("Self-signed certificate"); ok = 0; } break; case X509_V_ERR_CERT_UNTRUSTED: case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: if (ssl->verifyIssuer) { /* Issuer cannot be verified */ sp->errorMsg = sclone("Certificate not trusted"); ok = 0; } break; case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: if (ssl->verifyIssuer) { /* Issuer cannot be verified */ sp->errorMsg = sclone("Certificate not trusted"); ok = 0; } break; case X509_V_ERR_CERT_HAS_EXPIRED: sp->errorMsg = sfmt("Certificate has expired"); ok = 0; break; case X509_V_ERR_CERT_CHAIN_TOO_LONG: case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_CERT_REJECTED: case X509_V_ERR_CERT_SIGNATURE_FAILURE: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: case X509_V_ERR_INVALID_CA: default: sp->errorMsg = sfmt("Certificate verification error %d", error); ok = 0; break; } return ok; }