1 /* fastcgi_wrappers.c
2
3 These functions are in a separate file that includes the FastCGI
4 headers, which override the normal stdio routines.
5
6 Copyright (C) 2003 Alma Mater Software, Inc.
7 Author: "John Kelley Hinsdale" <hin@alma.com>
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 2
11 or (at your option) any later version
12 as published by the Free Software Foundation; see file GNU-GPL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software Foundation,
21 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
23 */
24
25 #include "config.h"
26
27 #include <unistd.h>
28
29 #ifdef _WIN32
30 #include <process.h>
31 #else
32 extern char **environ;
33 #endif
34
35 #include <stdlib.h> /* for malloc() */
36
37 /* For strchr(), strncmp() and friends */
38 #include <string.h>
39
40 #include "fcgi_stdio.h"
41
42 /* Crank this up as needed */
43 #define TEMPBUFSIZE 65536
44
45 #ifdef __FreeBSD__
t_strndup(const char * string,size_t n)46 char* t_strndup(const char* string, size_t n)
47 {
48 char* copy_string = 0;
49
50 if(0 == string || 0 == n)
51 return 0;
52
53 copy_string = (char*) malloc(n + 1);
54 if(0 == copy_string)
55 return 0;
56
57 memcpy(copy_string, string, n);
58 *(copy_string + n) = '\0';
59
60 return copy_string;
61 }
62 #endif
63
64 /* Local functions */
65 static char * read_stdio(FILE *);
66 static int write_stdio(FILE *, char *, int);
67 static void hexify (unsigned char *, int) ;
68
69 /* Externally visible functions */
70
71 /* Search environment for variable */
fcgi_getenv(char * var)72 char * fcgi_getenv(char * var) {
73 char **envp = environ;
74 for ( ; *envp != NULL; envp++) {
75 char * equ = strchr(*envp, '=');
76 if ( ! equ )
77 continue;
78 /* FIXME implement exact match, not prefix matching */
79 if ( 0 == strncmp(var, *envp, equ - *envp) )
80 return equ + 1;
81 }
82 /* Variable not found in environment */
83 return NULL;
84 }
85
86
87 /* Return the entire enviroment as a null-terminated linearized string
88 array, e.g.: { "KEY0", "VAL0", "KEY1", "VAL1", NULL } */
89
fcgi_env()90 char ** fcgi_env() {
91 char **envp = environ, **result = NULL;
92 int nvar = 0, i;
93
94 /* Count up # of vars. Allocate space for array of twice that many
95 strings (key & value for each env var) plus a terminating NULL
96 pointer. */
97 for ( ; *envp != NULL; envp++ )
98 nvar++;
99 result = (char **) malloc(sizeof(*result) * (2 * nvar + 1));
100 if ( ! result ) return NULL;
101
102 envp = environ;
103 i = 0;
104 for ( ; *envp != NULL; envp++, i+=2 ) {
105 char * equ = strchr(*envp, '=');
106 if ( ! equ ) {
107 /* Env. string is ot of form KEY=VAL. Unclear if this ever
108 occurs. If it does, treat the whole thing as the variable
109 and map it to NIL; this is distinct from "VAR=" which will
110 map to the empty string */
111 result[i] = strdup(*envp);
112 result[i+1] = NULL;
113 }
114 else {
115 #ifdef __FreeBSD__
116 result[i] = t_strndup(*envp, equ - *envp);
117 #else
118 result[i] = strndup(*envp, equ - *envp);
119 #endif
120 result[i+1] = strdup(equ + 1);
121 }
122 }
123
124 /* Terminate string array */
125 result[i] = NULL;
126 return result;
127 }
128
129
130 /* Read some bytes from stdin. Return a null-terminated hex string. This
131 does NOT necessarily read up to end of file, but rather will read until
132 its buffer is full. Therefore, if you want to slurp in the entire contents
133 of STDIN (which you usually do) you have to call this repeatedly.
134
135 */
fcgi_read_stdin()136 char * fcgi_read_stdin() {
137 return read_stdio(stdin);
138 }
read_stdio(FILE * f)139 static char * read_stdio(FILE * f) {
140
141 static unsigned char buf[2 * TEMPBUFSIZE + 1];
142 size_t nact = 0;
143
144 if ( ! feof(f) )
145 nact = fread(buf, 1, TEMPBUFSIZE, f);
146 if ( ferror(f) )
147 nact = 0;
148 hexify(buf, nact);
149 return buf;
150 }
151
152 /* Write to stdout or stderr */
fcgi_write_stdout(char * data,int len)153 int fcgi_write_stdout(char * data, int len) {
154 return write_stdio(stdout, data, len);
155 }
fcgi_write_stderr(char * data,int len)156 int fcgi_write_stderr(char * data, int len) {
157 return write_stdio(stderr, data, len);
158 }
write_stdio(FILE * f,char * data,int len)159 int write_stdio(FILE * f, char * data, int len) {
160 return fwrite(data, 1, len, f);
161 }
162
163 /* Wrappers. Can protect from possible implementation of FastCGI
164 API as preprocessor macros.
165 Reduces potential for #include conflicts in the generated *.c file.
166 Also useful to decouple prototypes as defined in fcgiapp.h and
167 fcgi_stdio.h from these declared on the Lisp side
168 (e.g. bool/int or short/long) -- rather hypothetical.
169 */
fcgi_is_cgi_wrapper()170 int fcgi_is_cgi_wrapper() {
171 return FCGX_IsCGI();
172 }
fcgi_accept_wrapper()173 int fcgi_accept_wrapper() {
174 return FCGI_Accept();
175 }
fcgi_finish_wrapper()176 void fcgi_finish_wrapper() {
177 FCGI_Finish();
178 }
179
180 /* Convert a binary buffer to null-terminated hex in place. Actual
181 allocation of buf must be twice N plus 1. Work from the end to the
182 start so we don't stomp on ourselves. */
183 /* Convert int to hex */
184 #define itoh(n)(((n) > 9) ? ((n) - 10 + 'A') : ((n) + '0'))
hexify(unsigned char * buf,int n)185 static void hexify (unsigned char * buf, int n)
186 {
187 int i;
188 for ( i = n-1; i >= 0; i-- ) {
189 unsigned char c = buf[i];
190 buf[2*i] = itoh(c / 16);
191 buf[2*i + 1] = itoh(c & 0xF);
192 }
193
194 /* Null terminate */
195 buf[2*n] = '\0';
196 }
197