xref: /PHP-5.5/sapi/pi3web/pi3web_sapi.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    | Pi3Web version 2.0                                                   |
16    +----------------------------------------------------------------------+
17    | This file is committed by the Pi3 development group.                 |
18    | (pi3web.sourceforge.net)                                             |
19    |                                                                      |
20    | Author: Holger Zimmermann (zimpel@users.sourceforge.net)             |
21    +----------------------------------------------------------------------+
22  */
23 
24 /* $Id$ */
25 
26 #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
27 
28 #include "php.h"
29 #include "php_main.h"
30 #include "php_variables.h"
31 #include "SAPI.h"
32 #include "php_globals.h"
33 #include "ext/standard/info.h"
34 #include "zend_highlight.h"
35 #include "zend_indent.h"
36 #include "zend_alloc.h"
37 #include "ext/standard/basic_functions.h"
38 #include "TSRM/TSRM.h"
39 #include "PiAPI.h"
40 #include "Pi3API.h"
41 
42 #include "pi3web_sapi.h"
43 
44 #define PI3WEB_SERVER_VAR_BUF_SIZE 1024
45 
46 int IWasLoaded=0;
47 
48 
php_info_pi3web(ZEND_MODULE_INFO_FUNC_ARGS)49 static void php_info_pi3web(ZEND_MODULE_INFO_FUNC_ARGS)
50 {
51 	char variable_buf[PI3WEB_SERVER_VAR_BUF_SIZE];
52 	DWORD variable_len;
53 	LPCONTROL_BLOCK lpCB = (LPCONTROL_BLOCK) SG(server_context);
54 	PIDB *pDB = (PIDB *)lpCB->GetVariableNames(lpCB->ConnID);
55 	PIDBIterator *pIter = PIDB_getIterator( pDB, PIDBTYPE_STRING, 0, 0 );
56 
57 	PUTS("<table border=0 cellpadding=3 cellspacing=1 width=600 align=center>\n");
58 	PUTS("<tr><th colspan=2 bgcolor=\"" PHP_HEADER_COLOR "\">Pi3Web Server Information</th></tr>\n");
59 	php_info_print_table_header(2, "Information Field", "Value");
60 	php_info_print_table_row(2, "Pi3Web SAPI module version", "$Id$");
61 	php_info_print_table_row(2, "Server Name Stamp", HTTPCore_getServerStamp());
62 	snprintf(variable_buf, 511, "%d", HTTPCore_debugEnabled());
63 	php_info_print_table_row(2, "Debug Enabled", variable_buf);
64 	PIPlatform_getCurrentDirectory( variable_buf, PI3WEB_SERVER_VAR_BUF_SIZE);
65 	php_info_print_table_row(2, "Current Path", variable_buf);
66 	if (lpCB->GetServerVariable(lpCB->ConnID, "SERVER_NAME", variable_buf, &variable_len)
67 		&& variable_buf[0]) {
68 		php_info_print_table_row(2, "Main Virtual Hostname", variable_buf);
69 	};
70 	snprintf(variable_buf, 511, "%d", PIPlatform_getProcessId());
71 	php_info_print_table_row(2, "Server PID", variable_buf);
72 	php_info_print_table_row(2, "Server Platform", PIPlatform_getDescription());
73 
74 	PUTS("</table><br />");
75 
76 	PUTS("<table border=0 cellpadding=3 cellspacing=1 width=600 align=center>\n");
77 	PUTS("<tr><th colspan=2 bgcolor=\"" PHP_HEADER_COLOR "\">HTTP Request Information</th></tr>\n");
78 	php_info_print_table_row(2, "HTTP Request Line", lpCB->lpszReq);
79 	PUTS("<tr><th colspan=2 bgcolor=\"" PHP_HEADER_COLOR "\">HTTP Headers</th></tr>\n");
80 	php_info_print_table_header(2, "Server Variable", "Value");
81 
82 	/* --- loop over all registered server variables --- */
83 	for(; pIter && PIDBIterator_atValidElement( pIter ); PIDBIterator_next( pIter ) )
84 	{
85 		PCHAR pKey;
86 		PIDBIterator_current( pIter, &pKey );
87 		if ( !pKey ) { /* sanity */ continue; };
88 
89 		variable_len = PI3WEB_SERVER_VAR_BUF_SIZE;
90 		if (lpCB->GetServerVariable(lpCB->ConnID, pKey, variable_buf, &variable_len)
91 			&& variable_buf[0]) {
92 			php_info_print_table_row(2, pKey, variable_buf);
93 		} else if (PIPlatform_getLastError() == PIAPI_EINVAL) {
94 			char *tmp_variable_buf;
95 
96 			tmp_variable_buf = (char *) emalloc(variable_len);
97 			if (lpCB->GetServerVariable(lpCB->ConnID, pKey, tmp_variable_buf, &variable_len)
98 				&& variable_buf[0]) {
99 				php_info_print_table_row(2, pKey, tmp_variable_buf);
100 			}
101 			efree(tmp_variable_buf);
102 		}
103 	}
104 
105 	PUTS("</table>");
106 }
107 
108 
109 static zend_module_entry php_pi3web_module = {
110 	STANDARD_MODULE_HEADER,
111 	"PI3WEB",
112 	NULL,
113 	NULL,
114 	NULL,
115 	NULL,
116 	NULL,
117 	php_info_pi3web,
118 	NULL,
119 	STANDARD_MODULE_PROPERTIES
120 };
121 
122 
zend_pi3web_ub_write(const char * str,uint str_length TSRMLS_DC)123 static int zend_pi3web_ub_write(const char *str, uint str_length TSRMLS_DC)
124 {
125 	DWORD num_bytes = str_length;
126 	LPCONTROL_BLOCK cb;
127 
128 	cb = (LPCONTROL_BLOCK) SG(server_context);
129 
130 	if ( !IWasLoaded ) return 0;
131 	cb->WriteClient(cb->ConnID, (char *) str, &num_bytes, 0 );
132 
133 	if (num_bytes != str_length)
134 		php_handle_aborted_connection();
135 	return num_bytes;
136 }
137 
138 
sapi_pi3web_header_handler(sapi_header_struct * sapi_header,sapi_headers_struct * sapi_headers TSRMLS_DC)139 static int sapi_pi3web_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC)
140 {
141 	return SAPI_HEADER_ADD;
142 }
143 
144 
accumulate_header_length(sapi_header_struct * sapi_header,uint * total_length TSRMLS_DC)145 static void accumulate_header_length(sapi_header_struct *sapi_header, uint *total_length TSRMLS_DC)
146 {
147 	*total_length += sapi_header->header_len+2;
148 }
149 
150 
concat_header(sapi_header_struct * sapi_header,char ** combined_headers_ptr TSRMLS_DC)151 static void concat_header(sapi_header_struct *sapi_header, char **combined_headers_ptr TSRMLS_DC)
152 {
153 	memcpy(*combined_headers_ptr, sapi_header->header, sapi_header->header_len);
154 	*combined_headers_ptr += sapi_header->header_len;
155 	**combined_headers_ptr = '\r';
156 	(*combined_headers_ptr)++;
157 	**combined_headers_ptr = '\n';
158 	(*combined_headers_ptr)++;
159 }
160 
161 
sapi_pi3web_send_headers(sapi_headers_struct * sapi_headers TSRMLS_DC)162 static int sapi_pi3web_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
163 {
164 	uint total_length = 2;		/* account for the trailing \r\n */
165 	char *combined_headers, *combined_headers_ptr;
166 	LPCONTROL_BLOCK lpCB = (LPCONTROL_BLOCK) SG(server_context);
167 	sapi_header_struct default_content_type;
168 
169 	if ( !IWasLoaded ) return SAPI_HEADER_SENT_SUCCESSFULLY;
170 
171 
172  	if (SG(sapi_headers).send_default_content_type) {
173 		sapi_get_default_content_type_header(&default_content_type TSRMLS_CC);
174 		accumulate_header_length(&default_content_type, (void *) &total_length TSRMLS_CC);
175 	}
176 	zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) accumulate_header_length, (void *) &total_length TSRMLS_CC);
177 
178 	/* Generate headers */
179 	combined_headers = (char *) emalloc(total_length+1);
180 	combined_headers_ptr = combined_headers;
181 	if (SG(sapi_headers).send_default_content_type) {
182 		concat_header(&default_content_type, (void *) &combined_headers_ptr TSRMLS_CC);
183 		sapi_free_header(&default_content_type); /* we no longer need it */
184 	}
185 	zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) concat_header, (void *) &combined_headers_ptr TSRMLS_CC);
186 	*combined_headers_ptr++ = '\r';
187 	*combined_headers_ptr++ = '\n';
188 	*combined_headers_ptr = 0;
189 
190 	lpCB->dwHttpStatusCode = SG(sapi_headers).http_response_code;
191 	lpCB->SendHeaderFunction(lpCB->ConnID, &total_length, (LPDWORD) combined_headers);
192 
193 	efree(combined_headers);
194 	if (SG(sapi_headers).http_status_line) {
195 		efree(SG(sapi_headers).http_status_line);
196 		SG(sapi_headers).http_status_line = 0;
197 	}
198 	return SAPI_HEADER_SENT_SUCCESSFULLY;
199 }
200 
201 
php_pi3web_startup(sapi_module_struct * sapi_module)202 static int php_pi3web_startup(sapi_module_struct *sapi_module)
203 {
204 	if (php_module_startup(sapi_module, &php_pi3web_module, 1)==FAILURE) {
205 		return FAILURE;
206 	} else {
207 		return SUCCESS;
208 	}
209 }
210 
211 
sapi_pi3web_read_post(char * buffer,uint count_bytes TSRMLS_DC)212 static int sapi_pi3web_read_post(char *buffer, uint count_bytes TSRMLS_DC)
213 {
214 	LPCONTROL_BLOCK lpCB = (LPCONTROL_BLOCK) SG(server_context);
215 	DWORD read_from_buf=0;
216 	DWORD read_from_input=0;
217 	DWORD total_read=0;
218 
219 	if ((DWORD)SG(read_post_bytes) < lpCB->cbAvailable) {
220 		read_from_buf = MIN(lpCB->cbAvailable-SG(read_post_bytes), count_bytes);
221 		memcpy(buffer, lpCB->lpbData+SG(read_post_bytes), read_from_buf);
222 		total_read += read_from_buf;
223 	}
224 	if (read_from_buf<count_bytes
225 		&& (SG(read_post_bytes)+read_from_buf) < lpCB->cbTotalBytes) {
226 		DWORD cbRead=0, cbSize;
227 
228 		read_from_input = MIN(count_bytes-read_from_buf, lpCB->cbTotalBytes-SG(read_post_bytes)-read_from_buf);
229 		while (cbRead < read_from_input) {
230 			cbSize = read_from_input - cbRead;
231 			if (!lpCB->ReadClient(lpCB->ConnID, buffer+read_from_buf+cbRead, &cbSize) || cbSize==0) {
232 				break;
233 			}
234 			cbRead += cbSize;
235 		}
236 		total_read += cbRead;
237 	}
238 
239 	/* removed after re-testing POST with Pi3Web 2.0.2 */
240 	/* SG(read_post_bytes) += total_read; */
241 	return total_read;
242 }
243 
244 
sapi_pi3web_read_cookies(TSRMLS_D)245 static char *sapi_pi3web_read_cookies(TSRMLS_D)
246 {
247 	LPCONTROL_BLOCK lpCB = (LPCONTROL_BLOCK) SG(server_context);
248 	char variable_buf[PI3WEB_SERVER_VAR_BUF_SIZE];
249 	DWORD variable_len = PI3WEB_SERVER_VAR_BUF_SIZE;
250 
251 	if (lpCB->GetServerVariable(lpCB->ConnID, "HTTP_COOKIE", variable_buf, &variable_len)) {
252 		return estrndup(variable_buf, variable_len);
253 	} else if (PIPlatform_getLastError()==PIAPI_EINVAL) {
254 		char *tmp_variable_buf = (char *) emalloc(variable_len+1);
255 
256 		if (lpCB->GetServerVariable(lpCB->ConnID, "HTTP_COOKIE", tmp_variable_buf, &variable_len)) {
257 			tmp_variable_buf[variable_len] = 0;
258 			return tmp_variable_buf;
259 		} else {
260 			efree(tmp_variable_buf);
261 		}
262 	}
263 	return NULL;
264 }
265 
init_request_info(LPCONTROL_BLOCK lpCB TSRMLS_DC)266 static void init_request_info(LPCONTROL_BLOCK lpCB TSRMLS_DC)
267 {
268 	SG(server_context) = lpCB;
269 	SG(request_info).request_method  = lpCB->lpszMethod;
270 	SG(request_info).query_string    = lpCB->lpszQueryString;
271 	SG(request_info).path_translated = lpCB->lpszPathTranslated;
272 	SG(request_info).request_uri     = lpCB->lpszUri;
273 	SG(request_info).content_type    = lpCB->lpszContentType;
274 	SG(request_info).content_length  = lpCB->cbTotalBytes;
275 	SG(request_info).auth_user       = (lpCB->lpszUser) ? (char *)estrdup((const char *)(lpCB->lpszUser)) : 0;
276 	SG(request_info).auth_password   = (lpCB->lpszPassword) ? (char *)estrdup((const char *)(lpCB->lpszPassword)) : 0;
277 	SG(sapi_headers).http_response_code = 200;
278 }
279 
sapi_pi3web_register_variables(zval * track_vars_array TSRMLS_DC)280 static void sapi_pi3web_register_variables(zval *track_vars_array TSRMLS_DC)
281 {
282 	char static_variable_buf[PI3WEB_SERVER_VAR_BUF_SIZE];
283 	char *variable_buf;
284 	DWORD variable_len = PI3WEB_SERVER_VAR_BUF_SIZE;
285 	LPCONTROL_BLOCK lpCB = (LPCONTROL_BLOCK) SG(server_context);
286 	PIDB *pDB = (PIDB *)lpCB->GetVariableNames(lpCB->ConnID);
287 	PIDBIterator *pIter = PIDB_getIterator( pDB, PIDBTYPE_STRING, 0, 0 );
288 
289 	/* --- loop over all registered server variables --- */
290 	for(; pIter && PIDBIterator_atValidElement( pIter ); PIDBIterator_next( pIter ) )
291 	{
292 		PCHAR pKey;
293 		PIDBIterator_current( pIter, &pKey );
294 		if ( !pKey ) { /* sanity */ continue; };
295 
296 		variable_len = PI3WEB_SERVER_VAR_BUF_SIZE;
297 		if (lpCB->GetServerVariable(lpCB->ConnID, pKey, static_variable_buf, &variable_len)
298 			&& (variable_len > 1)) {
299 			php_register_variable(pKey, static_variable_buf, track_vars_array TSRMLS_CC);
300 		} else if (PIPlatform_getLastError()==PIAPI_EINVAL) {
301 			variable_buf = (char *) emalloc(variable_len);
302 			if (lpCB->GetServerVariable(lpCB->ConnID, pKey, variable_buf, &variable_len)) {
303 				php_register_variable(pKey, variable_buf, track_vars_array TSRMLS_CC);
304 			}
305 			efree(variable_buf);
306 		}
307 
308 	}
309 
310 
311 	/* PHP_SELF support */
312 	variable_len = PI3WEB_SERVER_VAR_BUF_SIZE;
313 	if (lpCB->GetServerVariable(lpCB->ConnID, "SCRIPT_NAME", static_variable_buf, &variable_len)
314 		&& (variable_len > 1)) {
315 		php_register_variable("PHP_SELF", static_variable_buf, track_vars_array TSRMLS_CC);
316 	}
317 }
318 
319 static sapi_module_struct pi3web_sapi_module = {
320 	"pi3web",				/* name */
321 	"PI3WEB",				/* pretty name */
322 
323 	php_pi3web_startup,			/* startup */
324 	php_module_shutdown_wrapper,		/* shutdown */
325 	NULL,					/* activate */
326 	NULL,					/* deactivate */
327 	zend_pi3web_ub_write,			/* unbuffered write */
328 	NULL,					/* flush */
329 	NULL,					/* get uid */
330 	NULL,					/* getenv */
331 	php_error,				/* error handler */
332 	sapi_pi3web_header_handler,		/* header handler */
333 	sapi_pi3web_send_headers,		/* send headers handler */
334 	NULL,					/* send header handler */
335 	sapi_pi3web_read_post,			/* read POST data */
336 	sapi_pi3web_read_cookies,		/* read Cookies */
337 	sapi_pi3web_register_variables,	/* register server variables */
338 	NULL,					/* Log message */
339 	NULL,					/* Get request time */
340 	NULL,					/* Child terminate */
341 
342 	STANDARD_SAPI_MODULE_PROPERTIES
343 };
344 
PHP5_wrapper(LPCONTROL_BLOCK lpCB)345 MODULE_API DWORD PHP5_wrapper(LPCONTROL_BLOCK lpCB)
346 {
347 	zend_file_handle file_handle = {0};
348 	int iRet = PIAPI_COMPLETED;
349 	TSRMLS_FETCH();
350 
351 	zend_first_try {
352 		file_handle.filename = lpCB->lpszFileName;
353 		file_handle.free_filename = 0;
354 		file_handle.type = ZEND_HANDLE_FILENAME;
355 		file_handle.opened_path = NULL;
356 
357 		init_request_info(lpCB TSRMLS_CC);
358 		php_request_startup(TSRMLS_C);
359 
360 		switch ( lpCB->dwBehavior ) {
361 			case PHP_MODE_STANDARD:
362 				iRet = ( php_execute_script( &file_handle TSRMLS_CC ) ) ?
363 					PIAPI_COMPLETED : PIAPI_ERROR;
364 				break;
365 			case PHP_MODE_HIGHLIGHT: {
366 				zend_syntax_highlighter_ini syntax_highlighter_ini;
367 				if ( open_file_for_scanning( &file_handle TSRMLS_CC ) == SUCCESS )
368 					{
369 					php_get_highlight_struct( &syntax_highlighter_ini );
370 					zend_highlight( &syntax_highlighter_ini TSRMLS_CC );
371 					}
372 				else
373 					{
374 					iRet = PIAPI_ERROR;
375 					};
376 				};
377 				break;
378 			case PHP_MODE_INDENT: {
379 				sapi_header_line ctr = {0};
380 
381 				ctr.line = "Content-Type: text/plain";
382 				ctr.line_len = strlen(ctr.line);
383 
384 				sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
385 			  }
386 				if ( open_file_for_scanning( &file_handle TSRMLS_CC ) == SUCCESS )
387 					{
388 					zend_indent();
389 					}
390 				else
391 					{
392 					iRet = PIAPI_ERROR;
393 					};
394 				break;
395 			case PHP_MODE_LINT:
396 				iRet = (php_lint_script(&file_handle TSRMLS_CC) == SUCCESS) ?
397 					PIAPI_COMPLETED : PIAPI_ERROR;
398 				break;
399 			default:
400 				iRet = PIAPI_ERROR;;
401 			}
402 
403 		if (SG(request_info).cookie_data) {
404 			efree(SG(request_info).cookie_data);
405 		};
406 
407 		php_request_shutdown(NULL);
408 	} zend_catch {
409 		iRet = PIAPI_ERROR;
410 	} zend_end_try();
411 	return iRet;
412 }
413 
PHP5_startup()414 MODULE_API BOOL PHP5_startup() {
415 	tsrm_startup(1, 1, 0, NULL);
416 	sapi_startup(&pi3web_sapi_module);
417 	if (pi3web_sapi_module.startup) {
418 		pi3web_sapi_module.startup(&pi3web_sapi_module);
419 	};
420 	IWasLoaded = 1;
421 	return IWasLoaded;
422 };
423 
PHP5_shutdown()424 MODULE_API BOOL PHP5_shutdown() {
425 	if (pi3web_sapi_module.shutdown) {
426 		pi3web_sapi_module.shutdown(&pi3web_sapi_module);
427 	};
428 	sapi_shutdown();
429 	tsrm_shutdown();
430 	IWasLoaded = 0;
431 	return !IWasLoaded;
432 };
433 
434 /*
435  * Local variables:
436  * tab-width: 4
437  * c-basic-offset: 4
438  * End:
439  */
440