123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- /*
- jst.c -- JavaScript templates
- Copyright (c) All Rights Reserved. See details at the end of the file.
- */
- /********************************* Includes ***********************************/
- #include "goahead.h"
- #include "js.h"
- #if ME_GOAHEAD_JAVASCRIPT
- /********************************** Locals ************************************/
- static WebsHash websJstFunctions = -1; /* Symbol table of functions */
- /***************************** Forward Declarations ***************************/
- static char *strtokcmp(char *s1, char *s2);
- static char *skipWhite(char *s);
- /************************************* Code ***********************************/
- /*
- Process requests and expand all scripting commands. We read the entire web page into memory and then process. If
- you have really big documents, it is better to make them plain HTML files rather than Javascript web pages.
- Return true to indicate the request was handled, even for errors.
- */
- static bool jstHandler(Webs *wp)
- {
- WebsFileInfo sbuf;
- char *token, *lang, *result, *ep, *cp, *buf, *nextp, *last;
- ssize len;
- int rc, jid;
- assert(websValid(wp));
- assert(wp->filename && *wp->filename);
- assert(wp->ext && *wp->ext);
- buf = 0;
- if ((jid = jsOpenEngine(wp->vars, websJstFunctions)) < 0) {
- websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot create JavaScript engine");
- goto done;
- }
- jsSetUserHandle(jid, wp);
- if (websPageStat(wp, &sbuf) < 0) {
- websError(wp, HTTP_CODE_NOT_FOUND, "Cannot stat %s", wp->filename);
- goto done;
- }
- if (websPageOpen(wp, O_RDONLY | O_BINARY, 0666) < 0) {
- websError(wp, HTTP_CODE_NOT_FOUND, "Cannot open URL: %s", wp->filename);
- goto done;
- }
- /*
- Create a buffer to hold the web page in-memory
- */
- len = sbuf.size;
- if ((buf = walloc(len + 1)) == NULL) {
- websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot get memory");
- goto done;
- }
- buf[len] = '\0';
- if (websPageReadData(wp, buf, len) != len) {
- websError(wp, HTTP_CODE_NOT_FOUND, "Cannot read %s", wp->filename);
- goto done;
- }
- websPageClose(wp);
- websWriteHeaders(wp, (ssize) -1, 0);
- websWriteHeader(wp, "Pragma", "no-cache");
- websWriteHeader(wp, "Cache-Control", "no-cache");
- websWriteEndHeaders(wp);
- /*
- Scan for the next "<%"
- */
- last = buf;
- for (rc = 0; rc == 0 && *last && ((nextp = strstr(last, "<%")) != NULL); ) {
- websWriteBlock(wp, last, (nextp - last));
- nextp = skipWhite(nextp + 2);
- /*
- Decode the language
- */
- token = "language";
- if ((lang = strtokcmp(nextp, token)) != NULL) {
- if ((cp = strtokcmp(lang, "=javascript")) != NULL) {
- /* Ignore */;
- } else {
- cp = nextp;
- }
- nextp = cp;
- }
- /*
- Find tailing bracket and then evaluate the script
- */
- if ((ep = strstr(nextp, "%>")) != NULL) {
- *ep = '\0';
- last = ep + 2;
- nextp = skipWhite(nextp);
- /*
- Handle backquoted newlines
- */
- for (cp = nextp; *cp; ) {
- if (*cp == '\\' && (cp[1] == '\r' || cp[1] == '\n')) {
- *cp++ = ' ';
- while (*cp == '\r' || *cp == '\n') {
- *cp++ = ' ';
- }
- } else {
- cp++;
- }
- }
- if (*nextp) {
- result = NULL;
- if (jsEval(jid, nextp, &result) == 0) {
- /*
- On an error, discard all output accumulated so far and store the error in the result buffer.
- Be careful if the user has called websError() already.
- */
- rc = -1;
- if (websValid(wp)) {
- if (result) {
- websWrite(wp, "<h2><b>Javascript Error: %s</b></h2>\n", result);
- websWrite(wp, "<pre>%s</pre>", nextp);
- wfree(result);
- } else {
- websWrite(wp, "<h2><b>Javascript Error</b></h2>\n%s\n", nextp);
- }
- websWrite(wp, "</body></html>\n");
- rc = 0;
- }
- goto done;
- }
- }
- } else {
- websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Unterminated script in %s: \n", wp->filename);
- goto done;
- }
- }
- /*
- Output any trailing HTML page text
- */
- if (last && *last && rc == 0) {
- websWriteBlock(wp, last, strlen(last));
- }
- /*
- Common exit and cleanup
- */
- done:
- if (websValid(wp)) {
- websPageClose(wp);
- if (jid >= 0) {
- jsCloseEngine(jid);
- }
- }
- websDone(wp);
- wfree(buf);
- return 1;
- }
- static void closeJst()
- {
- if (websJstFunctions != -1) {
- hashFree(websJstFunctions);
- websJstFunctions = -1;
- }
- }
- PUBLIC int websJstOpen()
- {
- websJstFunctions = hashCreate(WEBS_HASH_INIT * 2);
- websDefineJst("write", websJstWrite);
- websDefineHandler("jst", 0, jstHandler, closeJst, 0);
- return 0;
- }
- /*
- Define a Javascript function. Bind an Javascript name to a C procedure.
- */
- PUBLIC int websDefineJst(char *name, WebsJstProc fn)
- {
- return jsSetGlobalFunctionDirect(websJstFunctions, name, (JsProc) fn);
- }
- /*
- Javascript write command. This implemements <% write("text"); %> command
- */
- PUBLIC int websJstWrite(int jid, Webs *wp, int argc, char **argv)
- {
- int i;
- assert(websValid(wp));
- for (i = 0; i < argc; ) {
- assert(argv);
- if (websWriteBlock(wp, argv[i], strlen(argv[i])) < 0) {
- return -1;
- }
- if (++i < argc) {
- if (websWriteBlock(wp, " ", 1) < 0) {
- return -1;
- }
- }
- }
- return 0;
- }
- /*
- Find s2 in s1. We skip leading white space in s1. Return a pointer to the location in s1 after s2 ends.
- */
- static char *strtokcmp(char *s1, char *s2)
- {
- ssize len;
- s1 = skipWhite(s1);
- len = strlen(s2);
- for (len = strlen(s2); len > 0 && (tolower((uchar) *s1) == tolower((uchar) *s2)); len--) {
- if (*s2 == '\0') {
- return s1;
- }
- s1++;
- s2++;
- }
- if (len == 0) {
- return s1;
- }
- return NULL;
- }
- static char *skipWhite(char *s)
- {
- assert(s);
- if (s == NULL) {
- return s;
- }
- while (*s && isspace((uchar) *s)) {
- s++;
- }
- return s;
- }
- #endif /* ME_GOAHEAD_JAVASCRIPT */
- /*
- Copyright (c) Embedthis Software. 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.
- */
|