Annotation of embedaddon/php/sapi/continuity/capi.c, revision 1.1.1.4
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.4 ! misho 5: | Copyright (c) 1997-2014 The PHP Group |
1.1 misho 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 Leigh <php (at) postfin (dot) com> |
16: +----------------------------------------------------------------------+
17: */
18:
19: /* For more information on Continuity: http://www.ashpool.com/ */
20:
21: /*
22: * This code is based on the PHP5 SAPI module for NSAPI by Jayakumar
23: * Muthukumarasamy
24: */
25:
26: /* PHP includes */
27: #define CONTINUITY 1
28: #define CAPI_DEBUG
29:
30: /* Define for CDP specific extensions */
31: #undef CONTINUITY_CDPEXT
32:
33: #include "php.h"
34: #include "php_variables.h"
35: #include "ext/standard/info.h"
36: #include "php_ini.h"
37: #include "php_globals.h"
38: #include "SAPI.h"
39: #include "php_main.h"
40: #include "php_version.h"
41: #include "TSRM.h"
42: #include "ext/standard/php_standard.h"
43:
44: /*
45: * CAPI includes
46: */
47: #include <continuity.h>
48: #include <http.h>
49:
50: #define NSLS_D struct capi_request_context *request_context
51: #define NSLS_DC , NSLS_D
52: #define NSLS_C request_context
53: #define NSLS_CC , NSLS_C
54: #define NSG(v) (request_context->v)
55:
56: /*
57: * ZTS needs to be defined for CAPI to work
58: */
59: #if !defined(ZTS)
60: #error "CAPI module needs ZTS to be defined"
61: #endif
62:
63: /*
64: * Structure to encapsulate the CAPI request in SAPI
65: */
66: typedef struct capi_request_context {
67: httpTtrans *t;
68: int read_post_bytes;
69: } capi_request_context;
70:
71: /**************/
72:
73: PHP_MINIT_FUNCTION(continuity);
74: PHP_MSHUTDOWN_FUNCTION(continuity);
75: PHP_RINIT_FUNCTION(continuity);
76: PHP_RSHUTDOWN_FUNCTION(continuity);
77: PHP_MINFO_FUNCTION(continuity);
78:
79: PHP_FUNCTION(continuity_virtual);
80: PHP_FUNCTION(continuity_request_headers);
81: PHP_FUNCTION(continuity_response_headers);
82:
83: const zend_function_entry continuity_functions[] = {
84: {NULL, NULL, NULL}
85: };
86:
87: zend_module_entry continuity_module_entry = {
88: STANDARD_MODULE_HEADER,
89: "continuity",
90: continuity_functions,
91: PHP_MINIT(continuity),
92: PHP_MSHUTDOWN(continuity),
93: NULL,
94: NULL,
95: PHP_MINFO(continuity),
96: NO_VERSION_YET,
97: STANDARD_MODULE_PROPERTIES
98: };
99:
100: PHP_MINIT_FUNCTION(continuity)
101: {
102: return SUCCESS;
103: }
104:
105: PHP_MSHUTDOWN_FUNCTION(continuity)
106: {
107: return SUCCESS;
108: }
109:
110: PHP_MINFO_FUNCTION(continuity)
111: {
112: php_info_print_table_start();
1.1.1.4 ! misho 113: php_info_print_table_row(2, "Continuity Module Revision", "$Id: 953991474d209af19f1e972ca77b9e5869dba973 $");
1.1 misho 114: php_info_print_table_row(2, "Server Version", conFget_build());
115: #ifdef CONTINUITY_CDPEXT
116: php_info_print_table_row(2,"CDP Extensions", "enabled");
117: #else
118: php_info_print_table_row(2,"CDP Extensions", "disabled");
119: #endif
120: php_info_print_table_end();
121:
122: /* DISPLAY_INI_ENTRIES(); */
123: }
124:
125: /**************/
126:
127: /*
128: * sapi_capi_ub_write: Write len bytes to the connection output.
129: */
130: static int sapi_capi_ub_write(const char *str, unsigned int str_length TSRMLS_DC)
131: {
132: int retval;
133: capi_request_context *rc;
134:
135: rc = (capi_request_context *) SG(server_context);
136: retval = httpFwrite(rc->t, (char *) str, str_length);
137: if (retval == -1 || retval == 0)
138: php_handle_aborted_connection();
139: return retval;
140: }
141:
142: /*
143: * sapi_capi_header_handler: Add/update response headers with those provided
144: * by the PHP engine.
145: */
146: static int sapi_capi_header_handler(sapi_header_struct * sapi_header, sapi_headers_struct * sapi_headers TSRMLS_DC)
147: {
148: char *header_name, *header_content, *p;
149: capi_request_context *rc = (capi_request_context *) SG(server_context);
150:
151: lstFset_delete_key(rc->t->res_hdrs, "Content-Type");
152:
153: header_name = sapi_header->header;
154: header_content = p = strchr(header_name, ':');
155: if (p == NULL) {
156: return 0;
157: }
158: *p = 0;
159: do {
160: header_content++;
161: } while (*header_content == ' ');
162:
163: lstFset_add(rc->t->res_hdrs, header_name, header_content);
164:
165: *p = ':'; /* restore '*p' */
166:
167: efree(sapi_header->header);
168:
169: return 0; /* don't use the default SAPI mechanism, CAPI
170: * duplicates this functionality */
171: }
172:
173: /*
174: * sapi_capi_send_headers: Transmit the headers to the client. This has the
175: * effect of starting the response under Continuity.
176: */
177: static int sapi_capi_send_headers(sapi_headers_struct * sapi_headers TSRMLS_DC)
178: {
179: int retval;
180: capi_request_context *rc = (capi_request_context *) SG(server_context);
181:
182: /*
183: * We could probably just do this in the header_handler. But, I don't know
184: * what the implication of doing it there is.
185: */
186:
187: if (SG(sapi_headers).send_default_content_type) {
188: /* lstFset_delete_key(rc->t->res_hdrs, "Content-Type"); */
189: lstFset_update(rc->t->res_hdrs, "Content-Type", "text/html");
190: }
191: httpFset_status(rc->t, SG(sapi_headers).http_response_code, NULL);
192: httpFstart_response(rc->t);
193:
194: return SAPI_HEADER_SENT_SUCCESSFULLY;
195:
196: }
197:
198: static int sapi_capi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
199: {
200: unsigned int max_read, total_read = 0;
201: capi_request_context *rc = (capi_request_context *) SG(server_context);
202:
203: if (rc->read_post_bytes == -1) {
204: max_read = MIN(count_bytes, SG(request_info).content_length);
205: } else {
206: if (rc->read_post_bytes == 0)
207: return 0;
208: max_read = MIN(count_bytes, (SG(request_info).content_length - rc->read_post_bytes));
209: }
210:
211: total_read = httpFread(rc->t, buffer, max_read);
212:
213: if (total_read < 0)
214: total_read = -1;
215: else
216: rc->read_post_bytes = total_read;
217:
218: return total_read;
219: }
220:
221: /*
222: * sapi_capi_read_cookies: Return cookie information into PHP.
223: */
224: static char *sapi_capi_read_cookies(TSRMLS_D)
225: {
226: char *cookie_string;
227: capi_request_context *rc = (capi_request_context *) SG(server_context);
228:
229: cookie_string = lstFset_get(rc->t->req_hdrs, "cookie");
230: return cookie_string;
231: }
232:
233: static void sapi_capi_register_server_variables(zval * track_vars_array TSRMLS_DC)
234: {
235: capi_request_context *rc = (capi_request_context *) SG(server_context);
236: size_t i;
237: char *value;
238: char buf[128];
239:
240: /* PHP_SELF and REQUEST_URI */
241: value = lstFset_get(rc->t->vars, "uri");
242: if (value != NULL) {
243: php_register_variable("PHP_SELF", value, track_vars_array TSRMLS_CC);
244: php_register_variable("REQUEST_URI", value, track_vars_array TSRMLS_CC);
245: }
246:
247: /* COUNTRY CODE */
248: value = lstFset_get(rc->t->vars, "ccode");
249: if(value!=NULL)
250: php_register_variable("COUNTRY_CODE", value, track_vars_array TSRMLS_CC);
251:
252: /* argv */
253: value = lstFset_get(rc->t->vars, "query");
254: if (value != NULL)
255: php_register_variable("argv", value, track_vars_array TSRMLS_CC);
256:
257: /* GATEWAY_INTERFACE */
258: php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
259:
260: /* SERVER_NAME and HTTP_HOST */
261: value = lstFset_get(rc->t->req_hdrs, "host");
262: if (value != NULL) {
263: php_register_variable("HTTP_HOST", value, track_vars_array TSRMLS_CC);
264: /* TODO: This should probably scrub the port value if one is present. */
265: php_register_variable("SERVER_NAME", value, track_vars_array TSRMLS_CC);
266: }
267: /* SERVER_SOFTWARE */
268: value = lstFset_get(rc->t->res_hdrs, "Server");
269: if (value != NULL)
270: php_register_variable("SERVER_SOFTWARE", value, track_vars_array TSRMLS_CC);
271:
272: /* SERVER_PROTOCOL */
273: value = lstFset_get(rc->t->vars, "protocol");
274: if (value != NULL)
275: php_register_variable("SERVER_PROTOCOL", value, track_vars_array TSRMLS_CC);
276:
277: /* REQUEST_METHOD */
278: value = lstFset_get(rc->t->vars, "method");
279: if (value != NULL)
280: php_register_variable("REQUEST_METHOD", value, track_vars_array TSRMLS_CC);
281:
282: /* QUERY_STRING */
283: value = lstFset_get(rc->t->vars, "query");
284: if (value != NULL)
285: php_register_variable("QUERY_STRING", value, track_vars_array TSRMLS_CC);
286:
287: /* DOCUMENT_ROOT */
288: value = lstFset_get(rc->t->vars, "docroot");
289: if (value != NULL)
290: php_register_variable("DOCUMENT_ROOT", value, track_vars_array TSRMLS_CC);
291:
292: /* HTTP_ACCEPT */
293: value = lstFset_get(rc->t->req_hdrs, "accept");
294: if (value != NULL)
295: php_register_variable("HTTP_ACCEPT", value, track_vars_array TSRMLS_CC);
296:
297: /* HTTP_ACCEPT_CHARSET */
298: value = lstFset_get(rc->t->req_hdrs, "accept-charset");
299: if (value != NULL)
300: php_register_variable("HTTP_ACCEPT_CHARSET", value, track_vars_array TSRMLS_CC);
301:
302: /* HTTP_ACCEPT_ENCODING */
303: value = lstFset_get(rc->t->req_hdrs, "accept-encoding");
304: if (value != NULL)
305: php_register_variable("HTTP_ACCEPT_ENCODING", value, track_vars_array TSRMLS_CC);
306:
307: /* HTTP_ACCEPT_LANGUAGE */
308: value = lstFset_get(rc->t->req_hdrs, "accept-language");
309: if (value != NULL)
310: php_register_variable("HTTP_ACCEPT_LANGUAGE", value, track_vars_array TSRMLS_CC);
311:
312: /* HTTP_CONNECTION */
313: value = lstFset_get(rc->t->req_hdrs, "connection");
314: if (value != NULL)
315: php_register_variable("HTTP_CONNECTION", value, track_vars_array TSRMLS_CC);
316:
317: /* HTTP_REFERER */
318: value = lstFset_get(rc->t->req_hdrs, "referer");
319: if (value != NULL)
320: php_register_variable("HTTP_REFERER", value, track_vars_array TSRMLS_CC);
321:
322: /* HTTP_USER_AGENT */
323: value = lstFset_get(rc->t->req_hdrs, "user-agent");
324: if (value != NULL)
325: php_register_variable("HTTP_USER_AGENT", value, track_vars_array TSRMLS_CC);
326:
327: /* REMOTE_ADDR */
328: utlFip_to_str(rc->t->cli_ipv4_addr, buf, sizeof(buf));
329: php_register_variable("REMOTE_ADDR", buf, track_vars_array TSRMLS_CC);
330:
331: /* REMOTE_PORT */
332:
333: /* SCRIPT_FILENAME and PATH_TRANSLATED */
334: value = lstFset_get(rc->t->vars, "path");
335: if (value != NULL) {
336: php_register_variable("SCRIPT_FILENAME", value, track_vars_array TSRMLS_CC);
337: php_register_variable("PATH_TRANSLATED", value, track_vars_array TSRMLS_CC);
338: }
339: /* SERVER_ADMIN */
340: /* Not applicable */
341:
342: /* SERVER_PORT */
343:
344: }
345:
1.1.1.2 misho 346: static void capi_log_message(char *message TSRMLS_DC)
1.1 misho 347: {
348: capi_request_context *rc = (capi_request_context *) SG(server_context);
349: logFmsg(0, "mod/php: %s", message);
350: }
351:
352: static int php_capi_startup(sapi_module_struct *sapi_module);
353:
354: sapi_module_struct capi_sapi_module = {
355: "Continuity", /* name */
356: "Continuity Server Enterprise Edition", /* pretty name */
357:
358: php_capi_startup, /* startup */
359: php_module_shutdown_wrapper, /* shutdown */
360:
361: NULL, /* activate */
362: NULL, /* deactivate */
363:
364: sapi_capi_ub_write, /* unbuffered write */
365: NULL, /* flush */
366: NULL, /* get uid */
367: NULL, /* getenv */
368:
369: php_error, /* error handler */
370:
371: sapi_capi_header_handler, /* header handler */
372: sapi_capi_send_headers, /* send headers handler */
373: NULL, /* send header handler */
374:
375: sapi_capi_read_post, /* read POST data */
376: sapi_capi_read_cookies, /* read Cookies */
377:
378: sapi_capi_register_server_variables, /* register server variables */
379: capi_log_message, /* Log message */
380: NULL, /* Get request time */
381: NULL, /* Child terminate */
382:
383: NULL, /* Block interruptions */
384: NULL, /* Unblock interruptions */
385:
386: STANDARD_SAPI_MODULE_PROPERTIES
387: };
388:
389: static int php_capi_startup(sapi_module_struct *sapi_module) {
390: if(php_module_startup(sapi_module,&continuity_module_entry,1)==FAILURE) {
391: return FAILURE;
392: }
393: return SUCCESS;
394: }
395:
396:
397: static char *
398: capi_strdup(char *str)
399: {
400: if (str != NULL)
401: return strFcopy(str);
402: return NULL;
403: }
404:
405: static void capi_free(void *addr)
406: {
407: if (addr != NULL)
408: free(addr);
409: }
410:
411: static void capi_request_ctor(NSLS_D TSRMLS_DC)
412: {
413: char *query_string = lstFset_get(NSG(t->vars), "query");
414: char *uri = lstFset_get(NSG(t->vars), "uri");
415: char *path_info = lstFset_get(NSG(t->vars), "path-info");
416: char *path_translated = lstFset_get(NSG(t->vars), "path");
417: char *request_method = lstFset_get(NSG(t->vars), "method");
418: char *content_type = lstFset_get(NSG(t->req_hdrs), "content-type");
419: char *content_length = lstFset_get(NSG(t->req_hdrs), "content-length");
420:
421: SG(request_info).query_string = capi_strdup(query_string);
422: SG(request_info).request_uri = capi_strdup(uri);
423: SG(request_info).request_method = capi_strdup(request_method);
424: SG(request_info).path_translated = capi_strdup(path_translated);
425: SG(request_info).content_type = capi_strdup(content_type);
426: SG(request_info).content_length = (content_length == NULL) ? 0 : strtoul(content_length, 0, 0);
427: SG(sapi_headers).http_response_code = 200;
428: }
429:
430: static void capi_request_dtor(NSLS_D TSRMLS_DC)
431: {
432: capi_free(SG(request_info).query_string);
433: capi_free(SG(request_info).request_uri);
434: capi_free(SG(request_info).request_method);
435: capi_free(SG(request_info).path_translated);
436: capi_free(SG(request_info).content_type);
437: }
438:
439: int capi_module_main(NSLS_D TSRMLS_DC)
440: {
441: zend_file_handle file_handle;
442:
443: if (php_request_startup(TSRMLS_C) == FAILURE) {
444: return FAILURE;
445: }
446: file_handle.type = ZEND_HANDLE_FILENAME;
447: file_handle.filename = SG(request_info).path_translated;
448: file_handle.free_filename = 0;
449: file_handle.opened_path = NULL;
450:
451: php_execute_script(&file_handle TSRMLS_CC);
452: php_request_shutdown(NULL);
453:
454: return SUCCESS;
455: }
456:
457: int phpFinit(lstTset * opt)
458: {
459: php_core_globals *core_globals;
460:
461: tsrm_startup(128, 1, 0, NULL);
462: core_globals = ts_resource(core_globals_id);
463:
464: logFmsg(0, "mod/php: PHP Interface v3 (module)");
465: logFmsg(0, "mod/php: Copyright (c) 1999-2005 The PHP Group. All rights reserved.");
466:
467: sapi_startup(&capi_sapi_module);
468: capi_sapi_module.startup(&capi_sapi_module);
469:
470: return STATUS_PROCEED;
471: }
472:
473: int phpFservice(httpTtrans * t, lstTset * opts)
474: {
475: int retval;
476: capi_request_context *request_context;
477:
478: TSRMLS_FETCH();
479:
480: request_context = (capi_request_context *) malloc(sizeof(capi_request_context));
481: request_context->t = t;
482: request_context->read_post_bytes = -1;
483:
484: SG(server_context) = request_context;
485:
486: capi_request_ctor(NSLS_C TSRMLS_CC);
487: retval = capi_module_main(NSLS_C TSRMLS_CC);
488: capi_request_dtor(NSLS_C TSRMLS_CC);
489:
490: free(request_context);
491:
492: /*
493: * This call is ostensibly provided to free the memory from PHP/TSRM when
494: * the thread terminated, but, it leaks a structure in some hash list
495: * according to the developers. Not calling this will leak the entire
496: * interpreter, around 100k, but calling it and then terminating the
497: * thread will leak the struct (around a k). The only answer with the
498: * current TSRM implementation is to reuse the threads that allocate TSRM
499: * resources.
500: */
501: /* ts_free_thread(); */
502:
503: if (retval == SUCCESS) {
504: return STATUS_EXIT;
505: } else {
506: return STATUS_ERROR;
507: }
508: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>