Annotation of embedaddon/php/sapi/nsapi/nsapi.c, revision 1.1
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:
! 20: /* $Id: nsapi.c 321634 2012-01-01 13:15:04Z felipe $ */
! 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();
! 315: php_info_print_table_row(2, "NSAPI Module Revision", "$Revision: 321634 $");
! 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 {
! 350: php_end_ob_buffers(1 TSRMLS_CC);
! 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) {
! 417: if (!PG(safe_mode) || strncasecmp(entry->param->name, "authorization", 13)) {
! 418: add_assoc_string(return_value, entry->param->name, entry->param->value, 1);
! 419: }
! 420: entry=entry->next;
! 421: }
! 422: }
! 423: }
! 424: /* }}} */
! 425:
! 426: /* {{{ proto array nsapi_response_headers(void)
! 427: Get all headers from the response */
! 428: PHP_FUNCTION(nsapi_response_headers)
! 429: {
! 430: register int i;
! 431: struct pb_entry *entry;
! 432: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
! 433:
! 434: if (zend_parse_parameters_none() == FAILURE) {
! 435: return;
! 436: }
! 437:
! 438: array_init(return_value);
! 439:
! 440: for (i=0; i < rc->rq->srvhdrs->hsize; i++) {
! 441: entry=rc->rq->srvhdrs->ht[i];
! 442: while (entry) {
! 443: add_assoc_string(return_value, entry->param->name, entry->param->value, 1);
! 444: entry=entry->next;
! 445: }
! 446: }
! 447: }
! 448: /* }}} */
! 449:
! 450:
! 451: /*************/
! 452: /* SAPI part */
! 453: /*************/
! 454:
! 455: static int sapi_nsapi_ub_write(const char *str, unsigned int str_length TSRMLS_DC)
! 456: {
! 457: int retval;
! 458: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
! 459:
! 460: if (!SG(headers_sent)) {
! 461: sapi_send_headers(TSRMLS_C);
! 462: }
! 463:
! 464: retval = net_write(rc->sn->csd, (char *)str, str_length);
! 465: if (retval == IO_ERROR /* -1 */ || retval == IO_EOF /* 0 */) {
! 466: php_handle_aborted_connection();
! 467: }
! 468: return retval;
! 469: }
! 470:
! 471: /* modified version of apache2 */
! 472: static void sapi_nsapi_flush(void *server_context)
! 473: {
! 474: nsapi_request_context *rc = (nsapi_request_context *)server_context;
! 475: TSRMLS_FETCH();
! 476:
! 477: if (!rc) {
! 478: /* we have no context, so no flushing needed. This fixes a SIGSEGV on shutdown */
! 479: return;
! 480: }
! 481:
! 482: if (!SG(headers_sent)) {
! 483: sapi_send_headers(TSRMLS_C);
! 484: }
! 485:
! 486: /* flushing is only supported in iPlanet servers from version 6.1 on, make it conditional */
! 487: #if NSAPI_VERSION >= 302
! 488: if (net_flush(rc->sn->csd) < 0) {
! 489: php_handle_aborted_connection();
! 490: }
! 491: #endif
! 492: }
! 493:
! 494: /* callback for zend_llist_apply on SAPI_HEADER_DELETE_ALL operation */
! 495: static int php_nsapi_remove_header(sapi_header_struct *sapi_header TSRMLS_DC)
! 496: {
! 497: char *header_name, *p;
! 498: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
! 499:
! 500: /* copy the header, because NSAPI needs reformatting and we do not want to change the parameter */
! 501: header_name = pool_strdup(rc->sn->pool, sapi_header->header);
! 502:
! 503: /* extract name, this works, if only the header without ':' is given, too */
! 504: if (p = strchr(header_name, ':')) {
! 505: *p = 0;
! 506: }
! 507:
! 508: /* header_name to lower case because NSAPI reformats the headers and wants lowercase */
! 509: for (p=header_name; *p; p++) {
! 510: *p=tolower(*p);
! 511: }
! 512:
! 513: /* remove the header */
! 514: param_free(pblock_remove(header_name, rc->rq->srvhdrs));
! 515: pool_free(rc->sn->pool, header_name);
! 516:
! 517: return ZEND_HASH_APPLY_KEEP;
! 518: }
! 519:
! 520: static int sapi_nsapi_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC)
! 521: {
! 522: char *header_name, *header_content, *p;
! 523: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
! 524:
! 525: switch(op) {
! 526: case SAPI_HEADER_DELETE_ALL:
! 527: /* this only deletes headers set or overwritten by PHP, headers previously set by NSAPI are left intact */
! 528: zend_llist_apply(&sapi_headers->headers, (llist_apply_func_t) php_nsapi_remove_header TSRMLS_CC);
! 529: return 0;
! 530:
! 531: case SAPI_HEADER_DELETE:
! 532: /* reuse the zend_llist_apply callback function for this, too */
! 533: php_nsapi_remove_header(sapi_header TSRMLS_CC);
! 534: return 0;
! 535:
! 536: case SAPI_HEADER_ADD:
! 537: case SAPI_HEADER_REPLACE:
! 538: /* copy the header, because NSAPI needs reformatting and we do not want to change the parameter */
! 539: header_name = pool_strdup(rc->sn->pool, sapi_header->header);
! 540:
! 541: /* split header and align pointer for content */
! 542: header_content = strchr(header_name, ':');
! 543: if (header_content) {
! 544: *header_content = 0;
! 545: do {
! 546: header_content++;
! 547: } while (*header_content==' ');
! 548:
! 549: /* header_name to lower case because NSAPI reformats the headers and wants lowercase */
! 550: for (p=header_name; *p; p++) {
! 551: *p=tolower(*p);
! 552: }
! 553:
! 554: /* if REPLACE, remove first. "Content-type" is always removed, as SAPI has a bug according to this */
! 555: if (op==SAPI_HEADER_REPLACE || strcmp(header_name, "content-type")==0) {
! 556: param_free(pblock_remove(header_name, rc->rq->srvhdrs));
! 557: }
! 558: /* ADD header to nsapi table */
! 559: pblock_nvinsert(header_name, header_content, rc->rq->srvhdrs);
! 560: }
! 561:
! 562: pool_free(rc->sn->pool, header_name);
! 563: return SAPI_HEADER_ADD;
! 564:
! 565: default:
! 566: return 0;
! 567: }
! 568: }
! 569:
! 570: static int sapi_nsapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
! 571: {
! 572: int retval;
! 573: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
! 574:
! 575: if (SG(sapi_headers).send_default_content_type) {
! 576: char *hd;
! 577: param_free(pblock_remove("content-type", rc->rq->srvhdrs));
! 578: hd = sapi_get_default_content_type(TSRMLS_C);
! 579: pblock_nvinsert("content-type", hd, rc->rq->srvhdrs);
! 580: efree(hd);
! 581: }
! 582:
! 583: protocol_status(rc->sn, rc->rq, SG(sapi_headers).http_response_code, NULL);
! 584: retval = protocol_start_response(rc->sn, rc->rq);
! 585:
! 586: if (retval == REQ_PROCEED || retval == REQ_NOACTION) {
! 587: return SAPI_HEADER_SENT_SUCCESSFULLY;
! 588: } else {
! 589: return SAPI_HEADER_SEND_FAILED;
! 590: }
! 591: }
! 592:
! 593: static int sapi_nsapi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
! 594: {
! 595: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
! 596: char *read_ptr = buffer, *content_length_str = NULL;
! 597: uint bytes_read = 0;
! 598: int length, content_length = 0;
! 599: netbuf *nbuf = rc->sn->inbuf;
! 600:
! 601: /*
! 602: * Yesss!
! 603: */
! 604: count_bytes = MIN(count_bytes, SG(request_info).content_length-rc->read_post_bytes);
! 605: content_length = SG(request_info).content_length;
! 606:
! 607: if (content_length <= 0) {
! 608: return 0;
! 609: }
! 610:
! 611: /*
! 612: * Gobble any pending data in the netbuf.
! 613: */
! 614: length = nbuf->cursize - nbuf->pos;
! 615: length = MIN(count_bytes, length);
! 616: if (length > 0) {
! 617: memcpy(read_ptr, nbuf->inbuf + nbuf->pos, length);
! 618: bytes_read += length;
! 619: read_ptr += length;
! 620: content_length -= length;
! 621: nbuf->pos += length;
! 622: }
! 623:
! 624: /*
! 625: * Read the remaining from the socket.
! 626: */
! 627: while (content_length > 0 && bytes_read < count_bytes) {
! 628: int bytes_to_read = count_bytes - bytes_read;
! 629:
! 630: if (content_length < bytes_to_read) {
! 631: bytes_to_read = content_length;
! 632: }
! 633:
! 634: length = net_read(rc->sn->csd, read_ptr, bytes_to_read, NSAPI_G(read_timeout));
! 635:
! 636: if (length == IO_ERROR || length == IO_EOF) {
! 637: break;
! 638: }
! 639:
! 640: bytes_read += length;
! 641: read_ptr += length;
! 642: content_length -= length;
! 643: }
! 644:
! 645: if ( bytes_read > 0 ) {
! 646: rc->read_post_bytes += bytes_read;
! 647: }
! 648: return bytes_read;
! 649: }
! 650:
! 651: static char *sapi_nsapi_read_cookies(TSRMLS_D)
! 652: {
! 653: char *cookie_string;
! 654: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
! 655:
! 656: cookie_string = pblock_findval("cookie", rc->rq->headers);
! 657: return cookie_string;
! 658: }
! 659:
! 660: static void sapi_nsapi_register_server_variables(zval *track_vars_array TSRMLS_DC)
! 661: {
! 662: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
! 663: register size_t i;
! 664: int pos;
! 665: char *value,*p;
! 666: char buf[32];
! 667: struct pb_entry *entry;
! 668:
! 669: for (i = 0; i < nsapi_reqpb_size; i++) {
! 670: value = pblock_findval(nsapi_reqpb[i].nsapi_eq, rc->rq->reqpb);
! 671: if (value) {
! 672: php_register_variable((char *)nsapi_reqpb[i].env_var, value, track_vars_array TSRMLS_CC);
! 673: }
! 674: }
! 675:
! 676: for (i=0; i < rc->rq->headers->hsize; i++) {
! 677: entry=rc->rq->headers->ht[i];
! 678: while (entry) {
! 679: if (!PG(safe_mode) || strncasecmp(entry->param->name, "authorization", 13)) {
! 680: if (strcasecmp(entry->param->name, "content-length")==0 || strcasecmp(entry->param->name, "content-type")==0) {
! 681: value=estrdup(entry->param->name);
! 682: pos = 0;
! 683: } else {
! 684: spprintf(&value, 0, "HTTP_%s", entry->param->name);
! 685: pos = 5;
! 686: }
! 687: if (value) {
! 688: for(p = value + pos; *p; p++) {
! 689: *p = toupper(*p);
! 690: if (!isalnum(*p)) {
! 691: *p = '_';
! 692: }
! 693: }
! 694: php_register_variable(value, entry->param->value, track_vars_array TSRMLS_CC);
! 695: efree(value);
! 696: }
! 697: }
! 698: entry=entry->next;
! 699: }
! 700: }
! 701:
! 702: for (i = 0; i < nsapi_vars_size; i++) {
! 703: value = pblock_findval(nsapi_vars[i].nsapi_eq, rc->rq->vars);
! 704: if (value) {
! 705: php_register_variable((char *)nsapi_vars[i].env_var, value, track_vars_array TSRMLS_CC);
! 706: }
! 707: }
! 708:
! 709: for (i = 0; i < nsapi_client_size; i++) {
! 710: value = pblock_findval(nsapi_client[i].nsapi_eq, rc->sn->client);
! 711: if (value) {
! 712: php_register_variable((char *)nsapi_client[i].env_var, value, track_vars_array TSRMLS_CC);
! 713: }
! 714: }
! 715:
! 716: if (value = session_dns(rc->sn)) {
! 717: php_register_variable("REMOTE_HOST", value, track_vars_array TSRMLS_CC);
! 718: nsapi_free(value);
! 719: }
! 720:
! 721: slprintf(buf, sizeof(buf), "%d", conf_getglobals()->Vport);
! 722: php_register_variable("SERVER_PORT", buf, track_vars_array TSRMLS_CC);
! 723: php_register_variable("SERVER_NAME", conf_getglobals()->Vserver_hostname, track_vars_array TSRMLS_CC);
! 724:
! 725: value = http_uri2url_dynamic("", "", rc->sn, rc->rq);
! 726: php_register_variable("SERVER_URL", value, track_vars_array TSRMLS_CC);
! 727: nsapi_free(value);
! 728:
! 729: php_register_variable("SERVER_SOFTWARE", system_version(), track_vars_array TSRMLS_CC);
! 730: if (security_active) {
! 731: php_register_variable("HTTPS", "ON", track_vars_array TSRMLS_CC);
! 732: }
! 733: php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
! 734:
! 735: /* DOCUMENT_ROOT */
! 736: if (value = request_translate_uri("/", rc->sn)) {
! 737: pos = strlen(value);
! 738: php_register_variable_safe("DOCUMENT_ROOT", value, pos-1, track_vars_array TSRMLS_CC);
! 739: nsapi_free(value);
! 740: }
! 741:
! 742: /* PATH_INFO / PATH_TRANSLATED */
! 743: if (rc->path_info) {
! 744: if (value = request_translate_uri(rc->path_info, rc->sn)) {
! 745: php_register_variable("PATH_TRANSLATED", value, track_vars_array TSRMLS_CC);
! 746: nsapi_free(value);
! 747: }
! 748: php_register_variable("PATH_INFO", rc->path_info, track_vars_array TSRMLS_CC);
! 749: }
! 750:
! 751: /* Create full Request-URI & Script-Name */
! 752: if (SG(request_info).request_uri) {
! 753: pos = strlen(SG(request_info).request_uri);
! 754:
! 755: if (SG(request_info).query_string) {
! 756: spprintf(&value, 0, "%s?%s", SG(request_info).request_uri, SG(request_info).query_string);
! 757: if (value) {
! 758: php_register_variable("REQUEST_URI", value, track_vars_array TSRMLS_CC);
! 759: efree(value);
! 760: }
! 761: } else {
! 762: php_register_variable_safe("REQUEST_URI", SG(request_info).request_uri, pos, track_vars_array TSRMLS_CC);
! 763: }
! 764:
! 765: if (rc->path_info) {
! 766: pos -= strlen(rc->path_info);
! 767: if (pos<0) {
! 768: pos = 0;
! 769: }
! 770: }
! 771: php_register_variable_safe("SCRIPT_NAME", SG(request_info).request_uri, pos, track_vars_array TSRMLS_CC);
! 772: }
! 773: php_register_variable("SCRIPT_FILENAME", SG(request_info).path_translated, track_vars_array TSRMLS_CC);
! 774:
! 775: /* special variables in error mode */
! 776: if (rc->http_error) {
! 777: slprintf(buf, sizeof(buf), "%d", rc->http_error);
! 778: php_register_variable("ERROR_TYPE", buf, track_vars_array TSRMLS_CC);
! 779: }
! 780: }
! 781:
! 782: static void nsapi_log_message(char *message)
! 783: {
! 784: TSRMLS_FETCH();
! 785: nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
! 786:
! 787: if (rc) {
! 788: log_error(LOG_INFORM, pblock_findval("fn", rc->pb), rc->sn, rc->rq, "%s", message);
! 789: } else {
! 790: log_error(LOG_INFORM, "php5", NULL, NULL, "%s", message);
! 791: }
! 792: }
! 793:
! 794: static time_t sapi_nsapi_get_request_time(TSRMLS_D)
! 795: {
! 796: return REQ_TIME( ((nsapi_request_context *)SG(server_context))->rq );
! 797: }
! 798:
! 799: static int php_nsapi_startup(sapi_module_struct *sapi_module)
! 800: {
! 801: if (php_module_startup(sapi_module, &nsapi_module_entry, 1)==FAILURE) {
! 802: return FAILURE;
! 803: }
! 804: return SUCCESS;
! 805: }
! 806:
! 807: static struct stat* sapi_nsapi_get_stat(TSRMLS_D)
! 808: {
! 809: return request_stat_path(
! 810: SG(request_info).path_translated,
! 811: ((nsapi_request_context *)SG(server_context))->rq
! 812: );
! 813: }
! 814:
! 815: static sapi_module_struct nsapi_sapi_module = {
! 816: "nsapi", /* name */
! 817: "NSAPI", /* pretty name */
! 818:
! 819: php_nsapi_startup, /* startup */
! 820: php_module_shutdown_wrapper, /* shutdown */
! 821:
! 822: NULL, /* activate */
! 823: NULL, /* deactivate */
! 824:
! 825: sapi_nsapi_ub_write, /* unbuffered write */
! 826: sapi_nsapi_flush, /* flush */
! 827: sapi_nsapi_get_stat, /* get uid/stat */
! 828: NULL, /* getenv */
! 829:
! 830: php_error, /* error handler */
! 831:
! 832: sapi_nsapi_header_handler, /* header handler */
! 833: sapi_nsapi_send_headers, /* send headers handler */
! 834: NULL, /* send header handler */
! 835:
! 836: sapi_nsapi_read_post, /* read POST data */
! 837: sapi_nsapi_read_cookies, /* read Cookies */
! 838:
! 839: sapi_nsapi_register_server_variables, /* register server variables */
! 840: nsapi_log_message, /* Log message */
! 841: sapi_nsapi_get_request_time, /* Get request time */
! 842: NULL, /* Child terminate */
! 843:
! 844: NULL, /* Block interruptions */
! 845: NULL, /* Unblock interruptions */
! 846:
! 847: STANDARD_SAPI_MODULE_PROPERTIES
! 848: };
! 849:
! 850: static void nsapi_php_ini_entries(NSLS_D TSRMLS_DC)
! 851: {
! 852: struct pb_entry *entry;
! 853: register int i,j,ok;
! 854:
! 855: for (i=0; i < NSG(pb)->hsize; i++) {
! 856: entry=NSG(pb)->ht[i];
! 857: while (entry) {
! 858: /* exclude standard entries given to "Service" which should not go into ini entries */
! 859: ok=1;
! 860: for (j=0; nsapi_exclude_from_ini_entries[j]; j++) {
! 861: ok&=(strcasecmp(entry->param->name, nsapi_exclude_from_ini_entries[j])!=0);
! 862: }
! 863:
! 864: if (ok) {
! 865: /* change the ini entry */
! 866: if (zend_alter_ini_entry(entry->param->name, strlen(entry->param->name)+1,
! 867: entry->param->value, strlen(entry->param->value),
! 868: PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE)==FAILURE) {
! 869: 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);
! 870: }
! 871: }
! 872: entry=entry->next;
! 873: }
! 874: }
! 875: }
! 876:
! 877: void NSAPI_PUBLIC php5_close(void *vparam)
! 878: {
! 879: if (nsapi_sapi_module.shutdown) {
! 880: nsapi_sapi_module.shutdown(&nsapi_sapi_module);
! 881: }
! 882:
! 883: if (nsapi_sapi_module.php_ini_path_override) {
! 884: free(nsapi_sapi_module.php_ini_path_override);
! 885: }
! 886:
! 887: #ifdef PHP_WIN32
! 888: if (nsapi_dll) {
! 889: free(nsapi_dll);
! 890: nsapi_dll = NULL;
! 891: }
! 892: #endif
! 893:
! 894: sapi_shutdown();
! 895: tsrm_shutdown();
! 896:
! 897: log_error(LOG_INFORM, "php5_close", NULL, NULL, "Shutdown PHP Module");
! 898: }
! 899:
! 900: /*********************************************************
! 901: / init SAF
! 902: /
! 903: / Init fn="php5_init" [php_ini="/path/to/php.ini"] [server_lib="ns-httpdXX.dll"]
! 904: / Initialize the NSAPI module in magnus.conf
! 905: /
! 906: / php_ini: gives path to php.ini file
! 907: / server_lib: (only Win32) gives name of DLL (without path) to look for
! 908: / servact_* functions
! 909: /
! 910: /*********************************************************/
! 911: int NSAPI_PUBLIC php5_init(pblock *pb, Session *sn, Request *rq)
! 912: {
! 913: php_core_globals *core_globals;
! 914: char *strval;
! 915: int threads=128; /* default for server */
! 916:
! 917: /* fetch max threads from NSAPI and initialize TSRM with it */
! 918: threads=conf_getglobals()->Vpool_maxthreads;
! 919: if (threads<1) {
! 920: threads=128; /* default for server */
! 921: }
! 922: tsrm_startup(threads, 1, 0, NULL);
! 923:
! 924: core_globals = ts_resource(core_globals_id);
! 925:
! 926: /* look if php_ini parameter is given to php5_init */
! 927: if (strval = pblock_findval("php_ini", pb)) {
! 928: nsapi_sapi_module.php_ini_path_override = strdup(strval);
! 929: }
! 930:
! 931: #ifdef PHP_WIN32
! 932: /* look if server_lib parameter is given to php5_init
! 933: * (this disables the automatic search for the newest ns-httpdXX.dll) */
! 934: if (strval = pblock_findval("server_lib", pb)) {
! 935: nsapi_dll = strdup(strval);
! 936: }
! 937: #endif
! 938:
! 939: /* start SAPI */
! 940: sapi_startup(&nsapi_sapi_module);
! 941: nsapi_sapi_module.startup(&nsapi_sapi_module);
! 942:
! 943: daemon_atrestart(&php5_close, NULL);
! 944:
! 945: log_error(LOG_INFORM, pblock_findval("fn", pb), sn, rq, "Initialized PHP Module (%d threads expected)", threads);
! 946: return REQ_PROCEED;
! 947: }
! 948:
! 949: /*********************************************************
! 950: / normal use in Service directive:
! 951: /
! 952: / Service fn="php5_execute" type=... method=... [inikey=inivalue inikey=inivalue...]
! 953: /
! 954: / use in Service for a directory to supply a php-made directory listing instead of server default:
! 955: /
! 956: / Service fn="php5_execute" type="magnus-internal/directory" script="/path/to/script.php" [inikey=inivalue inikey=inivalue...]
! 957: /
! 958: / use in Error SAF to display php script as error page:
! 959: /
! 960: / Error fn="php5_execute" code=XXX script="/path/to/script.php" [inikey=inivalue inikey=inivalue...]
! 961: / Error fn="php5_execute" reason="Reason" script="/path/to/script.php" [inikey=inivalue inikey=inivalue...]
! 962: /
! 963: /*********************************************************/
! 964: int NSAPI_PUBLIC php5_execute(pblock *pb, Session *sn, Request *rq)
! 965: {
! 966: int retval;
! 967: nsapi_request_context *request_context;
! 968: zend_file_handle file_handle = {0};
! 969: struct stat *fst;
! 970:
! 971: char *path_info;
! 972: char *query_string = pblock_findval("query", rq->reqpb);
! 973: char *uri = pblock_findval("uri", rq->reqpb);
! 974: char *request_method = pblock_findval("method", rq->reqpb);
! 975: char *content_type = pblock_findval("content-type", rq->headers);
! 976: char *content_length = pblock_findval("content-length", rq->headers);
! 977: char *directive = pblock_findval("Directive", pb);
! 978: int error_directive = (directive && !strcasecmp(directive, "error"));
! 979: int fixed_script = 1;
! 980:
! 981: /* try to use script parameter -> Error or Service for directory listing */
! 982: char *path_translated = pblock_findval("script", pb);
! 983:
! 984: TSRMLS_FETCH();
! 985:
! 986: /* if script parameter is missing: normal use as Service SAF */
! 987: if (!path_translated) {
! 988: path_translated = pblock_findval("path", rq->vars);
! 989: path_info = pblock_findval("path-info", rq->vars);
! 990: fixed_script = 0;
! 991: if (error_directive) {
! 992: /* go to next error directive if script parameter is missing */
! 993: log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Missing 'script' parameter");
! 994: return REQ_NOACTION;
! 995: }
! 996: } else {
! 997: /* in error the path_info is the uri to the requested page */
! 998: path_info = pblock_findval("uri", rq->reqpb);
! 999: }
! 1000:
! 1001: /* check if this uri was included in an other PHP script with nsapi_virtual()
! 1002: by looking for a request context in the current thread */
! 1003: if (SG(server_context)) {
! 1004: /* send 500 internal server error */
! 1005: log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Cannot make nesting PHP requests with nsapi_virtual()");
! 1006: if (error_directive) {
! 1007: return REQ_NOACTION;
! 1008: } else {
! 1009: protocol_status(sn, rq, 500, NULL);
! 1010: return REQ_ABORTED;
! 1011: }
! 1012: }
! 1013:
! 1014: request_context = (nsapi_request_context *)pool_malloc(sn->pool, sizeof(nsapi_request_context));
! 1015: if (!request_context) {
! 1016: log_error(LOG_CATASTROPHE, pblock_findval("fn", pb), sn, rq, "Insufficient memory to process PHP request!");
! 1017: return REQ_ABORTED;
! 1018: }
! 1019: request_context->pb = pb;
! 1020: request_context->sn = sn;
! 1021: request_context->rq = rq;
! 1022: request_context->read_post_bytes = 0;
! 1023: request_context->fixed_script = fixed_script;
! 1024: request_context->http_error = (error_directive) ? rq->status_num : 0;
! 1025: request_context->path_info = path_info;
! 1026:
! 1027: SG(server_context) = request_context;
! 1028: SG(request_info).query_string = query_string;
! 1029: SG(request_info).request_uri = uri;
! 1030: SG(request_info).request_method = request_method;
! 1031: SG(request_info).path_translated = path_translated;
! 1032: SG(request_info).content_type = content_type;
! 1033: SG(request_info).content_length = (content_length == NULL) ? 0 : strtoul(content_length, 0, 0);
! 1034: SG(sapi_headers).http_response_code = (error_directive) ? rq->status_num : 200;
! 1035:
! 1036: nsapi_php_ini_entries(NSLS_C TSRMLS_CC);
! 1037:
! 1038: if (!PG(safe_mode)) php_handle_auth_data(pblock_findval("authorization", rq->headers) TSRMLS_CC);
! 1039:
! 1040: file_handle.type = ZEND_HANDLE_FILENAME;
! 1041: file_handle.filename = SG(request_info).path_translated;
! 1042: file_handle.free_filename = 0;
! 1043: file_handle.opened_path = NULL;
! 1044:
! 1045: fst = request_stat_path(SG(request_info).path_translated, rq);
! 1046: if (fst && S_ISREG(fst->st_mode)) {
! 1047: if (php_request_startup(TSRMLS_C) == SUCCESS) {
! 1048: php_execute_script(&file_handle TSRMLS_CC);
! 1049: php_request_shutdown(NULL);
! 1050: retval=REQ_PROCEED;
! 1051: } else {
! 1052: /* send 500 internal server error */
! 1053: log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Cannot prepare PHP engine!");
! 1054: if (error_directive) {
! 1055: retval=REQ_NOACTION;
! 1056: } else {
! 1057: protocol_status(sn, rq, 500, NULL);
! 1058: retval=REQ_ABORTED;
! 1059: }
! 1060: }
! 1061: } else {
! 1062: /* send 404 because file not found */
! 1063: log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Cannot execute PHP script: %s (File not found)", SG(request_info).path_translated);
! 1064: if (error_directive) {
! 1065: retval=REQ_NOACTION;
! 1066: } else {
! 1067: protocol_status(sn, rq, 404, NULL);
! 1068: retval=REQ_ABORTED;
! 1069: }
! 1070: }
! 1071:
! 1072: pool_free(sn->pool, request_context);
! 1073: SG(server_context) = NULL;
! 1074:
! 1075: return retval;
! 1076: }
! 1077:
! 1078: /*********************************************************
! 1079: / authentication
! 1080: /
! 1081: / we have to make a 'fake' authenticator for netscape so it
! 1082: / will pass authentication through to php, and allow us to
! 1083: / check authentication with our scripts.
! 1084: /
! 1085: / php5_auth_trans
! 1086: / main function called from netscape server to authenticate
! 1087: / a line in obj.conf:
! 1088: / funcs=php5_auth_trans shlib="path/to/this/phpnsapi.dll"
! 1089: / and:
! 1090: / <Object ppath="path/to/be/authenticated/by/php/*">
! 1091: / AuthTrans fn="php5_auth_trans"
! 1092: /*********************************************************/
! 1093: int NSAPI_PUBLIC php5_auth_trans(pblock * pb, Session * sn, Request * rq)
! 1094: {
! 1095: /* This is a DO NOTHING function that allows authentication
! 1096: * information
! 1097: * to be passed through to PHP scripts.
! 1098: */
! 1099: return REQ_PROCEED;
! 1100: }
! 1101:
! 1102: /*
! 1103: * Local variables:
! 1104: * tab-width: 4
! 1105: * c-basic-offset: 4
! 1106: * End:
! 1107: * vim600: sw=4 ts=4 fdm=marker
! 1108: * vim<600: sw=4 ts=4
! 1109: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>