4 * FastCGI-stdio compatibility package
7 * Copyright (c) 1996 Open Market, Inc.
9 * See the file "LICENSE" for information on usage and redistribution
10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15 static const char rcsid[] = "$Id: fcgi_stdio.c,v 1.14 2001/09/01 01:09:30 robs Exp $";
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 */
23 #include "fcgi_config.h"
30 #define DLLAPI __declspec(dllexport)
37 #define NO_FCGI_DEFINES
38 #include "fcgi_stdio.h"
39 #undef NO_FCGI_DEFINES
43 extern char **environ;
45 #ifdef HAVE_FILENO_PROTO
48 extern int fileno(FILE *stream);
51 extern FILE *fdopen(int fildes, const char *type);
52 extern FILE *popen(const char *command, const char *type);
53 extern int pclose(FILE *stream);
58 #define pclose _pclose
62 FCGI_FILE _fcgi_sF[3];
66 *----------------------------------------------------------------------
70 * Accepts a new request from the HTTP server and creates
71 * a conventional execution environment for the request.
73 * If the application was invoked as a FastCGI server,
74 * the first call to FCGI_Accept indicates that the application
75 * has completed its initialization and is ready to accept
76 * a request. Subsequent calls to FCGI_Accept indicate that
77 * the application has completed its processing of the
78 * current request and is ready to accept a new request.
80 * If the application was invoked as a CGI program, the first
81 * call to FCGI_Accept is essentially a no-op and the second
82 * call returns EOF (-1).
85 * 0 for successful call, -1 for error (application should exit).
88 * If the application was invoked as a FastCGI server,
89 * and this is not the first call to this procedure,
90 * FCGI_Accept first performs the equivalent of FCGI_Finish.
92 * On every call, FCGI_Accept accepts the new request and
93 * reads the FCGI_PARAMS stream into an environment array,
94 * i.e. a NULL-terminated array of strings of the form
95 * ``name=value''. It assigns a pointer to this array
96 * to the global variable environ, used by the standard
97 * library function getenv. It creates new FCGI_FILE *s
98 * representing input from the HTTP server, output to the HTTP
99 * server, and error output to the HTTP server, and assigns these
100 * new files to stdin, stdout, and stderr respectively.
102 * DO NOT mutate or retain pointers to environ or any values
103 * contained in it (e.g. to the result of calling getenv(3)),
104 * since these are freed by the next call to FCGI_Finish or
105 * FCGI_Accept. In particular do not use setenv(3) or putenv(3)
106 * in conjunction with FCGI_Accept.
108 *----------------------------------------------------------------------
110 static int acceptCalled = FALSE;
111 static int isCGI = FALSE;
113 int FCGI_Accept(void)
117 * First call to FCGI_Accept. Is application running
118 * as FastCGI or as CGI?
120 isCGI = FCGX_IsCGI();
122 atexit(&FCGI_Finish);
125 * Not first call to FCGI_Accept and running as CGI means
126 * application is done.
131 FCGI_stdin->stdio_stream = stdin;
132 FCGI_stdin->fcgx_stream = NULL;
133 FCGI_stdout->stdio_stream = stdout;
134 FCGI_stdout->fcgx_stream = NULL;
135 FCGI_stderr->stdio_stream = stderr;
136 FCGI_stderr->fcgx_stream = NULL;
138 FCGX_Stream *in, *out, *error;
139 FCGX_ParamArray envp;
140 int acceptResult = FCGX_Accept(&in, &out, &error, &envp);
141 if(acceptResult < 0) {
144 FCGI_stdin->stdio_stream = NULL;
145 FCGI_stdin->fcgx_stream = in;
146 FCGI_stdout->stdio_stream = NULL;
147 FCGI_stdout->fcgx_stream = out;
148 FCGI_stderr->stdio_stream = NULL;
149 FCGI_stderr->fcgx_stream = error;
156 *----------------------------------------------------------------------
160 * Finishes the current request from the HTTP server.
164 * Flushes any buffered output to the HTTP server. Then frees
165 * all storage allocated by the previous call, including all
166 * storage reachable from the value of environ set by the previous
167 * call to FCGI_Accept.
169 * DO NOT use stdin, stdout, stderr, or environ between calling
170 * FCGI_Finish and calling FCGI_Accept.
172 * DO NOT mutate or retain pointers to environ or any values
173 * contained in it (e.g. to the result of calling getenv(3)),
174 * since these are freed by the next call to FCGI_Finish or
175 * FCGI_Accept. In particular do not use setenv(3) or putenv(3)
176 * in conjunction with FCGI_Accept.
178 *----------------------------------------------------------------------
180 void FCGI_Finish(void)
182 if(!acceptCalled || isCGI) {
186 FCGI_stdin->fcgx_stream = NULL;
187 FCGI_stdout->fcgx_stream = NULL;
188 FCGI_stderr->fcgx_stream = NULL;
193 *----------------------------------------------------------------------
195 * FCGI_StartFilterData --
198 * The current request is for the filter role, and stdin is
199 * positioned at EOF of FCGI_STDIN. The call repositions
200 * stdin to the start of FCGI_DATA.
201 * If the preconditions are not met (e.g. FCGI_STDIN has not
202 * been read to EOF), the call sets the stream error code to
203 * FCGX_CALL_SEQ_ERROR.
206 * 0 for a normal return, < 0 for error
208 *----------------------------------------------------------------------
210 int FCGI_StartFilterData(void)
212 if(FCGI_stdin->stdio_stream) {
215 return FCGX_StartFilterData(FCGI_stdin->fcgx_stream);
220 *----------------------------------------------------------------------
222 * FCGI_SetExitStatus --
224 * Sets the exit status for the current request. The exit status
225 * is the status code the request would have exited with, had
226 * the request been run as a CGI program. You can call
227 * FCGI_SetExitStatus several times during a request; the last call
228 * before the request ends (by calling FCGI_Accept) determines the
231 *----------------------------------------------------------------------
233 void FCGI_SetExitStatus(int status)
235 if(FCGI_stdin->fcgx_stream) {
236 FCGX_SetExitStatus(status, FCGI_stdin->fcgx_stream);
241 *----------------------------------------------------------------------
245 * Wrapper for function defined in H&S Section 11.2
247 *----------------------------------------------------------------------
249 void FCGI_perror(const char *str)
251 FCGI_fputs(str, FCGI_stderr);
252 FCGI_fputs(": ", FCGI_stderr);
253 FCGI_fputs(strerror(OS_Errno), FCGI_stderr);
258 *----------------------------------------------------------------------
260 * FCGI_OpenFromFILE --
262 * Constructs a new FCGI_FILE * from the FILE *stream.
265 * NULL if stream == NULL or storage could not be allocated,
266 * otherwise the new FCGI_FILE *.
268 *----------------------------------------------------------------------
270 static FCGI_FILE *FCGI_OpenFromFILE(FILE *stream)
277 fp = (FCGI_FILE *) malloc(sizeof(FCGI_FILE));
280 fp->stdio_stream = stream;
281 fp->fcgx_stream = NULL;
288 *----------------------------------------------------------------------
290 * FCGI_fopen, FCGI_fclose, FCGI_fflush, FCGI_freopen --
292 * Wrappers for functions defined in H&S Section 15.2
294 *----------------------------------------------------------------------
296 FCGI_FILE *FCGI_fopen(const char *path, const char *mode)
298 FILE * file = fopen(path, mode);
299 FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
301 if (file && !fcgi_file)
307 int FCGI_fclose(FCGI_FILE *fp)
310 if(fp->stdio_stream) {
311 n = fclose(fp->stdio_stream);
312 fp->stdio_stream = NULL;
313 } else if(fp->fcgx_stream) {
314 n = FCGX_FClose(fp->fcgx_stream);
315 fp->fcgx_stream = NULL;
317 if((fp != FCGI_stdin) && (fp != FCGI_stdout) && (fp != FCGI_stderr)) {
323 int FCGI_fflush(FCGI_FILE *fp)
328 return fflush(fp->stdio_stream);
329 else if(fp->fcgx_stream)
330 return FCGX_FFlush(fp->fcgx_stream);
334 FCGI_FILE *FCGI_freopen(const char *path, const char *mode,
337 if(fp->stdio_stream) {
338 if(freopen(path, mode, fp->stdio_stream) == NULL)
342 } else if(fp->fcgx_stream) {
343 (void) FCGX_FClose(fp->fcgx_stream);
344 fp->stdio_stream = fopen(path, mode);
345 if(fp->stdio_stream == NULL)
348 fp->fcgx_stream = NULL;
356 *----------------------------------------------------------------------
358 * FCGI_setvbuf, FCGI_setbuf --
360 * Wrappers for functions defined in H&S Section 15.3
362 *----------------------------------------------------------------------
364 int FCGI_setvbuf(FCGI_FILE *fp, char *buf, int bufmode, size_t size)
367 return setvbuf(fp->stdio_stream, buf, bufmode, size);
373 void FCGI_setbuf(FCGI_FILE *fp, char *buf)
376 setbuf(fp->stdio_stream, buf);
380 *----------------------------------------------------------------------
382 * FCGI_fseek, FCGI_ftell, FCGI_rewind, FCGI_fgetpos, FCGI_fsetpos --
384 * Wrappers for functions defined in H&S Section 15.5
386 *----------------------------------------------------------------------
388 int FCGI_fseek(FCGI_FILE *fp, long offset, int whence)
391 return fseek(fp->stdio_stream, offset, whence);
398 int FCGI_ftell(FCGI_FILE *fp)
401 return ftell(fp->stdio_stream);
408 void FCGI_rewind(FCGI_FILE *fp)
411 rewind(fp->stdio_stream);
417 int FCGI_fgetpos(FCGI_FILE *fp, fpos_t *pos)
420 return fgetpos(fp->stdio_stream, pos);
427 int FCGI_fsetpos(FCGI_FILE *fp, const fpos_t *pos)
430 return fsetpos(fp->stdio_stream, pos);
439 *----------------------------------------------------------------------
441 * FCGI_fgetc, FCGI_getchar, FCGI_ungetc --
443 * Wrappers for functions defined in H&S Section 15.6
445 * XXX: getc and getchar are generally defined as macros
446 * for performance reasons
448 *----------------------------------------------------------------------
450 int FCGI_fgetc(FCGI_FILE *fp)
453 return fgetc(fp->stdio_stream);
454 else if(fp->fcgx_stream)
455 return FCGX_GetChar(fp->fcgx_stream);
459 int FCGI_getchar(void)
461 return FCGI_fgetc(FCGI_stdin);
464 int FCGI_ungetc(int c, FCGI_FILE *fp)
467 return ungetc(c, fp->stdio_stream);
468 else if(fp->fcgx_stream)
469 return FCGX_UnGetChar(c, fp->fcgx_stream);
474 *----------------------------------------------------------------------
476 * FCGI_fgets, FCGI_gets --
478 * Wrappers for functions defined in H&S Section 15.7
480 *----------------------------------------------------------------------
482 char *FCGI_fgets(char *str, int size, FCGI_FILE *fp)
485 return fgets(str, size, fp->stdio_stream);
486 else if(fp->fcgx_stream)
487 return FCGX_GetLine(str, size, fp->fcgx_stream);
492 * The gets() function reads characters from the standard input stream
493 * into the array pointed to by str until a newline character is read
494 * or an end-of-file condition is encountered. The newline character
495 * is discarded and the string is terminated with a null character.
497 char *FCGI_gets(char *str)
502 for (s = str; ((c = FCGI_getchar()) != '\n');) {
516 *----------------------------------------------------------------------
518 * Wrappers for functions defined in H&S Section 15.8
520 * XXX: missing: fscanf, scanf
522 *----------------------------------------------------------------------
526 *----------------------------------------------------------------------
528 * FCGI_fputc, FCGI_putchar --
530 * Wrappers for functions defined in H&S Section 15.9
532 * XXX: putc and putchar are generally defined as macros
533 * for performance reasons
535 *----------------------------------------------------------------------
537 int FCGI_fputc(int c, FCGI_FILE *fp)
540 return fputc(c, fp->stdio_stream);
541 else if(fp->fcgx_stream)
542 return FCGX_PutChar(c, fp->fcgx_stream);
546 int FCGI_putchar(int c)
548 return FCGI_fputc(c, FCGI_stdout);
552 *----------------------------------------------------------------------
554 * FCGI_fputs, FCGI_puts
556 * Wrappers for functions defined in H&S Section 15.10
558 *----------------------------------------------------------------------
560 int FCGI_fputs(const char *str, FCGI_FILE *fp)
563 return fputs(str, fp->stdio_stream);
564 else if(fp->fcgx_stream)
565 return FCGX_PutS(str, fp->fcgx_stream);
569 int FCGI_puts(const char *str)
572 if(FCGI_stdout->stdio_stream) {
573 n = fputs(str, FCGI_stdout->stdio_stream);
577 return fputc('\n', FCGI_stdout->stdio_stream);
578 } else if(FCGI_stdout->fcgx_stream) {
579 n = FCGX_PutS(str, FCGI_stdout->fcgx_stream);
583 return FCGX_PutChar('\n', FCGI_stdout->fcgx_stream);
589 *----------------------------------------------------------------------
591 * FCGI_fprintf, FCGI_printf --
593 * Wrappers for functions defined in H&S Section 15.11
595 *----------------------------------------------------------------------
597 int FCGI_fprintf(FCGI_FILE *fp, const char *format, ...)
601 va_start(ap, format);
603 n = vfprintf(fp->stdio_stream, format, ap);
604 else if(fp->fcgx_stream)
605 n = FCGX_VFPrintF(fp->fcgx_stream, format, ap);
610 int FCGI_printf(const char *format, ...)
614 va_start(ap, format);
615 n = FCGI_vfprintf(FCGI_stdout, format, ap);
621 *----------------------------------------------------------------------
623 * FCGI_vfprintf, FCGI_vprintf --
625 * Wrappers for functions defined in H&S Section 15.12
627 *----------------------------------------------------------------------
629 int FCGI_vfprintf(FCGI_FILE *fp, const char *format, va_list ap)
632 return vfprintf(fp->stdio_stream, format, ap);
633 else if(fp->fcgx_stream)
634 return FCGX_VFPrintF(fp->fcgx_stream, format, ap);
638 int FCGI_vprintf(const char *format, va_list ap)
640 if(FCGI_stdout->stdio_stream)
641 return vfprintf(FCGI_stdout->stdio_stream, format, ap);
642 else if(FCGI_stdout->fcgx_stream)
643 return FCGX_VFPrintF(FCGI_stdout->fcgx_stream, format, ap);
648 *----------------------------------------------------------------------
650 * FCGI_fread, FCGI_fwrite --
652 * Wrappers for functions defined in H&S Section 15.13
654 *----------------------------------------------------------------------
656 size_t FCGI_fread(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp)
660 return fread(ptr, size, nmemb, fp->stdio_stream);
661 else if(fp->fcgx_stream) {
662 if((size * nmemb) == 0) {
665 n = FCGX_GetStr((char *) ptr, size * nmemb, fp->fcgx_stream);
671 size_t FCGI_fwrite(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp)
675 return fwrite(ptr, size, nmemb, fp->stdio_stream);
676 else if(fp->fcgx_stream) {
677 if((size * nmemb) == 0) {
680 n = FCGX_PutStr((char *) ptr, size * nmemb, fp->fcgx_stream);
687 *----------------------------------------------------------------------
689 * FCGI_feof, FCGI_ferror, FCGI_clearerr --
691 * Wrappers for functions defined in H&S Section 15.14
693 *----------------------------------------------------------------------
695 int FCGI_feof(FCGI_FILE *fp)
697 if(fp->stdio_stream) {
698 return feof(fp->stdio_stream);
699 } else if (fp->fcgx_stream){
700 return FCGX_HasSeenEOF(fp->fcgx_stream);
706 int FCGI_ferror(FCGI_FILE *fp)
708 if(fp->stdio_stream) {
709 return ferror(fp->stdio_stream);
710 } else if(fp->fcgx_stream) {
711 return FCGX_GetError(fp->fcgx_stream);
716 void FCGI_clearerr(FCGI_FILE *fp)
718 if(fp->stdio_stream) {
719 clearerr(fp->stdio_stream);
720 } else if(fp->fcgx_stream) {
721 FCGX_ClearError(fp->fcgx_stream);
727 *----------------------------------------------------------------------
731 * Wrappers for function defined in H&S Section 15.16
733 *----------------------------------------------------------------------
735 FCGI_FILE *FCGI_tmpfile(void)
737 FILE * file = tmpfile();
738 FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
740 if (file && !fcgi_file)
747 *----------------------------------------------------------------------
749 * FCGI_fileno, FCGI_fdopen, FCGI_popen, FCGI_pclose --
751 * Wrappers for POSIX, X/OPEN functions not in ISO C
753 *----------------------------------------------------------------------
755 int FCGI_fileno(FCGI_FILE *fp)
758 return fileno(fp->stdio_stream);
763 FCGI_FILE *FCGI_fdopen(int fd, const char *mode)
765 FILE * file = fdopen(fd, mode);
766 FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
768 if (file && !fcgi_file)
774 FCGI_FILE *FCGI_popen(const char *cmd, const char *type)
776 FILE * file = popen(cmd, type);
777 FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
779 if (file && !fcgi_file)
785 int FCGI_pclose(FCGI_FILE *fp)
788 if (fp->stdio_stream) {
789 n = pclose(fp->stdio_stream);
790 fp->stdio_stream = NULL;
791 } else if(fp->fcgx_stream) {
793 * The caller is deeply confused; don't free the storage.
797 if((fp != FCGI_stdin) && (fp != FCGI_stdout) && (fp != FCGI_stderr)) {