test.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /*
  2. test.c -- Unit test program for GoAhead
  3. Usage: goahead-test [options] [documents] [endpoints...]
  4. Options:
  5. --auth authFile # User and role configuration
  6. --home directory # Change to directory to run
  7. --log logFile:level # Log to file file at verbosity level
  8. --route routeFile # Route configuration file
  9. --verbose # Same as --log stderr:2
  10. --version # Output version information
  11. Copyright (c) All Rights Reserved. See details at the end of the file.
  12. */
  13. /********************************* Includes ***********************************/
  14. #include "goahead.h"
  15. #include "js.h"
  16. /********************************* Defines ************************************/
  17. static int finished = 0;
  18. #undef ME_GOAHEAD_LISTEN
  19. /*
  20. These must match TOP.es.set
  21. */
  22. #if TEST_IPV6
  23. #if ME_COM_SSL
  24. #define ME_GOAHEAD_LISTEN "http://127.0.0.1:18080, https://127.0.0.1:14443, http://[::1]:18090, https://[::1]:14453"
  25. #else
  26. #define ME_GOAHEAD_LISTEN "http://127.0.0.1:18080, http://[::1]:18090"
  27. #endif
  28. #else
  29. #if ME_COM_SSL
  30. #define ME_GOAHEAD_LISTEN "http://127.0.0.1:18080, https://127.0.0.1:14443"
  31. #else
  32. #define ME_GOAHEAD_LISTEN "http://127.0.0.1:18080"
  33. #endif
  34. #endif
  35. /********************************* Forwards ***********************************/
  36. static void initPlatform(void);
  37. static void logHeader(void);
  38. static void usage(void);
  39. static bool testHandler(Webs *wp);
  40. #if ME_GOAHEAD_JAVASCRIPT
  41. static int aspTest(int eid, Webs *wp, int argc, char **argv);
  42. static int bigTest(int eid, Webs *wp, int argc, char **argv);
  43. #endif
  44. static void actionTest(Webs *wp);
  45. static void sessionTest(Webs *wp);
  46. static void showTest(Webs *wp);
  47. #if ME_GOAHEAD_UPLOAD && !ME_ROM
  48. static void uploadTest(Webs *wp);
  49. #endif
  50. #if ME_GOAHEAD_LEGACY
  51. static int legacyTest(Webs *wp, char *prefix, char *dir, int flags);
  52. #endif
  53. #if ME_UNIX_LIKE
  54. static void sigHandler(int signo);
  55. #endif
  56. static void exitProc(void *data, int id);
  57. /*********************************** Code *************************************/
  58. MAIN(goahead, int argc, char **argv, char **envp)
  59. {
  60. char *argp, *auth, *home, *documents, *endpoints, *endpoint, *route, *tok, *lspec;
  61. int argind, duration;
  62. route = "route.txt";
  63. auth = "auth.txt";
  64. duration = 0;
  65. for (argind = 1; argind < argc; argind++) {
  66. argp = argv[argind];
  67. if (*argp != '-') {
  68. break;
  69. } else if (smatch(argp, "--auth") || smatch(argp, "-a")) {
  70. if (argind >= argc) usage();
  71. auth = argv[++argind];
  72. #if ME_UNIX_LIKE && !MACOSX
  73. } else if (smatch(argp, "--background") || smatch(argp, "-b")) {
  74. websSetBackground(1);
  75. #endif
  76. } else if (smatch(argp, "--debugger") || smatch(argp, "-d") || smatch(argp, "-D")) {
  77. websSetDebug(1);
  78. } else if (smatch(argp, "--duration")) {
  79. if (argind >= argc) usage();
  80. duration = atoi(argv[++argind]);
  81. } else if (smatch(argp, "--home")) {
  82. if (argind >= argc) usage();
  83. home = argv[++argind];
  84. if (chdir(home) < 0) {
  85. error("Cannot change directory to %s", home);
  86. exit(-1);
  87. }
  88. } else if (smatch(argp, "--log") || smatch(argp, "-l")) {
  89. if (argind >= argc) usage();
  90. logSetPath(argv[++argind]);
  91. } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) {
  92. logSetPath("stdout:2");
  93. } else if (smatch(argp, "--route") || smatch(argp, "-r")) {
  94. route = argv[++argind];
  95. } else if (smatch(argp, "--version") || smatch(argp, "-V")) {
  96. printf("%s\n", ME_VERSION);
  97. exit(0);
  98. } else if (*argp == '-' && isdigit((uchar) argp[1])) {
  99. lspec = sfmt("stdout:%s", &argp[1]);
  100. logSetPath(lspec);
  101. wfree(lspec);
  102. } else {
  103. usage();
  104. }
  105. }
  106. documents = ME_GOAHEAD_DOCUMENTS;
  107. if (argc > argind) {
  108. documents = argv[argind++];
  109. }
  110. initPlatform();
  111. if (websOpen(documents, route) < 0) {
  112. error("Cannot initialize server. Exiting.");
  113. return -1;
  114. }
  115. logHeader();
  116. if (websLoad(auth) < 0) {
  117. error("Cannot load %s", auth);
  118. return -1;
  119. }
  120. if (argind < argc) {
  121. while (argind < argc) {
  122. endpoint = argv[argind++];
  123. if (websListen(endpoint) < 0) {
  124. return -1;
  125. }
  126. }
  127. } else {
  128. endpoints = sclone(ME_GOAHEAD_LISTEN);
  129. for (endpoint = stok(endpoints, ", \t", &tok); endpoint; endpoint = stok(NULL, ", \t,", &tok)) {
  130. if (getenv("TRAVIS")) {
  131. if (strstr(endpoint, "::1") != 0) {
  132. /* Travis CI does not support IPv6 */
  133. continue;
  134. }
  135. }
  136. if (websListen(endpoint) < 0) {
  137. return -1;
  138. }
  139. }
  140. wfree(endpoints);
  141. }
  142. websDefineHandler("test", testHandler, 0, 0, 0);
  143. websAddRoute("/test", "test", 0);
  144. #if ME_GOAHEAD_LEGACY
  145. websUrlHandlerDefine("/legacy/", 0, 0, legacyTest, 0);
  146. #endif
  147. #if ME_GOAHEAD_JAVASCRIPT
  148. websDefineJst("aspTest", aspTest);
  149. websDefineJst("bigTest", bigTest);
  150. #endif
  151. websDefineAction("test", actionTest);
  152. websDefineAction("sessionTest", sessionTest);
  153. websDefineAction("showTest", showTest);
  154. #if ME_GOAHEAD_UPLOAD && !ME_ROM
  155. websDefineAction("uploadTest", uploadTest);
  156. #endif
  157. #if ME_UNIX_LIKE && !MACOSX
  158. /*
  159. Service events till terminated
  160. */
  161. if (websGetBackground()) {
  162. if (daemon(0, 0) < 0) {
  163. error("Cannot run as daemon");
  164. return -1;
  165. }
  166. }
  167. #endif
  168. if (duration) {
  169. printf("Running for %d secs\n", duration);
  170. websStartEvent(duration * 1000, (WebsEventProc) exitProc, 0);
  171. }
  172. websServiceEvents(&finished);
  173. logmsg(1, "Instructed to exit\n");
  174. websClose();
  175. return 0;
  176. }
  177. static void exitProc(void *data, int id)
  178. {
  179. websStopEvent(id);
  180. finished = 1;
  181. }
  182. static void logHeader(void)
  183. {
  184. char home[ME_GOAHEAD_LIMIT_STRING];
  185. getcwd(home, sizeof(home));
  186. logmsg(2, "Configuration for %s", ME_TITLE);
  187. logmsg(2, "---------------------------------------------");
  188. logmsg(2, "Version: %s", ME_VERSION);
  189. logmsg(2, "BuildType: %s", ME_DEBUG ? "Debug" : "Release");
  190. logmsg(2, "CPU: %s", ME_CPU);
  191. logmsg(2, "OS: %s", ME_OS);
  192. logmsg(2, "Host: %s", websGetServer());
  193. logmsg(2, "Directory: %s", home);
  194. logmsg(2, "Documents: %s", websGetDocuments());
  195. logmsg(2, "Configure: %s", ME_CONFIG_CMD);
  196. logmsg(2, "---------------------------------------------");
  197. }
  198. static void usage(void) {
  199. fprintf(stderr, "\n%s Usage:\n\n"
  200. " %s [options] [documents] [IPaddress][:port]...\n\n"
  201. " Options:\n"
  202. " --auth authFile # User and role configuration\n"
  203. #if ME_UNIX_LIKE && !MACOSX
  204. " --background # Run as a Unix daemon\n"
  205. #endif
  206. " --debugger # Run in debug mode\n"
  207. " --home directory # Change to directory to run\n"
  208. " --log logFile:level # Log to file file at verbosity level\n"
  209. " --route routeFile # Route configuration file\n"
  210. " --verbose # Same as --log stderr:2\n"
  211. " --version # Output version information\n\n",
  212. ME_TITLE, ME_NAME);
  213. exit(-1);
  214. }
  215. void initPlatform(void)
  216. {
  217. #if ME_UNIX_LIKE
  218. signal(SIGINT, sigHandler);
  219. signal(SIGTERM, sigHandler);
  220. signal(SIGKILL, sigHandler);
  221. #ifdef SIGPIPE
  222. signal(SIGPIPE, SIG_IGN);
  223. #endif
  224. #elif ME_WIN_LIKE
  225. _fmode=_O_BINARY;
  226. #endif
  227. }
  228. #if ME_UNIX_LIKE
  229. static void sigHandler(int signo)
  230. {
  231. finished = 1;
  232. }
  233. #endif
  234. /*
  235. Simple handler and route test
  236. Note: Accesses to "/" are normally remapped automatically to /index.html
  237. */
  238. static bool testHandler(Webs *wp)
  239. {
  240. if (smatch(wp->path, "/")) {
  241. websRewriteRequest(wp, "/home.html");
  242. /* Fall through */
  243. }
  244. return 0;
  245. }
  246. #if ME_GOAHEAD_JAVASCRIPT
  247. /*
  248. Parse the form variables: name, address and echo back
  249. */
  250. static int aspTest(int eid, Webs *wp, int argc, char **argv)
  251. {
  252. char *name, *address;
  253. if (jsArgs(argc, argv, "%s %s", &name, &address) < 2) {
  254. websError(wp, 400, "Insufficient args\n");
  255. return -1;
  256. }
  257. return (int) websWrite(wp, "Name: %s, Address %s", name, address);
  258. }
  259. /*
  260. Generate a large response
  261. */
  262. static int bigTest(int eid, Webs *wp, int argc, char **argv)
  263. {
  264. int i;
  265. websSetStatus(wp, 200);
  266. websWriteHeaders(wp, -1, 0);
  267. websWriteEndHeaders(wp);
  268. websWrite(wp, "<html>\n");
  269. for (i = 0; i < 800; i++) {
  270. websWrite(wp, " Line: %05d %s", i, "aaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbccccccccccccccccccddddddd<br/>\r\n");
  271. }
  272. websWrite(wp, "</html>\n");
  273. websDone(wp);
  274. return 0;
  275. }
  276. #endif
  277. /*
  278. Implement /action/actionTest. Parse the form variables: name, address and echo back.
  279. */
  280. static void actionTest(Webs *wp)
  281. {
  282. cchar *name, *address;
  283. name = websGetVar(wp, "name", NULL);
  284. address = websGetVar(wp, "address", NULL);
  285. websSetStatus(wp, 200);
  286. websWriteHeaders(wp, -1, 0);
  287. websWriteEndHeaders(wp);
  288. websWrite(wp, "<html><body><h2>name: %s, address: %s</h2></body></html>\n", name, address);
  289. websFlush(wp, 0);
  290. websDone(wp);
  291. }
  292. static void sessionTest(Webs *wp)
  293. {
  294. cchar *number;
  295. if (scaselessmatch(wp->method, "POST")) {
  296. number = websGetVar(wp, "number", 0);
  297. websSetSessionVar(wp, "number", number);
  298. } else {
  299. number = websGetSessionVar(wp, "number", 0);
  300. }
  301. websSetStatus(wp, 200);
  302. websWriteHeaders(wp, -1, 0);
  303. websWriteEndHeaders(wp);
  304. websWrite(wp, "<html><body><p>Number %s</p></body></html>\n", number);
  305. websDone(wp);
  306. }
  307. static void showTest(Webs *wp)
  308. {
  309. WebsKey *s;
  310. websSetStatus(wp, 200);
  311. websWriteHeaders(wp, -1, 0);
  312. websWriteEndHeaders(wp);
  313. websWrite(wp, "<html><body><pre>\n");
  314. for (s = hashFirst(wp->vars); s; s = hashNext(wp->vars, s)) {
  315. websWrite(wp, "%s=%s\n", s->name.value.string, s->content.value.string);
  316. }
  317. websWrite(wp, "</pre></body></html>\n");
  318. websDone(wp);
  319. }
  320. #if ME_GOAHEAD_UPLOAD && !ME_ROM
  321. /*
  322. Dump the file upload details. Don't actually do anything with the uploaded file.
  323. */
  324. static void uploadTest(Webs *wp)
  325. {
  326. WebsKey *s;
  327. WebsUpload *up;
  328. char *upfile;
  329. websSetStatus(wp, 200);
  330. websWriteHeaders(wp, -1, 0);
  331. websWriteHeader(wp, "Content-Type", "text/plain");
  332. websWriteEndHeaders(wp);
  333. if (scaselessmatch(wp->method, "POST")) {
  334. for (s = hashFirst(wp->files); s; s = hashNext(wp->files, s)) {
  335. up = s->content.value.symbol;
  336. websWrite(wp, "FILE: %s\r\n", s->name.value.string);
  337. websWrite(wp, "FILENAME=%s\r\n", up->filename);
  338. websWrite(wp, "CLIENT=%s\r\n", up->clientFilename);
  339. websWrite(wp, "TYPE=%s\r\n", up->contentType);
  340. websWrite(wp, "SIZE=%d\r\n", up->size);
  341. upfile = sfmt("%s/tmp/%s", websGetDocuments(), up->clientFilename);
  342. if (rename(up->filename, upfile) < 0) {
  343. error("Cannot rename uploaded file: %s to %s, errno %d", up->filename, upfile, errno);
  344. }
  345. wfree(upfile);
  346. }
  347. websWrite(wp, "\r\nVARS:\r\n");
  348. for (s = hashFirst(wp->vars); s; s = hashNext(wp->vars, s)) {
  349. websWrite(wp, "%s=%s\r\n", s->name.value.string, s->content.value.string);
  350. }
  351. }
  352. websDone(wp);
  353. }
  354. #endif
  355. #if ME_GOAHEAD_LEGACY
  356. /*
  357. Legacy handler with old parameter sequence
  358. */
  359. static int legacyTest(Webs *wp, char *prefix, char *dir, int flags)
  360. {
  361. websSetStatus(wp, 200);
  362. websWriteHeaders(wp, -1, 0);
  363. websWriteHeader(wp, "Content-Type", "text/plain");
  364. websWriteEndHeaders(wp);
  365. websWrite(wp, "Hello Legacy World\n");
  366. websDone(wp);
  367. return 1;
  368. }
  369. #endif
  370. /*
  371. @copy default
  372. Copyright (c) Embedthis Software LLC, 2003-2014. All Rights Reserved.
  373. This software is distributed under commercial and open source licenses.
  374. You may use the Embedthis GoAhead open source license or you may acquire
  375. a commercial license from Embedthis Software. You agree to be fully bound
  376. by the terms of either license. Consult the LICENSE.md distributed with
  377. this software for full details and other copyrights.
  378. Local variables:
  379. tab-width: 4
  380. c-basic-offset: 4
  381. End:
  382. vim: sw=4 ts=4 expandtab
  383. @end
  384. */