r8397: merged an upstream fix for the expression bug tpot found yesterday
[jra/samba/.git] / source4 / lib / appweb / esp / esp.c
1 /*
2  *      @file   esp.c
3  *      @brief  Embedded Server Pages (ESP) core processing.
4  *      @overview The ESP handler provides an efficient way to generate 
5  *              dynamic pages using server-side Javascript. This code provides 
6  *              core processing, and should be called by an associated web 
7  *              server URL handler.
8  */
9 /********************************* Copyright **********************************/
10 /*
11  *      @copy   default
12  *      
13  *      Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
14  *      
15  *      This software is distributed under commercial and open source licenses.
16  *      You may use the GPL open source license described below or you may acquire 
17  *      a commercial license from Mbedthis Software. You agree to be fully bound 
18  *      by the terms of either license. Consult the LICENSE.TXT distributed with 
19  *      this software for full details.
20  *      
21  *      This software is open source; you can redistribute it and/or modify it 
22  *      under the terms of the GNU General Public License as published by the 
23  *      Free Software Foundation; either version 2 of the License, or (at your 
24  *      option) any later version. See the GNU General Public License for more 
25  *      details at: http://www.mbedthis.com/downloads/gplLicense.html
26  *      
27  *      This program is distributed WITHOUT ANY WARRANTY; without even the 
28  *      implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
29  *      
30  *      This GPL license does NOT permit incorporating this software into 
31  *      proprietary programs. If you are unable to comply with the GPL, you must
32  *      acquire a commercial license to use this software. Commercial licenses 
33  *      for this software and support services are available from Mbedthis 
34  *      Software at http://www.mbedthis.com 
35  *      
36  *      @end
37  */
38 /********************************** Includes **********************************/
39
40 #include        "esp.h"
41
42 #if BLD_FEATURE_ESP_MODULE
43
44 /*********************************** Locals ***********************************/
45 /*
46  *      Master ESP control interface with the web server
47  */
48
49 static const Esp *esp;
50
51 /***************************** Forward Declarations ***************************/
52
53 static int      buildScript(EspRequest *ep, char **jsBuf, char *input, char
54                                 **errMsg);
55
56 /************************************ Code ************************************/
57 /*
58  *      Called at server initialization
59  */
60
61 int espOpen(const Esp *control)
62 {
63         mprAssert(control);
64
65 #if BLD_FEATURE_MULTITHREAD
66         ejsOpen(control->lock, control->unlock, control->lockData);
67 #else
68         ejsOpen(0, 0, 0);
69 #endif
70
71         /*
72          *      Register the standard procedures
73          */
74         espRegisterProcs();
75
76         /*
77          *      Just for brain dead systems that don't zero global memory
78          */
79         esp = control;
80         return 0;
81 }
82
83 /******************************************************************************/
84 /*
85  *      Called at server termination
86  */
87
88 void espClose()
89 {
90         ejsClose();
91 }
92
93 /******************************************************************************/
94 /*
95  *      Create for new ESP request. Assumed that this is called after all the 
96  *      HTTP headers have been read but before POST data has been read. It is 
97  *      expected that any session cookies have been read and that "variables" 
98  *      contains references to all the environment objects including "session". 
99  *      requestHandle is the web server request handle.
100  */
101
102 EspRequest *espCreateRequest(EspHandle webServerRequestHandle, char *uri, 
103         MprVar *variables)
104 {
105         EspRequest      *ep;
106         MprVar          *global;
107 #if BLD_FEATURE_LEGACY_API
108         MprVar          *np;
109         char            keyBuf[ESP_MAX_HEADER];
110         int                     i;
111 #endif
112
113         mprAssert(variables);
114
115         ep = mprMalloc(sizeof(EspRequest));
116         if (ep == 0) {
117                 return 0;
118         }
119         memset(ep, 0, sizeof(EspRequest));
120         ep->requestHandle = webServerRequestHandle;
121         ep->esp = esp;
122         ep->uri = mprStrdup(uri);
123         ep->docPath = 0;
124         ep->variables = variables;
125         
126         /*
127          *      The handle passed to ejsOpenEngine is passed to every C function 
128          *      called by JavaScript.
129          */
130         ep->eid = ejsOpenEngine((EjsHandle) ep, (EjsHandle) webServerRequestHandle);
131         if (ep->eid < 0) {
132                 mprFree(ep);
133                 return 0;
134         }
135
136         /*
137          *      All these copies and SetProperties will only copy references 
138          *      They will increments the object ref counts.
139          */
140         mprCopyVar(&variables[ESP_GLOBAL_OBJ], ejsGetGlobalObject(ep->eid), 
141                 MPR_SHALLOW_COPY);
142         mprCopyVar(&variables[ESP_LOCAL_OBJ], ejsGetLocalObject(ep->eid), 
143                 MPR_SHALLOW_COPY);
144
145         global = &variables[ESP_GLOBAL_OBJ];
146         mprCreateProperty(global, "application", &variables[ESP_APPLICATION_OBJ]);
147         mprCreateProperty(global, "cookies", &variables[ESP_COOKIES_OBJ]);
148         mprCreateProperty(global, "files", &variables[ESP_FILES_OBJ]);
149         mprCreateProperty(global, "form", &variables[ESP_FORM_OBJ]);
150         mprCreateProperty(global, "headers", &variables[ESP_HEADERS_OBJ]);
151         mprCreateProperty(global, "request", &variables[ESP_REQUEST_OBJ]);
152
153         /*
154          *      FUTURE -- could server be shared across all requests for a given host
155          *      and be made read-only.
156          */
157         mprCreateProperty(global, "server", &variables[ESP_SERVER_OBJ]);
158
159 #if BLD_FEATURE_SESSION
160         mprCreateProperty(global, "session", &variables[ESP_SESSION_OBJ]);
161 #endif
162
163 #if BLD_FEATURE_LEGACY_API
164         /*
165          *      DEPRECATED: 2.0
166          *      Define variables as globals. headers[] are prefixed with "HTTP_".
167          *      NOTE: MaRequest::setVar does not copy into globals, whereas espSetVar
168          *      does if legacy_api is defined. So variables pre-defined by MaRequest 
169          *      must be copied here into globals[].\r
170          *
171          *      NOTE: if a variable is in session[] and in form[], the form[] will
172          *      override being later in the variables[] list. Use mprSetProperty 
173          *      instead of mprCreateProperty to cover for this case.
174          */
175         for (i = 0; i < ESP_OBJ_MAX; i++) {
176                 if (i == ESP_GLOBAL_OBJ || i == ESP_LOCAL_OBJ) {
177                         continue;
178                 }
179                 if (variables[i].type != MPR_TYPE_OBJECT) {
180                         continue;
181                 }
182                 np = mprGetFirstProperty(&variables[i], MPR_ENUM_DATA);
183                 while (np) {
184                         if (i == ESP_HEADERS_OBJ) {
185                                 mprSprintf(keyBuf, sizeof(keyBuf) - 1, "HTTP_%s", np->name);
186                                 mprSetProperty(global, keyBuf, np);
187                         } else {
188                                 mprSetProperty(global, np->name, np);
189                         }
190                         np = mprGetNextProperty(&variables[i], np, MPR_ENUM_DATA);
191                 }
192         }
193 #endif
194         return ep;
195 }
196
197 /******************************************************************************/
198  
199 void espDestroyRequest(EspRequest *ep)
200 {
201         mprAssert(ep);
202         mprAssert(ep->eid >= 0);
203
204         mprFree(ep->uri);
205         mprFree(ep->docPath);
206         ejsCloseEngine(ep->eid);
207         mprFree(ep);
208 }
209
210 /******************************************************************************/
211 /*
212  *      The callback function will be called:
213  *
214  *              (fn)(EjsId eid, EspRequest *ep, argc, argv);
215  *
216  *      Callers can get their web server handle by calling:
217  *
218  *              rq = (requiredCast) espGetHandle(ep);
219  */
220
221 void espDefineCFunction(EspRequest *ep, const char *functionName, EspCFunction fn, 
222         void *thisPtr)
223 {
224         mprAssert(functionName && *functionName);
225         mprAssert(fn);
226
227         if (ep) {
228                 ejsDefineCFunction(ep->eid, functionName, (MprCFunction) fn, 
229                         thisPtr, 0);
230         } else {
231                 ejsDefineCFunction(-1, functionName, (MprCFunction) fn, thisPtr, 0);
232         }
233 }
234
235 /******************************************************************************/
236
237 void espDefineStringCFunction(EspRequest *ep, const char *functionName, 
238         EspStringCFunction fn, void *thisPtr)
239 {
240         mprAssert(functionName && *functionName);
241         mprAssert(fn);
242
243         if (ep) {
244                 ejsDefineStringCFunction(ep->eid, functionName, (MprStringCFunction) fn,
245                         thisPtr, 0);
246         } else {
247                 ejsDefineStringCFunction(-1, functionName, (MprStringCFunction) fn, 
248                         thisPtr, 0);
249         }
250 }
251
252 /******************************************************************************/
253
254 void *espGetRequestHandle(EspRequest *ep)
255 {
256         return ep->requestHandle;
257 }
258
259 /******************************************************************************/
260
261 EjsId espGetScriptHandle(EspRequest *ep)
262 {
263         return ep->eid;
264 }
265
266 /******************************************************************************/
267
268 char *espGetStringVar(EspRequest *ep, EspEnvType oType, char *var, 
269         char *defaultValue)
270 {
271         MprVar  value;
272
273         if (espGetVar(ep, oType, var, &value) < 0 || 
274                         value.type != MPR_TYPE_STRING) {
275                 return defaultValue;
276         } 
277         return value.string;
278 }
279
280 /******************************************************************************/
281
282 int espGetVar(EspRequest *ep, EspEnvType oType, char *var, MprVar *value)
283 {
284         MprVar          *vp;
285
286         mprAssert(ep);
287         mprAssert(var);
288
289         vp = mprGetProperty(&ep->variables[oType], var, 0);
290         if (vp == 0) {
291                 return -1;
292         }
293         *value = *vp;
294         return 0;
295 }
296
297 /******************************************************************************/
298 /*
299  *      Process the ESP page. docBuf holds the page already. We expect that
300  *      ep->variables holds all the pertinent environment variables.
301  */
302
303 int espProcessRequest(EspRequest *ep, const char *docPath, char *docBuf, 
304                                           char **errMsg)
305 {
306         char    *jsBuf;
307
308         mprAssert(ep);
309
310         ep->docPath = mprStrdup(docPath);
311
312         jsBuf = 0;
313         if (buildScript(ep, &jsBuf, docBuf, errMsg) < 0) {
314                 return MPR_ERR_CANT_COMPLETE;
315         }
316
317         if (jsBuf) {
318                 mprLog(7, "esp: script is:\n%s\n", jsBuf);
319
320                 /*
321                  *      Now evaluate the entire escript
322                  *      MOB could cache the script 
323                  */
324                 if (ejsEvalScript(ep->eid, jsBuf, 0, errMsg) < 0) {
325                         return MPR_ERR_ABORTED;
326                 }
327
328                 mprFree(jsBuf);
329         }
330         return 0;
331 }
332
333 /******************************************************************************/
334
335 void espRedirect(EspRequest *ep, int code, char *url)
336 {
337         mprAssert(ep);
338         mprAssert(url);
339
340         ep->esp->redirect(ep->requestHandle, code, url);
341 }
342
343 /******************************************************************************/
344
345 void espError(EspRequest *ep, const char *fmt, ...)
346 {
347         va_list         args;
348         char            *buf;
349
350         mprAssert(ep);
351         mprAssert(fmt);
352
353         va_start(args, fmt);
354         mprAllocVsprintf(&buf, MPR_MAX_HEAP_SIZE, fmt, args);
355         ejsSetErrorMsg(ep->eid, buf);
356         mprFree(buf);
357         va_end(args);
358 }
359
360 /******************************************************************************/
361
362 void espSetHeader(EspRequest *ep, char *header, bool allowMultiple)
363 {
364         mprAssert(ep);
365
366         ep->esp->setHeader(ep->requestHandle, header, allowMultiple);
367 }
368
369 /******************************************************************************/
370 /*
371  *      Caller does not need to destroy the var
372  */
373
374 MprVar *espGetResult(EspRequest *ep)
375 {
376         mprAssert(ep);
377
378         return ejsGetReturnValue(ep->eid);
379 }
380
381 /******************************************************************************/
382
383 void espSetReturn(EspRequest *ep, MprVar value)
384 {
385         mprAssert(ep);
386
387         ejsSetReturnValue(ep->eid, value);
388 }
389
390 /******************************************************************************/
391
392 void espSetReturnString(EspRequest *ep, const char *str)
393 {
394         mprAssert(ep);
395
396         ejsSetReturnValue(ep->eid, mprCreateStringVar(str, 0));
397 }
398
399 /******************************************************************************/
400
401 void espSetResponseCode(EspRequest *ep, int code)
402 {
403         mprAssert(ep);
404
405         ep->esp->setResponseCode(ep->requestHandle, code);
406 }
407
408 /******************************************************************************/
409
410 void espSetVar(EspRequest *ep, EspEnvType oType, char *var, MprVar value)
411 {
412         mprCreatePropertyValue(&ep->variables[oType], var, value);
413 }
414
415 /******************************************************************************/
416
417 void espSetStringVar(EspRequest *ep, EspEnvType oType, 
418                                          const char *var, const char *value)
419 {
420         /*
421          *      Will create or update if already existing
422          */
423         mprCreatePropertyValue(&ep->variables[oType], var, 
424                 mprCreateStringVar(value, 0));
425 }
426
427 /******************************************************************************/
428
429 int espUnsetVar(EspRequest *ep, EspEnvType oType, char *var)
430 {
431         return mprDeleteProperty(&ep->variables[oType], var);
432 }
433
434 /******************************************************************************/
435
436 int espWrite(EspRequest *ep, char *buf, int size)
437 {
438         mprAssert(ep);
439         mprAssert(buf);
440         mprAssert(size >= 0);
441
442         return ep->esp->writeBlock(ep->requestHandle, buf, size);
443 }
444
445 /******************************************************************************/
446
447 int espWriteString(EspRequest *ep, char *buf)
448 {
449         mprAssert(ep);
450         mprAssert(buf);
451
452         return ep->esp->writeBlock(ep->requestHandle, buf, strlen(buf));
453 }
454
455 /******************************************************************************/
456
457 int espWriteFmt(EspRequest *ep, char *fmt, ...)
458 {
459         va_list         args;
460         char            *buf;
461         int                     rc, len;
462
463         mprAssert(ep);
464         mprAssert(fmt);
465
466         va_start(args, fmt);
467         len = mprAllocVsprintf(&buf, MPR_MAX_HEAP_SIZE, fmt, args);
468         rc = ep->esp->writeBlock(ep->requestHandle, buf, len);
469         mprFree(buf);
470         va_end(args);
471         return rc;
472 }
473
474 /******************************************************************************/
475 /******************************************************************************/
476 /******************************************************************************/
477 /*
478  *      Get a javascript identifier. Must allow x.y['abc'] or x.y["abc"].
479  *      Must be careful about quoting and only allow quotes inside []. 
480  */
481
482 static int getIdentifier(EspParse *parse)
483 {
484         int             atQuote, prevC, c;
485
486         mprAssert(parse);
487
488         atQuote = 0;
489         prevC = 0;
490         c = *parse->inp++;
491
492         while (isalnum(c) || c == '_' || c == '.' || c == '[' || 
493                         c == ']' || c == '\'' || c == '\"') {
494                 if (c == '\'' || c == '\"') {
495                         if (c == atQuote) {
496                                 atQuote = 0;
497                         } else if (prevC == '[') {
498                                 atQuote = c;
499                         } else {
500                                 break;
501                         }
502                 }
503                 if (parse->tokp >= parse->endp) {
504                         parse->token = (char*) mprRealloc(parse->token, 
505                                 parse->tokLen + ESP_TOK_INCR);
506                         if (parse->token == 0) {
507                                 return MPR_ERR_CANT_ALLOCATE;
508                         }
509                         parse->token[parse->tokLen] = '\0';
510                         parse->tokLen += ESP_TOK_INCR;
511                         parse->endp = &parse->token[parse->tokLen - 1];
512                 }
513                 *parse->tokp++ = c;
514                 prevC = c;
515                 c = *parse->inp++;
516         }
517
518         parse->inp--;
519         *parse->tokp = '\0';
520
521         return 0;
522 }
523
524 /******************************************************************************/
525 /*
526  *      Get the next ESP input token. input points to the next input token.
527  *      parse->token will hold the parsed token. The function returns the token id.
528  */
529
530 static int getEspToken(int state, EspParse *parse)
531 {
532         char    *cp;
533         int             tid, done, c, quoted;
534
535         tid = ESP_TOK_LITERAL;
536         parse->tokp = parse->token;
537         parse->tokp[0] = '\0';
538         quoted = 0;
539
540         c = *parse->inp++;
541         for (done = 0; !done; c = *parse->inp++) {
542
543                 /*
544                  *      Get room for more characters in the token buffer
545                  */
546                 if (parse->tokp >= parse->endp) {
547                         parse->token = (char*) mprRealloc(parse->token, 
548                                 parse->tokLen + ESP_TOK_INCR);
549                         if (parse->token == 0) {
550                                 return ESP_TOK_ERR;
551                         }
552                         parse->token[parse->tokLen] = '\0';\r
553                         parse->tokp = &parse->token[parse->tokLen - 1];
554                         parse->tokLen += ESP_TOK_INCR;
555                         parse->endp = &parse->token[parse->tokLen - 1];
556                 }
557
558                 switch (c) {
559                 case 0:
560                         if (*parse->token) {
561                                 done++;
562                                 parse->inp--;
563                                 break;
564                         }
565                         return ESP_TOK_EOF;
566
567                 default:
568                         if (c == '\"' && state != ESP_STATE_IN_ESP_TAG) {
569                                 *parse->tokp++ = '\\';
570                         }
571                         *parse->tokp++ = c;
572                         quoted = 0;
573                         break;
574
575                 case '\\':
576                         quoted = 1;
577                         *parse->tokp++ = c;
578                         break;
579
580                 case '@':
581                         if (*parse->inp == '@' && state != ESP_STATE_IN_ESP_TAG) {
582                                 if (quoted) {
583                                         parse->tokp--;
584                                         quoted = 0;
585                                 } else {
586                                         if (*parse->token) {
587                                                 parse->inp--;
588                                         } else {
589                                                 parse->inp++;
590                                                 tid = ESP_TOK_ATAT;
591                                                 if (getIdentifier(parse) < 0) {
592                                                         return ESP_TOK_ERR;
593                                                 }
594                                         }
595                                         done++;
596                                         break;
597                                 }
598                         }
599                         *parse->tokp++ = c;
600                         break;
601
602                 case '<':
603                         if (*parse->inp == '%' && state != ESP_STATE_IN_ESP_TAG) {
604                                 if (quoted) {
605                                         parse->tokp--;
606                                         quoted = 0;
607                                         *parse->tokp++ = c;
608                                         break;
609                                 }
610                                 if (*parse->token) {
611                                         parse->inp--;
612                                         done++;
613                                         break;
614                                 }
615                                 parse->inp++;
616                                 while (isspace((int) *parse->inp)) {
617                                         parse->inp++;
618                                 }
619                                 if (*parse->inp == '=') {
620                                         parse->inp++;
621                                         while (isspace((int) *parse->inp)) {
622                                                 parse->inp++;
623                                         }
624                                         tid = ESP_TOK_EQUALS;
625                                         if (getIdentifier(parse) < 0) {
626                                                 return ESP_TOK_ERR;
627                                         }
628                                         done++;
629                                         break;
630                                 }
631                                 if (*parse->inp == 'i' && 
632                                                 strncmp(parse->inp, "include", 7) == 0 &&
633                                                 isspace((int) parse->inp[7])) {
634                                         tid = ESP_TOK_INCLUDE;
635                                         parse->inp += 7;
636                                         while (isspace((int) *parse->inp)) {
637                                                 parse->inp++;
638                                         }
639                                         while (*parse->inp && !isspace((int) *parse->inp) && 
640                                                         *parse->inp != '%' && parse->tokp < parse->endp) {
641                                                 *parse->tokp++ = *parse->inp++;
642                                         }
643                                         *parse->tokp = '\0';
644                                         if (parse->token[0] == '"') {
645                                                 parse->tokp = parse->token;
646                                                 for (cp = &parse->token[1]; *cp; ) {
647                                                         *parse->tokp++ = *cp++;
648                                                 }
649                                                 if (cp[-1] == '"') {
650                                                         parse->tokp--;
651                                                 }
652                                                 *parse->tokp = '\0';
653                                         }
654                                         
655                                 } else {
656                                         tid = ESP_TOK_START_ESP;
657                                 }
658                                 done++;
659                                 break;
660                         }
661                         *parse->tokp++ = c;
662                         break;
663
664                 case '%':
665                         if (*parse->inp == '>' && state == ESP_STATE_IN_ESP_TAG) {
666                                 if (quoted) {
667                                         parse->tokp--;
668                                         quoted = 0;
669                                 } else {
670                                         if (*parse->token) {
671                                                 parse->inp--;
672                                         } else {
673                                                 tid = ESP_TOK_END_ESP;
674                                                 parse->inp++;
675                                         }
676                                         done++;
677                                         break;
678                                 }
679                         }
680                         *parse->tokp++ = c;
681                         break;
682                 }
683         }
684
685         *parse->tokp = '\0';
686         parse->inp--;
687         return tid;
688 }
689
690 /******************************************************************************/
691 /*
692  *      Convert an ESP page into a JavaScript. We also expand include files.
693  */
694
695 static int buildScript(EspRequest *ep, char **jsBuf, char *input, char **errMsg)
696 {
697         EspParse        parse;
698         char            path[MPR_MAX_FNAME], dir[MPR_MAX_FNAME], incPath[MPR_MAX_FNAME];
699         char            *incBuf, *incText;
700         int                     state, tid, len, rc, maxScriptSize, incSize;
701
702         mprAssert(ep);
703         mprAssert(jsBuf);
704         mprAssert(input);
705
706         rc = 0;
707         len = 0;
708         state = ESP_STATE_BEGIN;
709         if (errMsg) {
710                 *errMsg = 0;
711         }
712
713         memset(&parse, 0, sizeof(parse));
714         parse.token = (char*) mprMalloc(ESP_TOK_INCR);
715         if (parse.token == 0) {
716                 return MPR_ERR_CANT_ALLOCATE;
717         }
718         parse.token[0] = '\0';
719         parse.tokLen = ESP_TOK_INCR;
720         parse.endp = &parse.token[parse.tokLen - 1];
721         parse.tokp = parse.token;
722         parse.inBuf = input;
723         parse.inp = parse.inBuf;
724
725         maxScriptSize = esp->maxScriptSize;
726
727         tid = getEspToken(state, &parse);
728         while (tid != ESP_TOK_EOF && len >= 0) {
729
730                 switch (tid) {
731                 default:
732                 case ESP_TOK_ERR:
733                         mprFree(parse.token);
734                         return MPR_ERR_BAD_SYNTAX;
735                         
736                 case ESP_TOK_LITERAL:
737                         len = mprReallocStrcat(jsBuf, maxScriptSize, len, 0, 
738                                 "write(\"", parse.token, "\");\n", 0);
739                         break;
740
741                 case ESP_TOK_ATAT:
742                         /*
743                          *      Trick to get undefined variables to evaluate to "".
744                          *      Catenate with "" to cause toString to run. 
745                          */
746                         len = mprReallocStrcat(jsBuf, maxScriptSize, len, 0, 
747                                 "write(\"\" + ", parse.token, ");\n", 0);
748                         break;
749
750                 case ESP_TOK_EQUALS:
751                         len = mprReallocStrcat(jsBuf, maxScriptSize, len, 0, 
752                                 "write(\"\" + ", parse.token, ");\n", 0);
753                         state = ESP_STATE_IN_ESP_TAG;
754                         break;
755
756                 case ESP_TOK_START_ESP:
757                         state = ESP_STATE_IN_ESP_TAG;
758                         tid = getEspToken(state, &parse);
759                         while (tid != ESP_TOK_EOF && tid != ESP_TOK_EOF && 
760                                         tid != ESP_TOK_END_ESP && len >= 0) {
761                                 len = mprReallocStrcat(jsBuf, maxScriptSize, len, 0, 
762                                         parse.token, 0);
763                                 tid = getEspToken(state, &parse);
764                         }
765                         state = ESP_STATE_BEGIN;
766                         break;
767
768                 case ESP_TOK_END_ESP:
769                         state = ESP_STATE_BEGIN;
770                         break;
771
772                 case ESP_TOK_INCLUDE:
773                         if (parse.token[0] == '/') {
774                                 mprStrcpy(incPath, sizeof(incPath), parse.token);
775                         } else {
776                                 mprGetDirName(dir, sizeof(dir), ep->uri);
777                                 mprSprintf(incPath, sizeof(incPath), "%s/%s",
778                                         dir, parse.token);
779                         }
780                         if (esp->mapToStorage(ep->requestHandle, path, sizeof(path),
781                                         incPath, 0) < 0) {
782                                 mprAllocSprintf(errMsg, MPR_MAX_STRING, 
783                                         "Can't find include file: %s", path);
784                                 rc = MPR_ERR_CANT_OPEN;
785                                 break;
786                         }
787                         if (esp->readFile(ep->requestHandle, &incText, &incSize, path) < 0){
788                                 mprAllocSprintf(errMsg, MPR_MAX_STRING, 
789                                         "Can't read include file: %s", path);
790                                 rc = MPR_ERR_CANT_READ;
791                                 break;
792                         }
793                         incText[incSize] = '\0';
794
795                         /*
796                          *      Recurse and process the include script
797                          */
798                         incBuf = 0;
799                         if ((rc = buildScript(ep, &incBuf, incText, errMsg)) < 0) {
800                                 mprFree(incText);
801                                 mprFree(parse.token);
802                                 return rc;
803                         }
804
805                         len = mprReallocStrcat(jsBuf, maxScriptSize, len, 0, incBuf, 0);
806                         mprFree(incText);
807                         mprFree(incBuf);
808                         state = ESP_STATE_IN_ESP_TAG;
809                         break;
810                 }
811                 tid = getEspToken(state, &parse);
812         }
813         mprFree(parse.token);
814         if (len < 0) {
815                 mprAllocSprintf(errMsg, MPR_MAX_STRING,
816                         "Script token is too big in %s.\nConfigured maximum is %d.", 
817                         path, maxScriptSize);
818                 return MPR_ERR_WONT_FIT;
819         }
820         return rc;
821 }
822
823 /******************************************************************************/
824 /******************************* Wrapped Routines *****************************/
825 /******************************************************************************/
826
827 int espCopyVar(EspRequest *ep, char *var, MprVar *value, int copyDepth)
828 {
829         return ejsCopyVar(ep->eid, var, value, copyDepth);
830 }
831
832 /******************************************************************************/
833
834 MprVar espCreateObjVar(char *name, int hashSize)
835 {
836         return ejsCreateObj(name, hashSize);
837 }
838
839 /******************************************************************************/
840
841 MprVar espCreateArrayVar(char *name, int size)
842 {
843         return ejsCreateArray(name, size);
844 }
845
846 /******************************************************************************/
847
848 bool espDestroyVar(MprVar *obj)
849 {
850         return ejsDestroyVar(obj);
851 }
852
853 /******************************************************************************/
854
855 MprVar *espCreateProperty(MprVar *obj, char *property, MprVar *newValue)
856 {
857         return mprCreateProperty(obj, property, newValue);
858 }
859
860 /******************************************************************************/
861
862 MprVar *espCreatePropertyValue(MprVar *obj, char *property, MprVar newValue)
863 {
864         return mprCreatePropertyValue(obj, property, newValue);
865 }
866
867 /******************************************************************************/
868
869 void espDefineFunction(EspRequest *ep, const char *functionName, char *args, char *body)
870 {
871         ejsDefineFunction(ep->eid, functionName, args, body);
872 }
873
874 /******************************************************************************/
875
876 int espDeleteProperty(MprVar *obj, char *property)
877 {
878         return mprDeleteProperty(obj, property);
879 }
880
881 /******************************************************************************/
882
883 int espDeleteVar(EspRequest *ep, char *var)
884 {
885         return ejsDeleteVar(ep->eid, var);
886 }
887
888 /******************************************************************************/
889 int espEvalFile(EspRequest *ep, char *path, MprVar *result, char **emsg)
890 {
891         return ejsEvalFile(ep->eid, path, result, emsg);
892 }
893
894 /******************************************************************************/
895
896 int espEvalScript(EspRequest *ep, char *script, MprVar *result, char **emsg)
897 {
898         return ejsEvalScript(ep->eid, script, result, emsg);
899 }
900
901 /******************************************************************************/
902
903 int espGetPropertyCount(MprVar *obj, int includeFlags)
904 {
905         if (obj->type != MPR_TYPE_OBJECT) {
906                 return MPR_ERR_BAD_STATE;
907         }
908         return mprGetPropertyCount(obj, includeFlags);
909 }
910
911 /******************************************************************************/
912
913 MprVar *espGetFirstProperty(MprVar *obj, int includeFlags)
914 {
915         return mprGetFirstProperty(obj, includeFlags);
916 }
917
918 /******************************************************************************/
919
920 MprVar *espGetGlobalObject(EspRequest *ep)
921 {
922         return ejsGetGlobalObject(ep->eid);
923 }
924
925 /******************************************************************************/
926
927 MprVar *espGetLocalObject(EspRequest *ep)
928 {
929         return ejsGetLocalObject(ep->eid);
930 }
931
932 /******************************************************************************/
933
934 MprVar *espGetNextProperty(MprVar *obj, MprVar *currentProperty, 
935         int includeFlags)
936 {
937         return mprGetNextProperty(obj, currentProperty, includeFlags);
938 }
939
940 /******************************************************************************/
941
942 MprVar *espGetProperty(MprVar *obj, char *property, MprVar *value)
943 {
944         return mprGetProperty(obj, property, value);
945 }
946
947 /******************************************************************************/
948
949 void *espGetThisPtr(EspRequest *ep)
950 {
951         return ejsGetThisPtr(ep->eid);
952 }
953
954 /******************************************************************************/
955 #if XX_UNUSED_XX
956  
957 int espReadProperty(MprVar *dest, MprVar *prop)
958 {
959         mprAssert(prop);
960         mprAssert(dest);
961
962         *dest = *prop;
963         return 0;
964 }
965
966 #endif
967 /******************************************************************************/
968
969 int espReadVar(EspRequest *ep, char *var, MprVar *value)
970 {
971         return ejsReadVar(ep->eid, var, value);
972 }
973
974 /******************************************************************************/
975
976 int espRunFunction(EspRequest *ep, MprVar *obj, char *functionName, 
977         MprArray *args)
978 {
979         return ejsRunFunction(ep->eid, obj, functionName, args);
980 }
981
982 /******************************************************************************/
983
984 MprVar *espSetProperty(MprVar *obj, char *property, MprVar *newValue)
985 {
986         return mprSetProperty(obj, property, newValue);
987 }
988
989 /******************************************************************************/
990
991 MprVar *espSetPropertyValue(MprVar *obj, char *property, MprVar newValue)
992 {
993         return mprSetPropertyValue(obj, property, newValue);
994 }
995
996 /******************************************************************************/
997
998 int espWriteVar(EspRequest *ep, char *var, MprVar *value)
999 {
1000         return ejsWriteVar(ep->eid, var, value);
1001 }
1002
1003 /******************************************************************************/
1004
1005 int espWriteVarValue(EspRequest *ep, char *var, MprVar value)
1006 {
1007         return ejsWriteVarValue(ep->eid, var, value);
1008 }
1009
1010 /******************************************************************************/
1011 #if XX_UNUSED_XX
1012
1013 int espWriteProperty(MprVar *prop, MprVar *newValue)
1014 {
1015         return mprWriteProperty(prop, newValue);
1016 }
1017
1018 /******************************************************************************/
1019
1020 int espWritePropertyValue(MprVar *prop, MprVar newValue)
1021 {
1022         return mprWritePropertyValue(prop, newValue);
1023 }
1024
1025 #endif
1026 /******************************************************************************/
1027
1028 #else   /* !BLD_FEATURE_ESP_MODULE */
1029 void espDummy() {}
1030
1031 /******************************************************************************/
1032 #endif /* BLD_FEATURE_ESP_MODULE */
1033
1034 /*
1035  * Local variables:
1036  * tab-width: 4
1037  * c-basic-offset: 4
1038  * End:
1039  * vim:tw=78
1040  * vim600: sw=4 ts=4 fdm=marker
1041  * vim<600: sw=4 ts=4
1042  */