xref: /PHP-5.5/sapi/webjames/webjames.c (revision 73c1be26)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2015 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Author: Alex Waugh <alex@alexwaugh.com>                              |
16    +----------------------------------------------------------------------+
17 */
18 
19 
20 #include "php.h"
21 #include "SAPI.h"
22 #include "php_main.h"
23 #include "php_variables.h"
24 
25 #define WEBJAMES_PHP_ONLY
26 #include "php_webjames.h"
27 
28 #include <unixlib/local.h>
29 
30 #define WEBJAMES_SAPI_VERSION "1.0.2"
31 
32 typedef struct {
33 	struct connection *conn; /*structure holding all the details of the current request*/
34 	int bodyread; /*amount of POST body read*/
35 	closefn oldclose; /*function to call to close the connection*/
36 } php_webjames_globals;
37 
38 static php_webjames_globals webjames_globals;
39 
40 #define WG(v) (webjames_globals.v)
41 
sapi_webjames_ub_write(const char * str,uint str_length TSRMLS_DC)42 static int sapi_webjames_ub_write(const char *str, uint str_length TSRMLS_DC)
43 /*unbuffered write - send data straight out to socket*/
44 {
45 	int totalbytes = 0;
46 
47 	do {
48 		int bytes;
49 		bytes = webjames_writebuffer(WG(conn),str,str_length);
50 		if (bytes<0) {
51 			PG(connection_status) = PHP_CONNECTION_ABORTED;
52 			if (!PG(ignore_user_abort)) {
53 				zend_bailout();
54 			}
55 			return bytes;
56 		}
57 		str += bytes;
58 		str_length -= bytes;
59 		totalbytes += bytes;
60 	} while (str_length);
61 	return totalbytes;
62 }
63 
sapi_webjames_send_header(sapi_header_struct * sapi_header,void * server_context TSRMLS_DC)64 static void sapi_webjames_send_header(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC)
65 /*send an HTTP header*/
66 {
67 	char *header = sapi_header->header;
68 	int len = sapi_header->header_len;
69 	if (WG(conn)->flags.outputheaders) {
70 		while (sapi_header && len > 0) {
71 			int bytes;
72 			bytes = webjames_writebuffer(WG(conn), header, len);
73 			if (bytes<0) {
74 				PG(connection_status) = PHP_CONNECTION_ABORTED;
75 				if (!PG(ignore_user_abort)) {
76 					zend_bailout();
77 				}
78 				return;
79 			}
80 			header += bytes;
81 			len -= bytes;
82 		}
83 		webjames_writestring(WG(conn), "\r\n");
84 	}
85 }
86 
sapi_webjames_read_post(char * buffer,uint count_bytes TSRMLS_DC)87 static int sapi_webjames_read_post(char *buffer, uint count_bytes TSRMLS_DC)
88 /*read some of the post data*/
89 {
90 	if (WG(conn)->body==NULL) return 0;
91 	if (count_bytes+WG(bodyread)>WG(conn)->bodysize) count_bytes=WG(conn)->bodysize-WG(bodyread);
92 	memcpy(buffer, WG(conn)->body+WG(bodyread), count_bytes);
93 	WG(bodyread)+=count_bytes;
94 	return count_bytes;
95 }
96 
sapi_webjames_read_cookies(TSRMLS_D)97 static char *sapi_webjames_read_cookies(TSRMLS_D)
98 {
99 	return WG(conn)->cookie;
100 }
101 
102 #define BUF_SIZE 512
103 #define ADD_STRING(name,string)\
104 	php_register_variable(name, string, track_vars_array TSRMLS_CC)
105 
106 #define ADD_NUM(name,field) {\
107 	snprintf(buf, BUF_SIZE, "%d", WG(conn)->field);\
108 	php_register_variable(name, buf, track_vars_array TSRMLS_CC);\
109 }
110 
111 #define ADD_FIELD(name, field) \
112 	if (WG(conn)->field) { \
113 		php_register_variable(name, WG(conn)->field, track_vars_array TSRMLS_CC); \
114 	}
115 
sapi_webjames_register_variables(zval * track_vars_array TSRMLS_DC)116 static void sapi_webjames_register_variables(zval *track_vars_array TSRMLS_DC)
117 {
118 	char buf[BUF_SIZE + 1];
119 	char *docroot;
120 
121 	buf[BUF_SIZE] = '\0';
122 
123 	ADD_STRING("SERVER_SOFTWARE", configuration.server);
124 	ADD_STRING("SERVER_NAME", configuration.serverip);
125 	ADD_FIELD("SERVER_PROTOCOL", protocol);
126 	ADD_NUM("SERVER_PORT", port);
127 	ADD_STRING("SERVER_ADMIN",configuration.webmaster);
128 	ADD_STRING("GATEWAY_INTERFACE", "CGI/1.1");
129 
130 	docroot = __unixify(WG(conn)->homedir,0,NULL,1024,0);
131 	if (docroot) ADD_STRING("DOCUMENT_ROOT", docroot);
132 
133 	ADD_FIELD("REQUEST_METHOD", methodstr);
134 	ADD_FIELD("REQUEST_URI", requesturi);
135 	ADD_STRING("PATH_TRANSLATED", SG(request_info).path_translated);
136 	ADD_FIELD("SCRIPT_NAME", uri);
137 	ADD_FIELD("PHP_SELF", uri);
138 	ADD_FIELD("QUERY_STRING", args);
139 
140 
141 	snprintf(buf, BUF_SIZE, "%d.%d.%d.%d", WG(conn)->ipaddr[0], WG(conn)->ipaddr[1], WG(conn)->ipaddr[2], WG(conn)->ipaddr[3]);
142 	ADD_STRING("REMOTE_ADDR", buf);
143 	if (WG(conn)->dnsstatus == DNS_OK) ADD_FIELD("REMOTE_HOST", host);
144 
145 	if ((WG(conn)->method == METHOD_POST) || (WG(conn)->method == METHOD_PUT)) {
146 		ADD_NUM("CONTENT_LENGTH", bodysize);
147 		ADD_FIELD("CONTENT_TYPE", type);
148 	}
149 
150 	if ((WG(conn)->method == METHOD_PUT) || (WG(conn)->method == METHOD_DELETE)) ADD_FIELD("ENTITY_PATH", requesturi);
151 
152 	if (WG(conn)->pwd) {
153 		ADD_STRING("AUTH_TYPE", "basic");
154 		ADD_FIELD("REMOTE_USER", authorization);
155 	}
156 
157 	ADD_FIELD("HTTP_COOKIE", cookie);
158 	ADD_FIELD("HTTP_USER_AGENT", useragent);
159 	ADD_FIELD("HTTP_REFERER", referer);
160 	ADD_FIELD("HTTP_ACCEPT", accept);
161 	ADD_FIELD("HTTP_ACCEPT_LANGUAGE", acceptlanguage);
162 	ADD_FIELD("HTTP_ACCEPT_CHARSET", acceptcharset);
163 	ADD_FIELD("HTTP_ACCEPT_ENCODING", acceptencoding);
164 }
165 
webjames_module_main(TSRMLS_D)166 static void webjames_module_main(TSRMLS_D)
167 {
168 	zend_file_handle file_handle;
169 	FILE *fp=NULL;
170 	char *path;
171 
172 	/* Convert filename to Unix format*/
173 	__riscosify_control|=__RISCOSIFY_STRICT_UNIX_SPECS;
174 	path = __unixify(WG(conn)->filename,0,NULL,1024,0);
175 	if (path) SG(request_info).path_translated = estrdup(path);
176 
177 	SG(request_info).query_string = WG(conn)->args;
178 	SG(request_info).request_uri = WG(conn)->requesturi;
179 	SG(request_info).request_method = WG(conn)->methodstr;
180 	if (WG(conn)->method==METHOD_HEAD) {
181 		SG(request_info).headers_only = 1;
182 	} else {
183 		SG(request_info).headers_only = 0;
184 	}
185 	SG(sapi_headers).http_response_code = 200;
186 	SG(request_info).content_type = WG(conn)->type;
187 	SG(request_info).content_length = WG(conn)->bodysize;
188 
189 	SG(request_info).auth_user = NULL;
190 	SG(request_info).auth_password = NULL;
191 	if (WG(conn)->authorization) {
192 		char *colon=strchr(WG(conn)->authorization,':');
193 		if (colon) {
194 			SG(request_info).auth_user = emalloc(colon-WG(conn)->authorization+1);
195 			if (SG(request_info).auth_user) {
196 				memcpy(SG(request_info).auth_user,WG(conn)->authorization,colon-WG(conn)->authorization);
197 				SG(request_info).auth_user[colon-WG(conn)->authorization]='\0';
198 				SG(request_info).auth_password = estrdup(colon+1);
199 			}
200 		}
201 	}
202 
203 	/*ensure that syslog calls get logged separately from WebJames' main log */
204 	openlog("PHP",0,0);
205 
206 	file_handle.type = ZEND_HANDLE_FILENAME;
207 	file_handle.filename = SG(request_info).path_translated;
208 	file_handle.free_filename = 0;
209 	file_handle.opened_path = NULL;
210 
211 	if (php_request_startup(TSRMLS_C) == FAILURE) {
212 		return;
213 	}
214 
215 	php_execute_script(&file_handle TSRMLS_CC);
216 	php_request_shutdown(NULL);
217 }
218 
webjames_php_close(struct connection * conn,int force)219 static void webjames_php_close(struct connection *conn, int force)
220 /*called by webjames if it wants to close the connection*/
221 {
222 	TSRMLS_FETCH();
223 
224 	php_request_shutdown(NULL);
225 	WG(oldclose)(conn,force);
226 }
227 
webjames_php_request(struct connection * conn)228 void webjames_php_request(struct connection *conn)
229 /*called by WebJames to start handler*/
230 {
231 	TSRMLS_FETCH();
232 
233 	WG(conn) = conn;
234 	WG(bodyread) = 0;
235 	WG(oldclose) = conn->close;
236 	conn->close=webjames_php_close;
237 
238 	webjames_module_main(TSRMLS_C);
239 
240 	WG(oldclose)(WG(conn), 0);
241 }
242 
php_info_webjames(ZEND_MODULE_INFO_FUNC_ARGS)243 static void php_info_webjames(ZEND_MODULE_INFO_FUNC_ARGS)
244 {
245 	php_info_print_table_start();
246 	php_info_print_table_row(2, "SAPI module version", WEBJAMES_SAPI_VERSION);
247 	php_info_print_table_row(2, "WebJames version", WEBJAMES_VERSION " (" WEBJAMES_DATE ")");
248 	php_info_print_table_end();
249 }
250 
251 static zend_module_entry php_webjames_module = {
252 #if ZEND_MODULE_API_NO >= 20010901
253     STANDARD_MODULE_HEADER,
254 #endif
255   "WebJames",
256   NULL,
257   NULL,
258   NULL,
259   NULL,
260   NULL,
261   php_info_webjames,
262 #if ZEND_MODULE_API_NO >= 20010901
263   WEBJAMES_SAPI_VERSION,
264 #endif
265   STANDARD_MODULE_PROPERTIES
266 };
267 
268 
php_webjames_startup(sapi_module_struct * sapi_module)269 static int php_webjames_startup(sapi_module_struct *sapi_module)
270 {
271   if(php_module_startup(sapi_module, &php_webjames_module, 1) == FAILURE) {
272     return FAILURE;
273   } else {
274     return SUCCESS;
275   }
276 }
277 
278 static sapi_module_struct sapi_module = {
279 	"webjames",                             /* name */
280 	"WebJames",                             /* pretty name */
281 
282 	php_webjames_startup,                   /* startup */
283 	php_module_shutdown_wrapper,            /* shutdown */
284 
285 	NULL,									/* activate */
286 	NULL,									/* deactivate */
287 
288 	sapi_webjames_ub_write,                 /* unbuffered write */
289 	NULL,                                   /* flush */
290 	NULL,									/* get uid */
291 	NULL,									/* getenv */
292 
293 	php_error,                              /* error handler */
294 
295 	NULL,                                   /* header handler */
296 	NULL,             						/* send headers handler */
297 	sapi_webjames_send_header,              /* send header handler */
298 	sapi_webjames_read_post,                /* read POST data */
299 	sapi_webjames_read_cookies,             /* read Cookies */
300 
301 	sapi_webjames_register_variables,       /* register server variables */
302 	NULL,									/* Log message */
303 	NULL,									/* Get request time */
304 	NULL,									/* Child terminate */
305 
306 	STANDARD_SAPI_MODULE_PROPERTIES
307 };
308 
webjames_php_init(void)309 int webjames_php_init(void)
310 /*called when WebJames initialises*/
311 {
312 	TSRMLS_FETCH();
313 	if (strcmp(configuration.webjames_h_revision,WEBJAMES_H_REVISION)!=0) {
314 		/*This file was compiled against a different revision of
315 		  webjames.h than webjames was, which could be bad news*/
316 		webjames_writelog(0,"PHP module is compiled for WebJames (%s) and was linked with a different version (%s)",WEBJAMES_H_REVISION,configuration.webjames_h_revision);
317 		return 0; /*failed to initialise*/
318 	}
319 	sapi_startup(&sapi_module);
320 	sapi_module.startup(&sapi_module);
321 	SG(server_context) = (void *) 1;
322 	return 1; /*initialised correctly*/
323 }
324 
webjames_php_shutdown(void)325 void webjames_php_shutdown(void)
326 /*called when WebJames is about to quit*/
327 {
328 	sapi_module.shutdown(&sapi_module);
329 	sapi_shutdown();
330 }
331