File Coverage

fcgiapp.c
Criterion Covered Total %
statement 349 853 40.9
branch 109 408 26.7
condition n/a
subroutine n/a
pod n/a
total 458 1261 36.3


line stmt bran cond sub pod time code
1             /*
2             * fcgiapp.c --
3             *
4             * FastCGI application library: request-at-a-time
5             *
6             *
7             * Copyright (c) 1996 Open Market, Inc.
8             *
9             * See the file "LICENSE" for information on usage and redistribution
10             * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11             *
12             */
13             #ifndef lint
14             static const char rcsid[] = "$Id: fcgiapp.c,v 1.35 2003/06/22 00:16:43 robs Exp $";
15             #endif /* not lint */
16              
17             #include
18             #include
19             #include /* for fcntl */
20             #include
21             #include /* for memchr() */
22             #include
23             #include
24             #include
25             #include
26             #include
27              
28             #include "fcgi_config.h"
29              
30             #ifdef HAVE_SYS_SOCKET_H
31             #include /* for getpeername */
32             #endif
33              
34             #ifdef HAVE_SYS_TIME_H
35             #include
36             #endif
37              
38             #ifdef HAVE_UNISTD_H
39             #include
40             #endif
41              
42             #ifdef HAVE_LIMITS_H
43             #include
44             #endif
45              
46             #ifdef _WIN32
47             #define DLLAPI __declspec(dllexport)
48             #endif
49              
50             #include "fcgimisc.h"
51             #include "fastcgi.h"
52             #include "fcgios.h"
53             #include "fcgiapp.h"
54              
55             /*
56             * This is a workaround for one version of the HP C compiler
57             * (c89 on HP-UX 9.04, also Stratus FTX), which will dump core
58             * if given 'long double' for varargs.
59             */
60             #ifdef HAVE_VA_ARG_LONG_DOUBLE_BUG
61             #define LONG_DOUBLE double
62             #else
63             #define LONG_DOUBLE long double
64             #endif
65              
66             /*
67             * Globals
68             */
69             static int libInitialized = 0;
70             static int isFastCGI = -1;
71             static char *webServerAddressList = NULL;
72             static FCGX_Request the_request;
73              
74 0           void FCGX_ShutdownPending(void)
75             {
76 0           OS_ShutdownPending();
77 0           }
78              
79 26           static void *Malloc(size_t size)
80             {
81 26           void *result = malloc(size);
82 26 50         ASSERT(size == 0 || result != NULL);
    50          
83 26           return result;
84             }
85              
86 2           static char *StringCopy(char *str)
87             {
88 2           int strLen = strlen(str);
89 2           char *newString = (char *)Malloc(strLen + 1);
90 2           memcpy(newString, str, strLen);
91 2           newString[strLen] = '\000';
92 2           return newString;
93             }
94              
95              
96             /*
97             *----------------------------------------------------------------------
98             *
99             * FCGX_GetChar --
100             *
101             * Reads a byte from the input stream and returns it.
102             *
103             * Results:
104             * The byte, or EOF (-1) if the end of input has been reached.
105             *
106             *----------------------------------------------------------------------
107             */
108 6           int FCGX_GetChar(FCGX_Stream *stream)
109             {
110 6 50         if (stream->isClosed || ! stream->isReader)
    50          
111 0           return EOF;
112              
113 6 100         if (stream->rdNext != stream->stop)
114 2           return *stream->rdNext++;
115              
116 4           stream->fillBuffProc(stream);
117 4 100         if (stream->isClosed)
118 2           return EOF;
119              
120 2           stream->stopUnget = stream->rdNext;
121 2 50         if (stream->rdNext != stream->stop)
122 2           return *stream->rdNext++;
123              
124 0 0         ASSERT(stream->isClosed); /* bug in fillBufProc if not */
125 0           return EOF;
126             }
127              
128             /*
129             *----------------------------------------------------------------------
130             *
131             * FCGX_GetStr --
132             *
133             * Reads up to n consecutive bytes from the input stream
134             * into the character array str. Performs no interpretation
135             * of the input bytes.
136             *
137             * Results:
138             * Number of bytes read. If result is smaller than n,
139             * the end of input has been reached.
140             *
141             *----------------------------------------------------------------------
142             */
143 6           int FCGX_GetStr(char *str, int n, FCGX_Stream *stream)
144             {
145             int m, bytesMoved;
146              
147 6 50         if (stream->isClosed || ! stream->isReader || n <= 0) {
    50          
    50          
148 0           return 0;
149             }
150             /*
151             * Fast path: n bytes are already available
152             */
153 6 100         if(n <= (stream->stop - stream->rdNext)) {
154 4           memcpy(str, stream->rdNext, n);
155 4           stream->rdNext += n;
156 4           return n;
157             }
158             /*
159             * General case: stream is closed or buffer fill procedure
160             * needs to be called
161             */
162 2           bytesMoved = 0;
163             for (;;) {
164 4 100         if(stream->rdNext != stream->stop) {
165 2           m = min(n - bytesMoved, stream->stop - stream->rdNext);
166 2           memcpy(str, stream->rdNext, m);
167 2           bytesMoved += m;
168 2           stream->rdNext += m;
169 2 50         if(bytesMoved == n)
170 2           return bytesMoved;
171 0           str += m;
172             }
173 2 50         if(stream->isClosed || !stream->isReader)
    50          
174 0           return bytesMoved;
175 2           stream->fillBuffProc(stream);
176 2 50         if (stream->isClosed)
177 0           return bytesMoved;
178              
179 2           stream->stopUnget = stream->rdNext;
180 2           }
181             }
182              
183             /*
184             *----------------------------------------------------------------------
185             *
186             * FCGX_GetLine --
187             *
188             * Reads up to n-1 consecutive bytes from the input stream
189             * into the character array str. Stops before n-1 bytes
190             * have been read if '\n' or EOF is read. The terminating '\n'
191             * is copied to str. After copying the last byte into str,
192             * stores a '\0' terminator.
193             *
194             * Results:
195             * NULL if EOF is the first thing read from the input stream,
196             * str otherwise.
197             *
198             *----------------------------------------------------------------------
199             */
200 0           char *FCGX_GetLine(char *str, int n, FCGX_Stream *stream)
201             {
202             int c;
203 0           char *p = str;
204              
205 0           n--;
206 0 0         while (n > 0) {
207 0           c = FCGX_GetChar(stream);
208 0 0         if(c == EOF) {
209 0 0         if(p == str)
210 0           return NULL;
211             else
212 0           break;
213             }
214 0           *p++ = (char) c;
215 0           n--;
216 0 0         if(c == '\n')
217 0           break;
218             }
219 0           *p = '\0';
220 0           return str;
221             }
222              
223             /*
224             *----------------------------------------------------------------------
225             *
226             * FCGX_UnGetChar --
227             *
228             * Pushes back the character c onto the input stream. One
229             * character of pushback is guaranteed once a character
230             * has been read. No pushback is possible for EOF.
231             *
232             * Results:
233             * Returns c if the pushback succeeded, EOF if not.
234             *
235             *----------------------------------------------------------------------
236             */
237 0           int FCGX_UnGetChar(int c, FCGX_Stream *stream) {
238 0 0         if(c == EOF
239 0 0         || stream->isClosed
240 0 0         || !stream->isReader
241 0 0         || stream->rdNext == stream->stopUnget)
242 0           return EOF;
243 0           --(stream->rdNext);
244 0           *stream->rdNext = (unsigned char) c;
245 0           return c;
246             }
247              
248             /*
249             *----------------------------------------------------------------------
250             *
251             * FCGX_HasSeenEOF --
252             *
253             * Returns EOF if end-of-file has been detected while reading
254             * from stream; otherwise returns 0.
255             *
256             * Note that FCGX_HasSeenEOF(s) may return 0, yet an immediately
257             * following FCGX_GetChar(s) may return EOF. This function, like
258             * the standard C stdio function feof, does not provide the
259             * ability to peek ahead.
260             *
261             * Results:
262             * EOF if end-of-file has been detected, 0 if not.
263             *
264             *----------------------------------------------------------------------
265             */
266 0           int FCGX_HasSeenEOF(FCGX_Stream *stream) {
267 0 0         return (stream->isClosed) ? EOF : 0;
268             }
269              
270             /*
271             *----------------------------------------------------------------------
272             *
273             * FCGX_PutChar --
274             *
275             * Writes a byte to the output stream.
276             *
277             * Results:
278             * The byte, or EOF (-1) if an error occurred.
279             *
280             *----------------------------------------------------------------------
281             */
282 0           int FCGX_PutChar(int c, FCGX_Stream *stream)
283             {
284 0 0         if(stream->wrNext != stream->stop)
285 0           return (*stream->wrNext++ = (unsigned char) c);
286 0 0         if(stream->isClosed || stream->isReader)
    0          
287 0           return EOF;
288 0           stream->emptyBuffProc(stream, FALSE);
289 0 0         if(stream->wrNext != stream->stop)
290 0           return (*stream->wrNext++ = (unsigned char) c);
291 0 0         ASSERT(stream->isClosed); /* bug in emptyBuffProc if not */
292 0           return EOF;
293             }
294              
295             /*
296             *----------------------------------------------------------------------
297             *
298             * FCGX_PutStr --
299             *
300             * Writes n consecutive bytes from the character array str
301             * into the output stream. Performs no interpretation
302             * of the output bytes.
303             *
304             * Results:
305             * Number of bytes written (n) for normal return,
306             * EOF (-1) if an error occurred.
307             *
308             *----------------------------------------------------------------------
309             */
310 8           int FCGX_PutStr(const char *str, int n, FCGX_Stream *stream)
311             {
312             int m, bytesMoved;
313              
314             /*
315             * Fast path: room for n bytes in the buffer
316             */
317 8 50         if(n <= (stream->stop - stream->wrNext)) {
318 8           memcpy(stream->wrNext, str, n);
319 8           stream->wrNext += n;
320 8           return n;
321             }
322             /*
323             * General case: stream is closed or buffer empty procedure
324             * needs to be called
325             */
326 0           bytesMoved = 0;
327             for (;;) {
328 0 0         if(stream->wrNext != stream->stop) {
329 0           m = min(n - bytesMoved, stream->stop - stream->wrNext);
330 0           memcpy(stream->wrNext, str, m);
331 0           bytesMoved += m;
332 0           stream->wrNext += m;
333 0 0         if(bytesMoved == n)
334 0           return bytesMoved;
335 0           str += m;
336             }
337 0 0         if(stream->isClosed || stream->isReader)
    0          
338 0           return -1;
339 0           stream->emptyBuffProc(stream, FALSE);
340 0           }
341             }
342              
343             /*
344             *----------------------------------------------------------------------
345             *
346             * FCGX_PutS --
347             *
348             * Writes a character string to the output stream.
349             *
350             * Results:
351             * number of bytes written for normal return,
352             * EOF (-1) if an error occurred.
353             *
354             *----------------------------------------------------------------------
355             */
356 0           int FCGX_PutS(const char *str, FCGX_Stream *stream)
357             {
358 0           return FCGX_PutStr(str, strlen(str), stream);
359             }
360              
361             /*
362             *----------------------------------------------------------------------
363             *
364             * FCGX_FPrintF --
365             *
366             * Performs output formatting and writes the results
367             * to the output stream.
368             *
369             * Results:
370             * number of bytes written for normal return,
371             * EOF (-1) if an error occurred.
372             *
373             *----------------------------------------------------------------------
374             */
375 0           int FCGX_FPrintF(FCGX_Stream *stream, const char *format, ...)
376             {
377             int result;
378             va_list ap;
379 0           va_start(ap, format);
380 0           result = FCGX_VFPrintF(stream, format, ap);
381 0           va_end(ap);
382 0           return result;
383             }
384              
385             /*
386             *----------------------------------------------------------------------
387             *
388             * FCGX_VFPrintF --
389             *
390             * Performs output formatting and writes the results
391             * to the output stream.
392             *
393             * Results:
394             * number of bytes written for normal return,
395             * EOF (-1) if an error occurred.
396             *
397             *----------------------------------------------------------------------
398             */
399              
400             #define PRINTF_BUFFLEN 100
401             /*
402             * More than sufficient space for all unmodified conversions
403             * except %s and %f.
404             */
405             #define FMT_BUFFLEN 25
406             /*
407             * Max size of a format specifier is 1 + 5 + 7 + 7 + 2 + 1 + slop
408             */
409             static void CopyAndAdvance(char **destPtr, char **srcPtr, int n);
410              
411 0           int FCGX_VFPrintF(FCGX_Stream *stream, const char *format, va_list arg)
412             {
413             char *f, *fStop, *percentPtr, *p, *fmtBuffPtr, *buffPtr;
414 0           int op, performedOp, sizeModifier, buffCount = 0, buffLen, specifierLength;
415 0           int fastPath, n, auxBuffLen = 0, buffReqd, minWidth, precision, exp;
416 0           char *auxBuffPtr = NULL;
417 0           int streamCount = 0;
418             char fmtBuff[FMT_BUFFLEN];
419             char buff[PRINTF_BUFFLEN];
420              
421             int intArg;
422             short shortArg;
423             long longArg;
424             unsigned unsignedArg;
425             unsigned long uLongArg;
426             unsigned short uShortArg;
427 0           char *charPtrArg = NULL;
428             void *voidPtrArg;
429             int *intPtrArg;
430             long *longPtrArg;
431             short *shortPtrArg;
432 0           double doubleArg = 0.0;
433 0           LONG_DOUBLE lDoubleArg = 0.0L;
434              
435 0           fmtBuff[0] = '%';
436 0           f = (char *) format;
437 0           fStop = f + strlen(f);
438 0 0         while (f != fStop) {
439 0           percentPtr = (char *)memchr(f, '%', fStop - f);
440 0 0         if(percentPtr == NULL) percentPtr = fStop;
441 0 0         if(percentPtr != f) {
442 0 0         if(FCGX_PutStr(f, percentPtr - f, stream) < 0)
443 0           goto ErrorReturn;
444 0           streamCount += percentPtr - f;
445 0           f = percentPtr;
446 0 0         if(f == fStop) break;
447             }
448 0           fastPath = TRUE;
449             /*
450             * The following loop always executes either once or twice.
451             */
452             for (;;) {
453 0 0         if(fastPath) {
454             /*
455             * Fast path: Scan optimistically, hoping that no flags,
456             * minimum field width, or precision are specified.
457             * Use the preallocated buffer, which is large enough
458             * for all fast path cases. If the conversion specifier
459             * is really more complex, run the loop a second time
460             * using the slow path.
461             * Note that fast path execution of %s bypasses the buffer
462             * and %f is not attempted on the fast path due to
463             * its large buffering requirements.
464             */
465 0           op = *(percentPtr + 1);
466 0 0         switch(op) {
467             case 'l':
468             case 'L':
469             case 'h':
470 0           sizeModifier = op;
471 0           op = *(percentPtr + 2);
472 0           fmtBuff[1] = (char) sizeModifier;
473 0           fmtBuff[2] = (char) op;
474 0           fmtBuff[3] = '\0';
475 0           specifierLength = 3;
476 0           break;
477             default:
478 0           sizeModifier = ' ';
479 0           fmtBuff[1] = (char) op;
480 0           fmtBuff[2] = '\0';
481 0           specifierLength = 2;
482 0           break;
483             }
484 0           buffPtr = buff;
485 0           buffLen = PRINTF_BUFFLEN;
486             } else {
487             /*
488             * Slow path: Scan the conversion specifier and construct
489             * a new format string, compute an upper bound on the
490             * amount of buffering that sprintf will require,
491             * and allocate a larger buffer if necessary.
492             */
493 0           p = percentPtr + 1;
494 0           fmtBuffPtr = &fmtBuff[1];
495             /*
496             * Scan flags
497             */
498 0           n = strspn(p, "-0+ #");
499 0 0         if(n > 5)
500 0           goto ErrorReturn;
501 0           CopyAndAdvance(&fmtBuffPtr, &p, n);
502             /*
503             * Scan minimum field width
504             */
505 0           n = strspn(p, "0123456789");
506 0 0         if(n == 0) {
507 0 0         if(*p == '*') {
508 0 0         minWidth = va_arg(arg, int);
509 0 0         if(abs(minWidth) > 999999)
510 0           goto ErrorReturn;
511             /*
512             * The following use of strlen rather than the
513             * value returned from sprintf is because SUNOS4
514             * returns a char * instead of an int count.
515             */
516 0           sprintf(fmtBuffPtr, "%d", minWidth);
517 0           fmtBuffPtr += strlen(fmtBuffPtr);
518 0           p++;
519             } else {
520 0           minWidth = 0;
521             }
522 0 0         } else if(n <= 6) {
523 0           minWidth = strtol(p, NULL, 10);
524 0           CopyAndAdvance(&fmtBuffPtr, &p, n);
525             } else {
526 0           goto ErrorReturn;
527             }
528             /*
529             * Scan precision
530             */
531 0 0         if(*p == '.') {
532 0           CopyAndAdvance(&fmtBuffPtr, &p, 1);
533 0           n = strspn(p, "0123456789");
534 0 0         if(n == 0) {
535 0 0         if(*p == '*') {
536 0 0         precision = va_arg(arg, int);
537 0 0         if(precision < 0) precision = 0;
538 0 0         if(precision > 999999)
539 0           goto ErrorReturn;
540             /*
541             * The following use of strlen rather than the
542             * value returned from sprintf is because SUNOS4
543             * returns a char * instead of an int count.
544             */
545 0           sprintf(fmtBuffPtr, "%d", precision);
546 0           fmtBuffPtr += strlen(fmtBuffPtr);
547 0           p++;
548             } else {
549 0           precision = 0;
550             }
551 0 0         } else if(n <= 6) {
552 0           precision = strtol(p, NULL, 10);
553 0           CopyAndAdvance(&fmtBuffPtr, &p, n);
554             } else {
555 0           goto ErrorReturn;
556             }
557             } else {
558 0           precision = -1;
559             }
560             /*
561             * Scan size modifier and conversion operation
562             */
563 0 0         switch(*p) {
564             case 'l':
565             case 'L':
566             case 'h':
567 0           sizeModifier = *p;
568 0           CopyAndAdvance(&fmtBuffPtr, &p, 1);
569 0           break;
570             default:
571 0           sizeModifier = ' ';
572 0           break;
573             }
574 0           op = *p;
575 0           CopyAndAdvance(&fmtBuffPtr, &p, 1);
576 0 0         ASSERT(fmtBuffPtr - fmtBuff < FMT_BUFFLEN);
577 0           *fmtBuffPtr = '\0';
578 0           specifierLength = p - percentPtr;
579             /*
580             * Bound the required buffer size. For s and f
581             * conversions this requires examining the argument.
582             */
583 0           switch(op) {
584             case 'd':
585             case 'i':
586             case 'u':
587             case 'o':
588             case 'x':
589             case 'X':
590             case 'c':
591             case 'p':
592 0           buffReqd = max(precision, 46);
593 0           break;
594             case 's':
595 0 0         charPtrArg = va_arg(arg, char *);
596 0 0         if (!charPtrArg) charPtrArg = "(null)";
597 0 0         if(precision == -1) {
598 0           buffReqd = strlen(charPtrArg);
599             } else {
600 0           p = (char *)memchr(charPtrArg, '\0', precision);
601 0 0         buffReqd =
602 0           (p == NULL) ? precision : p - charPtrArg;
603             }
604 0           break;
605             case 'f':
606 0           switch(sizeModifier) {
607             case ' ':
608 0 0         doubleArg = va_arg(arg, double);
609 0           frexp(doubleArg, &exp);
610 0           break;
611             case 'L':
612 0           lDoubleArg = va_arg(arg, LONG_DOUBLE);
613             /* XXX Need to check for the presence of
614             * frexpl() and use it if available */
615 0           frexp((double) lDoubleArg, &exp);
616 0           break;
617             default:
618 0           goto ErrorReturn;
619             }
620 0 0         if(precision == -1) precision = 6;
621 0 0         buffReqd = precision + 3 + ((exp > 0) ? exp/3 : 0);
622 0           break;
623             case 'e':
624             case 'E':
625             case 'g':
626             case 'G':
627 0 0         if(precision == -1) precision = 6;
628 0           buffReqd = precision + 8;
629 0           break;
630             case 'n':
631             case '%':
632             default:
633 0           goto ErrorReturn;
634             break;
635             }
636 0           buffReqd = max(buffReqd + 10, minWidth);
637             /*
638             * Allocate the buffer
639             */
640 0 0         if(buffReqd <= PRINTF_BUFFLEN) {
641 0           buffPtr = buff;
642 0           buffLen = PRINTF_BUFFLEN;
643             } else {
644 0 0         if(auxBuffPtr == NULL || buffReqd > auxBuffLen) {
    0          
645 0 0         if(auxBuffPtr != NULL) free(auxBuffPtr);
646 0           auxBuffPtr = (char *)Malloc(buffReqd);
647 0           auxBuffLen = buffReqd;
648 0 0         if(auxBuffPtr == NULL)
649 0           goto ErrorReturn;
650             }
651 0           buffPtr = auxBuffPtr;
652 0           buffLen = auxBuffLen;
653             }
654             }
655             /*
656             * This giant switch statement requires the following variables
657             * to be set up: op, sizeModifier, arg, buffPtr, fmtBuff.
658             * When fastPath == FALSE and op == 's' or 'f', the argument
659             * has been read into charPtrArg, doubleArg, or lDoubleArg.
660             * The statement produces the boolean performedOp, TRUE iff
661             * the op/sizeModifier were executed and argument consumed;
662             * if performedOp, the characters written into buffPtr[]
663             * and the character count buffCount (== EOF meaning error).
664             *
665             * The switch cases are arranged in the same order as in the
666             * description of fprintf in section 15.11 of Harbison and Steele.
667             */
668 0           performedOp = TRUE;
669 0           switch(op) {
670             case 'd':
671             case 'i':
672 0           switch(sizeModifier) {
673             case ' ':
674 0 0         intArg = va_arg(arg, int);
675 0           sprintf(buffPtr, fmtBuff, intArg);
676 0           buffCount = strlen(buffPtr);
677 0           break;
678             case 'l':
679 0 0         longArg = va_arg(arg, long);
680 0           sprintf(buffPtr, fmtBuff, longArg);
681 0           buffCount = strlen(buffPtr);
682 0           break;
683             case 'h':
684 0 0         shortArg = (short) va_arg(arg, int);
685 0           sprintf(buffPtr, fmtBuff, shortArg);
686 0           buffCount = strlen(buffPtr);
687 0           break;
688             default:
689 0           goto ErrorReturn;
690             }
691 0           break;
692             case 'u':
693             case 'o':
694             case 'x':
695             case 'X':
696 0           switch(sizeModifier) {
697             case ' ':
698 0 0         unsignedArg = va_arg(arg, unsigned);
699 0           sprintf(buffPtr, fmtBuff, unsignedArg);
700 0           buffCount = strlen(buffPtr);
701 0           break;
702             case 'l':
703 0 0         uLongArg = va_arg(arg, unsigned long);
704 0           sprintf(buffPtr, fmtBuff, uLongArg);
705 0           buffCount = strlen(buffPtr);
706 0           break;
707             case 'h':
708 0 0         uShortArg = (unsigned short) va_arg(arg, int);
709 0           sprintf(buffPtr, fmtBuff, uShortArg);
710 0           buffCount = strlen(buffPtr);
711 0           break;
712             default:
713 0           goto ErrorReturn;
714             }
715 0           break;
716             case 'c':
717 0           switch(sizeModifier) {
718             case ' ':
719 0 0         intArg = va_arg(arg, int);
720 0           sprintf(buffPtr, fmtBuff, intArg);
721 0           buffCount = strlen(buffPtr);
722 0           break;
723             case 'l':
724             /*
725             * XXX: Allowed by ISO C Amendment 1, but
726             * many platforms don't yet support wint_t
727             */
728 0           goto ErrorReturn;
729             default:
730 0           goto ErrorReturn;
731             }
732 0           break;
733             case 's':
734 0           switch(sizeModifier) {
735             case ' ':
736 0 0         if(fastPath) {
737 0 0         buffPtr = va_arg(arg, char *);
738 0           buffCount = strlen(buffPtr);
739 0           buffLen = buffCount + 1;
740             } else {
741 0           sprintf(buffPtr, fmtBuff, charPtrArg);
742 0           buffCount = strlen(buffPtr);
743             }
744 0           break;
745             case 'l':
746             /*
747             * XXX: Don't know how to convert a sequence
748             * of wide characters into a byte stream, or
749             * even how to predict the buffering required.
750             */
751 0           goto ErrorReturn;
752             default:
753 0           goto ErrorReturn;
754             }
755 0           break;
756             case 'p':
757 0 0         if(sizeModifier != ' ')
758 0           goto ErrorReturn;
759 0 0         voidPtrArg = va_arg(arg, void *);
760 0           sprintf(buffPtr, fmtBuff, voidPtrArg);
761 0           buffCount = strlen(buffPtr);
762 0           break;
763             case 'n':
764 0           switch(sizeModifier) {
765             case ' ':
766 0 0         intPtrArg = va_arg(arg, int *);
767 0           *intPtrArg = streamCount;
768 0           break;
769             case 'l':
770 0 0         longPtrArg = va_arg(arg, long *);
771 0           *longPtrArg = streamCount;
772 0           break;
773             case 'h':
774 0 0         shortPtrArg = (short *) va_arg(arg, short *);
775 0           *shortPtrArg = (short) streamCount;
776 0           break;
777             default:
778 0           goto ErrorReturn;
779             }
780 0           buffCount = 0;
781 0           break;
782             case 'f':
783 0 0         if(fastPath) {
784 0           performedOp = FALSE;
785 0           break;
786             }
787 0           switch(sizeModifier) {
788             case ' ':
789 0           sprintf(buffPtr, fmtBuff, doubleArg);
790 0           buffCount = strlen(buffPtr);
791 0           break;
792             case 'L':
793 0           sprintf(buffPtr, fmtBuff, lDoubleArg);
794 0           buffCount = strlen(buffPtr);
795 0           break;
796             default:
797 0           goto ErrorReturn;
798             }
799 0           break;
800             case 'e':
801             case 'E':
802             case 'g':
803             case 'G':
804 0           switch(sizeModifier) {
805             case ' ':
806 0 0         doubleArg = va_arg(arg, double);
807 0           sprintf(buffPtr, fmtBuff, doubleArg);
808 0           buffCount = strlen(buffPtr);
809 0           break;
810             case 'L':
811 0           lDoubleArg = va_arg(arg, LONG_DOUBLE);
812 0           sprintf(buffPtr, fmtBuff, lDoubleArg);
813 0           buffCount = strlen(buffPtr);
814 0           break;
815             default:
816 0           goto ErrorReturn;
817             }
818 0           break;
819             case '%':
820 0 0         if(sizeModifier != ' ')
821 0           goto ErrorReturn;
822 0           buff[0] = '%';
823 0           buffCount = 1;
824 0           break;
825             case '\0':
826 0           goto ErrorReturn;
827             default:
828 0           performedOp = FALSE;
829 0           break;
830             } /* switch(op) */
831 0 0         if(performedOp) break;
832 0 0         if(!fastPath)
833 0           goto ErrorReturn;
834 0           fastPath = FALSE;
835 0           } /* for (;;) */
836 0 0         ASSERT(buffCount < buffLen);
837 0 0         if(buffCount > 0) {
838 0 0         if(FCGX_PutStr(buffPtr, buffCount, stream) < 0)
839 0           goto ErrorReturn;
840 0           streamCount += buffCount;
841 0 0         } else if(buffCount < 0) {
842 0           goto ErrorReturn;
843             }
844 0           f += specifierLength;
845             } /* while(f != fStop) */
846 0           goto NormalReturn;
847             ErrorReturn:
848 0           streamCount = -1;
849             NormalReturn:
850 0 0         if(auxBuffPtr != NULL) free(auxBuffPtr);
851 0           return streamCount;
852             }
853              
854             /*
855             * Copy n characters from *srcPtr to *destPtr, then increment
856             * both *srcPtr and *destPtr by n.
857             */
858 0           static void CopyAndAdvance(char **destPtr, char **srcPtr, int n)
859             {
860 0           char *dest = *destPtr;
861 0           char *src = *srcPtr;
862             int i;
863 0 0         for (i = 0; i < n; i++)
864 0           *dest++ = *src++;
865 0           *destPtr = dest;
866 0           *srcPtr = src;
867 0           }
868              
869             /*
870             *----------------------------------------------------------------------
871             *
872             * FCGX_FFlush --
873             *
874             * Flushes any buffered output.
875             *
876             * Server-push is a legitimate application of FCGX_FFlush.
877             * Otherwise, FCGX_FFlush is not very useful, since FCGX_Accept
878             * does it implicitly. FCGX_FFlush may reduce performance
879             * by increasing the total number of operating system calls
880             * the application makes.
881             *
882             * Results:
883             * EOF (-1) if an error occurred.
884             *
885             *----------------------------------------------------------------------
886             */
887 4           int FCGX_FFlush(FCGX_Stream *stream)
888             {
889 4 50         if(stream->isClosed || stream->isReader)
    50          
890 0           return 0;
891 4           stream->emptyBuffProc(stream, FALSE);
892 4 50         return (stream->isClosed) ? -1 : 0;
893             }
894              
895             /*
896             *----------------------------------------------------------------------
897             *
898             * FCGX_FClose --
899             *
900             * Performs FCGX_FFlush and closes the stream.
901             *
902             * This is not a very useful operation, since FCGX_Accept
903             * does it implicitly. Closing the out stream before the
904             * err stream results in an extra write if there's nothing
905             * in the err stream, and therefore reduces performance.
906             *
907             * Results:
908             * EOF (-1) if an error occurred.
909             *
910             *----------------------------------------------------------------------
911             */
912 4           int FCGX_FClose(FCGX_Stream *stream)
913             {
914 4 50         if (stream == NULL) return 0;
915              
916 4 50         if(!stream->wasFCloseCalled) {
917 4 50         if(!stream->isReader) {
918 4           stream->emptyBuffProc(stream, TRUE);
919             }
920 4           stream->wasFCloseCalled = TRUE;
921 4           stream->isClosed = TRUE;
922 4 50         if(stream->isReader) {
923 0           stream->wrNext = stream->stop = stream->rdNext;
924             } else {
925 4           stream->rdNext = stream->stop = stream->wrNext;
926             }
927             }
928 4 50         return (stream->FCGI_errno == 0) ? 0 : EOF;
929             }
930              
931             /*
932             *----------------------------------------------------------------------
933             *
934             * SetError --
935             *
936             * An error has occurred; save the error code in the stream
937             * for diagnostic purposes and set the stream state so that
938             * reads return EOF and writes have no effect.
939             *
940             *----------------------------------------------------------------------
941             */
942 0           static void SetError(FCGX_Stream *stream, int FCGI_errno)
943             {
944             /*
945             * Preserve only the first error.
946             */
947 0 0         if(stream->FCGI_errno == 0) {
948 0           stream->FCGI_errno = FCGI_errno;
949             }
950            
951 0           stream->isClosed = TRUE;
952 0           }
953              
954             /*
955             *----------------------------------------------------------------------
956             *
957             * FCGX_GetError --
958             *
959             * Return the stream error code. 0 means no error, > 0
960             * is an errno(2) error, < 0 is an FCGX_errno error.
961             *
962             *----------------------------------------------------------------------
963             */
964 2           int FCGX_GetError(FCGX_Stream *stream) {
965 2           return stream->FCGI_errno;
966             }
967              
968             /*
969             *----------------------------------------------------------------------
970             *
971             * FCGX_ClearError --
972             *
973             * Clear the stream error code and end-of-file indication.
974             *
975             *----------------------------------------------------------------------
976             */
977 0           void FCGX_ClearError(FCGX_Stream *stream) {
978 0           stream->FCGI_errno = 0;
979             /*
980             * stream->isClosed = FALSE;
981             * XXX: should clear isClosed but work is needed to make it safe
982             * to do so. For example, if an application calls FClose, gets
983             * an I/O error on the write, calls ClearError and retries
984             * the FClose, FClose (really EmptyBuffProc) will write a second
985             * EOF record. If an application calls PutChar instead of FClose
986             * after the ClearError, the application will write more data.
987             * The stream's state must discriminate between various states
988             * of the stream that are now all lumped under isClosed.
989             */
990 0           }
991              
992             /*
993             *======================================================================
994             * Parameters
995             *======================================================================
996             */
997              
998             /*
999             * A vector of pointers representing the parameters received
1000             * by a FastCGI application server, with the vector's length
1001             * and last valid element so adding new parameters is efficient.
1002             */
1003              
1004             typedef struct Params {
1005             FCGX_ParamArray vec; /* vector of strings */
1006             int length; /* number of string vec can hold */
1007             char **cur; /* current item in vec; *cur == NULL */
1008             } Params;
1009             typedef Params *ParamsPtr;
1010              
1011             /*
1012             *----------------------------------------------------------------------
1013             *
1014             * NewParams --
1015             *
1016             * Creates a new Params structure.
1017             *
1018             * Results:
1019             * Pointer to the new structure.
1020             *
1021             *----------------------------------------------------------------------
1022             */
1023 2           static ParamsPtr NewParams(int length)
1024             {
1025             ParamsPtr result;
1026 2           result = (Params *)Malloc(sizeof(Params));
1027 2           result->vec = (char **)Malloc(length * sizeof(char *));
1028 2           result->length = length;
1029 2           result->cur = result->vec;
1030 2           *result->cur = NULL;
1031 2           return result;
1032             }
1033              
1034             /*
1035             *----------------------------------------------------------------------
1036             *
1037             * FreeParams --
1038             *
1039             * Frees a Params structure and all the parameters it contains.
1040             *
1041             * Side effects:
1042             * env becomes invalid.
1043             *
1044             *----------------------------------------------------------------------
1045             */
1046 4           static void FreeParams(ParamsPtr *paramsPtrPtr)
1047             {
1048 4           ParamsPtr paramsPtr = *paramsPtrPtr;
1049             char **p;
1050 4 100         if(paramsPtr == NULL) {
1051 2           return;
1052             }
1053 6 100         for (p = paramsPtr->vec; p < paramsPtr->cur; p++) {
1054 4           free(*p);
1055             }
1056 2           free(paramsPtr->vec);
1057 2           free(paramsPtr);
1058 2           *paramsPtrPtr = NULL;
1059             }
1060              
1061             /*
1062             *----------------------------------------------------------------------
1063             *
1064             * PutParam --
1065             *
1066             * Add a name/value pair to a Params structure.
1067             *
1068             * Results:
1069             * None.
1070             *
1071             * Side effects:
1072             * Parameters structure updated.
1073             *
1074             *----------------------------------------------------------------------
1075             */
1076 4           static void PutParam(ParamsPtr paramsPtr, char *nameValue)
1077             {
1078             int size;
1079              
1080 4           *paramsPtr->cur++ = nameValue;
1081 4           size = paramsPtr->cur - paramsPtr->vec;
1082 4 50         if(size >= paramsPtr->length) {
1083 0           paramsPtr->length *= 2;
1084 0           paramsPtr->vec = (FCGX_ParamArray)realloc(paramsPtr->vec, paramsPtr->length * sizeof(char *));
1085 0           paramsPtr->cur = paramsPtr->vec + size;
1086             }
1087 4           *paramsPtr->cur = NULL;
1088 4           }
1089              
1090             /*
1091             *----------------------------------------------------------------------
1092             *
1093             * FCGX_GetParam -- obtain value of FCGI parameter in environment
1094             *
1095             *
1096             * Results:
1097             * Value bound to name, NULL if name not present in the
1098             * environment envp. Caller must not mutate the result
1099             * or retain it past the end of this request.
1100             *
1101             *----------------------------------------------------------------------
1102             */
1103 0           char *FCGX_GetParam(const char *name, FCGX_ParamArray envp)
1104             {
1105             int len;
1106             char **p;
1107              
1108 0 0         if (name == NULL || envp == NULL) return NULL;
    0          
1109              
1110 0           len = strlen(name);
1111              
1112 0 0         for (p = envp; *p; ++p) {
1113 0 0         if((strncmp(name, *p, len) == 0) && ((*p)[len] == '=')) {
    0          
1114 0           return *p+len+1;
1115             }
1116             }
1117 0           return NULL;
1118             }
1119              
1120             /*
1121             *----------------------------------------------------------------------
1122             *
1123             * Start of FastCGI-specific code
1124             *
1125             *----------------------------------------------------------------------
1126             */
1127              
1128             /*
1129             *----------------------------------------------------------------------
1130             *
1131             * ReadParams --
1132             *
1133             * Reads FastCGI name-value pairs from stream until EOF. Converts
1134             * each pair to name=value format and adds it to Params structure.
1135             *
1136             *----------------------------------------------------------------------
1137             */
1138 2           static int ReadParams(Params *paramsPtr, FCGX_Stream *stream)
1139             {
1140             int nameLen, valueLen;
1141             unsigned char lenBuff[3];
1142             char *nameValue;
1143              
1144 4 100         while((nameLen = FCGX_GetChar(stream)) != EOF) {
1145             /*
1146             * Read name length (one or four bytes) and value length
1147             * (one or four bytes) from stream.
1148             */
1149 2 50         if((nameLen & 0x80) != 0) {
1150 0 0         if(FCGX_GetStr((char *) &lenBuff[0], 3, stream) != 3) {
1151 0           SetError(stream, FCGX_PARAMS_ERROR);
1152 0           return -1;
1153             }
1154 0           nameLen = ((nameLen & 0x7f) << 24) + (lenBuff[0] << 16)
1155 0           + (lenBuff[1] << 8) + lenBuff[2];
1156             }
1157 2 50         if((valueLen = FCGX_GetChar(stream)) == EOF) {
1158 0           SetError(stream, FCGX_PARAMS_ERROR);
1159 0           return -1;
1160             }
1161 2 50         if((valueLen & 0x80) != 0) {
1162 0 0         if(FCGX_GetStr((char *) &lenBuff[0], 3, stream) != 3) {
1163 0           SetError(stream, FCGX_PARAMS_ERROR);
1164 0           return -1;
1165             }
1166 0           valueLen = ((valueLen & 0x7f) << 24) + (lenBuff[0] << 16)
1167 0           + (lenBuff[1] << 8) + lenBuff[2];
1168             }
1169             /*
1170             * nameLen and valueLen are now valid; read the name and value
1171             * from stream and construct a standard environment entry.
1172             */
1173 2           nameValue = (char *)Malloc(nameLen + valueLen + 2);
1174 2 50         if(FCGX_GetStr(nameValue, nameLen, stream) != nameLen) {
1175 0           SetError(stream, FCGX_PARAMS_ERROR);
1176 0           free(nameValue);
1177 0           return -1;
1178             }
1179 2           *(nameValue + nameLen) = '=';
1180 2 50         if(FCGX_GetStr(nameValue + nameLen + 1, valueLen, stream)
1181             != valueLen) {
1182 0           SetError(stream, FCGX_PARAMS_ERROR);
1183 0           free(nameValue);
1184 0           return -1;
1185             }
1186 2           *(nameValue + nameLen + valueLen + 1) = '\0';
1187 2           PutParam(paramsPtr, nameValue);
1188             }
1189 2           return 0;
1190             }
1191              
1192             /*
1193             *----------------------------------------------------------------------
1194             *
1195             * MakeHeader --
1196             *
1197             * Constructs an FCGI_Header struct.
1198             *
1199             *----------------------------------------------------------------------
1200             */
1201 8           static FCGI_Header MakeHeader(
1202             int type,
1203             int requestId,
1204             int contentLength,
1205             int paddingLength)
1206             {
1207             FCGI_Header header;
1208 8 50         ASSERT(contentLength >= 0 && contentLength <= FCGI_MAX_LENGTH);
    50          
1209 8 50         ASSERT(paddingLength >= 0 && paddingLength <= 0xff);
    50          
1210 8           header.version = FCGI_VERSION_1;
1211 8           header.type = (unsigned char) type;
1212 8           header.requestIdB1 = (unsigned char) ((requestId >> 8) & 0xff);
1213 8           header.requestIdB0 = (unsigned char) ((requestId ) & 0xff);
1214 8           header.contentLengthB1 = (unsigned char) ((contentLength >> 8) & 0xff);
1215 8           header.contentLengthB0 = (unsigned char) ((contentLength ) & 0xff);
1216 8           header.paddingLength = (unsigned char) paddingLength;
1217 8           header.reserved = 0;
1218 8           return header;
1219             }
1220              
1221             /*
1222             *----------------------------------------------------------------------
1223             *
1224             * MakeEndRequestBody --
1225             *
1226             * Constructs an FCGI_EndRequestBody struct.
1227             *
1228             *----------------------------------------------------------------------
1229             */
1230 2           static FCGI_EndRequestBody MakeEndRequestBody(
1231             int appStatus,
1232             int protocolStatus)
1233             {
1234             FCGI_EndRequestBody body;
1235 2           body.appStatusB3 = (unsigned char) ((appStatus >> 24) & 0xff);
1236 2           body.appStatusB2 = (unsigned char) ((appStatus >> 16) & 0xff);
1237 2           body.appStatusB1 = (unsigned char) ((appStatus >> 8) & 0xff);
1238 2           body.appStatusB0 = (unsigned char) ((appStatus ) & 0xff);
1239 2           body.protocolStatus = (unsigned char) protocolStatus;
1240 2           memset(body.reserved, 0, sizeof(body.reserved));
1241 2           return body;
1242             }
1243              
1244             /*
1245             *----------------------------------------------------------------------
1246             *
1247             * MakeUnknownTypeBody --
1248             *
1249             * Constructs an FCGI_MakeUnknownTypeBody struct.
1250             *
1251             *----------------------------------------------------------------------
1252             */
1253 0           static FCGI_UnknownTypeBody MakeUnknownTypeBody(
1254             int type)
1255             {
1256             FCGI_UnknownTypeBody body;
1257 0           body.type = (unsigned char) type;
1258 0           memset(body.reserved, 0, sizeof(body.reserved));
1259 0           return body;
1260             }
1261              
1262             /*
1263             *----------------------------------------------------------------------
1264             *
1265             * AlignInt8 --
1266             *
1267             * Returns the smallest integer greater than or equal to n
1268             * that's a multiple of 8.
1269             *
1270             *----------------------------------------------------------------------
1271             */
1272 10           static int AlignInt8(unsigned n) {
1273 10           return (n + 7) & (UINT_MAX - 7);
1274             }
1275              
1276             /*
1277             *----------------------------------------------------------------------
1278             *
1279             * AlignPtr8 --
1280             *
1281             * Returns the smallest pointer greater than or equal to p
1282             * that's a multiple of 8.
1283             *
1284             *----------------------------------------------------------------------
1285             */
1286 6           static unsigned char *AlignPtr8(unsigned char *p) {
1287 6           unsigned long u = (unsigned long) p;
1288 6           u = ((u + 7) & (ULONG_MAX - 7)) - u;
1289 6           return p + u;
1290             }
1291              
1292              
1293             /*
1294             * State associated with a stream
1295             */
1296             typedef struct FCGX_Stream_Data {
1297             unsigned char *buff; /* buffer after alignment */
1298             int bufflen; /* number of bytes buff can store */
1299             unsigned char *mBuff; /* buffer as returned by Malloc */
1300             unsigned char *buffStop; /* reader: last valid byte + 1 of entire buffer.
1301             * stop generally differs from buffStop for
1302             * readers because of record structure.
1303             * writer: buff + bufflen */
1304             int type; /* reader: FCGI_PARAMS or FCGI_STDIN
1305             * writer: FCGI_STDOUT or FCGI_STDERR */
1306             int eorStop; /* reader: stop stream at end-of-record */
1307             int skip; /* reader: don't deliver content bytes */
1308             int contentLen; /* reader: bytes of unread content */
1309             int paddingLen; /* reader: bytes of unread padding */
1310             int isAnythingWritten; /* writer: data has been written to ipcFd */
1311             int rawWrite; /* writer: write data without stream headers */
1312             FCGX_Request *reqDataPtr; /* request data not specific to one stream */
1313             } FCGX_Stream_Data;
1314              
1315             /*
1316             *----------------------------------------------------------------------
1317             *
1318             * WriteCloseRecords --
1319             *
1320             * Writes an EOF record for the stream content if necessary.
1321             * If this is the last writer to close, writes an FCGI_END_REQUEST
1322             * record.
1323             *
1324             *----------------------------------------------------------------------
1325             */
1326 4           static void WriteCloseRecords(struct FCGX_Stream *stream)
1327             {
1328 4           FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
1329             /*
1330             * Enter rawWrite mode so final records won't be encapsulated as
1331             * stream data.
1332             */
1333 4           data->rawWrite = TRUE;
1334             /*
1335             * Generate EOF for stream content if needed.
1336             */
1337 6 100         if(!(data->type == FCGI_STDERR
    50          
1338 2 50         && stream->wrNext == data->buff
1339 2           && !data->isAnythingWritten)) {
1340             FCGI_Header header;
1341 2           header = MakeHeader(data->type, data->reqDataPtr->requestId, 0, 0);
1342 2           FCGX_PutStr((char *) &header, sizeof(header), stream);
1343             };
1344             /*
1345             * Generate FCGI_END_REQUEST record if needed.
1346             */
1347 4 100         if(data->reqDataPtr->nWriters == 1) {
1348             FCGI_EndRequestRecord endRequestRecord;
1349 2           endRequestRecord.header = MakeHeader(FCGI_END_REQUEST,
1350 2           data->reqDataPtr->requestId,
1351             sizeof(endRequestRecord.body), 0);
1352 2           endRequestRecord.body = MakeEndRequestBody(
1353 2           data->reqDataPtr->appStatus, FCGI_REQUEST_COMPLETE);
1354 2           FCGX_PutStr((char *) &endRequestRecord,
1355             sizeof(endRequestRecord), stream);
1356             }
1357 4           data->reqDataPtr->nWriters--;
1358 4           }
1359              
1360              
1361              
1362 6           static int write_it_all(int fd, char *buf, int len)
1363             {
1364             int wrote;
1365              
1366 12 100         while (len) {
1367 6           wrote = OS_Write(fd, buf, len);
1368 6 50         if (wrote < 0)
1369 0           return wrote;
1370 6           len -= wrote;
1371 6           buf += wrote;
1372             }
1373 6           return len;
1374             }
1375              
1376             /*
1377             *----------------------------------------------------------------------
1378             *
1379             * EmptyBuffProc --
1380             *
1381             * Encapsulates any buffered stream content in a FastCGI
1382             * record. Writes the data, making the buffer empty.
1383             *
1384             *----------------------------------------------------------------------
1385             */
1386 8           static void EmptyBuffProc(struct FCGX_Stream *stream, int doClose)
1387             {
1388 8           FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
1389             int cLen, eLen;
1390             /*
1391             * If the buffer contains stream data, fill in the header.
1392             * Pad the record to a multiple of 8 bytes in length. Padding
1393             * can't overflow the buffer because the buffer is a multiple
1394             * of 8 bytes in length. If the buffer contains no stream
1395             * data, reclaim the space reserved for the header.
1396             */
1397 8 50         if(!data->rawWrite) {
1398 8           cLen = stream->wrNext - data->buff - sizeof(FCGI_Header);
1399 8 100         if(cLen > 0) {
1400 4           eLen = AlignInt8(cLen);
1401             /*
1402             * Giving the padding a well-defined value keeps Purify happy.
1403             */
1404 4           memset(stream->wrNext, 0, eLen - cLen);
1405 4           stream->wrNext += eLen - cLen;
1406 4           *((FCGI_Header *) data->buff)
1407 4           = MakeHeader(data->type,
1408 4           data->reqDataPtr->requestId, cLen, eLen - cLen);
1409             } else {
1410 4           stream->wrNext = data->buff;
1411             }
1412             }
1413 8 100         if(doClose) {
1414 4           WriteCloseRecords(stream);
1415             };
1416 8 100         if (stream->wrNext != data->buff) {
1417 6           data->isAnythingWritten = TRUE;
1418 6 50         if (write_it_all(data->reqDataPtr->ipcFd, (char *)data->buff, stream->wrNext - data->buff) < 0) {
1419 0           SetError(stream, OS_Errno);
1420 0           return;
1421             }
1422 6           stream->wrNext = data->buff;
1423             }
1424             /*
1425             * The buffer is empty.
1426             */
1427 8 100         if(!data->rawWrite) {
1428 4           stream->wrNext += sizeof(FCGI_Header);
1429             }
1430             }
1431              
1432             /*
1433             * Return codes for Process* functions
1434             */
1435             #define STREAM_RECORD 0
1436             #define SKIP 1
1437             #define BEGIN_RECORD 2
1438             #define MGMT_RECORD 3
1439              
1440             /*
1441             *----------------------------------------------------------------------
1442             *
1443             * ProcessManagementRecord --
1444             *
1445             * Reads and responds to a management record. The only type of
1446             * management record this library understands is FCGI_GET_VALUES.
1447             * The only variables that this library's FCGI_GET_VALUES
1448             * understands are FCGI_MAX_CONNS, FCGI_MAX_REQS, and FCGI_MPXS_CONNS.
1449             * Ignore other FCGI_GET_VALUES variables; respond to other
1450             * management records with a FCGI_UNKNOWN_TYPE record.
1451             *
1452             *----------------------------------------------------------------------
1453             */
1454 0           static int ProcessManagementRecord(int type, FCGX_Stream *stream)
1455             {
1456 0           FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
1457             ParamsPtr paramsPtr;
1458             char **pPtr;
1459             char response[64]; /* 64 = 8 + 3*(1+1+14+1)* + padding */
1460 0           char *responseP = &response[FCGI_HEADER_LEN];
1461 0           char *name, value = '\0';
1462             int len, paddedLen;
1463 0 0         if(type == FCGI_GET_VALUES) {
1464 0           paramsPtr = NewParams(3);
1465 0           ReadParams(paramsPtr, stream);
1466 0 0         if((FCGX_GetError(stream) != 0) || (data->contentLen != 0)) {
    0          
1467 0           FreeParams(¶msPtr);
1468 0           return FCGX_PROTOCOL_ERROR;
1469             }
1470 0 0         for (pPtr = paramsPtr->vec; pPtr < paramsPtr->cur; pPtr++) {
1471 0           name = *pPtr;
1472 0           *(strchr(name, '=')) = '\0';
1473 0 0         if(strcmp(name, FCGI_MAX_CONNS) == 0) {
1474 0           value = '1';
1475 0 0         } else if(strcmp(name, FCGI_MAX_REQS) == 0) {
1476 0           value = '1';
1477 0 0         } else if(strcmp(name, FCGI_MPXS_CONNS) == 0) {
1478 0           value = '0';
1479             } else {
1480 0           name = NULL;
1481             }
1482 0 0         if(name != NULL) {
1483 0           len = strlen(name);
1484 0           sprintf(responseP, "%c%c%s%c", len, 1, name, value);
1485 0           responseP += len + 3;
1486             }
1487             }
1488 0           len = responseP - &response[FCGI_HEADER_LEN];
1489 0           paddedLen = AlignInt8(len);
1490 0           *((FCGI_Header *) response)
1491 0           = MakeHeader(FCGI_GET_VALUES_RESULT, FCGI_NULL_REQUEST_ID,
1492             len, paddedLen - len);
1493 0           FreeParams(¶msPtr);
1494             } else {
1495 0           paddedLen = len = sizeof(FCGI_UnknownTypeBody);
1496 0           ((FCGI_UnknownTypeRecord *) response)->header
1497 0           = MakeHeader(FCGI_UNKNOWN_TYPE, FCGI_NULL_REQUEST_ID,
1498             len, 0);
1499 0           ((FCGI_UnknownTypeRecord *) response)->body
1500 0           = MakeUnknownTypeBody(type);
1501             }
1502 0 0         if (write_it_all(data->reqDataPtr->ipcFd, response, FCGI_HEADER_LEN + paddedLen) < 0) {
1503 0           SetError(stream, OS_Errno);
1504 0           return -1;
1505             }
1506              
1507 0           return MGMT_RECORD;
1508             }
1509              
1510             /*
1511             *----------------------------------------------------------------------
1512             *
1513             * ProcessBeginRecord --
1514             *
1515             * Reads an FCGI_BEGIN_REQUEST record.
1516             *
1517             * Results:
1518             * BEGIN_RECORD for normal return. FCGX_PROTOCOL_ERROR for
1519             * protocol error. SKIP for attempt to multiplex
1520             * connection. -1 for error from write (errno in stream).
1521             *
1522             * Side effects:
1523             * In case of BEGIN_RECORD return, stores requestId, role,
1524             * keepConnection values, and sets isBeginProcessed = TRUE.
1525             *
1526             *----------------------------------------------------------------------
1527             */
1528 2           static int ProcessBeginRecord(int requestId, FCGX_Stream *stream)
1529             {
1530 2           FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
1531             FCGI_BeginRequestBody body;
1532 2 50         if(requestId == 0 || data->contentLen != sizeof(body)) {
    50          
1533 0           return FCGX_PROTOCOL_ERROR;
1534             }
1535 2 50         if(data->reqDataPtr->isBeginProcessed) {
1536             /*
1537             * The Web server is multiplexing the connection. This library
1538             * doesn't know how to handle multiplexing, so respond with
1539             * FCGI_END_REQUEST{protocolStatus = FCGI_CANT_MPX_CONN}
1540             */
1541             FCGI_EndRequestRecord endRequestRecord;
1542 0           endRequestRecord.header = MakeHeader(FCGI_END_REQUEST,
1543             requestId, sizeof(endRequestRecord.body), 0);
1544             endRequestRecord.body
1545 0           = MakeEndRequestBody(0, FCGI_CANT_MPX_CONN);
1546 0 0         if (write_it_all(data->reqDataPtr->ipcFd, (char *)&endRequestRecord, sizeof(endRequestRecord)) < 0) {
1547 0           SetError(stream, OS_Errno);
1548 0           return -1;
1549             }
1550              
1551 0           return SKIP;
1552             }
1553             /*
1554             * Accept this new request. Read the record body.
1555             */
1556 2           data->reqDataPtr->requestId = requestId;
1557 2 50         if(FCGX_GetStr((char *) &body, sizeof(body), stream)
1558             != sizeof(body)) {
1559 0           return FCGX_PROTOCOL_ERROR;
1560             }
1561 2           data->reqDataPtr->keepConnection = (body.flags & FCGI_KEEP_CONN);
1562 2           data->reqDataPtr->role = (body.roleB1 << 8) + body.roleB0;
1563 2           data->reqDataPtr->isBeginProcessed = TRUE;
1564 2           return BEGIN_RECORD;
1565             }
1566              
1567             /*
1568             *----------------------------------------------------------------------
1569             *
1570             * ProcessHeader --
1571             *
1572             * Interprets FCGI_Header. Processes FCGI_BEGIN_REQUEST and
1573             * management records here; extracts information from stream
1574             * records (FCGI_PARAMS, FCGI_STDIN) into stream.
1575             *
1576             * Results:
1577             * >= 0 for a normal return, < 0 for error
1578             *
1579             * Side effects:
1580             * XXX: Many (more than there used to be).
1581             * If !stream->isRequestIdSet, ProcessHeader initializes
1582             * stream->requestId from header and sets stream->isRequestIdSet
1583             * to TRUE. ProcessHeader also sets stream->contentLen to header's
1584             * contentLength, and sets stream->paddingLen to the header's
1585             * paddingLength.
1586             *
1587             *----------------------------------------------------------------------
1588             */
1589 6           static int ProcessHeader(FCGI_Header header, FCGX_Stream *stream)
1590             {
1591 6           FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
1592             int requestId;
1593 6 50         if(header.version != FCGI_VERSION_1) {
1594 0           return FCGX_UNSUPPORTED_VERSION;
1595             }
1596 12           requestId = (header.requestIdB1 << 8)
1597 6           + header.requestIdB0;
1598 12           data->contentLen = (header.contentLengthB1 << 8)
1599 6           + header.contentLengthB0;
1600 6           data->paddingLen = header.paddingLength;
1601 6 100         if(header.type == FCGI_BEGIN_REQUEST) {
1602 2           return ProcessBeginRecord(requestId, stream);
1603             }
1604 4 50         if(requestId == FCGI_NULL_REQUEST_ID) {
1605 0           return ProcessManagementRecord(header.type, stream);
1606             }
1607 4 50         if(requestId != data->reqDataPtr->requestId) {
1608 0           return SKIP;
1609             }
1610 4 50         if(header.type != data->type) {
1611 0           return FCGX_PROTOCOL_ERROR;
1612             }
1613 4           return STREAM_RECORD;
1614             }
1615              
1616             /*
1617             *----------------------------------------------------------------------
1618             *
1619             * FillBuffProc --
1620             *
1621             * Reads bytes from the ipcFd, supplies bytes to a stream client.
1622             *
1623             *----------------------------------------------------------------------
1624             */
1625 8           static void FillBuffProc(FCGX_Stream *stream)
1626             {
1627 8           FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
1628             FCGI_Header header;
1629 8           int headerLen = 0;
1630             int status, count;
1631              
1632             for (;;) {
1633             /*
1634             * If data->buff is empty, do a read.
1635             */
1636 10 100         if(stream->rdNext == data->buffStop) {
1637 2           count = OS_Read(data->reqDataPtr->ipcFd, (char *)data->buff,
1638 2           data->bufflen);
1639 2 50         if(count <= 0) {
1640 0 0         SetError(stream, (count == 0 ? FCGX_PROTOCOL_ERROR : OS_Errno));
1641 8           return;
1642             }
1643 2           stream->rdNext = data->buff;
1644 2           data->buffStop = data->buff + count;
1645             }
1646             /*
1647             * Now data->buff is not empty. If the current record contains
1648             * more content bytes, deliver all that are present in data->buff.
1649             */
1650 10 100         if(data->contentLen > 0) {
1651 4           count = min(data->contentLen, data->buffStop - stream->rdNext);
1652 4           data->contentLen -= count;
1653 4 50         if(!data->skip) {
1654 4           stream->wrNext = stream->stop = stream->rdNext + count;
1655 4           return;
1656             } else {
1657 0           stream->rdNext += count;
1658 0 0         if(data->contentLen > 0) {
1659 0           continue;
1660             } else {
1661 0           data->skip = FALSE;
1662             }
1663             }
1664             }
1665             /*
1666             * If the current record (whose content has been fully consumed by
1667             * the client) was padded, skip over the padding bytes.
1668             */
1669 6 50         if(data->paddingLen > 0) {
1670 0           count = min(data->paddingLen, data->buffStop - stream->rdNext);
1671 0           data->paddingLen -= count;
1672 0           stream->rdNext += count;
1673 0 0         if(data->paddingLen > 0) {
1674 0           continue;
1675             }
1676             }
1677             /*
1678             * All done with the current record, including the padding.
1679             * If we're in a recursive call from ProcessHeader, deliver EOF.
1680             */
1681 6 50         if(data->eorStop) {
1682 0           stream->stop = stream->rdNext;
1683 0           stream->isClosed = TRUE;
1684 0           return;
1685             }
1686             /*
1687             * Fill header with bytes from the input buffer.
1688             */
1689 6           count = min((int)sizeof(header) - headerLen,
1690             data->buffStop - stream->rdNext);
1691 6           memcpy(((char *)(&header)) + headerLen, stream->rdNext, count);
1692 6           headerLen += count;
1693 6           stream->rdNext += count;
1694 6 50         if(headerLen < sizeof(header)) {
1695 0           continue;
1696             };
1697 6           headerLen = 0;
1698             /*
1699             * Interpret header. eorStop prevents ProcessHeader from reading
1700             * past the end-of-record when using stream to read content.
1701             */
1702 6           data->eorStop = TRUE;
1703 6           stream->stop = stream->rdNext;
1704 6           status = ProcessHeader(header, stream);
1705 6           data->eorStop = FALSE;
1706 6           stream->isClosed = FALSE;
1707 6           switch(status) {
1708             case STREAM_RECORD:
1709             /*
1710             * If this stream record header marked the end of stream
1711             * data deliver EOF to the stream client, otherwise loop
1712             * and deliver data.
1713             *
1714             * XXX: If this is final stream and
1715             * stream->rdNext != data->buffStop, buffered
1716             * data is next request (server pipelining)?
1717             */
1718 4 100         if(data->contentLen == 0) {
1719 2           stream->wrNext = stream->stop = stream->rdNext;
1720 2           stream->isClosed = TRUE;
1721 2           return;
1722             }
1723 2           break;
1724             case SKIP:
1725 0           data->skip = TRUE;
1726 0           break;
1727             case BEGIN_RECORD:
1728             /*
1729             * If this header marked the beginning of a new
1730             * request, return role information to caller.
1731             */
1732 2           return;
1733             break;
1734             case MGMT_RECORD:
1735 0           break;
1736             default:
1737 0 0         ASSERT(status < 0);
1738 0           SetError(stream, status);
1739 0           return;
1740             break;
1741             }
1742 2           }
1743             }
1744              
1745             /*
1746             *----------------------------------------------------------------------
1747             *
1748             * NewStream --
1749             *
1750             * Creates a stream to read or write from an open ipcFd.
1751             * The stream performs reads/writes of up to bufflen bytes.
1752             *
1753             *----------------------------------------------------------------------
1754             */
1755 6           static FCGX_Stream *NewStream(
1756             FCGX_Request *reqDataPtr, int bufflen, int isReader, int streamType)
1757             {
1758             /*
1759             * XXX: It would be a lot cleaner to have a NewStream that only
1760             * knows about the type FCGX_Stream, with all other
1761             * necessary data passed in. It appears that not just
1762             * data and the two procs are needed for initializing stream,
1763             * but also data->buff and data->buffStop. This has implications
1764             * for procs that want to swap buffers, too.
1765             */
1766 6           FCGX_Stream *stream = (FCGX_Stream *)Malloc(sizeof(FCGX_Stream));
1767 6           FCGX_Stream_Data *data = (FCGX_Stream_Data *)Malloc(sizeof(FCGX_Stream_Data));
1768 6           data->reqDataPtr = reqDataPtr;
1769 6 50         bufflen = AlignInt8(min(max(bufflen, 32), FCGI_MAX_LENGTH + 1));
1770 6           data->bufflen = bufflen;
1771 6           data->mBuff = (unsigned char *)Malloc(bufflen);
1772 6           data->buff = AlignPtr8(data->mBuff);
1773 6 50         if(data->buff != data->mBuff) {
1774 0           data->bufflen -= 8;
1775             }
1776 6 100         if(isReader) {
1777 2           data->buffStop = data->buff;
1778             } else {
1779 4           data->buffStop = data->buff + data->bufflen;
1780             }
1781 6           data->type = streamType;
1782 6           data->eorStop = FALSE;
1783 6           data->skip = FALSE;
1784 6           data->contentLen = 0;
1785 6           data->paddingLen = 0;
1786 6           data->isAnythingWritten = FALSE;
1787 6           data->rawWrite = FALSE;
1788              
1789 6           stream->data = data;
1790 6           stream->isReader = isReader;
1791 6           stream->isClosed = FALSE;
1792 6           stream->wasFCloseCalled = FALSE;
1793 6           stream->FCGI_errno = 0;
1794 6 100         if(isReader) {
1795 2           stream->fillBuffProc = FillBuffProc;
1796 2           stream->emptyBuffProc = NULL;
1797 2           stream->rdNext = data->buff;
1798 2           stream->stop = stream->rdNext;
1799 2           stream->stopUnget = data->buff;
1800 2           stream->wrNext = stream->stop;
1801             } else {
1802 4           stream->fillBuffProc = NULL;
1803 4           stream->emptyBuffProc = EmptyBuffProc;
1804 4           stream->wrNext = data->buff + sizeof(FCGI_Header);
1805 4           stream->stop = data->buffStop;
1806 4           stream->stopUnget = NULL;
1807 4           stream->rdNext = stream->stop;
1808             }
1809 6           return stream;
1810             }
1811              
1812             /*
1813             *----------------------------------------------------------------------
1814             *
1815             * FCGX_FreeStream --
1816             *
1817             * Frees all storage allocated when *streamPtr was created,
1818             * and nulls out *streamPtr.
1819             *
1820             *----------------------------------------------------------------------
1821             */
1822 12           void FCGX_FreeStream(FCGX_Stream **streamPtr)
1823             {
1824 12           FCGX_Stream *stream = *streamPtr;
1825             FCGX_Stream_Data *data;
1826 12 100         if(stream == NULL) {
1827 6           return;
1828             }
1829 6           data = (FCGX_Stream_Data *)stream->data;
1830 6           data->reqDataPtr = NULL;
1831 6           free(data->mBuff);
1832 6           free(data);
1833 6           free(stream);
1834 6           *streamPtr = NULL;
1835             }
1836              
1837             /*
1838             *----------------------------------------------------------------------
1839             *
1840             * SetReaderType --
1841             *
1842             * Re-initializes the stream to read data of the specified type.
1843             *
1844             *----------------------------------------------------------------------
1845             */
1846 4           static FCGX_Stream *SetReaderType(FCGX_Stream *stream, int streamType)
1847             {
1848 4           FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
1849 4 50         ASSERT(stream->isReader);
1850 4           data->type = streamType;
1851 4           data->eorStop = FALSE;
1852 4           data->skip = FALSE;
1853 4           data->contentLen = 0;
1854 4           data->paddingLen = 0;
1855 4           stream->wrNext = stream->stop = stream->rdNext;
1856 4           stream->isClosed = FALSE;
1857 4           return stream;
1858             }
1859              
1860             /*
1861             *----------------------------------------------------------------------
1862             *
1863             * NewReader --
1864             *
1865             * Creates a stream to read streamType records for the given
1866             * request. The stream performs OS reads of up to bufflen bytes.
1867             *
1868             *----------------------------------------------------------------------
1869             */
1870 2           static FCGX_Stream *NewReader(FCGX_Request *reqDataPtr, int bufflen, int streamType)
1871             {
1872 2           return NewStream(reqDataPtr, bufflen, TRUE, streamType);
1873             }
1874              
1875             /*
1876             *----------------------------------------------------------------------
1877             *
1878             * NewWriter --
1879             *
1880             * Creates a stream to write streamType FastCGI records, using
1881             * the ipcFd and RequestId contained in *reqDataPtr.
1882             * The stream performs OS writes of up to bufflen bytes.
1883             *
1884             *----------------------------------------------------------------------
1885             */
1886 4           static FCGX_Stream *NewWriter(FCGX_Request *reqDataPtr, int bufflen, int streamType)
1887             {
1888 4           return NewStream(reqDataPtr, bufflen, FALSE, streamType);
1889             }
1890              
1891             /*
1892             *----------------------------------------------------------------------
1893             *
1894             * FCGX_CreateWriter --
1895             *
1896             * Creates a stream to write streamType FastCGI records, using
1897             * the given ipcFd and request Id. This function is provided
1898             * for use by cgi-fcgi. In order to be defensive against misuse,
1899             * this function leaks a little storage; cgi-fcgi doesn't care.
1900             *
1901             *----------------------------------------------------------------------
1902             */
1903 0           FCGX_Stream *FCGX_CreateWriter(
1904             int ipcFd,
1905             int requestId,
1906             int bufflen,
1907             int streamType)
1908             {
1909 0           FCGX_Request *reqDataPtr = (FCGX_Request *)Malloc(sizeof(FCGX_Request));
1910 0           reqDataPtr->ipcFd = ipcFd;
1911 0           reqDataPtr->requestId = requestId;
1912             /*
1913             * Suppress writing an FCGI_END_REQUEST record.
1914             */
1915 0           reqDataPtr->nWriters = 2;
1916 0           return NewWriter(reqDataPtr, bufflen, streamType);
1917             }
1918              
1919             /*
1920             *======================================================================
1921             * Control
1922             *======================================================================
1923             */
1924              
1925             /*
1926             *----------------------------------------------------------------------
1927             *
1928             * FCGX_IsCGI --
1929             *
1930             * This routine determines if the process is running as a CGI or
1931             * FastCGI process. The distinction is made by determining whether
1932             * FCGI_LISTENSOCK_FILENO is a listener ipcFd or the end of a
1933             * pipe (ie. standard in).
1934             *
1935             * Results:
1936             * TRUE if the process is a CGI process, FALSE if FastCGI.
1937             *
1938             *----------------------------------------------------------------------
1939             */
1940 0           int FCGX_IsCGI(void)
1941             {
1942 0 0         if (isFastCGI != -1) {
1943 0           return !isFastCGI;
1944             }
1945              
1946 0 0         if (!libInitialized) {
1947 0           int rc = FCGX_Init();
1948 0 0         if (rc) {
1949             /* exit() isn't great, but hey */
1950 0           exit((rc < 0) ? rc : -rc);
1951             }
1952             }
1953              
1954 0           isFastCGI = OS_IsFcgi(FCGI_LISTENSOCK_FILENO);
1955              
1956 0           return !isFastCGI;
1957             }
1958              
1959             /*
1960             *----------------------------------------------------------------------
1961             *
1962             * FCGX_Finish --
1963             *
1964             * Finishes the current request from the HTTP server.
1965             *
1966             * Side effects:
1967             *
1968             * Finishes the request accepted by (and frees any
1969             * storage allocated by) the previous call to FCGX_Accept.
1970             *
1971             * DO NOT retain pointers to the envp array or any strings
1972             * contained in it (e.g. to the result of calling FCGX_GetParam),
1973             * since these will be freed by the next call to FCGX_Finish
1974             * or FCGX_Accept.
1975             *
1976             *----------------------------------------------------------------------
1977             */
1978              
1979 0           void FCGX_Finish(void)
1980             {
1981 0           FCGX_Finish_r(&the_request);
1982 0           }
1983              
1984             /*
1985             *----------------------------------------------------------------------
1986             *
1987             * FCGX_Finish_r --
1988             *
1989             * Finishes the current request from the HTTP server.
1990             *
1991             * Side effects:
1992             *
1993             * Finishes the request accepted by (and frees any
1994             * storage allocated by) the previous call to FCGX_Accept.
1995             *
1996             * DO NOT retain pointers to the envp array or any strings
1997             * contained in it (e.g. to the result of calling FCGX_GetParam),
1998             * since these will be freed by the next call to FCGX_Finish
1999             * or FCGX_Accept.
2000             *
2001             *----------------------------------------------------------------------
2002             */
2003 4           void FCGX_Finish_r(FCGX_Request *reqDataPtr)
2004             {
2005             int close;
2006              
2007 4 50         if (reqDataPtr == NULL) {
2008 0           return;
2009             }
2010              
2011 4           close = !reqDataPtr->keepConnection;
2012              
2013             /* This should probably use a 'status' member instead of 'in' */
2014 4 100         if (reqDataPtr->in) {
2015 2           close |= FCGX_FClose(reqDataPtr->err);
2016 2           close |= FCGX_FClose(reqDataPtr->out);
2017 2           close |= FCGX_GetError(reqDataPtr->in);
2018              
2019             /* discard any remaining data in input stream on persistent connections */
2020 2 50         if (!close && !reqDataPtr->in->isClosed && reqDataPtr->keepConnection) {
    0          
    0          
2021 0           FCGX_Stream *stream = reqDataPtr->in;
2022              
2023             do {
2024 0           stream->rdNext = stream->stop;
2025 0           stream->fillBuffProc(stream);
2026 0 0         } while (!stream->isClosed);
2027              
2028 0           close |= FCGX_GetError(stream);
2029             }
2030             }
2031              
2032 4           FCGX_Free(reqDataPtr, close);
2033             }
2034              
2035 4           void FCGX_Free(FCGX_Request * request, int close)
2036             {
2037 4 50         if (request == NULL)
2038 0           return;
2039              
2040 4           FCGX_FreeStream(&request->in);
2041 4           FCGX_FreeStream(&request->out);
2042 4           FCGX_FreeStream(&request->err);
2043 4           FreeParams(&request->paramsPtr);
2044              
2045 4 50         if (close) {
2046 4           OS_IpcClose(request->ipcFd, ! request->detached);
2047 4           request->ipcFd = -1;
2048 4           request->detached = 0;
2049             }
2050             }
2051              
2052 2           int FCGX_OpenSocket(const char *path, int backlog)
2053             {
2054 2           int rc = OS_CreateLocalIpcFd(path, backlog);
2055 2 50         if (rc == FCGI_LISTENSOCK_FILENO && isFastCGI == 0) {
    0          
2056             /* XXX probably need to call OS_LibInit() again for Win */
2057 0           isFastCGI = 1;
2058             }
2059 2           return rc;
2060             }
2061              
2062 4           int FCGX_InitRequest(FCGX_Request *request, int sock, int flags)
2063             {
2064 4           memset(request, 0, sizeof(FCGX_Request));
2065              
2066             /* @@@ Should check that sock is open and listening */
2067 4           request->listen_sock = sock;
2068              
2069             /* @@@ Should validate against "known" flags */
2070 4           request->flags = flags;
2071              
2072 4           request->ipcFd = -1;
2073              
2074 4           return 0;
2075             }
2076              
2077             /*
2078             *----------------------------------------------------------------------
2079             *
2080             * FCGX_Init --
2081             *
2082             * Initilize the FCGX library. This is called by FCGX_Accept()
2083             * but must be called by the user when using FCGX_Accept_r().
2084             *
2085             * Results:
2086             * 0 for successful call.
2087             *
2088             *----------------------------------------------------------------------
2089             */
2090 3           int FCGX_Init(void)
2091             {
2092             char *p;
2093              
2094 3 50         if (libInitialized) {
2095 0           return 0;
2096             }
2097              
2098 3           FCGX_InitRequest(&the_request, FCGI_LISTENSOCK_FILENO, 0);
2099              
2100 3 50         if (OS_LibInit(NULL) == -1) {
2101 0 0         return OS_Errno ? OS_Errno : -9997;
2102             }
2103              
2104 3           p = getenv("FCGI_WEB_SERVER_ADDRS");
2105 3 50         webServerAddressList = p ? StringCopy(p) : NULL;
2106              
2107 3           libInitialized = 1;
2108 3           return 0;
2109             }
2110              
2111             /*
2112             *----------------------------------------------------------------------
2113             *
2114             * FCGX_Accept --
2115             *
2116             * Accepts a new request from the HTTP server.
2117             *
2118             * Results:
2119             * 0 for successful call, -1 for error.
2120             *
2121             * Side effects:
2122             *
2123             * Finishes the request accepted by (and frees any
2124             * storage allocated by) the previous call to FCGX_Accept.
2125             * Creates input, output, and error streams and
2126             * assigns them to *in, *out, and *err respectively.
2127             * Creates a parameters data structure to be accessed
2128             * via getenv(3) (if assigned to environ) or by FCGX_GetParam
2129             * and assigns it to *envp.
2130             *
2131             * DO NOT retain pointers to the envp array or any strings
2132             * contained in it (e.g. to the result of calling FCGX_GetParam),
2133             * since these will be freed by the next call to FCGX_Finish
2134             * or FCGX_Accept.
2135             *
2136             *----------------------------------------------------------------------
2137             */
2138              
2139 0           int FCGX_Accept(
2140             FCGX_Stream **in,
2141             FCGX_Stream **out,
2142             FCGX_Stream **err,
2143             FCGX_ParamArray *envp)
2144             {
2145             int rc;
2146              
2147 0 0         if (! libInitialized) {
2148 0           rc = FCGX_Init();
2149 0 0         if (rc) {
2150 0           return rc;
2151             }
2152             }
2153              
2154 0           rc = FCGX_Accept_r(&the_request);
2155              
2156 0           *in = the_request.in;
2157 0           *out = the_request.out;
2158 0           *err = the_request.err;
2159 0           *envp = the_request.envp;
2160              
2161 0           return rc;
2162             }
2163              
2164             /*
2165             *----------------------------------------------------------------------
2166             *
2167             * FCGX_Accept_r --
2168             *
2169             * Accepts a new request from the HTTP server.
2170             *
2171             * Results:
2172             * 0 for successful call, -1 for error.
2173             *
2174             * Side effects:
2175             *
2176             * Finishes the request accepted by (and frees any
2177             * storage allocated by) the previous call to FCGX_Accept.
2178             * Creates input, output, and error streams and
2179             * assigns them to *in, *out, and *err respectively.
2180             * Creates a parameters data structure to be accessed
2181             * via getenv(3) (if assigned to environ) or by FCGX_GetParam
2182             * and assigns it to *envp.
2183             *
2184             * DO NOT retain pointers to the envp array or any strings
2185             * contained in it (e.g. to the result of calling FCGX_GetParam),
2186             * since these will be freed by the next call to FCGX_Finish
2187             * or FCGX_Accept.
2188             *
2189             *----------------------------------------------------------------------
2190             */
2191 2           int FCGX_Accept_r(FCGX_Request *reqDataPtr)
2192             {
2193 2 50         if (!libInitialized) {
2194 0           return -9998;
2195             }
2196              
2197             /* Finish the current request, if any. */
2198 2           FCGX_Finish_r(reqDataPtr);
2199              
2200             for (;;) {
2201             /*
2202             * If a connection isn't open, accept a new connection (blocking).
2203             * If an OS error occurs in accepting the connection,
2204             * return -1 to the caller, who should exit.
2205             */
2206 2 50         if (reqDataPtr->ipcFd < 0) {
2207 2           int fail_on_intr = reqDataPtr->flags & FCGI_FAIL_ACCEPT_ON_INTR;
2208              
2209 2           reqDataPtr->ipcFd = OS_Accept(reqDataPtr->listen_sock, fail_on_intr, webServerAddressList);
2210 2 50         if (reqDataPtr->ipcFd < 0) {
2211 0 0         return (errno > 0) ? (0 - errno) : -9999;
2212             }
2213             }
2214             /*
2215             * A connection is open. Read from the connection in order to
2216             * get the request's role and environment. If protocol or other
2217             * errors occur, close the connection and try again.
2218             */
2219 2           reqDataPtr->isBeginProcessed = FALSE;
2220 2           reqDataPtr->in = NewReader(reqDataPtr, 8192, 0);
2221 2           FillBuffProc(reqDataPtr->in);
2222 2 50         if(!reqDataPtr->isBeginProcessed) {
2223 0           goto TryAgain;
2224             }
2225             {
2226             char *roleStr;
2227 2           switch(reqDataPtr->role) {
2228             case FCGI_RESPONDER:
2229 2           roleStr = "FCGI_ROLE=RESPONDER";
2230 2           break;
2231             case FCGI_AUTHORIZER:
2232 0           roleStr = "FCGI_ROLE=AUTHORIZER";
2233 0           break;
2234             case FCGI_FILTER:
2235 0           roleStr = "FCGI_ROLE=FILTER";
2236 0           break;
2237             default:
2238 0           goto TryAgain;
2239             }
2240 2           reqDataPtr->paramsPtr = NewParams(30);
2241 2           PutParam(reqDataPtr->paramsPtr, StringCopy(roleStr));
2242             }
2243 2           SetReaderType(reqDataPtr->in, FCGI_PARAMS);
2244 2 50         if(ReadParams(reqDataPtr->paramsPtr, reqDataPtr->in) >= 0) {
2245             /*
2246             * Finished reading the environment. No errors occurred, so
2247             * leave the connection-retry loop.
2248             */
2249 2           break;
2250             }
2251              
2252             /*
2253             * Close the connection and try again.
2254             */
2255             TryAgain:
2256 0           FCGX_Free(reqDataPtr, 1);
2257              
2258 0           } /* for (;;) */
2259             /*
2260             * Build the remaining data structures representing the new
2261             * request and return successfully to the caller.
2262             */
2263 2           SetReaderType(reqDataPtr->in, FCGI_STDIN);
2264 2           reqDataPtr->out = NewWriter(reqDataPtr, 8192, FCGI_STDOUT);
2265 2           reqDataPtr->err = NewWriter(reqDataPtr, 512, FCGI_STDERR);
2266 2           reqDataPtr->nWriters = 2;
2267 2           reqDataPtr->envp = reqDataPtr->paramsPtr->vec;
2268 2           return 0;
2269             }
2270              
2271             /*
2272             *----------------------------------------------------------------------
2273             *
2274             * FCGX_StartFilterData --
2275             *
2276             * stream is an input stream for a FCGI_FILTER request.
2277             * stream is positioned at EOF on FCGI_STDIN.
2278             * Repositions stream to the start of FCGI_DATA.
2279             * If the preconditions are not met (e.g. FCGI_STDIN has not
2280             * been read to EOF) sets the stream error code to
2281             * FCGX_CALL_SEQ_ERROR.
2282             *
2283             * Results:
2284             * 0 for a normal return, < 0 for error
2285             *
2286             *----------------------------------------------------------------------
2287             */
2288              
2289 0           int FCGX_StartFilterData(FCGX_Stream *stream)
2290             {
2291 0           FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
2292 0 0         if(data->reqDataPtr->role != FCGI_FILTER
2293 0 0         || !stream->isReader
2294 0 0         || !stream->isClosed
2295 0 0         || data->type != FCGI_STDIN) {
2296 0           SetError(stream, FCGX_CALL_SEQ_ERROR);
2297 0           return -1;
2298             }
2299 0           SetReaderType(stream, FCGI_DATA);
2300 0           return 0;
2301             }
2302              
2303             /*
2304             *----------------------------------------------------------------------
2305             *
2306             * FCGX_SetExitStatus --
2307             *
2308             * Sets the exit status for stream's request. The exit status
2309             * is the status code the request would have exited with, had
2310             * the request been run as a CGI program. You can call
2311             * SetExitStatus several times during a request; the last call
2312             * before the request ends determines the value.
2313             *
2314             *----------------------------------------------------------------------
2315             */
2316              
2317 0           void FCGX_SetExitStatus(int status, FCGX_Stream *stream)
2318             {
2319 0           FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
2320 0           data->reqDataPtr->appStatus = status;
2321 0           }
2322              
2323              
2324             int
2325 0           FCGX_Attach(FCGX_Request * r)
2326             {
2327 0           r->detached = FALSE;
2328 0           return 0;
2329             }
2330              
2331              
2332             int
2333 0           FCGX_Detach(FCGX_Request * r)
2334             {
2335 0 0         if (r->ipcFd <= 0)
2336             {
2337 0           return -1;
2338             }
2339              
2340 0           r->detached = TRUE;
2341 0           return 0;
2342             }