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