Annotation of embedaddon/php/sapi/nsapi/nsapi.c, revision 1.1.1.2
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1997-2012 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: Jayakumar Muthukumarasamy <jk@kasenna.com> |
16: | Uwe Schindler <uwe@thetaphi.de> |
17: +----------------------------------------------------------------------+
18: */
19:
1.1.1.2 ! misho 20: /* $Id: 1579ef78c86f04635727009bb2abb383accd31f5 $ */
1.1 misho 21:
22: /*
23: * PHP includes
24: */
25: #define NSAPI 1
26:
27: #ifdef HAVE_CONFIG_H
28: #include "config.h"
29: #endif
30:
31: #include "php.h"
32: #include "php_variables.h"
33: #include "ext/standard/info.h"
34: #include "php_ini.h"
35: #include "php_globals.h"
36: #include "SAPI.h"
37: #include "php_main.h"
38: #include "php_version.h"
39: #include "TSRM.h"
40: #include "ext/standard/php_standard.h"
41: #include <sys/types.h>
42: #include <sys/stat.h>
43:
44: #ifndef RTLD_DEFAULT
45: #define RTLD_DEFAULT NULL
46: #endif
47:
48: /*
49: * If neither XP_UNIX not XP_WIN32 is defined use PHP_WIN32
50: */
51: #if !defined(XP_UNIX) && !defined(XP_WIN32)
52: #ifdef PHP_WIN32
53: #define XP_WIN32
54: #else
55: #define XP_UNIX
56: #endif
57: #endif
58:
59: /*
60: * The manual define of HPUX is to fix bug #46020, nsapi.h needs this to detect HPUX
61: */
62: #ifdef __hpux
63: #define HPUX
64: #endif
65:
66: /*
67: * NSAPI includes
68: */
69: #include "nsapi.h"
70:
71: /* fix for gcc4 visibility issue */
72: #ifndef PHP_WIN32
73: # undef NSAPI_PUBLIC
74: # define NSAPI_PUBLIC PHPAPI
75: #endif
76:
77: #define NSLS_D struct nsapi_request_context *request_context
78: #define NSLS_DC , NSLS_D
79: #define NSLS_C request_context
80: #define NSLS_CC , NSLS_C
81: #define NSG(v) (request_context->v)
82:
83: /*
84: * ZTS needs to be defined for NSAPI to work
85: */
86: #if !defined(ZTS)
87: #error "NSAPI module needs ZTS to be defined"
88: #endif
89:
90: /*
91: * Structure to encapsulate the NSAPI request in SAPI
92: */
93: typedef struct nsapi_request_context {
94: pblock *pb;
95: Session *sn;
96: Request *rq;
97: int read_post_bytes;
98: char *path_info;
99: int fixed_script; /* 0 if script is from URI, 1 if script is from "script" parameter */
100: short http_error; /* 0 in normal mode; for errors the HTTP error code */
101: } nsapi_request_context;
102:
103: /*
104: * Mappings between NSAPI names and environment variables. This
105: * mapping was obtained from the sample programs at the iplanet
106: * website.
107: */
108: typedef struct nsapi_equiv {
109: const char *env_var;
110: const char *nsapi_eq;
111: } nsapi_equiv;
112:
113: static nsapi_equiv nsapi_reqpb[] = {
114: { "QUERY_STRING", "query" },
115: { "REQUEST_LINE", "clf-request" },
116: { "REQUEST_METHOD", "method" },
117: { "PHP_SELF", "uri" },
118: { "SERVER_PROTOCOL", "protocol" }
119: };
120: static size_t nsapi_reqpb_size = sizeof(nsapi_reqpb)/sizeof(nsapi_reqpb[0]);
121:
122: static nsapi_equiv nsapi_vars[] = {
123: { "AUTH_TYPE", "auth-type" },
124: { "CLIENT_CERT", "auth-cert" },
125: { "REMOTE_USER", "auth-user" }
126: };
127: static size_t nsapi_vars_size = sizeof(nsapi_vars)/sizeof(nsapi_vars[0]);
128:
129: static nsapi_equiv nsapi_client[] = {
130: { "HTTPS_KEYSIZE", "keysize" },
131: { "HTTPS_SECRETSIZE", "secret-keysize" },
132: { "REMOTE_ADDR", "ip" },
133: { "REMOTE_HOST", "ip" }
134: };
135: static size_t nsapi_client_size = sizeof(nsapi_client)/sizeof(nsapi_client[0]);
136:
137: /* this parameters to "Service"/"Error" are NSAPI ones which should not be php.ini keys and are excluded */
138: static char *nsapi_exclude_from_ini_entries[] = { "fn", "type", "method", "directive", "code", "reason", "script", "bucket", NULL };
139:
140: static void nsapi_free(void *addr)
141: {
142: if (addr != NULL) {
143: FREE(addr);
144: }
145: }
146:
147:
148: /*******************/
149: /* PHP module part */
150: /*******************/
151:
152: PHP_MINIT_FUNCTION(nsapi);
153: PHP_MSHUTDOWN_FUNCTION(nsapi);
154: PHP_RINIT_FUNCTION(nsapi);
155: PHP_RSHUTDOWN_FUNCTION(nsapi);
156: PHP_MINFO_FUNCTION(nsapi);
157:
158: PHP_FUNCTION(nsapi_virtual);
159: PHP_FUNCTION(nsapi_request_headers);
160: PHP_FUNCTION(nsapi_response_headers);
161:
162: ZEND_BEGIN_MODULE_GLOBALS(nsapi)
163: long read_timeout;
164: ZEND_END_MODULE_GLOBALS(nsapi)
165:
166: ZEND_DECLARE_MODULE_GLOBALS(nsapi)
167:
168: #define NSAPI_G(v) TSRMG(nsapi_globals_id, zend_nsapi_globals *, v)
169:
170:
171: /* {{{ arginfo */
172: ZEND_BEGIN_ARG_INFO_EX(arginfo_nsapi_virtual, 0, 0, 1)
173: ZEND_ARG_INFO(0, uri)
174: ZEND_END_ARG_INFO()
175:
176: ZEND_BEGIN_ARG_INFO(arginfo_nsapi_request_headers, 0)
177: ZEND_END_ARG_INFO()
178:
179: ZEND_BEGIN_ARG_INFO(arginfo_nsapi_response_headers, 0)
180: ZEND_END_ARG_INFO()
181: /* }}} */
182:
183: /* {{{ nsapi_functions[]
184: *
185: * Every user visible function must have an entry in nsapi_functions[].
186: */
187: const zend_function_entry nsapi_functions[] = {
188: PHP_FE(nsapi_virtual, arginfo_nsapi_virtual) /* Make subrequest */
189: PHP_FALIAS(virtual, nsapi_virtual, arginfo_nsapi_virtual) /* compatibility */
190: PHP_FE(nsapi_request_headers, arginfo_nsapi_request_headers) /* get request headers */
191: PHP_FALIAS(getallheaders, nsapi_request_headers, arginfo_nsapi_request_headers) /* compatibility */
192: PHP_FALIAS(apache_request_headers, nsapi_request_headers, arginfo_nsapi_request_headers) /* compatibility */
193: PHP_FE(nsapi_response_headers, arginfo_nsapi_response_headers) /* get response headers */
194: PHP_FALIAS(apache_response_headers, nsapi_response_headers, arginfo_nsapi_response_headers) /* compatibility */
195: {NULL, NULL, NULL}
196: };
197: /* }}} */
198:
199: /* {{{ nsapi_module_entry
200: */
201: zend_module_entry nsapi_module_entry = {
202: STANDARD_MODULE_HEADER,
203: "nsapi",
204: nsapi_functions,
205: PHP_MINIT(nsapi),
206: PHP_MSHUTDOWN(nsapi),
207: NULL,
208: NULL,
209: PHP_MINFO(nsapi),
210: NO_VERSION_YET,
211: STANDARD_MODULE_PROPERTIES
212: };
213: /* }}} */
214:
215: /* {{{ PHP_INI
216: */
217: PHP_INI_BEGIN()
218: STD_PHP_INI_ENTRY("nsapi.read_timeout", "60", PHP_INI_ALL, OnUpdateLong, read_timeout, zend_nsapi_globals, nsapi_globals)
219: PHP_INI_END()
220: /* }}} */
221:
222: /* newer servers hide this functions from the programmer so redefine the functions dynamically
223: thanks to Chris Elving from Sun for the function declarations */
224: typedef int (*nsapi_servact_prototype)(Session *sn, Request *rq);
225: nsapi_servact_prototype nsapi_servact_uri2path = NULL;
226: nsapi_servact_prototype nsapi_servact_pathchecks = NULL;
227: nsapi_servact_prototype nsapi_servact_fileinfo = NULL;
228: nsapi_servact_prototype nsapi_servact_service = NULL;
229:
230: #ifdef PHP_WIN32
231: /* The following dll-names for nsapi are in use at this time. The undocumented
232: * servact_* functions are always in the newest one, older ones are supported by
233: * the server only by wrapping the function table nothing else. So choose
234: * the newest one found in process space for dynamic linking */
235: static char *nsapi_dlls[] = { "ns-httpd40.dll", "ns-httpd36.dll", "ns-httpd35.dll", "ns-httpd30.dll", NULL };
236: /* if user specifies an other dll name by server_lib parameter
237: * it is placed in the following variable and only this DLL is
238: * checked for the servact_* functions */
239: char *nsapi_dll = NULL;
240: #endif
241:
242: /* {{{ php_nsapi_init_dynamic_symbols
243: */
244: static void php_nsapi_init_dynamic_symbols(void)
245: {
246: /* find address of internal NSAPI functions */
247: #ifdef PHP_WIN32
248: register int i;
249: DL_HANDLE module = NULL;
250: if (nsapi_dll) {
251: /* try user specified server_lib */
252: module = GetModuleHandle(nsapi_dll);
253: if (!module) {
254: log_error(LOG_WARN, "php5_init", NULL, NULL, "Cannot find DLL specified by server_lib parameter: %s", nsapi_dll);
255: }
256: } else {
257: /* find a LOADED dll module from nsapi_dlls */
258: for (i=0; nsapi_dlls[i]; i++) {
259: if (module = GetModuleHandle(nsapi_dlls[i])) {
260: break;
261: }
262: }
263: }
264: if (!module) return;
265: #else
266: DL_HANDLE module = RTLD_DEFAULT;
267: #endif
268: nsapi_servact_uri2path = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_uri2path");
269: nsapi_servact_pathchecks = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_pathchecks");
270: nsapi_servact_fileinfo = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_fileinfo");
271: nsapi_servact_service = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_service");
272: if (!(nsapi_servact_uri2path && nsapi_servact_pathchecks && nsapi_servact_fileinfo && nsapi_servact_service)) {
273: /* not found - could be cause they are undocumented */
274: nsapi_servact_uri2path = NULL;
275: nsapi_servact_pathchecks = NULL;
276: nsapi_servact_fileinfo = NULL;
277: nsapi_servact_service = NULL;
278: }
279: }
280: /* }}} */
281:
282: /* {{{ php_nsapi_init_globals
283: */
284: static void php_nsapi_init_globals(zend_nsapi_globals *nsapi_globals)
285: {
286: nsapi_globals->read_timeout = 60;
287: }
288: /* }}} */
289:
290: /* {{{ PHP_MINIT_FUNCTION
291: */
292: PHP_MINIT_FUNCTION(nsapi)
293: {
294: php_nsapi_init_dynamic_symbols();
295: ZEND_INIT_MODULE_GLOBALS(nsapi, php_nsapi_init_globals, NULL);
296: REGISTER_INI_ENTRIES();
297: return SUCCESS;
298: }
299: /* }}} */
300:
301: /* {{{ PHP_MSHUTDOWN_FUNCTION
302: */
303: PHP_MSHUTDOWN_FUNCTION(nsapi)
304: {
305: UNREGISTER_INI_ENTRIES();
306: return SUCCESS;
307: }
308: /* }}} */
309:
310: /* {{{ PHP_MINFO_FUNCTION
311: */
312: PHP_MINFO_FUNCTION(nsapi)
313: {
314: php_info_print_table_start();
1.1.1.2 ! misho 315: php_info_print_table_row(2, "NSAPI Module Revision", "$Id: 1579ef78c86f04635727009bb2abb383accd31f5 $");
1.1 misho 316: php_info_print_table_row(2, "Server Software", system_version());
317: php_info_print_table_row(2, "Sub-requests with nsapi_virtual()",
318: (nsapi_servact_service)?((zend_ini_long("zlib.output_compression", sizeof("zlib.output_compression"), 0))?"not supported with zlib.output_compression":"enabled"):"not supported on this platform" );
319: php_info_print_table_end();
320:
321: DISPLAY_INI_ENTRIES();
322: }
323: /* }}} */
324:
325: /* {{{ proto bool nsapi_virtual(string uri)
326: Perform an NSAPI sub-request */
327: /* This function is equivalent to <!--#include virtual...-->
328: * in SSI. It does an NSAPI sub-request. It is useful
329: * for including CGI scripts or .shtml files, or anything else
330: * that you'd parse through webserver.
331: */
332: PHP_FUNCTION(nsapi_virtual)
333: {
334: int uri_len,rv;
335: char *uri,*value;
336: Request *rq;
337: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
338:
339: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &uri, &uri_len) == FAILURE) {
340: return;
341: }
342:
343: if (!nsapi_servact_service) {
344: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - Sub-requests not supported on this platform", uri);
345: RETURN_FALSE;
346: } else if (zend_ini_long("zlib.output_compression", sizeof("zlib.output_compression"), 0)) {
347: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - Sub-requests do not work with zlib.output_compression", uri);
348: RETURN_FALSE;
349: } else {
1.1.1.2 ! misho 350: php_output_end_all(TSRMLS_C);
1.1 misho 351: php_header(TSRMLS_C);
352:
353: /* do the sub-request */
354: /* thanks to Chris Elving from Sun for this code sniplet */
355: if ((rq = request_restart_internal(uri, NULL)) == NULL) {
356: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - Internal request creation failed", uri);
357: RETURN_FALSE;
358: }
359:
360: /* insert host of current request to get page from same vhost */
361: param_free(pblock_remove("host", rq->headers));
362: if (value = pblock_findval("host", rc->rq->headers)) {
363: pblock_nvinsert("host", value, rq->headers);
364: }
365:
366: /* go through the normal request stages as given in obj.conf,
367: but leave out the logging/error section */
368: do {
369: rv = (*nsapi_servact_uri2path)(rc->sn, rq);
370: if (rv != REQ_PROCEED) {
371: continue;
372: }
373:
374: rv = (*nsapi_servact_pathchecks)(rc->sn, rq);
375: if (rv != REQ_PROCEED) {
376: continue;
377: }
378:
379: rv = (*nsapi_servact_fileinfo)(rc->sn, rq);
380: if (rv != REQ_PROCEED) {
381: continue;
382: }
383:
384: rv = (*nsapi_servact_service)(rc->sn, rq);
385: } while (rv == REQ_RESTART);
386:
387: if (rq->status_num != 200) {
388: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - HTTP status code %d during subrequest", uri, rq->status_num);
389: request_free(rq);
390: RETURN_FALSE;
391: }
392:
393: request_free(rq);
394:
395: RETURN_TRUE;
396: }
397: }
398: /* }}} */
399:
400: /* {{{ proto array nsapi_request_headers(void)
401: Get all headers from the request */
402: PHP_FUNCTION(nsapi_request_headers)
403: {
404: register int i;
405: struct pb_entry *entry;
406: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
407:
408: if (zend_parse_parameters_none() == FAILURE) {
409: return;
410: }
411:
412: array_init(return_value);
413:
414: for (i=0; i < rc->rq->headers->hsize; i++) {
415: entry=rc->rq->headers->ht[i];
416: while (entry) {
1.1.1.2 ! misho 417: add_assoc_string(return_value, entry->param->name, entry->param->value, 1);
1.1 misho 418: entry=entry->next;
419: }
420: }
421: }
422: /* }}} */
423:
424: /* {{{ proto array nsapi_response_headers(void)
425: Get all headers from the response */
426: PHP_FUNCTION(nsapi_response_headers)
427: {
428: register int i;
429: struct pb_entry *entry;
430: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
431:
432: if (zend_parse_parameters_none() == FAILURE) {
433: return;
434: }
435:
436: array_init(return_value);
437:
438: for (i=0; i < rc->rq->srvhdrs->hsize; i++) {
439: entry=rc->rq->srvhdrs->ht[i];
440: while (entry) {
441: add_assoc_string(return_value, entry->param->name, entry->param->value, 1);
442: entry=entry->next;
443: }
444: }
445: }
446: /* }}} */
447:
448:
449: /*************/
450: /* SAPI part */
451: /*************/
452:
453: static int sapi_nsapi_ub_write(const char *str, unsigned int str_length TSRMLS_DC)
454: {
455: int retval;
456: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
457:
458: if (!SG(headers_sent)) {
459: sapi_send_headers(TSRMLS_C);
460: }
461:
462: retval = net_write(rc->sn->csd, (char *)str, str_length);
463: if (retval == IO_ERROR /* -1 */ || retval == IO_EOF /* 0 */) {
464: php_handle_aborted_connection();
465: }
466: return retval;
467: }
468:
469: /* modified version of apache2 */
470: static void sapi_nsapi_flush(void *server_context)
471: {
472: nsapi_request_context *rc = (nsapi_request_context *)server_context;
473: TSRMLS_FETCH();
474:
475: if (!rc) {
476: /* we have no context, so no flushing needed. This fixes a SIGSEGV on shutdown */
477: return;
478: }
479:
480: if (!SG(headers_sent)) {
481: sapi_send_headers(TSRMLS_C);
482: }
483:
484: /* flushing is only supported in iPlanet servers from version 6.1 on, make it conditional */
485: #if NSAPI_VERSION >= 302
486: if (net_flush(rc->sn->csd) < 0) {
487: php_handle_aborted_connection();
488: }
489: #endif
490: }
491:
492: /* callback for zend_llist_apply on SAPI_HEADER_DELETE_ALL operation */
493: static int php_nsapi_remove_header(sapi_header_struct *sapi_header TSRMLS_DC)
494: {
495: char *header_name, *p;
496: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
497:
498: /* copy the header, because NSAPI needs reformatting and we do not want to change the parameter */
499: header_name = pool_strdup(rc->sn->pool, sapi_header->header);
500:
501: /* extract name, this works, if only the header without ':' is given, too */
502: if (p = strchr(header_name, ':')) {
503: *p = 0;
504: }
505:
506: /* header_name to lower case because NSAPI reformats the headers and wants lowercase */
507: for (p=header_name; *p; p++) {
508: *p=tolower(*p);
509: }
510:
511: /* remove the header */
512: param_free(pblock_remove(header_name, rc->rq->srvhdrs));
513: pool_free(rc->sn->pool, header_name);
514:
515: return ZEND_HASH_APPLY_KEEP;
516: }
517:
518: static int sapi_nsapi_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC)
519: {
520: char *header_name, *header_content, *p;
521: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
522:
523: switch(op) {
524: case SAPI_HEADER_DELETE_ALL:
525: /* this only deletes headers set or overwritten by PHP, headers previously set by NSAPI are left intact */
526: zend_llist_apply(&sapi_headers->headers, (llist_apply_func_t) php_nsapi_remove_header TSRMLS_CC);
527: return 0;
528:
529: case SAPI_HEADER_DELETE:
530: /* reuse the zend_llist_apply callback function for this, too */
531: php_nsapi_remove_header(sapi_header TSRMLS_CC);
532: return 0;
533:
534: case SAPI_HEADER_ADD:
535: case SAPI_HEADER_REPLACE:
536: /* copy the header, because NSAPI needs reformatting and we do not want to change the parameter */
537: header_name = pool_strdup(rc->sn->pool, sapi_header->header);
538:
539: /* split header and align pointer for content */
540: header_content = strchr(header_name, ':');
541: if (header_content) {
542: *header_content = 0;
543: do {
544: header_content++;
545: } while (*header_content==' ');
546:
547: /* header_name to lower case because NSAPI reformats the headers and wants lowercase */
548: for (p=header_name; *p; p++) {
549: *p=tolower(*p);
550: }
551:
552: /* if REPLACE, remove first. "Content-type" is always removed, as SAPI has a bug according to this */
553: if (op==SAPI_HEADER_REPLACE || strcmp(header_name, "content-type")==0) {
554: param_free(pblock_remove(header_name, rc->rq->srvhdrs));
555: }
556: /* ADD header to nsapi table */
557: pblock_nvinsert(header_name, header_content, rc->rq->srvhdrs);
558: }
559:
560: pool_free(rc->sn->pool, header_name);
561: return SAPI_HEADER_ADD;
562:
563: default:
564: return 0;
565: }
566: }
567:
568: static int sapi_nsapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
569: {
570: int retval;
571: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
572:
573: if (SG(sapi_headers).send_default_content_type) {
574: char *hd;
575: param_free(pblock_remove("content-type", rc->rq->srvhdrs));
576: hd = sapi_get_default_content_type(TSRMLS_C);
577: pblock_nvinsert("content-type", hd, rc->rq->srvhdrs);
578: efree(hd);
579: }
580:
581: protocol_status(rc->sn, rc->rq, SG(sapi_headers).http_response_code, NULL);
582: retval = protocol_start_response(rc->sn, rc->rq);
583:
584: if (retval == REQ_PROCEED || retval == REQ_NOACTION) {
585: return SAPI_HEADER_SENT_SUCCESSFULLY;
586: } else {
587: return SAPI_HEADER_SEND_FAILED;
588: }
589: }
590:
591: static int sapi_nsapi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
592: {
593: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
594: char *read_ptr = buffer, *content_length_str = NULL;
595: uint bytes_read = 0;
596: int length, content_length = 0;
597: netbuf *nbuf = rc->sn->inbuf;
598:
599: /*
600: * Yesss!
601: */
602: count_bytes = MIN(count_bytes, SG(request_info).content_length-rc->read_post_bytes);
603: content_length = SG(request_info).content_length;
604:
605: if (content_length <= 0) {
606: return 0;
607: }
608:
609: /*
610: * Gobble any pending data in the netbuf.
611: */
612: length = nbuf->cursize - nbuf->pos;
613: length = MIN(count_bytes, length);
614: if (length > 0) {
615: memcpy(read_ptr, nbuf->inbuf + nbuf->pos, length);
616: bytes_read += length;
617: read_ptr += length;
618: content_length -= length;
619: nbuf->pos += length;
620: }
621:
622: /*
623: * Read the remaining from the socket.
624: */
625: while (content_length > 0 && bytes_read < count_bytes) {
626: int bytes_to_read = count_bytes - bytes_read;
627:
628: if (content_length < bytes_to_read) {
629: bytes_to_read = content_length;
630: }
631:
632: length = net_read(rc->sn->csd, read_ptr, bytes_to_read, NSAPI_G(read_timeout));
633:
634: if (length == IO_ERROR || length == IO_EOF) {
635: break;
636: }
637:
638: bytes_read += length;
639: read_ptr += length;
640: content_length -= length;
641: }
642:
643: if ( bytes_read > 0 ) {
644: rc->read_post_bytes += bytes_read;
645: }
646: return bytes_read;
647: }
648:
649: static char *sapi_nsapi_read_cookies(TSRMLS_D)
650: {
651: char *cookie_string;
652: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
653:
654: cookie_string = pblock_findval("cookie", rc->rq->headers);
655: return cookie_string;
656: }
657:
658: static void sapi_nsapi_register_server_variables(zval *track_vars_array TSRMLS_DC)
659: {
660: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
661: register size_t i;
662: int pos;
663: char *value,*p;
664: char buf[32];
665: struct pb_entry *entry;
666:
667: for (i = 0; i < nsapi_reqpb_size; i++) {
668: value = pblock_findval(nsapi_reqpb[i].nsapi_eq, rc->rq->reqpb);
669: if (value) {
670: php_register_variable((char *)nsapi_reqpb[i].env_var, value, track_vars_array TSRMLS_CC);
671: }
672: }
673:
674: for (i=0; i < rc->rq->headers->hsize; i++) {
675: entry=rc->rq->headers->ht[i];
676: while (entry) {
1.1.1.2 ! misho 677: if (strcasecmp(entry->param->name, "content-length")==0 || strcasecmp(entry->param->name, "content-type")==0) {
! 678: value=estrdup(entry->param->name);
! 679: pos = 0;
! 680: } else {
! 681: spprintf(&value, 0, "HTTP_%s", entry->param->name);
! 682: pos = 5;
! 683: }
! 684: if (value) {
! 685: for(p = value + pos; *p; p++) {
! 686: *p = toupper(*p);
! 687: if (!isalnum(*p)) {
! 688: *p = '_';
1.1 misho 689: }
690: }
1.1.1.2 ! misho 691: php_register_variable(value, entry->param->value, track_vars_array TSRMLS_CC);
! 692: efree(value);
1.1 misho 693: }
694: entry=entry->next;
695: }
696: }
697:
698: for (i = 0; i < nsapi_vars_size; i++) {
699: value = pblock_findval(nsapi_vars[i].nsapi_eq, rc->rq->vars);
700: if (value) {
701: php_register_variable((char *)nsapi_vars[i].env_var, value, track_vars_array TSRMLS_CC);
702: }
703: }
704:
705: for (i = 0; i < nsapi_client_size; i++) {
706: value = pblock_findval(nsapi_client[i].nsapi_eq, rc->sn->client);
707: if (value) {
708: php_register_variable((char *)nsapi_client[i].env_var, value, track_vars_array TSRMLS_CC);
709: }
710: }
711:
712: if (value = session_dns(rc->sn)) {
713: php_register_variable("REMOTE_HOST", value, track_vars_array TSRMLS_CC);
714: nsapi_free(value);
715: }
716:
717: slprintf(buf, sizeof(buf), "%d", conf_getglobals()->Vport);
718: php_register_variable("SERVER_PORT", buf, track_vars_array TSRMLS_CC);
719: php_register_variable("SERVER_NAME", conf_getglobals()->Vserver_hostname, track_vars_array TSRMLS_CC);
720:
721: value = http_uri2url_dynamic("", "", rc->sn, rc->rq);
722: php_register_variable("SERVER_URL", value, track_vars_array TSRMLS_CC);
723: nsapi_free(value);
724:
725: php_register_variable("SERVER_SOFTWARE", system_version(), track_vars_array TSRMLS_CC);
726: if (security_active) {
727: php_register_variable("HTTPS", "ON", track_vars_array TSRMLS_CC);
728: }
729: php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
730:
731: /* DOCUMENT_ROOT */
732: if (value = request_translate_uri("/", rc->sn)) {
733: pos = strlen(value);
734: php_register_variable_safe("DOCUMENT_ROOT", value, pos-1, track_vars_array TSRMLS_CC);
735: nsapi_free(value);
736: }
737:
738: /* PATH_INFO / PATH_TRANSLATED */
739: if (rc->path_info) {
740: if (value = request_translate_uri(rc->path_info, rc->sn)) {
741: php_register_variable("PATH_TRANSLATED", value, track_vars_array TSRMLS_CC);
742: nsapi_free(value);
743: }
744: php_register_variable("PATH_INFO", rc->path_info, track_vars_array TSRMLS_CC);
745: }
746:
747: /* Create full Request-URI & Script-Name */
748: if (SG(request_info).request_uri) {
749: pos = strlen(SG(request_info).request_uri);
750:
751: if (SG(request_info).query_string) {
752: spprintf(&value, 0, "%s?%s", SG(request_info).request_uri, SG(request_info).query_string);
753: if (value) {
754: php_register_variable("REQUEST_URI", value, track_vars_array TSRMLS_CC);
755: efree(value);
756: }
757: } else {
758: php_register_variable_safe("REQUEST_URI", SG(request_info).request_uri, pos, track_vars_array TSRMLS_CC);
759: }
760:
761: if (rc->path_info) {
762: pos -= strlen(rc->path_info);
763: if (pos<0) {
764: pos = 0;
765: }
766: }
767: php_register_variable_safe("SCRIPT_NAME", SG(request_info).request_uri, pos, track_vars_array TSRMLS_CC);
768: }
769: php_register_variable("SCRIPT_FILENAME", SG(request_info).path_translated, track_vars_array TSRMLS_CC);
770:
771: /* special variables in error mode */
772: if (rc->http_error) {
773: slprintf(buf, sizeof(buf), "%d", rc->http_error);
774: php_register_variable("ERROR_TYPE", buf, track_vars_array TSRMLS_CC);
775: }
776: }
777:
1.1.1.2 ! misho 778: static void nsapi_log_message(char *message TSRMLS_DC)
1.1 misho 779: {
780: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
781:
782: if (rc) {
783: log_error(LOG_INFORM, pblock_findval("fn", rc->pb), rc->sn, rc->rq, "%s", message);
784: } else {
785: log_error(LOG_INFORM, "php5", NULL, NULL, "%s", message);
786: }
787: }
788:
1.1.1.2 ! misho 789: static double sapi_nsapi_get_request_time(TSRMLS_D)
1.1 misho 790: {
791: return REQ_TIME( ((nsapi_request_context *)SG(server_context))->rq );
792: }
793:
794: static int php_nsapi_startup(sapi_module_struct *sapi_module)
795: {
796: if (php_module_startup(sapi_module, &nsapi_module_entry, 1)==FAILURE) {
797: return FAILURE;
798: }
799: return SUCCESS;
800: }
801:
802: static struct stat* sapi_nsapi_get_stat(TSRMLS_D)
803: {
804: return request_stat_path(
805: SG(request_info).path_translated,
806: ((nsapi_request_context *)SG(server_context))->rq
807: );
808: }
809:
810: static sapi_module_struct nsapi_sapi_module = {
811: "nsapi", /* name */
812: "NSAPI", /* pretty name */
813:
814: php_nsapi_startup, /* startup */
815: php_module_shutdown_wrapper, /* shutdown */
816:
817: NULL, /* activate */
818: NULL, /* deactivate */
819:
820: sapi_nsapi_ub_write, /* unbuffered write */
821: sapi_nsapi_flush, /* flush */
822: sapi_nsapi_get_stat, /* get uid/stat */
823: NULL, /* getenv */
824:
825: php_error, /* error handler */
826:
827: sapi_nsapi_header_handler, /* header handler */
828: sapi_nsapi_send_headers, /* send headers handler */
829: NULL, /* send header handler */
830:
831: sapi_nsapi_read_post, /* read POST data */
832: sapi_nsapi_read_cookies, /* read Cookies */
833:
834: sapi_nsapi_register_server_variables, /* register server variables */
835: nsapi_log_message, /* Log message */
836: sapi_nsapi_get_request_time, /* Get request time */
837: NULL, /* Child terminate */
838:
839: NULL, /* Block interruptions */
840: NULL, /* Unblock interruptions */
841:
842: STANDARD_SAPI_MODULE_PROPERTIES
843: };
844:
845: static void nsapi_php_ini_entries(NSLS_D TSRMLS_DC)
846: {
847: struct pb_entry *entry;
848: register int i,j,ok;
849:
850: for (i=0; i < NSG(pb)->hsize; i++) {
851: entry=NSG(pb)->ht[i];
852: while (entry) {
853: /* exclude standard entries given to "Service" which should not go into ini entries */
854: ok=1;
855: for (j=0; nsapi_exclude_from_ini_entries[j]; j++) {
856: ok&=(strcasecmp(entry->param->name, nsapi_exclude_from_ini_entries[j])!=0);
857: }
858:
859: if (ok) {
860: /* change the ini entry */
861: if (zend_alter_ini_entry(entry->param->name, strlen(entry->param->name)+1,
862: entry->param->value, strlen(entry->param->value),
863: PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE)==FAILURE) {
864: log_error(LOG_WARN, pblock_findval("fn", NSG(pb)), NSG(sn), NSG(rq), "Cannot change php.ini key \"%s\" to \"%s\"", entry->param->name, entry->param->value);
865: }
866: }
867: entry=entry->next;
868: }
869: }
870: }
871:
872: void NSAPI_PUBLIC php5_close(void *vparam)
873: {
874: if (nsapi_sapi_module.shutdown) {
875: nsapi_sapi_module.shutdown(&nsapi_sapi_module);
876: }
877:
878: if (nsapi_sapi_module.php_ini_path_override) {
879: free(nsapi_sapi_module.php_ini_path_override);
880: }
881:
882: #ifdef PHP_WIN32
883: if (nsapi_dll) {
884: free(nsapi_dll);
885: nsapi_dll = NULL;
886: }
887: #endif
888:
889: sapi_shutdown();
890: tsrm_shutdown();
891:
892: log_error(LOG_INFORM, "php5_close", NULL, NULL, "Shutdown PHP Module");
893: }
894:
895: /*********************************************************
896: / init SAF
897: /
898: / Init fn="php5_init" [php_ini="/path/to/php.ini"] [server_lib="ns-httpdXX.dll"]
899: / Initialize the NSAPI module in magnus.conf
900: /
901: / php_ini: gives path to php.ini file
902: / server_lib: (only Win32) gives name of DLL (without path) to look for
903: / servact_* functions
904: /
905: /*********************************************************/
906: int NSAPI_PUBLIC php5_init(pblock *pb, Session *sn, Request *rq)
907: {
908: php_core_globals *core_globals;
909: char *strval;
910: int threads=128; /* default for server */
911:
912: /* fetch max threads from NSAPI and initialize TSRM with it */
913: threads=conf_getglobals()->Vpool_maxthreads;
914: if (threads<1) {
915: threads=128; /* default for server */
916: }
917: tsrm_startup(threads, 1, 0, NULL);
918:
919: core_globals = ts_resource(core_globals_id);
920:
921: /* look if php_ini parameter is given to php5_init */
922: if (strval = pblock_findval("php_ini", pb)) {
923: nsapi_sapi_module.php_ini_path_override = strdup(strval);
924: }
925:
926: #ifdef PHP_WIN32
927: /* look if server_lib parameter is given to php5_init
928: * (this disables the automatic search for the newest ns-httpdXX.dll) */
929: if (strval = pblock_findval("server_lib", pb)) {
930: nsapi_dll = strdup(strval);
931: }
932: #endif
933:
934: /* start SAPI */
935: sapi_startup(&nsapi_sapi_module);
936: nsapi_sapi_module.startup(&nsapi_sapi_module);
937:
938: daemon_atrestart(&php5_close, NULL);
939:
940: log_error(LOG_INFORM, pblock_findval("fn", pb), sn, rq, "Initialized PHP Module (%d threads expected)", threads);
941: return REQ_PROCEED;
942: }
943:
944: /*********************************************************
945: / normal use in Service directive:
946: /
947: / Service fn="php5_execute" type=... method=... [inikey=inivalue inikey=inivalue...]
948: /
949: / use in Service for a directory to supply a php-made directory listing instead of server default:
950: /
951: / Service fn="php5_execute" type="magnus-internal/directory" script="/path/to/script.php" [inikey=inivalue inikey=inivalue...]
952: /
953: / use in Error SAF to display php script as error page:
954: /
955: / Error fn="php5_execute" code=XXX script="/path/to/script.php" [inikey=inivalue inikey=inivalue...]
956: / Error fn="php5_execute" reason="Reason" script="/path/to/script.php" [inikey=inivalue inikey=inivalue...]
957: /
958: /*********************************************************/
959: int NSAPI_PUBLIC php5_execute(pblock *pb, Session *sn, Request *rq)
960: {
961: int retval;
962: nsapi_request_context *request_context;
963: zend_file_handle file_handle = {0};
964: struct stat *fst;
965:
966: char *path_info;
967: char *query_string = pblock_findval("query", rq->reqpb);
968: char *uri = pblock_findval("uri", rq->reqpb);
969: char *request_method = pblock_findval("method", rq->reqpb);
970: char *content_type = pblock_findval("content-type", rq->headers);
971: char *content_length = pblock_findval("content-length", rq->headers);
972: char *directive = pblock_findval("Directive", pb);
973: int error_directive = (directive && !strcasecmp(directive, "error"));
974: int fixed_script = 1;
975:
976: /* try to use script parameter -> Error or Service for directory listing */
977: char *path_translated = pblock_findval("script", pb);
978:
979: TSRMLS_FETCH();
980:
981: /* if script parameter is missing: normal use as Service SAF */
982: if (!path_translated) {
983: path_translated = pblock_findval("path", rq->vars);
984: path_info = pblock_findval("path-info", rq->vars);
985: fixed_script = 0;
986: if (error_directive) {
987: /* go to next error directive if script parameter is missing */
988: log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Missing 'script' parameter");
989: return REQ_NOACTION;
990: }
991: } else {
992: /* in error the path_info is the uri to the requested page */
993: path_info = pblock_findval("uri", rq->reqpb);
994: }
995:
996: /* check if this uri was included in an other PHP script with nsapi_virtual()
997: by looking for a request context in the current thread */
998: if (SG(server_context)) {
999: /* send 500 internal server error */
1000: log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Cannot make nesting PHP requests with nsapi_virtual()");
1001: if (error_directive) {
1002: return REQ_NOACTION;
1003: } else {
1004: protocol_status(sn, rq, 500, NULL);
1005: return REQ_ABORTED;
1006: }
1007: }
1008:
1009: request_context = (nsapi_request_context *)pool_malloc(sn->pool, sizeof(nsapi_request_context));
1010: if (!request_context) {
1011: log_error(LOG_CATASTROPHE, pblock_findval("fn", pb), sn, rq, "Insufficient memory to process PHP request!");
1012: return REQ_ABORTED;
1013: }
1014: request_context->pb = pb;
1015: request_context->sn = sn;
1016: request_context->rq = rq;
1017: request_context->read_post_bytes = 0;
1018: request_context->fixed_script = fixed_script;
1019: request_context->http_error = (error_directive) ? rq->status_num : 0;
1020: request_context->path_info = path_info;
1021:
1022: SG(server_context) = request_context;
1023: SG(request_info).query_string = query_string;
1024: SG(request_info).request_uri = uri;
1025: SG(request_info).request_method = request_method;
1026: SG(request_info).path_translated = path_translated;
1027: SG(request_info).content_type = content_type;
1028: SG(request_info).content_length = (content_length == NULL) ? 0 : strtoul(content_length, 0, 0);
1029: SG(sapi_headers).http_response_code = (error_directive) ? rq->status_num : 200;
1030:
1031: nsapi_php_ini_entries(NSLS_C TSRMLS_CC);
1032:
1.1.1.2 ! misho 1033: php_handle_auth_data(pblock_findval("authorization", rq->headers) TSRMLS_CC);
1.1 misho 1034:
1035: file_handle.type = ZEND_HANDLE_FILENAME;
1036: file_handle.filename = SG(request_info).path_translated;
1037: file_handle.free_filename = 0;
1038: file_handle.opened_path = NULL;
1039:
1040: fst = request_stat_path(SG(request_info).path_translated, rq);
1041: if (fst && S_ISREG(fst->st_mode)) {
1042: if (php_request_startup(TSRMLS_C) == SUCCESS) {
1043: php_execute_script(&file_handle TSRMLS_CC);
1044: php_request_shutdown(NULL);
1045: retval=REQ_PROCEED;
1046: } else {
1047: /* send 500 internal server error */
1048: log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Cannot prepare PHP engine!");
1049: if (error_directive) {
1050: retval=REQ_NOACTION;
1051: } else {
1052: protocol_status(sn, rq, 500, NULL);
1053: retval=REQ_ABORTED;
1054: }
1055: }
1056: } else {
1057: /* send 404 because file not found */
1058: log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Cannot execute PHP script: %s (File not found)", SG(request_info).path_translated);
1059: if (error_directive) {
1060: retval=REQ_NOACTION;
1061: } else {
1062: protocol_status(sn, rq, 404, NULL);
1063: retval=REQ_ABORTED;
1064: }
1065: }
1066:
1067: pool_free(sn->pool, request_context);
1068: SG(server_context) = NULL;
1069:
1070: return retval;
1071: }
1072:
1073: /*********************************************************
1074: / authentication
1075: /
1076: / we have to make a 'fake' authenticator for netscape so it
1077: / will pass authentication through to php, and allow us to
1078: / check authentication with our scripts.
1079: /
1080: / php5_auth_trans
1081: / main function called from netscape server to authenticate
1082: / a line in obj.conf:
1083: / funcs=php5_auth_trans shlib="path/to/this/phpnsapi.dll"
1084: / and:
1085: / <Object ppath="path/to/be/authenticated/by/php/*">
1086: / AuthTrans fn="php5_auth_trans"
1087: /*********************************************************/
1088: int NSAPI_PUBLIC php5_auth_trans(pblock * pb, Session * sn, Request * rq)
1089: {
1090: /* This is a DO NOTHING function that allows authentication
1091: * information
1092: * to be passed through to PHP scripts.
1093: */
1094: return REQ_PROCEED;
1095: }
1096:
1097: /*
1098: * Local variables:
1099: * tab-width: 4
1100: * c-basic-offset: 4
1101: * End:
1102: * vim600: sw=4 ts=4 fdm=marker
1103: * vim<600: sw=4 ts=4
1104: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>