A little header juggling.
[catagits/fcgi2.git] / libfcgi / fcgi_stdio.c
1 /*
2  * fcgi_stdio.c --
3  *
4  *      FastCGI-stdio compatibility package
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
15 static const char rcsid[] = "$Id: fcgi_stdio.c,v 1.12 2001/06/20 16:04:17 robs Exp $";
16 #endif /* not lint */
17
18 #include <errno.h>  /* for errno */
19 #include <stdarg.h> /* for va_arg */
20 #include <stdlib.h> /* for malloc */
21 #include <string.h> /* for strerror */
22
23 #include "fcgi_config.h"
24
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28
29 #define DLLAPI  __declspec(dllexport)
30
31 #define NO_FCGI_DEFINES
32 #include "fcgi_stdio.h"
33 #undef NO_FCGI_DEFINES
34
35 #include "fcgiapp.h"
36 #include "fcgios.h"
37 #include "fcgimisc.h"
38
39 #ifndef _WIN32
40
41 extern char **environ;
42
43 /* These definitions should be supplied by stdio.h but for some
44  * reason they get lost on certain platforms. */
45 #ifndef fileno
46 extern int fileno(FILE *stream);
47 #endif
48
49 extern FILE *fdopen(int fildes, const char *type);
50 extern FILE *popen(const char *command, const char *type);
51 extern int pclose(FILE *stream);
52
53 #else /* _WIN32 */
54
55 #define popen _popen
56 #define pclose _pclose
57
58 #endif /* _WIN32 */
59
60 FCGI_FILE _fcgi_sF[3];
61
62
63 /*
64  *----------------------------------------------------------------------
65  *
66  * FCGI_Accept --
67  *
68  *      Accepts a new request from the HTTP server and creates
69  *      a conventional execution environment for the request.
70  *
71  *      If the application was invoked as a FastCGI server,
72  *      the first call to FCGI_Accept indicates that the application
73  *      has completed its initialization and is ready to accept
74  *      a request.  Subsequent calls to FCGI_Accept indicate that
75  *      the application has completed its processing of the
76  *      current request and is ready to accept a new request.
77  *
78  *      If the application was invoked as a CGI program, the first
79  *      call to FCGI_Accept is essentially a no-op and the second
80  *      call returns EOF (-1).
81  *
82  * Results:
83  *    0 for successful call, -1 for error (application should exit).
84  *
85  * Side effects:
86  *      If the application was invoked as a FastCGI server,
87  *      and this is not the first call to this procedure,
88  *      FCGI_Accept first performs the equivalent of FCGI_Finish.
89  *
90  *      On every call, FCGI_Accept accepts the new request and
91  *      reads the FCGI_PARAMS stream into an environment array,
92  *      i.e. a NULL-terminated array of strings of the form
93  *      ``name=value''.  It assigns a pointer to this array
94  *      to the global variable environ, used by the standard
95  *      library function getenv.  It creates new FCGI_FILE *s
96  *      representing input from the HTTP server, output to the HTTP
97  *      server, and error output to the HTTP server, and assigns these
98  *      new files to stdin, stdout, and stderr respectively.
99  *
100  *      DO NOT mutate or retain pointers to environ or any values
101  *      contained in it (e.g. to the result of calling getenv(3)),
102  *      since these are freed by the next call to FCGI_Finish or
103  *      FCGI_Accept.  In particular do not use setenv(3) or putenv(3)
104  *      in conjunction with FCGI_Accept.
105  *
106  *----------------------------------------------------------------------
107  */
108 static int acceptCalled = FALSE;
109 static int isCGI = FALSE;
110
111 int FCGI_Accept(void)
112 {
113     if(!acceptCalled) {
114         /*
115          * First call to FCGI_Accept.  Is application running
116          * as FastCGI or as CGI?
117          */
118         isCGI = FCGX_IsCGI();
119         acceptCalled = TRUE;
120         atexit(&FCGI_Finish);
121     } else if(isCGI) {
122         /*
123          * Not first call to FCGI_Accept and running as CGI means
124          * application is done.
125          */
126         return(EOF);
127     }
128     if(isCGI) {
129         FCGI_stdin->stdio_stream = stdin;
130         FCGI_stdin->fcgx_stream = NULL;
131         FCGI_stdout->stdio_stream = stdout;
132         FCGI_stdout->fcgx_stream = NULL;
133         FCGI_stderr->stdio_stream = stderr;
134         FCGI_stderr->fcgx_stream = NULL;
135     } else {
136         FCGX_Stream *in, *out, *error;
137         FCGX_ParamArray envp;
138         int acceptResult = FCGX_Accept(&in, &out, &error, &envp);
139         if(acceptResult < 0) {
140             return acceptResult;
141         }
142         FCGI_stdin->stdio_stream = NULL;
143         FCGI_stdin->fcgx_stream = in;
144         FCGI_stdout->stdio_stream = NULL;
145         FCGI_stdout->fcgx_stream = out;
146         FCGI_stderr->stdio_stream = NULL;
147         FCGI_stderr->fcgx_stream = error;
148         environ = envp;
149     }
150     return 0;
151 }
152
153 /*
154  *----------------------------------------------------------------------
155  *
156  * FCGI_Finish --
157  *
158  *      Finishes the current request from the HTTP server.
159  *
160  * Side effects:
161  *
162  *      Flushes any buffered output to the HTTP server.  Then frees
163  *      all storage allocated by the previous call, including all
164  *      storage reachable from the value of environ set by the previous
165  *      call to FCGI_Accept.
166  *
167  *      DO NOT use stdin, stdout, stderr, or environ between calling
168  *      FCGI_Finish and calling FCGI_Accept.
169  *
170  *      DO NOT mutate or retain pointers to environ or any values
171  *      contained in it (e.g. to the result of calling getenv(3)),
172  *      since these are freed by the next call to FCGI_Finish or
173  *      FCGI_Accept.  In particular do not use setenv(3) or putenv(3)
174  *      in conjunction with FCGI_Accept.
175  *
176  *----------------------------------------------------------------------
177  */
178 void FCGI_Finish(void)
179 {
180     if(!acceptCalled || isCGI) {
181         return;
182     }
183     FCGX_Finish();
184     FCGI_stdin->fcgx_stream = NULL;
185     FCGI_stdout->fcgx_stream = NULL;
186     FCGI_stderr->fcgx_stream = NULL;
187     environ = NULL;
188 }
189
190 /*
191  *----------------------------------------------------------------------
192  *
193  * FCGI_StartFilterData --
194  *
195  *
196  *      The current request is for the filter role, and stdin is
197  *      positioned at EOF of FCGI_STDIN.  The call repositions
198  *      stdin to the start of FCGI_DATA.
199  *      If the preconditions are not met (e.g. FCGI_STDIN has not
200  *      been read to EOF), the call sets the stream error code to
201  *      FCGX_CALL_SEQ_ERROR.
202  *
203  * Results:
204  *      0 for a normal return, < 0 for error
205  *
206  *----------------------------------------------------------------------
207  */
208 int FCGI_StartFilterData(void)
209 {
210     if(FCGI_stdin->stdio_stream) {
211         return -1;
212     } else {
213         return FCGX_StartFilterData(FCGI_stdin->fcgx_stream);
214     }
215 }
216
217 /*
218  *----------------------------------------------------------------------
219  *
220  * FCGI_SetExitStatus --
221  *
222  *      Sets the exit status for the current request. The exit status
223  *      is the status code the request would have exited with, had
224  *      the request been run as a CGI program.  You can call
225  *      FCGI_SetExitStatus several times during a request; the last call
226  *      before the request ends (by calling FCGI_Accept) determines the
227  *      value.
228  *
229  *----------------------------------------------------------------------
230  */
231 void FCGI_SetExitStatus(int status)
232 {
233     if(FCGI_stdin->fcgx_stream) {
234         FCGX_SetExitStatus(status, FCGI_stdin->fcgx_stream);
235     }
236 }
237
238 /*
239  *----------------------------------------------------------------------
240  *
241  * FCGI_perror --
242  *
243  *       Wrapper for function defined in H&S Section 11.2
244  *
245  *----------------------------------------------------------------------
246  */
247 void FCGI_perror(const char *str)
248 {
249     FCGI_fputs(str, FCGI_stderr);
250     FCGI_fputs(": ", FCGI_stderr);
251     FCGI_fputs(strerror(OS_Errno), FCGI_stderr);
252     return;
253 }
254
255 /*
256  *----------------------------------------------------------------------
257  *
258  * FCGI_OpenFromFILE --
259  *
260  *      Constructs a new FCGI_FILE * from the FILE *stream.
261  *
262  * Results:
263  *      NULL if stream == NULL or storage could not be allocated,
264  *      otherwise the new FCGI_FILE *.
265  *
266  *----------------------------------------------------------------------
267  */
268 static FCGI_FILE *FCGI_OpenFromFILE(FILE *stream)
269 {
270     FCGI_FILE *fp;
271
272     if (stream == NULL)
273         return NULL;
274
275     fp = (FCGI_FILE *) malloc(sizeof(FCGI_FILE));
276     if (fp != NULL)
277     {
278         fp->stdio_stream = stream;
279         fp->fcgx_stream = NULL;
280     }
281
282     return fp;
283 }
284
285 /*
286  *----------------------------------------------------------------------
287  *
288  * FCGI_fopen, FCGI_fclose, FCGI_fflush, FCGI_freopen --
289  *
290  *       Wrappers for functions defined in H&S Section 15.2
291  *
292  *----------------------------------------------------------------------
293  */
294 FCGI_FILE *FCGI_fopen(const char *path, const char *mode)
295 {
296     FILE * file = fopen(path, mode);
297     FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
298
299     if (file && !fcgi_file)
300         fclose(file);
301
302     return fcgi_file;
303 }
304
305 int FCGI_fclose(FCGI_FILE *fp)
306 {
307     int n = EOF;
308     if(fp->stdio_stream) {
309         n = fclose(fp->stdio_stream);
310         fp->stdio_stream = NULL;
311     } else if(fp->fcgx_stream) {
312         n = FCGX_FClose(fp->fcgx_stream);
313         fp->fcgx_stream = NULL;
314     }
315     if((fp != FCGI_stdin) && (fp != FCGI_stdout) && (fp != FCGI_stderr)) {
316         free(fp);
317     }
318     return n;
319 }
320
321 int FCGI_fflush(FCGI_FILE *fp)
322 {
323     if(fp == NULL)
324         return fflush(NULL);
325     if(fp->stdio_stream)
326         return fflush(fp->stdio_stream);
327     else if(fp->fcgx_stream)
328         return FCGX_FFlush(fp->fcgx_stream);
329     return EOF;
330 }
331
332 FCGI_FILE *FCGI_freopen(const char *path, const char *mode,
333                         FCGI_FILE *fp)
334 {
335     if(fp->stdio_stream) {
336         if(freopen(path, mode, fp->stdio_stream) == NULL)
337             return NULL;
338         else
339             return fp;
340     } else if(fp->fcgx_stream) {
341         (void) FCGX_FClose(fp->fcgx_stream);
342         fp->stdio_stream = fopen(path, mode);
343         if(fp->stdio_stream == NULL)
344             return NULL;
345         else {
346             fp->fcgx_stream = NULL;
347             return fp;
348         }
349     }
350     return NULL;
351 }
352
353 /*
354  *----------------------------------------------------------------------
355  *
356  * FCGI_setvbuf, FCGI_setbuf --
357  *
358  *       Wrappers for functions defined in H&S Section 15.3
359  *
360  *----------------------------------------------------------------------
361  */
362 int FCGI_setvbuf(FCGI_FILE *fp, char *buf, int bufmode, size_t size)
363 {
364     if(fp->stdio_stream)
365         return setvbuf(fp->stdio_stream, buf, bufmode, size);
366     else {
367         return -1;
368     }
369 }
370
371 void FCGI_setbuf(FCGI_FILE *fp, char *buf)
372 {
373     if(fp->stdio_stream)
374         setbuf(fp->stdio_stream, buf);
375 }
376
377 /*
378  *----------------------------------------------------------------------
379  *
380  * FCGI_fseek, FCGI_ftell, FCGI_rewind, FCGI_fgetpos, FCGI_fsetpos --
381  *
382  *       Wrappers for functions defined in H&S Section 15.5
383  *
384  *----------------------------------------------------------------------
385  */
386 int FCGI_fseek(FCGI_FILE *fp, long offset, int whence)
387 {
388     if(fp->stdio_stream)
389         return fseek(fp->stdio_stream, offset, whence);
390     else {
391         OS_SetErrno(ESPIPE);
392         return -1;
393     }
394 }
395
396 int FCGI_ftell(FCGI_FILE *fp)
397 {
398     if(fp->stdio_stream)
399         return ftell(fp->stdio_stream);
400     else {
401         OS_SetErrno(ESPIPE);
402         return -1;
403     }
404 }
405
406 void FCGI_rewind(FCGI_FILE *fp)
407 {
408     if(fp->stdio_stream)
409         rewind(fp->stdio_stream);
410     else
411         OS_SetErrno(ESPIPE);
412 }
413
414 #ifdef HAVE_FPOS
415 int FCGI_fgetpos(FCGI_FILE *fp, fpos_t *pos)
416 {
417     if(fp->stdio_stream)
418         return fgetpos(fp->stdio_stream, pos);
419     else {
420         OS_SetErrno(ESPIPE);
421         return -1;
422     }
423 }
424
425 int FCGI_fsetpos(FCGI_FILE *fp, const fpos_t *pos)
426 {
427     if(fp->stdio_stream)
428         return fsetpos(fp->stdio_stream, pos);
429     else {
430         OS_SetErrno(ESPIPE);
431         return -1;
432     }
433 }
434 #endif
435
436 /*
437  *----------------------------------------------------------------------
438  *
439  * FCGI_fgetc, FCGI_getchar, FCGI_ungetc --
440  *
441  *       Wrappers for functions defined in H&S Section 15.6
442  *
443  *       XXX: getc and getchar are generally defined as macros
444  *            for performance reasons
445  *
446  *----------------------------------------------------------------------
447  */
448 int FCGI_fgetc(FCGI_FILE *fp)
449 {
450     if(fp->stdio_stream)
451         return fgetc(fp->stdio_stream);
452     else if(fp->fcgx_stream)
453         return FCGX_GetChar(fp->fcgx_stream);
454     return EOF;
455 }
456
457 int FCGI_getchar(void)
458 {
459     return FCGI_fgetc(FCGI_stdin);
460 }
461
462 int FCGI_ungetc(int c, FCGI_FILE *fp)
463 {
464     if(fp->stdio_stream)
465         return ungetc(c, fp->stdio_stream);
466     else if(fp->fcgx_stream)
467         return FCGX_UnGetChar(c, fp->fcgx_stream);
468     return EOF;
469 }
470
471 /*
472  *----------------------------------------------------------------------
473  *
474  * FCGI_fgets, FCGI_gets --
475  *
476  *       Wrappers for functions defined in H&S Section 15.7
477  *
478  *----------------------------------------------------------------------
479  */
480 char *FCGI_fgets(char *str, int size, FCGI_FILE *fp)
481 {
482     if(fp->stdio_stream)
483         return fgets(str, size, fp->stdio_stream);
484     else if(fp->fcgx_stream)
485         return FCGX_GetLine(str, size, fp->fcgx_stream);
486     return NULL;
487 }
488
489 /*
490  * The gets() function reads characters from the standard input stream
491  * into the array pointed to by str until a newline character is read
492  * or an end-of-file condition is encountered.  The newline character
493  * is discarded and the string is terminated with a null character. 
494  */
495 char *FCGI_gets(char *str)
496 {
497     char *s;
498     int c;
499
500     for (s = str; ((c = FCGI_getchar()) != '\n');) {
501         if(c == EOF) {
502             if(s == str)
503                 return NULL;
504             else
505                 break;
506         } else
507             *s++ = (char) c;
508     }
509     *s = 0;
510     return str;
511 }
512
513 /*
514  *----------------------------------------------------------------------
515  *
516  *       Wrappers for functions defined in H&S Section 15.8
517  *
518  *       XXX: missing: fscanf, scanf
519  *
520  *----------------------------------------------------------------------
521  */
522
523 /*
524  *----------------------------------------------------------------------
525  *
526  * FCGI_fputc, FCGI_putchar --
527  *
528  *       Wrappers for functions defined in H&S Section 15.9
529  *
530  *       XXX: putc and putchar are generally defined as macros
531  *            for performance reasons
532  *
533  *----------------------------------------------------------------------
534  */
535 int FCGI_fputc(int c, FCGI_FILE *fp)
536 {
537     if(fp->stdio_stream)
538         return fputc(c, fp->stdio_stream);
539     else if(fp->fcgx_stream)
540         return FCGX_PutChar(c, fp->fcgx_stream);
541     else return EOF;
542 }
543
544 int FCGI_putchar(int c)
545 {
546     return FCGI_fputc(c, FCGI_stdout);
547 }
548
549 /*
550  *----------------------------------------------------------------------
551  *
552  * FCGI_fputs, FCGI_puts
553  *
554  *       Wrappers for functions defined in H&S Section 15.10
555  *
556  *----------------------------------------------------------------------
557  */
558 int FCGI_fputs(const char *str, FCGI_FILE *fp)
559 {
560     if(fp->stdio_stream)
561         return fputs(str, fp->stdio_stream);
562     else if(fp->fcgx_stream)
563         return FCGX_PutS(str, fp->fcgx_stream);
564     return EOF;
565 }
566
567 int FCGI_puts(const char *str)
568 {
569     int n;
570     if(FCGI_stdout->stdio_stream) {
571         n = fputs(str, FCGI_stdout->stdio_stream);
572         if(n < 0)
573             return n;
574         else
575             return fputc('\n', FCGI_stdout->stdio_stream);
576     } else if(FCGI_stdout->fcgx_stream) {
577         n = FCGX_PutS(str, FCGI_stdout->fcgx_stream);
578         if(n < 0)
579             return n;
580         else
581             return FCGX_PutChar('\n', FCGI_stdout->fcgx_stream);
582     }
583     return EOF;
584 }
585
586 /*
587  *----------------------------------------------------------------------
588  *
589  * FCGI_fprintf, FCGI_printf --
590  *
591  *       Wrappers for functions defined in H&S Section 15.11
592  *
593  *----------------------------------------------------------------------
594  */
595 int FCGI_fprintf(FCGI_FILE *fp, const char *format, ...)
596 {
597     va_list ap;
598     int n = 0;
599     va_start(ap, format);
600     if(fp->stdio_stream)
601         n = vfprintf(fp->stdio_stream, format, ap);
602     else if(fp->fcgx_stream)
603         n = FCGX_VFPrintF(fp->fcgx_stream, format, ap);
604     va_end(ap);
605     return n;
606 }
607
608 int FCGI_printf(const char *format, ...)
609 {
610     va_list ap;
611     int n;
612     va_start(ap, format);
613     n = FCGI_vfprintf(FCGI_stdout, format, ap);
614     va_end(ap);
615     return n;
616 }
617
618 /*
619  *----------------------------------------------------------------------
620  *
621  * FCGI_vfprintf, FCGI_vprintf --
622  *
623  *       Wrappers for functions defined in H&S Section 15.12
624  *
625  *----------------------------------------------------------------------
626  */
627 int FCGI_vfprintf(FCGI_FILE *fp, const char *format, va_list ap)
628 {
629     if(fp->stdio_stream)
630         return vfprintf(fp->stdio_stream, format, ap);
631     else if(fp->fcgx_stream)
632         return FCGX_VFPrintF(fp->fcgx_stream, format, ap);
633     return EOF;
634 }
635
636 int FCGI_vprintf(const char *format, va_list ap)
637 {
638     if(FCGI_stdout->stdio_stream)
639         return vfprintf(FCGI_stdout->stdio_stream, format, ap);
640     else if(FCGI_stdout->fcgx_stream)
641         return FCGX_VFPrintF(FCGI_stdout->fcgx_stream, format, ap);
642     return EOF;
643 }
644
645 /*
646  *----------------------------------------------------------------------
647  *
648  * FCGI_fread, FCGI_fwrite --
649  *
650  *       Wrappers for functions defined in H&S Section 15.13
651  *
652  *----------------------------------------------------------------------
653  */
654 size_t FCGI_fread(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp)
655 {
656     int n;
657     if(fp->stdio_stream)
658         return fread(ptr, size, nmemb, fp->stdio_stream);
659     else if(fp->fcgx_stream) {
660         if((size * nmemb) == 0) {
661             return 0;
662         }
663         n = FCGX_GetStr((char *) ptr, size * nmemb, fp->fcgx_stream);
664         return (n/size);
665     }
666     return (size_t)EOF;
667 }
668
669 size_t FCGI_fwrite(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp)
670 {
671     int n;
672     if(fp->stdio_stream)
673         return fwrite(ptr, size, nmemb, fp->stdio_stream);
674     else if(fp->fcgx_stream) {
675         if((size * nmemb) == 0) {
676             return 0;
677         }
678         n = FCGX_PutStr((char *) ptr, size * nmemb, fp->fcgx_stream);
679         return (n/size);
680     }
681     return (size_t)EOF;
682 }
683
684 /*
685  *----------------------------------------------------------------------
686  *
687  * FCGI_feof, FCGI_ferror, FCGI_clearerr --
688  *
689  *       Wrappers for functions defined in H&S Section 15.14
690  *
691  *----------------------------------------------------------------------
692  */
693 int FCGI_feof(FCGI_FILE *fp)
694 {
695     if(fp->stdio_stream) {
696         return feof(fp->stdio_stream);
697     } else if (fp->fcgx_stream){
698         return FCGX_HasSeenEOF(fp->fcgx_stream);
699     }
700     return -1;
701
702 }
703
704 int FCGI_ferror(FCGI_FILE *fp)
705 {
706     if(fp->stdio_stream) {
707         return ferror(fp->stdio_stream);
708     } else if(fp->fcgx_stream) {
709         return FCGX_GetError(fp->fcgx_stream);
710     }
711     return -1;
712 }
713
714 void FCGI_clearerr(FCGI_FILE *fp)
715 {
716     if(fp->stdio_stream) {
717         clearerr(fp->stdio_stream);
718     } else if(fp->fcgx_stream) {
719         FCGX_ClearError(fp->fcgx_stream);
720     }
721     return;
722 }
723
724 /*
725  *----------------------------------------------------------------------
726  *
727  * FCGI_tmpfile --
728  *
729  *       Wrappers for function defined in H&S Section 15.16
730  *
731  *----------------------------------------------------------------------
732  */
733 FCGI_FILE *FCGI_tmpfile(void)
734 {
735     FILE * file = tmpfile();
736     FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
737
738     if (file && !fcgi_file)
739         fclose(file);
740
741     return fcgi_file;
742 }
743
744 /*
745  *----------------------------------------------------------------------
746  *
747  * FCGI_fileno, FCGI_fdopen, FCGI_popen, FCGI_pclose --
748  *
749  *       Wrappers for POSIX, X/OPEN functions not in ISO C
750  *
751  *----------------------------------------------------------------------
752  */
753 int FCGI_fileno(FCGI_FILE *fp)
754 {
755     if(fp->stdio_stream)
756         return fileno(fp->stdio_stream);
757     else
758         return -1;
759 }
760
761 FCGI_FILE *FCGI_fdopen(int fd, const char *mode)
762 {
763     FILE * file = fdopen(fd, mode);
764     FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
765
766     if (file && !fcgi_file)
767         fclose(file);
768
769     return fcgi_file;
770 }
771
772 FCGI_FILE *FCGI_popen(const char *cmd, const char *type)
773 {
774     FILE * file = popen(cmd, type);
775     FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
776
777     if (file && !fcgi_file)
778         pclose(file);
779
780     return fcgi_file;
781 }
782
783 int FCGI_pclose(FCGI_FILE *fp)
784 {
785     int n = EOF;
786     if (fp->stdio_stream) {
787         n = pclose(fp->stdio_stream);
788         fp->stdio_stream = NULL;
789     } else if(fp->fcgx_stream) {
790         /*
791          * The caller is deeply confused; don't free the storage.
792          */
793         return EOF;
794     }
795     if((fp != FCGI_stdin) && (fp != FCGI_stdout) && (fp != FCGI_stderr)) {
796         free(fp);
797     }
798     return n;
799 }