/*
test.c -- Unit test program for GoAhead
Usage: goahead-test [options] [documents] [endpoints...]
Options:
--auth authFile # User and role configuration
--home directory # Change to directory to run
--log logFile:level # Log to file file at verbosity level
--route routeFile # Route configuration file
--verbose # Same as --log stderr:2
--version # Output version information
Copyright (c) All Rights Reserved. See details at the end of the file.
*/
/********************************* Includes ***********************************/
#include "goahead.h"
#include "js.h"
/********************************* Defines ************************************/
static int finished = 0;
#undef ME_GOAHEAD_LISTEN
/*
These must match TOP.es.set
*/
#if TEST_IPV6
#if ME_COM_SSL
#define ME_GOAHEAD_LISTEN "http://127.0.0.1:18080, https://127.0.0.1:14443, http://[::1]:18090, https://[::1]:14453"
#else
#define ME_GOAHEAD_LISTEN "http://127.0.0.1:18080, http://[::1]:18090"
#endif
#else
#if ME_COM_SSL
#define ME_GOAHEAD_LISTEN "http://127.0.0.1:18080, https://127.0.0.1:14443"
#else
#define ME_GOAHEAD_LISTEN "http://127.0.0.1:18080"
#endif
#endif
/********************************* Forwards ***********************************/
static void initPlatform();
static void logHeader();
static void usage();
static bool testHandler(Webs *wp);
#if ME_GOAHEAD_JAVASCRIPT
static int aspTest(int eid, Webs *wp, int argc, char **argv);
static int bigTest(int eid, Webs *wp, int argc, char **argv);
#endif
static void actionTest(Webs *wp);
static void sessionTest(Webs *wp);
static void showTest(Webs *wp);
#if ME_GOAHEAD_UPLOAD && !ME_ROM
static void uploadTest(Webs *wp);
#endif
#if ME_GOAHEAD_LEGACY
static int legacyTest(Webs *wp, char *prefix, char *dir, int flags);
#endif
#if ME_UNIX_LIKE
static void sigHandler(int signo);
#endif
static void exitProc(void *data, int id);
/*********************************** Code *************************************/
MAIN(goahead, int argc, char **argv, char **envp)
{
char *argp, *auth, *home, *documents, *endpoints, *endpoint, *route, *tok, *lspec;
int argind, duration;
route = "route.txt";
auth = "auth.txt";
duration = 0;
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];
#if ME_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, "--duration")) {
if (argind >= argc) usage();
duration = atoi(argv[++argind]);
} else if (smatch(argp, "--home")) {
if (argind >= argc) usage();
home = argv[++argind];
if (chdir(home) < 0) {
error("Cannot 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", ME_VERSION);
exit(0);
} else if (*argp == '-' && isdigit((uchar) argp[1])) {
lspec = sfmt("stdout:%s", &argp[1]);
logSetPath(lspec);
wfree(lspec);
} else {
usage();
}
}
documents = ME_GOAHEAD_DOCUMENTS;
if (argc > argind) {
documents = argv[argind++];
}
initPlatform();
if (websOpen(documents, route) < 0) {
error("Cannot initialize server. Exiting.");
return -1;
}
logHeader();
if (websLoad(auth) < 0) {
error("Cannot load %s", auth);
return -1;
}
if (argind < argc) {
while (argind < argc) {
endpoint = argv[argind++];
if (websListen(endpoint) < 0) {
return -1;
}
}
} else {
endpoints = sclone(ME_GOAHEAD_LISTEN);
for (endpoint = stok(endpoints, ", \t", &tok); endpoint; endpoint = stok(NULL, ", \t,", &tok)) {
if (getenv("TRAVIS")) {
if (strstr(endpoint, "::1") != 0) {
/* Travis CI does not support IPv6 */
continue;
}
}
if (websListen(endpoint) < 0) {
return -1;
}
}
wfree(endpoints);
}
websDefineHandler("test", testHandler, 0, 0, 0);
websAddRoute("/test", "test", 0);
#if ME_GOAHEAD_LEGACY
websUrlHandlerDefine("/legacy/", 0, 0, legacyTest, 0);
#endif
#if ME_GOAHEAD_JAVASCRIPT
websDefineJst("aspTest", aspTest);
websDefineJst("bigTest", bigTest);
#endif
websDefineAction("test", actionTest);
websDefineAction("sessionTest", sessionTest);
websDefineAction("showTest", showTest);
#if ME_GOAHEAD_UPLOAD && !ME_ROM
websDefineAction("uploadTest", uploadTest);
#endif
#if ME_UNIX_LIKE && !MACOSX
/*
Service events till terminated
*/
if (websGetBackground()) {
if (daemon(0, 0) < 0) {
error("Cannot run as daemon");
return -1;
}
}
#endif
if (duration) {
printf("Running for %d secs\n", duration);
websStartEvent(duration * 1000, (WebsEventProc) exitProc, 0);
}
websServiceEvents(&finished);
logmsg(1, "Instructed to exit\n");
websClose();
return 0;
}
static void exitProc(void *data, int id)
{
websStopEvent(id);
finished = 1;
}
static void logHeader()
{
char home[ME_GOAHEAD_LIMIT_STRING];
getcwd(home, sizeof(home));
logmsg(2, "Configuration for %s", ME_TITLE);
logmsg(2, "---------------------------------------------");
logmsg(2, "Version: %s", ME_VERSION);
logmsg(2, "BuildType: %s", ME_DEBUG ? "Debug" : "Release");
logmsg(2, "CPU: %s", ME_CPU);
logmsg(2, "OS: %s", ME_OS);
logmsg(2, "Host: %s", websGetServer());
logmsg(2, "Directory: %s", home);
logmsg(2, "Documents: %s", websGetDocuments());
logmsg(2, "Configure: %s", ME_CONFIG_CMD);
logmsg(2, "---------------------------------------------");
}
static void usage() {
fprintf(stderr, "\n%s Usage:\n\n"
" %s [options] [documents] [IPaddress][:port]...\n\n"
" Options:\n"
" --auth authFile # User and role configuration\n"
#if ME_UNIX_LIKE && !MACOSX
" --background # Run as a Unix daemon\n"
#endif
" --debugger # Run in debug mode\n"
" --home directory # Change to directory to run\n"
" --log logFile:level # Log to file file at verbosity level\n"
" --route routeFile # Route configuration file\n"
" --verbose # Same as --log stderr:2\n"
" --version # Output version information\n\n",
ME_TITLE, ME_NAME);
exit(-1);
}
void initPlatform()
{
#if ME_UNIX_LIKE
printf("===> ME_UNIX_LIKE\n");
signal(SIGINT, sigHandler);
signal(SIGTERM, sigHandler);
signal(SIGKILL, sigHandler);
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
#endif
#elif ME_WIN_LIKE
_fmode=_O_BINARY;
#endif
}
#if ME_UNIX_LIKE
static void sigHandler(int signo)
{
finished = 1;
}
#endif
/*
Simple handler and route test
Note: Accesses to "/" are normally remapped automatically to /index.html
*/
static bool testHandler(Webs *wp)
{
if (smatch(wp->path, "/")) {
websRewriteRequest(wp, "/home.html");
/* Fall through */
}
return 0;
}
#if ME_GOAHEAD_JAVASCRIPT
/*
Parse the form variables: name, address and echo back
*/
static int aspTest(int eid, Webs *wp, int argc, char **argv)
{
char *name, *address;
if (jsArgs(argc, argv, "%s %s", &name, &address) < 2) {
websError(wp, 400, "Insufficient args\n");
return -1;
}
return (int) websWrite(wp, "Name: %s, Address %s", name, address);
}
/*
Generate a large response
*/
static int bigTest(int eid, Webs *wp, int argc, char **argv)
{
int i;
websSetStatus(wp, 200);
websWriteHeaders(wp, -1, 0);
websWriteEndHeaders(wp);
websWrite(wp, "\n");
for (i = 0; i < 800; i++) {
websWrite(wp, " Line: %05d %s", i, "aaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbccccccccccccccccccddddddd
\r\n");
}
websWrite(wp, "\n");
websDone(wp);
return 0;
}
#endif
/*
Implement /action/actionTest. Parse the form variables: name, address and echo back.
*/
static void actionTest(Webs *wp)
{
char *name, *address;
name = websGetVar(wp, "name", NULL);
address = websGetVar(wp, "address", NULL);
websSetStatus(wp, 200);
websWriteHeaders(wp, -1, 0);
websWriteEndHeaders(wp);
websWrite(wp, "
Number %s
\n", number); websDone(wp); } static void showTest(Webs *wp) { WebsKey *s; websSetStatus(wp, 200); websWriteHeaders(wp, -1, 0); websWriteEndHeaders(wp); websWrite(wp, "\n"); for (s = hashFirst(wp->vars); s; s = hashNext(wp->vars, s)) { websWrite(wp, "%s=%s\n", s->name.value.string, s->content.value.string); } websWrite(wp, "\n"); websDone(wp); } #if ME_GOAHEAD_UPLOAD && !ME_ROM /* Dump the file upload details. Don't actually do anything with the uploaded file. */ static void uploadTest(Webs *wp) { WebsKey *s; WebsUpload *up; char *upfile; printf("<>>>>>>>>>>come in >>>>>>>>>>>\n"); websSetStatus(wp, 200); websWriteHeaders(wp, -1, 0); websWriteHeader(wp, "Content-Type", "text/plain"); websWriteEndHeaders(wp); if (scaselessmatch(wp->method, "POST")) { for (s = hashFirst(wp->files); s; s = hashNext(wp->files, s)) { up = s->content.value.symbol; websWrite(wp, "FILE: %s\r\n", s->name.value.string); websWrite(wp, "FILENAME=%s\r\n", up->filename); websWrite(wp, "CLIENT=%s\r\n", up->clientFilename); websWrite(wp, "TYPE=%s\r\n", up->contentType); websWrite(wp, "SIZE=%d\r\n", up->size); upfile = sfmt("%s/tmp/%s", websGetDocuments(), up->clientFilename); if (rename(up->filename, upfile) < 0) { error("Cannot rename uploaded file: %s to %s, errno %d", up->filename, upfile, errno); } wfree(upfile); } websWrite(wp, "\r\nVARS:\r\n"); for (s = hashFirst(wp->vars); s; s = hashNext(wp->vars, s)) { websWrite(wp, "%s=%s\r\n", s->name.value.string, s->content.value.string); } } websDone(wp); } #endif #if ME_GOAHEAD_LEGACY /* Legacy handler with old parameter sequence */ static int legacyTest(Webs *wp, char *prefix, char *dir, int flags) { websSetStatus(wp, 200); websWriteHeaders(wp, -1, 0); websWriteHeader(wp, "Content-Type", "text/plain"); websWriteEndHeaders(wp); websWrite(wp, "Hello Legacy World\n"); websDone(wp); return 1; } #endif /* @copy default Copyright (c) Embedthis Software LLC, 2003-2014. All Rights Reserved. This software is distributed under commercial and open source licenses. You may use the Embedthis GoAhead open source license or you may acquire a commercial license from Embedthis Software. You agree to be fully bound by the terms of either license. Consult the LICENSE.md distributed with this software for full details and other copyrights. Local variables: tab-width: 4 c-basic-offset: 4 End: vim: sw=4 ts=4 expandtab @end */