Fix OS_Accept arg on Win32.
[catagits/fcgi2.git] / libfcgi / fcgiapp.c
CommitLineData
ae0319bf 1/*
0198fd3c 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 */
0198fd3c 13#ifndef lint
3da6011f 14static const char rcsid[] = "$Id: fcgiapp.c,v 1.11 1999/08/10 22:27:12 roberts Exp $";
0198fd3c 15#endif /* not lint */
16
6ad90ad2 17#include "fcgi_config.h"
18
0198fd3c 19#ifdef _WIN32
20#define DLLAPI __declspec(dllexport)
21#endif
22
6ad90ad2 23#include <assert.h>
24#include <errno.h>
25#include <fcntl.h> /* for fcntl */
26#include <math.h>
27#include <memory.h> /* for memchr() */
28#include <stdarg.h>
0198fd3c 29#include <stdio.h>
6ad90ad2 30#include <stdlib.h>
31#include <string.h>
0198fd3c 32#include <sys/types.h>
6ad90ad2 33
34#ifdef HAVE_SYS_SOCKET_H
35#include <sys/socket.h> /* for getpeername */
36#endif
37
0198fd3c 38#ifdef HAVE_SYS_TIME_H
39#include <sys/time.h>
40#endif
41
0198fd3c 42#ifdef HAVE_UNISTD_H
43#include <unistd.h>
44#endif
45
0198fd3c 46#include "fcgimisc.h"
0198fd3c 47#include "fcgiappmisc.h"
48#include "fastcgi.h"
49#include "fcgios.h"
6ad90ad2 50#include "fcgiapp.h"
0198fd3c 51
52/*
ae0319bf 53 * This is a workaround for one version of the HP C compiler
0198fd3c 54 * (c89 on HP-UX 9.04, also Stratus FTX), which will dump core
55 * if given 'long double' for varargs.
56 */
57#ifdef HAVE_VA_ARG_LONG_DOUBLE_BUG
58#define LONG_DOUBLE double
59#else
60#define LONG_DOUBLE long double
61#endif
62
5a7cc494 63/*
ae0319bf 64 * Globals
5a7cc494 65 */
66static int libInitialized = 0;
165bb74e 67static int isFastCGI = -1;
5a7cc494 68static char *webServerAddressList = NULL;
69static FCGX_Request reqData;
70static FCGX_Request *reqDataPtr = &reqData;
71
0198fd3c 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);
aadcc3c8 82 char *newString = (char *)Malloc(strLen + 1);
0198fd3c 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;
ae0319bf 194 else
0198fd3c 195 break;
ae0319bf 196 }
0198fd3c 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.
ae0319bf 262 *
0198fd3c 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.
ae0319bf 290 *
0198fd3c 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.
ae0319bf 336 *
0198fd3c 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.
ae0319bf 355 *
0198fd3c 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.
ae0319bf 379 *
0198fd3c 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) {
aadcc3c8 422 percentPtr = (char *)memchr(f, '%', fStop - f);
0198fd3c 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 *);
a25dc891 575 if (!charPtrArg) charPtrArg = "(null)";
0198fd3c 576 if(precision == -1) {
577 buffReqd = strlen(charPtrArg);
578 } else {
aadcc3c8 579 p = (char *)memchr(charPtrArg, '\0', precision);
0198fd3c 580 buffReqd =
581 (p == NULL) ? precision : p - charPtrArg;
582 }
583 break;
584 case 'f':
585 switch(sizeModifier) {
586 case ' ':
587 doubleArg = va_arg(arg, double);
588 frexp(doubleArg, &exp);
589 break;
590 case 'L':
591 lDoubleArg = va_arg(arg, LONG_DOUBLE);
592 frexp(lDoubleArg, &exp);
593 break;
594 default:
595 goto ErrorReturn;
596 }
597 if(precision == -1) precision = 6;
598 buffReqd = precision + 3 + ((exp > 0) ? exp/3 : 0);
599 break;
600 case 'e':
601 case 'E':
602 case 'g':
603 case 'G':
604 if(precision == -1) precision = 6;
605 buffReqd = precision + 8;
606 break;
607 case 'n':
608 case '%':
609 default:
610 goto ErrorReturn;
611 break;
612 }
613 buffReqd = max(buffReqd + 10, minWidth);
614 /*
615 * Allocate the buffer
616 */
617 if(buffReqd <= PRINTF_BUFFLEN) {
618 buffPtr = buff;
619 buffLen = PRINTF_BUFFLEN;
620 } else {
621 if(auxBuffPtr == NULL || buffReqd > auxBuffLen) {
622 if(auxBuffPtr != NULL) free(auxBuffPtr);
aadcc3c8 623 auxBuffPtr = (char *)Malloc(buffReqd);
0198fd3c 624 auxBuffLen = buffReqd;
625 if(auxBuffPtr == NULL) goto ErrorReturn;
626 }
627 buffPtr = auxBuffPtr;
628 buffLen = auxBuffLen;
629 }
630 }
631 /*
632 * This giant switch statement requires the following variables
633 * to be set up: op, sizeModifier, arg, buffPtr, fmtBuff.
634 * When fastPath == FALSE and op == 's' or 'f', the argument
635 * has been read into charPtrArg, doubleArg, or lDoubleArg.
636 * The statement produces the boolean performedOp, TRUE iff
637 * the op/sizeModifier were executed and argument consumed;
638 * if performedOp, the characters written into buffPtr[]
639 * and the character count buffCount (== EOF meaning error).
640 *
641 * The switch cases are arranged in the same order as in the
642 * description of fprintf in section 15.11 of Harbison and Steele.
643 */
644 performedOp = TRUE;
645 switch(op) {
646 case 'd':
647 case 'i':
648 switch(sizeModifier) {
649 case ' ':
650 intArg = va_arg(arg, int);
651 sprintf(buffPtr, fmtBuff, intArg);
652 buffCount = strlen(buffPtr);
653 break;
654 case 'l':
655 longArg = va_arg(arg, long);
656 sprintf(buffPtr, fmtBuff, longArg);
657 buffCount = strlen(buffPtr);
658 break;
659 case 'h':
660 shortArg = va_arg(arg, short);
661 sprintf(buffPtr, fmtBuff, shortArg);
662 buffCount = strlen(buffPtr);
663 break;
664 default:
665 goto ErrorReturn;
666 }
667 break;
668 case 'u':
669 case 'o':
670 case 'x':
671 case 'X':
672 switch(sizeModifier) {
673 case ' ':
674 unsignedArg = va_arg(arg, unsigned);
675 sprintf(buffPtr, fmtBuff, unsignedArg);
676 buffCount = strlen(buffPtr);
677 break;
678 case 'l':
679 uLongArg = va_arg(arg, unsigned long);
680 sprintf(buffPtr, fmtBuff, uLongArg);
681 buffCount = strlen(buffPtr);
682 break;
683 case 'h':
684 uShortArg = va_arg(arg, unsigned short);
685 sprintf(buffPtr, fmtBuff, uShortArg);
686 buffCount = strlen(buffPtr);
687 break;
688 default:
689 goto ErrorReturn;
690 }
691 break;
692 case 'c':
693 switch(sizeModifier) {
694 case ' ':
695 intArg = va_arg(arg, int);
696 sprintf(buffPtr, fmtBuff, intArg);
697 buffCount = strlen(buffPtr);
698 break;
699 case 'l':
700 /*
701 * XXX: Allowed by ISO C Amendment 1, but
702 * many platforms don't yet support wint_t
703 */
704 goto ErrorReturn;
705 default:
706 goto ErrorReturn;
707 }
708 break;
709 case 's':
710 switch(sizeModifier) {
711 case ' ':
712 if(fastPath) {
713 buffPtr = va_arg(arg, char *);
714 buffCount = strlen(buffPtr);
715 buffLen = buffCount + 1;
716 } else {
717 sprintf(buffPtr, fmtBuff, charPtrArg);
718 buffCount = strlen(buffPtr);
719 }
720 break;
721 case 'l':
722 /*
723 * XXX: Don't know how to convert a sequence
724 * of wide characters into a byte stream, or
725 * even how to predict the buffering required.
726 */
727 goto ErrorReturn;
728 default:
729 goto ErrorReturn;
730 }
731 break;
732 case 'p':
733 if(sizeModifier != ' ') goto ErrorReturn;
734 voidPtrArg = va_arg(arg, void *);
735 sprintf(buffPtr, fmtBuff, voidPtrArg);
736 buffCount = strlen(buffPtr);
737 break;
738 case 'n':
739 switch(sizeModifier) {
740 case ' ':
741 intPtrArg = va_arg(arg, int *);
742 *intPtrArg = streamCount;
743 break;
744 case 'l':
745 longPtrArg = va_arg(arg, long *);
746 *longPtrArg = streamCount;
747 break;
748 case 'h':
749 shortPtrArg = va_arg(arg, short *);
750 *shortPtrArg = streamCount;
751 break;
752 default:
753 goto ErrorReturn;
754 }
755 buffCount = 0;
756 break;
757 case 'f':
758 if(fastPath) {
759 performedOp = FALSE;
760 break;
761 }
762 switch(sizeModifier) {
763 case ' ':
764 sprintf(buffPtr, fmtBuff, doubleArg);
765 buffCount = strlen(buffPtr);
766 break;
767 case 'L':
768 sprintf(buffPtr, fmtBuff, lDoubleArg);
769 buffCount = strlen(buffPtr);
770 break;
771 default:
772 goto ErrorReturn;
773 }
774 break;
775 case 'e':
776 case 'E':
777 case 'g':
778 case 'G':
779 switch(sizeModifier) {
780 case ' ':
781 doubleArg = va_arg(arg, double);
782 sprintf(buffPtr, fmtBuff, doubleArg);
783 buffCount = strlen(buffPtr);
784 break;
785 case 'L':
786 lDoubleArg = va_arg(arg, LONG_DOUBLE);
787 sprintf(buffPtr, fmtBuff, lDoubleArg);
788 buffCount = strlen(buffPtr);
789 break;
790 default:
791 goto ErrorReturn;
792 }
793 break;
794 case '%':
795 if(sizeModifier != ' ')
796 goto ErrorReturn;
797 buff[0] = '%';
798 buffCount = 1;
799 break;
800 case '\0':
801 goto ErrorReturn;
802 default:
803 performedOp = FALSE;
804 break;
805 } /* switch(op) */
806 if(performedOp) break;
807 if(!fastPath) goto ErrorReturn;
808 fastPath = FALSE;
809 } /* for (;;) */
810 ASSERT(buffCount < buffLen);
811 if(buffCount > 0) {
812 if(FCGX_PutStr(buffPtr, buffCount, stream) < 0)
813 goto ErrorReturn;
814 streamCount += buffCount;
815 } else if(buffCount < 0) {
816 goto ErrorReturn;
817 }
818 f += specifierLength;
819 } /* while(f != fStop) */
820 goto NormalReturn;
821 ErrorReturn:
822 streamCount = -1;
823 NormalReturn:
824 if(auxBuffPtr != NULL) free(auxBuffPtr);
825 return streamCount;
826}
827
828/*
829 * Copy n characters from *srcPtr to *destPtr, then increment
830 * both *srcPtr and *destPtr by n.
831 */
832static void CopyAndAdvance(char **destPtr, char **srcPtr, int n)
833{
834 char *dest = *destPtr;
835 char *src = *srcPtr;
836 int i;
837 for (i = 0; i < n; i++)
838 *dest++ = *src++;
839 *destPtr = dest;
840 *srcPtr = src;
841}
842\f
843/*
844 *----------------------------------------------------------------------
845 *
846 * FCGX_FFlush --
847 *
848 * Flushes any buffered output.
849 *
850 * Server-push is a legitimate application of FCGX_FFlush.
851 * Otherwise, FCGX_FFlush is not very useful, since FCGX_Accept
852 * does it implicitly. FCGX_FFlush may reduce performance
853 * by increasing the total number of operating system calls
854 * the application makes.
855 *
856 * Results:
857 * EOF (-1) if an error occurred.
ae0319bf 858 *
0198fd3c 859 *----------------------------------------------------------------------
860 */
861int FCGX_FFlush(FCGX_Stream *stream)
862{
863 if(stream->isClosed || stream->isReader)
864 return 0;
865 stream->emptyBuffProc(stream, FALSE);
866 return (stream->isClosed) ? -1 : 0;
867}
868\f
869/*
870 *----------------------------------------------------------------------
871 *
872 * FCGX_FClose --
873 *
874 * Performs FCGX_FFlush and closes the stream.
875 *
876 * This is not a very useful operation, since FCGX_Accept
877 * does it implicitly. Closing the out stream before the
878 * err stream results in an extra write if there's nothing
879 * in the err stream, and therefore reduces performance.
880 *
881 * Results:
882 * EOF (-1) if an error occurred.
ae0319bf 883 *
0198fd3c 884 *----------------------------------------------------------------------
885 */
886int FCGX_FClose(FCGX_Stream *stream)
887{
888 if(!stream->wasFCloseCalled) {
889 if(!stream->isReader) {
890 stream->emptyBuffProc(stream, TRUE);
891 }
892 stream->wasFCloseCalled = TRUE;
893 stream->isClosed = TRUE;
894 if(stream->isReader) {
895 stream->wrNext = stream->stop = stream->rdNext;
896 } else {
897 stream->rdNext = stream->stop = stream->wrNext;
898 }
899 }
900 return (stream->FCGI_errno == 0) ? 0 : EOF;
901}
902\f
903/*
904 *----------------------------------------------------------------------
905 *
906 * SetError --
907 *
908 * An error has occurred; save the error code in the stream
909 * for diagnostic purposes and set the stream state so that
910 * reads return EOF and writes have no effect.
911 *
912 *----------------------------------------------------------------------
913 */
914static void SetError(FCGX_Stream *stream, int FCGI_errno)
915{
916 /*
917 * Preserve only the first error.
918 */
919 if(stream->FCGI_errno == 0) {
920 stream->FCGI_errno = FCGI_errno;
921 stream->isClosed = TRUE;
922 }
923}
924
925/*
926 *----------------------------------------------------------------------
927 *
928 * FCGX_GetError --
929 *
930 * Return the stream error code. 0 means no error, > 0
931 * is an errno(2) error, < 0 is an FCGX_errno error.
932 *
933 *----------------------------------------------------------------------
934 */
935int FCGX_GetError(FCGX_Stream *stream) {
936 return stream->FCGI_errno;
937}
938
939/*
940 *----------------------------------------------------------------------
941 *
942 * FCGX_ClearError --
943 *
944 * Clear the stream error code and end-of-file indication.
945 *
946 *----------------------------------------------------------------------
947 */
948void FCGX_ClearError(FCGX_Stream *stream) {
949 stream->FCGI_errno = 0;
950 /*
951 * stream->isClosed = FALSE;
952 * XXX: should clear isClosed but work is needed to make it safe
953 * to do so. For example, if an application calls FClose, gets
954 * an I/O error on the write, calls ClearError and retries
955 * the FClose, FClose (really EmptyBuffProc) will write a second
956 * EOF record. If an application calls PutChar instead of FClose
957 * after the ClearError, the application will write more data.
958 * The stream's state must discriminate between various states
959 * of the stream that are now all lumped under isClosed.
960 */
961}
962\f
963/*
964 *======================================================================
965 * Parameters
966 *======================================================================
967 */
968
969/*
970 * A vector of pointers representing the parameters received
971 * by a FastCGI application server, with the vector's length
972 * and last valid element so adding new parameters is efficient.
973 */
974
975typedef struct Params {
976 FCGX_ParamArray vec; /* vector of strings */
977 int length; /* number of string vec can hold */
978 char **cur; /* current item in vec; *cur == NULL */
979} Params;
980typedef Params *ParamsPtr;
981\f
982/*
983 *----------------------------------------------------------------------
984 *
985 * NewParams --
986 *
987 * Creates a new Params structure.
988 *
989 * Results:
990 * Pointer to the new structure.
991 *
992 *----------------------------------------------------------------------
993 */
994static ParamsPtr NewParams(int length)
995{
996 ParamsPtr result;
aadcc3c8 997 result = (Params *)Malloc(sizeof(Params));
998 result->vec = (char **)Malloc(length * sizeof(char *));
0198fd3c 999 result->length = length;
1000 result->cur = result->vec;
1001 *result->cur = NULL;
1002 return result;
1003}
1004\f
1005/*
1006 *----------------------------------------------------------------------
1007 *
1008 * FreeParams --
1009 *
1010 * Frees a Params structure and all the parameters it contains.
1011 *
1012 * Side effects:
0b7c9662 1013 * env becomes invalid.
0198fd3c 1014 *
1015 *----------------------------------------------------------------------
1016 */
1017static void FreeParams(ParamsPtr *paramsPtrPtr)
1018{
1019 ParamsPtr paramsPtr = *paramsPtrPtr;
1020 char **p;
1021 if(paramsPtr == NULL) {
1022 return;
1023 }
1024 for (p = paramsPtr->vec; p < paramsPtr->cur; p++) {
1025 free(*p);
1026 }
1027 free(paramsPtr->vec);
1028 free(paramsPtr);
1029 *paramsPtrPtr = NULL;
1030}
1031\f
1032/*
1033 *----------------------------------------------------------------------
1034 *
1035 * PutParam --
1036 *
1037 * Add a name/value pair to a Params structure.
1038 *
1039 * Results:
1040 * None.
1041 *
ae0319bf 1042 * Side effects:
0198fd3c 1043 * Parameters structure updated.
1044 *
1045 *----------------------------------------------------------------------
ae0319bf 1046 */
0198fd3c 1047static void PutParam(ParamsPtr paramsPtr, char *nameValue)
1048{
1049 int size;
1050
1051 *paramsPtr->cur++ = nameValue;
1052 size = paramsPtr->cur - paramsPtr->vec;
1053 if(size >= paramsPtr->length) {
1054 paramsPtr->length *= 2;
aadcc3c8 1055 paramsPtr->vec = (FCGX_ParamArray)realloc(paramsPtr->vec, paramsPtr->length * sizeof(char *));
0198fd3c 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 */
aadcc3c8 1141 nameValue = (char *)Malloc(nameLen + valueLen + 2);
0198fd3c 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{
aadcc3c8 1296 FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
0198fd3c 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;
ae0319bf 1333
19d98b91 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{
aadcc3c8 1356 FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
0198fd3c 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{
aadcc3c8 1424 FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
0198fd3c 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{
aadcc3c8 1497 FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
0198fd3c 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{
aadcc3c8 1558 FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
0198fd3c 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{
aadcc3c8 1594 FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
0198fd3c 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 */
aadcc3c8 1733 FCGX_Stream *stream = (FCGX_Stream *)Malloc(sizeof(FCGX_Stream));
1734 FCGX_Stream_Data *data = (FCGX_Stream_Data *)Malloc(sizeof(FCGX_Stream_Data));
0198fd3c 1735 data->reqDataPtr = reqDataPtr;
1736 bufflen = AlignInt8(min(max(bufflen, 32), FCGI_MAX_LENGTH + 1));
1737 data->bufflen = bufflen;
aadcc3c8 1738 data->mBuff = (unsigned char *)Malloc(bufflen);
0198fd3c 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 }
aadcc3c8 1796 data = (FCGX_Stream_Data *)stream->data;
0198fd3c 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{
aadcc3c8 1815 FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
0198fd3c 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{
aadcc3c8 1878 FCGX_Request *reqDataPtr = (FCGX_Request *)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 *
0198fd3c 1907 *----------------------------------------------------------------------
1908 */
1909int FCGX_IsCGI(void)
1910{
5a7cc494 1911 if (isFastCGI != -1) {
1912 return !isFastCGI;
0198fd3c 1913 }
ae0319bf 1914
5a7cc494 1915 if (!libInitialized) {
1916 int rc = FCGX_Init();
1917 if (rc) {
1918 /* exit() isn't great, but hey */
1919 exit((rc < 0) ? rc : -rc);
1920 }
ae0319bf 1921 }
0198fd3c 1922
0b7c9662 1923 isFastCGI = OS_IsFcgi(FCGI_LISTENSOCK_FILENO);
5a7cc494 1924
1925 return !isFastCGI;
0198fd3c 1926}
1927\f
1928/*
1929 *----------------------------------------------------------------------
1930 *
1931 * FCGX_Finish --
1932 *
1933 * Finishes the current request from the HTTP server.
1934 *
1935 * Side effects:
1936 *
1937 * Finishes the request accepted by (and frees any
1938 * storage allocated by) the previous call to FCGX_Accept.
1939 *
1940 * DO NOT retain pointers to the envp array or any strings
1941 * contained in it (e.g. to the result of calling FCGX_GetParam),
1942 * since these will be freed by the next call to FCGX_Finish
1943 * or FCGX_Accept.
1944 *
1945 *----------------------------------------------------------------------
1946 */
0198fd3c 1947
1948void FCGX_Finish(void)
1949{
5a7cc494 1950 FCGX_Finish_r(reqDataPtr);
1951}
1952
1953/*
1954 *----------------------------------------------------------------------
1955 *
1956 * FCGX_Finish_r --
1957 *
1958 * Finishes the current request from the HTTP server.
1959 *
1960 * Side effects:
1961 *
1962 * Finishes the request accepted by (and frees any
1963 * storage allocated by) the previous call to FCGX_Accept.
1964 *
1965 * DO NOT retain pointers to the envp array or any strings
1966 * contained in it (e.g. to the result of calling FCGX_GetParam),
1967 * since these will be freed by the next call to FCGX_Finish
1968 * or FCGX_Accept.
1969 *
1970 *----------------------------------------------------------------------
1971 */
1972void FCGX_Finish_r(FCGX_Request *reqDataPtr)
1973{
1974 if (reqDataPtr == NULL) {
1975 return;
1976 }
1977
0b7c9662 1978 if (reqDataPtr->in) {
1979 int errStatus = FCGX_FClose(reqDataPtr->err);
1980 int outStatus = FCGX_FClose(reqDataPtr->out);
5a7cc494 1981
ae0319bf 1982 if (errStatus || outStatus
0b7c9662 1983 || FCGX_GetError(reqDataPtr->in)
ae0319bf 1984 || !reqDataPtr->keepConnection)
5a7cc494 1985 {
1986 OS_IpcClose(reqDataPtr->ipcFd);
1987 }
1988
0198fd3c 1989 ASSERT(reqDataPtr->nWriters == 0);
5a7cc494 1990
0b7c9662 1991 FreeStream(&reqDataPtr->in);
1992 FreeStream(&reqDataPtr->out);
1993 FreeStream(&reqDataPtr->err);
5a7cc494 1994
0198fd3c 1995 FreeParams(&reqDataPtr->paramsPtr);
5a7cc494 1996 }
1997
1998 if (!reqDataPtr->keepConnection) {
1999 reqDataPtr->ipcFd = -1;
0198fd3c 2000 }
2001}
5a7cc494 2002
0b7c9662 2003int FCGX_OpenSocket(const char *path, int backlog)
2004{
165bb74e 2005 int rc = OS_CreateLocalIpcFd(path, backlog);
2006 if (rc == FCGI_LISTENSOCK_FILENO && isFastCGI == 0) {
2007 /* XXX probably need to call OS_LibInit() again for Win */
2008 isFastCGI = 1;
2009 }
3da6011f 2010 return rc;
0b7c9662 2011}
2012
2013int FCGX_InitRequest(FCGX_Request *request, int sock, int flags)
5a7cc494 2014{
2015 memset(request, 0, sizeof(FCGX_Request));
0b7c9662 2016
2017 /* @@@ Should check that sock is open and listening */
2018 request->listen_sock = sock;
2019
2020 /* @@@ Should validate against "known" flags */
2021 request->flags = flags;
2022
2023 return 0;
5a7cc494 2024}
2025
2026/*
2027 *----------------------------------------------------------------------
2028 *
2029 * FCGX_Init --
2030 *
2031 * Initilize the FCGX library. This is called by FCGX_Accept()
2032 * but must be called by the user when using FCGX_Accept_r().
2033 *
2034 * Results:
2035 * 0 for successful call.
2036 *
2037 *----------------------------------------------------------------------
2038 */
2039int FCGX_Init(void)
2040{
2041 char *p;
ae0319bf 2042
5a7cc494 2043 if (libInitialized) {
2044 return 0;
2045 }
2046
2047 /* If our compiler doesn't play by the ISO rules for struct layout, halt. */
2048 ASSERT(sizeof(FCGI_Header) == FCGI_HEADER_LEN);
2049
0b7c9662 2050 FCGX_InitRequest(&reqData, FCGI_LISTENSOCK_FILENO, 0);
5a7cc494 2051
2052 if (OS_LibInit(NULL) == -1) {
2053 return OS_Errno ? OS_Errno : -9997;
2054 }
2055
2056 p = getenv("FCGI_WEB_SERVER_ADDRS");
2057 webServerAddressList = p ? StringCopy(p) : "";
ae0319bf 2058
5a7cc494 2059 libInitialized = 1;
2060 return 0;
2061}
2062
0198fd3c 2063/*
2064 *----------------------------------------------------------------------
2065 *
2066 * FCGX_Accept --
2067 *
2068 * Accepts a new request from the HTTP server.
2069 *
2070 * Results:
2071 * 0 for successful call, -1 for error.
2072 *
2073 * Side effects:
2074 *
2075 * Finishes the request accepted by (and frees any
2076 * storage allocated by) the previous call to FCGX_Accept.
2077 * Creates input, output, and error streams and
2078 * assigns them to *in, *out, and *err respectively.
2079 * Creates a parameters data structure to be accessed
2080 * via getenv(3) (if assigned to environ) or by FCGX_GetParam
2081 * and assigns it to *envp.
2082 *
2083 * DO NOT retain pointers to the envp array or any strings
2084 * contained in it (e.g. to the result of calling FCGX_GetParam),
2085 * since these will be freed by the next call to FCGX_Finish
2086 * or FCGX_Accept.
2087 *
2088 *----------------------------------------------------------------------
2089 */
0198fd3c 2090
2091int FCGX_Accept(
2092 FCGX_Stream **in,
2093 FCGX_Stream **out,
2094 FCGX_Stream **err,
2095 FCGX_ParamArray *envp)
2096{
165bb74e 2097 int rc;
2098
5a7cc494 2099 if (!libInitialized) {
165bb74e 2100 if ((rc = FCGX_Init())) {
5a7cc494 2101 return (rc < 0) ? rc : -rc;
2102 }
ae0319bf 2103 }
0198fd3c 2104
165bb74e 2105 rc = FCGX_Accept_r(&reqData);
2106
2107 *in = reqData.in;
2108 *out = reqData.out;
2109 *err = reqData.err;
2110 *envp = reqData.envp;
2111
2112 return rc;
5a7cc494 2113}
0198fd3c 2114
5a7cc494 2115/*
2116 *----------------------------------------------------------------------
2117 *
2118 * FCGX_Accept_r --
2119 *
2120 * Accepts a new request from the HTTP server.
2121 *
2122 * Results:
2123 * 0 for successful call, -1 for error.
2124 *
2125 * Side effects:
2126 *
2127 * Finishes the request accepted by (and frees any
2128 * storage allocated by) the previous call to FCGX_Accept.
2129 * Creates input, output, and error streams and
2130 * assigns them to *in, *out, and *err respectively.
2131 * Creates a parameters data structure to be accessed
2132 * via getenv(3) (if assigned to environ) or by FCGX_GetParam
2133 * and assigns it to *envp.
2134 *
2135 * DO NOT retain pointers to the envp array or any strings
2136 * contained in it (e.g. to the result of calling FCGX_GetParam),
2137 * since these will be freed by the next call to FCGX_Finish
2138 * or FCGX_Accept.
2139 *
2140 *----------------------------------------------------------------------
2141 */
0b7c9662 2142int FCGX_Accept_r(FCGX_Request *reqDataPtr)
5a7cc494 2143{
2144 if (!libInitialized) {
2145 return -9998;
0198fd3c 2146 }
5a7cc494 2147
2148 /* Finish the current request, if any. */
2149 FCGX_Finish_r(reqDataPtr);
2150
2151 for (;;) {
0198fd3c 2152 /*
2153 * If a connection isn't open, accept a new connection (blocking).
2154 * If an OS error occurs in accepting the connection,
2155 * return -1 to the caller, who should exit.
2156 */
5a7cc494 2157 if (reqDataPtr->ipcFd < 0) {
0b7c9662 2158 int fail_on_intr = reqDataPtr->flags & FCGI_FAIL_ACCEPT_ON_INTR;
2159
2160 reqDataPtr->ipcFd = OS_Accept(reqDataPtr->listen_sock, fail_on_intr, webServerAddressList);
5a7cc494 2161 if (reqDataPtr->ipcFd < 0) {
2162 return (errno > 0) ? (0 - errno) : -9999;
2163 }
2164 }
0198fd3c 2165 /*
2166 * A connection is open. Read from the connection in order to
2167 * get the request's role and environment. If protocol or other
2168 * errors occur, close the connection and try again.
2169 */
2170 reqDataPtr->isBeginProcessed = FALSE;
0b7c9662 2171 reqDataPtr->in = NewReader(reqDataPtr, 8192, 0);
2172 FillBuffProc(reqDataPtr->in);
0198fd3c 2173 if(!reqDataPtr->isBeginProcessed) {
2174 goto TryAgain;
2175 }
2176 {
2177 char *roleStr;
2178 switch(reqDataPtr->role) {
2179 case FCGI_RESPONDER:
2180 roleStr = "FCGI_ROLE=RESPONDER";
2181 break;
2182 case FCGI_AUTHORIZER:
2183 roleStr = "FCGI_ROLE=AUTHORIZER";
2184 break;
2185 case FCGI_FILTER:
2186 roleStr = "FCGI_ROLE=FILTER";
2187 break;
2188 default:
2189 goto TryAgain;
2190 }
2191 reqDataPtr->paramsPtr = NewParams(30);
2192 PutParam(reqDataPtr->paramsPtr, StringCopy(roleStr));
2193 }
0b7c9662 2194 SetReaderType(reqDataPtr->in, FCGI_PARAMS);
2195 if(ReadParams(reqDataPtr->paramsPtr, reqDataPtr->in) >= 0) {
0198fd3c 2196 /*
2197 * Finished reading the environment. No errors occurred, so
2198 * leave the connection-retry loop.
2199 */
2200 break;
2201 }
2202 /*
2203 * Close the connection and try again.
2204 */
2205 TryAgain:
2206 FreeParams(&reqDataPtr->paramsPtr);
0b7c9662 2207 FreeStream(&reqDataPtr->in);
0198fd3c 2208 OS_Close(reqDataPtr->ipcFd);
2209 reqDataPtr->ipcFd = -1;
2210 } /* for (;;) */
2211 /*
2212 * Build the remaining data structures representing the new
2213 * request and return successfully to the caller.
2214 */
0b7c9662 2215 SetReaderType(reqDataPtr->in, FCGI_STDIN);
2216 reqDataPtr->out = NewWriter(reqDataPtr, 8192, FCGI_STDOUT);
2217 reqDataPtr->err = NewWriter(reqDataPtr, 512, FCGI_STDERR);
0198fd3c 2218 reqDataPtr->nWriters = 2;
165bb74e 2219 reqDataPtr->envp = reqDataPtr->paramsPtr->vec;
0198fd3c 2220 return 0;
2221}
2222\f
2223/*
2224 *----------------------------------------------------------------------
2225 *
2226 * FCGX_StartFilterData --
2227 *
2228 * stream is an input stream for a FCGI_FILTER request.
2229 * stream is positioned at EOF on FCGI_STDIN.
2230 * Repositions stream to the start of FCGI_DATA.
2231 * If the preconditions are not met (e.g. FCGI_STDIN has not
2232 * been read to EOF) sets the stream error code to
2233 * FCGX_CALL_SEQ_ERROR.
2234 *
2235 * Results:
ae0319bf 2236 * 0 for a normal return, < 0 for error
0198fd3c 2237 *
2238 *----------------------------------------------------------------------
2239 */
2240
2241int FCGX_StartFilterData(FCGX_Stream *stream)
2242{
aadcc3c8 2243 FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
0198fd3c 2244 if(data->reqDataPtr->role != FCGI_FILTER
2245 || !stream->isReader
2246 || !stream->isClosed
2247 || data->type != FCGI_STDIN) {
2248 SetError(stream, FCGX_CALL_SEQ_ERROR);
2249 return -1;
2250 }
0b7c9662 2251 SetReaderType(reqDataPtr->in, FCGI_DATA);
0198fd3c 2252 return 0;
2253}
2254\f
2255/*
2256 *----------------------------------------------------------------------
2257 *
2258 * FCGX_SetExitStatus --
2259 *
2260 * Sets the exit status for stream's request. The exit status
2261 * is the status code the request would have exited with, had
2262 * the request been run as a CGI program. You can call
2263 * SetExitStatus several times during a request; the last call
2264 * before the request ends determines the value.
2265 *
2266 *----------------------------------------------------------------------
2267 */
2268
2269void FCGX_SetExitStatus(int status, FCGX_Stream *stream)
2270{
aadcc3c8 2271 FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data;
0198fd3c 2272 data->reqDataPtr->appStatus = status;
2273}
5a7cc494 2274