4 * FastCGI-stdio compatibility package
7 * Copyright (c) 1996 Open Market, Inc.
9 * See the file "LICENSE.TERMS" 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.10 2001/06/18 14:44:37 robs Exp $";
18 #include "fcgi_config.h"
21 #define DLLAPI __declspec(dllexport)
22 #define WIN32_LEAN_AND_MEAN
26 #include <errno.h> /* for errno */
27 #include <stdarg.h> /* for va_arg */
28 #include <stdlib.h> /* for malloc */
29 #include <string.h> /* for strerror */
35 #define NO_FCGI_DEFINES
36 #include "fcgi_stdio.h"
37 #undef NO_FCGI_DEFINES
44 extern char **environ;
46 /* These definitions should be supplied by stdio.h but for some
47 * reason they get lost on certain platforms. */
49 extern int fileno(FILE *stream);
52 extern FILE *fdopen(int fildes, const char *type);
53 extern FILE *popen(const char *command, const char *type);
54 extern int pclose(FILE *stream);
59 #define pclose _pclose
71 FCGI_FILE _fcgi_sF[3];
75 *----------------------------------------------------------------------
79 * Accepts a new request from the HTTP server and creates
80 * a conventional execution environment for the request.
82 * If the application was invoked as a FastCGI server,
83 * the first call to FCGI_Accept indicates that the application
84 * has completed its initialization and is ready to accept
85 * a request. Subsequent calls to FCGI_Accept indicate that
86 * the application has completed its processing of the
87 * current request and is ready to accept a new request.
89 * If the application was invoked as a CGI program, the first
90 * call to FCGI_Accept is essentially a no-op and the second
91 * call returns EOF (-1).
94 * 0 for successful call, -1 for error (application should exit).
97 * If the application was invoked as a FastCGI server,
98 * and this is not the first call to this procedure,
99 * FCGI_Accept first performs the equivalent of FCGI_Finish.
101 * On every call, FCGI_Accept accepts the new request and
102 * reads the FCGI_PARAMS stream into an environment array,
103 * i.e. a NULL-terminated array of strings of the form
104 * ``name=value''. It assigns a pointer to this array
105 * to the global variable environ, used by the standard
106 * library function getenv. It creates new FCGI_FILE *s
107 * representing input from the HTTP server, output to the HTTP
108 * server, and error output to the HTTP server, and assigns these
109 * new files to stdin, stdout, and stderr respectively.
111 * DO NOT mutate or retain pointers to environ or any values
112 * contained in it (e.g. to the result of calling getenv(3)),
113 * since these are freed by the next call to FCGI_Finish or
114 * FCGI_Accept. In particular do not use setenv(3) or putenv(3)
115 * in conjunction with FCGI_Accept.
117 *----------------------------------------------------------------------
119 static int acceptCalled = FALSE;
120 static int isCGI = FALSE;
122 int FCGI_Accept(void)
126 * First call to FCGI_Accept. Is application running
127 * as FastCGI or as CGI?
129 isCGI = FCGX_IsCGI();
131 atexit(&FCGI_Finish);
134 * Not first call to FCGI_Accept and running as CGI means
135 * application is done.
140 FCGI_stdin->stdio_stream = stdin;
141 FCGI_stdin->fcgx_stream = NULL;
142 FCGI_stdout->stdio_stream = stdout;
143 FCGI_stdout->fcgx_stream = NULL;
144 FCGI_stderr->stdio_stream = stderr;
145 FCGI_stderr->fcgx_stream = NULL;
147 FCGX_Stream *in, *out, *error;
148 FCGX_ParamArray envp;
149 int acceptResult = FCGX_Accept(&in, &out, &error, &envp);
150 if(acceptResult < 0) {
153 FCGI_stdin->stdio_stream = NULL;
154 FCGI_stdin->fcgx_stream = in;
155 FCGI_stdout->stdio_stream = NULL;
156 FCGI_stdout->fcgx_stream = out;
157 FCGI_stderr->stdio_stream = NULL;
158 FCGI_stderr->fcgx_stream = error;
165 *----------------------------------------------------------------------
169 * Finishes the current request from the HTTP server.
173 * Flushes any buffered output to the HTTP server. Then frees
174 * all storage allocated by the previous call, including all
175 * storage reachable from the value of environ set by the previous
176 * call to FCGI_Accept.
178 * DO NOT use stdin, stdout, stderr, or environ between calling
179 * FCGI_Finish and calling FCGI_Accept.
181 * DO NOT mutate or retain pointers to environ or any values
182 * contained in it (e.g. to the result of calling getenv(3)),
183 * since these are freed by the next call to FCGI_Finish or
184 * FCGI_Accept. In particular do not use setenv(3) or putenv(3)
185 * in conjunction with FCGI_Accept.
187 *----------------------------------------------------------------------
189 void FCGI_Finish(void)
191 if(!acceptCalled || isCGI) {
195 FCGI_stdin->fcgx_stream = NULL;
196 FCGI_stdout->fcgx_stream = NULL;
197 FCGI_stderr->fcgx_stream = NULL;
202 *----------------------------------------------------------------------
204 * FCGI_StartFilterData --
207 * The current request is for the filter role, and stdin is
208 * positioned at EOF of FCGI_STDIN. The call repositions
209 * stdin to the start of FCGI_DATA.
210 * If the preconditions are not met (e.g. FCGI_STDIN has not
211 * been read to EOF), the call sets the stream error code to
212 * FCGX_CALL_SEQ_ERROR.
215 * 0 for a normal return, < 0 for error
217 *----------------------------------------------------------------------
220 int FCGI_StartFilterData(void)
222 if(FCGI_stdin->stdio_stream) {
225 return FCGX_StartFilterData(FCGI_stdin->fcgx_stream);
230 *----------------------------------------------------------------------
232 * FCGI_SetExitStatus --
234 * Sets the exit status for the current request. The exit status
235 * is the status code the request would have exited with, had
236 * the request been run as a CGI program. You can call
237 * FCGI_SetExitStatus several times during a request; the last call
238 * before the request ends (by calling FCGI_Accept) determines the
241 *----------------------------------------------------------------------
244 void FCGI_SetExitStatus(int status)
246 if(FCGI_stdin->fcgx_stream) {
247 FCGX_SetExitStatus(status, FCGI_stdin->fcgx_stream);
252 *----------------------------------------------------------------------
256 * Wrapper for function defined in H&S Section 11.2
258 *----------------------------------------------------------------------
261 void FCGI_perror(const char *str)
263 FCGI_fputs(str, FCGI_stderr);
264 FCGI_fputs(": ", FCGI_stderr);
265 FCGI_fputs(strerror(OS_Errno), FCGI_stderr);
270 *----------------------------------------------------------------------
272 * FCGI_OpenFromFILE --
274 * Constructs a new FCGI_FILE * from the FILE *stream.
277 * NULL if stream == NULL or storage could not be allocated,
278 * otherwise the new FCGI_FILE *.
280 *----------------------------------------------------------------------
283 static FCGI_FILE *FCGI_OpenFromFILE(FILE *stream)
290 fp = (FCGI_FILE *) malloc(sizeof(FCGI_FILE));
293 fp->stdio_stream = stream;
294 fp->fcgx_stream = NULL;
301 *----------------------------------------------------------------------
303 * FCGI_fopen, FCGI_fclose, FCGI_fflush, FCGI_freopen --
305 * Wrappers for functions defined in H&S Section 15.2
307 *----------------------------------------------------------------------
310 FCGI_FILE *FCGI_fopen(const char *path, const char *mode)
312 FILE * file = fopen(path, mode);
313 FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
315 if (file && !fcgi_file)
321 int FCGI_fclose(FCGI_FILE *fp)
324 if(fp->stdio_stream) {
325 n = fclose(fp->stdio_stream);
326 fp->stdio_stream = NULL;
327 } else if(fp->fcgx_stream) {
328 n = FCGX_FClose(fp->fcgx_stream);
329 fp->fcgx_stream = NULL;
331 if((fp != FCGI_stdin) && (fp != FCGI_stdout) && (fp != FCGI_stderr)) {
337 int FCGI_fflush(FCGI_FILE *fp)
342 return fflush(fp->stdio_stream);
343 else if(fp->fcgx_stream)
344 return FCGX_FFlush(fp->fcgx_stream);
348 FCGI_FILE *FCGI_freopen(const char *path, const char *mode,
351 if(fp->stdio_stream) {
352 if(freopen(path, mode, fp->stdio_stream) == NULL)
356 } else if(fp->fcgx_stream) {
357 (void) FCGX_FClose(fp->fcgx_stream);
358 fp->stdio_stream = fopen(path, mode);
359 if(fp->stdio_stream == NULL)
362 fp->fcgx_stream = NULL;
370 *----------------------------------------------------------------------
372 * FCGI_setvbuf, FCGI_setbuf --
374 * Wrappers for functions defined in H&S Section 15.3
376 *----------------------------------------------------------------------
378 int FCGI_setvbuf(FCGI_FILE *fp, char *buf, int bufmode, size_t size)
381 return setvbuf(fp->stdio_stream, buf, bufmode, size);
387 void FCGI_setbuf(FCGI_FILE *fp, char *buf)
390 setbuf(fp->stdio_stream, buf);
394 *----------------------------------------------------------------------
396 * FCGI_fseek, FCGI_ftell, FCGI_rewind, FCGI_fgetpos, FCGI_fsetpos --
398 * Wrappers for functions defined in H&S Section 15.5
400 *----------------------------------------------------------------------
403 int FCGI_fseek(FCGI_FILE *fp, long offset, int whence)
406 return fseek(fp->stdio_stream, offset, whence);
413 int FCGI_ftell(FCGI_FILE *fp)
416 return ftell(fp->stdio_stream);
423 void FCGI_rewind(FCGI_FILE *fp)
426 rewind(fp->stdio_stream);
432 int FCGI_fgetpos(FCGI_FILE *fp, fpos_t *pos)
435 return fgetpos(fp->stdio_stream, pos);
442 int FCGI_fsetpos(FCGI_FILE *fp, const fpos_t *pos)
445 return fsetpos(fp->stdio_stream, pos);
454 *----------------------------------------------------------------------
456 * FCGI_fgetc, FCGI_getchar, FCGI_ungetc --
458 * Wrappers for functions defined in H&S Section 15.6
460 * XXX: getc and getchar are generally defined as macros
461 * for performance reasons
463 *----------------------------------------------------------------------
466 int FCGI_fgetc(FCGI_FILE *fp)
469 return fgetc(fp->stdio_stream);
470 else if(fp->fcgx_stream)
471 return FCGX_GetChar(fp->fcgx_stream);
475 int FCGI_getchar(void)
477 return FCGI_fgetc(FCGI_stdin);
480 int FCGI_ungetc(int c, FCGI_FILE *fp)
483 return ungetc(c, fp->stdio_stream);
484 else if(fp->fcgx_stream)
485 return FCGX_UnGetChar(c, fp->fcgx_stream);
490 *----------------------------------------------------------------------
492 * FCGI_fgets, FCGI_gets --
494 * Wrappers for functions defined in H&S Section 15.7
496 *----------------------------------------------------------------------
499 char *FCGI_fgets(char *str, int size, FCGI_FILE *fp)
502 return fgets(str, size, fp->stdio_stream);
503 else if(fp->fcgx_stream)
504 return FCGX_GetLine(str, size, fp->fcgx_stream);
509 * There is no standard equivalent of gets that takes an explicit
510 * FILE * argument, so the following "wrapper" implements
511 * gets for both FILE * and FCGX_Stream * in terms of FCGI_getchar.
514 char *FCGI_gets(char *str)
518 for (s = str; ((c = FCGI_getchar()) != '\n');) {
532 *----------------------------------------------------------------------
536 * Wrappers for functions defined in H&S Section 15.8
538 * XXX: missing: fscanf, scanf
540 *----------------------------------------------------------------------
545 *----------------------------------------------------------------------
547 * FCGI_fputc, FCGI_putchar --
549 * Wrappers for functions defined in H&S Section 15.9
551 * XXX: putc and putchar are generally defined as macros
552 * for performance reasons
554 *----------------------------------------------------------------------
557 int FCGI_fputc(int c, FCGI_FILE *fp)
560 return fputc(c, fp->stdio_stream);
561 else if(fp->fcgx_stream)
562 return FCGX_PutChar(c, fp->fcgx_stream);
566 int FCGI_putchar(int c)
568 return FCGI_fputc(c, FCGI_stdout);
572 *----------------------------------------------------------------------
574 * FCGI_fputs, FCGI_puts
576 * Wrappers for functions defined in H&S Section 15.10
578 *----------------------------------------------------------------------
581 int FCGI_fputs(const char *str, FCGI_FILE *fp)
584 return fputs(str, fp->stdio_stream);
585 else if(fp->fcgx_stream)
586 return FCGX_PutS(str, fp->fcgx_stream);
590 int FCGI_puts(const char *str)
593 if(FCGI_stdout->stdio_stream) {
594 n = fputs(str, FCGI_stdout->stdio_stream);
598 return fputc('\n', FCGI_stdout->stdio_stream);
599 } else if(FCGI_stdout->fcgx_stream) {
600 n = FCGX_PutS(str, FCGI_stdout->fcgx_stream);
604 return FCGX_PutChar('\n', FCGI_stdout->fcgx_stream);
610 *----------------------------------------------------------------------
612 * FCGI_fprintf, FCGI_printf --
614 * Wrappers for functions defined in H&S Section 15.11
616 *----------------------------------------------------------------------
619 int FCGI_fprintf(FCGI_FILE *fp, const char *format, ...)
623 va_start(ap, format);
625 n = vfprintf(fp->stdio_stream, format, ap);
626 else if(fp->fcgx_stream)
627 n = FCGX_VFPrintF(fp->fcgx_stream, format, ap);
632 int FCGI_printf(const char *format, ...)
636 va_start(ap, format);
637 n = FCGI_vfprintf(FCGI_stdout, format, ap);
643 *----------------------------------------------------------------------
645 * FCGI_vfprintf, FCGI_vprintf --
647 * Wrappers for functions defined in H&S Section 15.12
649 *----------------------------------------------------------------------
652 int FCGI_vfprintf(FCGI_FILE *fp, const char *format, va_list ap)
655 return vfprintf(fp->stdio_stream, format, ap);
656 else if(fp->fcgx_stream)
657 return FCGX_VFPrintF(fp->fcgx_stream, format, ap);
661 int FCGI_vprintf(const char *format, va_list ap)
663 if(FCGI_stdout->stdio_stream)
664 return vfprintf(FCGI_stdout->stdio_stream, format, ap);
665 else if(FCGI_stdout->fcgx_stream)
666 return FCGX_VFPrintF(FCGI_stdout->fcgx_stream, format, ap);
671 *----------------------------------------------------------------------
673 * FCGI_fread, FCGI_fwrite --
675 * Wrappers for functions defined in H&S Section 15.13
677 *----------------------------------------------------------------------
680 size_t FCGI_fread(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp)
684 return fread(ptr, size, nmemb, fp->stdio_stream);
685 else if(fp->fcgx_stream) {
686 if((size * nmemb) == 0) {
689 n = FCGX_GetStr((char *) ptr, size * nmemb, fp->fcgx_stream);
695 size_t FCGI_fwrite(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp)
699 return fwrite(ptr, size, nmemb, fp->stdio_stream);
700 else if(fp->fcgx_stream) {
701 if((size * nmemb) == 0) {
704 n = FCGX_PutStr((char *) ptr, size * nmemb, fp->fcgx_stream);
711 *----------------------------------------------------------------------
713 * FCGI_feof, FCGI_ferror, FCGI_clearerr --
715 * Wrappers for functions defined in H&S Section 15.14
717 *----------------------------------------------------------------------
719 int FCGI_feof(FCGI_FILE *fp)
721 if(fp->stdio_stream) {
722 return feof(fp->stdio_stream);
723 } else if (fp->fcgx_stream){
724 return FCGX_HasSeenEOF(fp->fcgx_stream);
730 int FCGI_ferror(FCGI_FILE *fp)
732 if(fp->stdio_stream) {
733 return ferror(fp->stdio_stream);
734 } else if(fp->fcgx_stream) {
735 return FCGX_GetError(fp->fcgx_stream);
740 void FCGI_clearerr(FCGI_FILE *fp)
742 if(fp->stdio_stream) {
743 clearerr(fp->stdio_stream);
744 } else if(fp->fcgx_stream) {
745 FCGX_ClearError(fp->fcgx_stream);
751 *----------------------------------------------------------------------
755 * Wrappers for function defined in H&S Section 15.16
757 *----------------------------------------------------------------------
759 FCGI_FILE *FCGI_tmpfile(void)
761 FILE * file = tmpfile();
762 FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
764 if (file && !fcgi_file)
772 *----------------------------------------------------------------------
774 * FCGI_fileno, FCGI_fdopen, FCGI_popen, FCGI_pclose --
776 * Wrappers for POSIX, X/OPEN functions not in ISO C
778 *----------------------------------------------------------------------
781 int FCGI_fileno(FCGI_FILE *fp)
784 return fileno(fp->stdio_stream);
789 FCGI_FILE *FCGI_fdopen(int fd, const char *mode)
791 FILE * file = fdopen(fd, mode);
792 FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
794 if (file && !fcgi_file)
800 FCGI_FILE *FCGI_popen(const char *cmd, const char *type)
802 FILE * file = popen(cmd, type);
803 FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
805 if (file && !fcgi_file)
811 int FCGI_pclose(FCGI_FILE *fp)
814 if (fp->stdio_stream) {
815 n = pclose(fp->stdio_stream);
816 fp->stdio_stream = NULL;
817 } else if(fp->fcgx_stream) {
819 * The caller is deeply confused; don't free the storage.
823 if((fp != FCGI_stdin) && (fp != FCGI_stdout) && (fp != FCGI_stderr)) {
830 *----------------------------------------------------------------------