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