You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1021 lines
31 KiB

21 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
23 years ago
23 years ago
23 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
25 years ago
24 years ago
24 years ago
23 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2005 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.0 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_0.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. /* $Id$ */
  20. /*
  21. * PHP includes
  22. */
  23. #define NSAPI 1
  24. #ifdef HAVE_CONFIG_H
  25. #include "config.h"
  26. #endif
  27. #include "php.h"
  28. #include "php_variables.h"
  29. #include "ext/standard/info.h"
  30. #include "php_ini.h"
  31. #include "php_globals.h"
  32. #include "SAPI.h"
  33. #include "php_main.h"
  34. #include "php_version.h"
  35. #include "TSRM.h"
  36. #include "ext/standard/php_standard.h"
  37. #include <sys/types.h>
  38. #include <sys/stat.h>
  39. #ifndef RTLD_DEFAULT
  40. #define RTLD_DEFAULT NULL
  41. #endif
  42. /*
  43. * If neither XP_UNIX not XP_WIN32 is defined use PHP_WIN32
  44. */
  45. #if !defined(XP_UNIX) && !defined(XP_WIN32)
  46. #ifdef PHP_WIN32
  47. #define XP_WIN32
  48. #else
  49. #define XP_UNIX
  50. #endif
  51. #endif
  52. /*
  53. * NSAPI includes
  54. */
  55. #include "nsapi.h"
  56. #include "base/pblock.h"
  57. #include "base/session.h"
  58. #include "frame/req.h"
  59. #include "frame/protocol.h" /* protocol_start_response */
  60. #include "base/util.h" /* is_mozilla, getline */
  61. #include "frame/log.h" /* log_error */
  62. #define NSLS_D struct nsapi_request_context *request_context
  63. #define NSLS_DC , NSLS_D
  64. #define NSLS_C request_context
  65. #define NSLS_CC , NSLS_C
  66. #define NSG(v) (request_context->v)
  67. #define NS_BUF_SIZE 2048
  68. /*
  69. * ZTS needs to be defined for NSAPI to work
  70. */
  71. #if !defined(ZTS)
  72. #error "NSAPI module needs ZTS to be defined"
  73. #endif
  74. /*
  75. * Structure to encapsulate the NSAPI request in SAPI
  76. */
  77. typedef struct nsapi_request_context {
  78. pblock *pb;
  79. Session *sn;
  80. Request *rq;
  81. int read_post_bytes;
  82. char *path_info;
  83. int fixed_script; /* 0 if script is from URI, 1 if script is from "script" parameter */
  84. short http_error; /* 0 in normal mode; for errors the HTTP error code */
  85. } nsapi_request_context;
  86. /*
  87. * Mappings between NSAPI names and environment variables. This
  88. * mapping was obtained from the sample programs at the iplanet
  89. * website.
  90. */
  91. typedef struct nsapi_equiv {
  92. const char *env_var;
  93. const char *nsapi_eq;
  94. } nsapi_equiv;
  95. static nsapi_equiv nsapi_reqpb[] = {
  96. { "QUERY_STRING", "query" },
  97. { "REQUEST_LINE", "clf-request" },
  98. { "REQUEST_METHOD", "method" },
  99. { "PHP_SELF", "uri" },
  100. { "SERVER_PROTOCOL", "protocol" }
  101. };
  102. static size_t nsapi_reqpb_size = sizeof(nsapi_reqpb)/sizeof(nsapi_reqpb[0]);
  103. static nsapi_equiv nsapi_vars[] = {
  104. { "AUTH_TYPE", "auth-type" },
  105. { "CLIENT_CERT", "auth-cert" },
  106. { "REMOTE_USER", "auth-user" }
  107. };
  108. static size_t nsapi_vars_size = sizeof(nsapi_vars)/sizeof(nsapi_vars[0]);
  109. static nsapi_equiv nsapi_client[] = {
  110. { "HTTPS_KEYSIZE", "keysize" },
  111. { "HTTPS_SECRETSIZE", "secret-keysize" },
  112. { "REMOTE_ADDR", "ip" },
  113. { "REMOTE_HOST", "ip" }
  114. };
  115. static size_t nsapi_client_size = sizeof(nsapi_client)/sizeof(nsapi_client[0]);
  116. /* this parameters to "Service"/"Error" are NSAPI ones which should not be php.ini keys and are excluded */
  117. static char *nsapi_exclude_from_ini_entries[] = { "fn", "type", "method", "directive", "code", "reason", "script", "bucket", NULL };
  118. static char *nsapi_strdup(char *str)
  119. {
  120. if (str != NULL) {
  121. return STRDUP(str);
  122. }
  123. return NULL;
  124. }
  125. static void nsapi_free(void *addr)
  126. {
  127. if (addr != NULL) {
  128. FREE(addr);
  129. }
  130. }
  131. /*******************/
  132. /* PHP module part */
  133. /*******************/
  134. PHP_MINIT_FUNCTION(nsapi);
  135. PHP_MSHUTDOWN_FUNCTION(nsapi);
  136. PHP_RINIT_FUNCTION(nsapi);
  137. PHP_RSHUTDOWN_FUNCTION(nsapi);
  138. PHP_MINFO_FUNCTION(nsapi);
  139. PHP_FUNCTION(nsapi_virtual);
  140. PHP_FUNCTION(nsapi_request_headers);
  141. PHP_FUNCTION(nsapi_response_headers);
  142. ZEND_BEGIN_MODULE_GLOBALS(nsapi)
  143. long read_timeout;
  144. ZEND_END_MODULE_GLOBALS(nsapi)
  145. ZEND_DECLARE_MODULE_GLOBALS(nsapi)
  146. #define NSAPI_G(v) TSRMG(nsapi_globals_id, zend_nsapi_globals *, v)
  147. /* {{{ nsapi_functions[]
  148. *
  149. * Every user visible function must have an entry in nsapi_functions[].
  150. */
  151. function_entry nsapi_functions[] = {
  152. PHP_FE(nsapi_virtual, NULL) /* Make subrequest */
  153. PHP_FALIAS(virtual, nsapi_virtual, NULL) /* compatibility */
  154. PHP_FE(nsapi_request_headers, NULL) /* get request headers */
  155. PHP_FALIAS(getallheaders, nsapi_request_headers, NULL) /* compatibility */
  156. PHP_FALIAS(apache_request_headers, nsapi_request_headers, NULL) /* compatibility */
  157. PHP_FE(nsapi_response_headers, NULL) /* get response headers */
  158. PHP_FALIAS(apache_response_headers, nsapi_response_headers, NULL) /* compatibility */
  159. {NULL, NULL, NULL}
  160. };
  161. /* }}} */
  162. /* {{{ nsapi_module_entry
  163. */
  164. zend_module_entry nsapi_module_entry = {
  165. STANDARD_MODULE_HEADER,
  166. "nsapi",
  167. nsapi_functions,
  168. PHP_MINIT(nsapi),
  169. PHP_MSHUTDOWN(nsapi),
  170. NULL,
  171. NULL,
  172. PHP_MINFO(nsapi),
  173. NO_VERSION_YET,
  174. STANDARD_MODULE_PROPERTIES
  175. };
  176. /* }}} */
  177. /* {{{ PHP_INI
  178. */
  179. PHP_INI_BEGIN()
  180. STD_PHP_INI_ENTRY("nsapi.read_timeout", "60", PHP_INI_ALL, OnUpdateLong, read_timeout, zend_nsapi_globals, nsapi_globals)
  181. PHP_INI_END()
  182. /* }}} */
  183. /* newer servers hide this functions from the programmer so redefine the functions dynamically
  184. thanks to Chris Elving from Sun for the function declarations */
  185. typedef int (*nsapi_servact_prototype)(Session *sn, Request *rq);
  186. nsapi_servact_prototype nsapi_servact_uri2path = NULL;
  187. nsapi_servact_prototype nsapi_servact_pathchecks = NULL;
  188. nsapi_servact_prototype nsapi_servact_fileinfo = NULL;
  189. nsapi_servact_prototype nsapi_servact_service = NULL;
  190. #ifdef PHP_WIN32
  191. /* The following dll-names for nsapi are in use at this time. The undocumented
  192. * servact_* functions are always in the newest one, older ones are supported by
  193. * the server only by wrapping the function table nothing else. So choose
  194. * the newest one found in process space for dynamic linking */
  195. static char *nsapi_dlls[] = { "ns-httpd40.dll", "ns-httpd36.dll", "ns-httpd35.dll", "ns-httpd30.dll", NULL };
  196. /* if user specifies an other dll name by server_lib parameter
  197. * it is placed in the following variable and only this DLL is
  198. * checked for the servact_* functions */
  199. char *nsapi_dll = NULL;
  200. #endif
  201. /* {{{ php_nsapi_init_dynamic_symbols
  202. */
  203. static void php_nsapi_init_dynamic_symbols(void)
  204. {
  205. #if defined(servact_uri2path) && defined(servact_pathchecks) && defined(servact_fileinfo) && defined(servact_service)
  206. /* use functions from nsapi.h if available */
  207. nsapi_servact_uri2path = &servact_uri2path;
  208. nsapi_servact_pathchecks = &servact_pathchecks;
  209. nsapi_servact_fileinfo = &servact_fileinfo;
  210. nsapi_servact_service = &servact_service;
  211. #else
  212. /* find address of internal NSAPI functions */
  213. #ifdef PHP_WIN32
  214. register int i;
  215. DL_HANDLE module = NULL;
  216. if (nsapi_dll) {
  217. /* try user specified server_lib */
  218. module = GetModuleHandle(nsapi_dll);
  219. if (!module) {
  220. log_error(LOG_WARN, "php5_init", NULL, NULL, "Cannot find DLL specified by server_lib parameter: %s", nsapi_dll);
  221. }
  222. } else {
  223. /* find a LOADED dll module from nsapi_dlls */
  224. for (i=0; nsapi_dlls[i]; i++) {
  225. if (module = GetModuleHandle(nsapi_dlls[i])) {
  226. break;
  227. }
  228. }
  229. }
  230. if (!module) return;
  231. #else
  232. DL_HANDLE module = RTLD_DEFAULT;
  233. #endif
  234. nsapi_servact_uri2path = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_uri2path");
  235. nsapi_servact_pathchecks = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_pathchecks");
  236. nsapi_servact_fileinfo = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_fileinfo");
  237. nsapi_servact_service = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_service");
  238. if (!(nsapi_servact_uri2path && nsapi_servact_pathchecks && nsapi_servact_fileinfo && nsapi_servact_service)) {
  239. /* not found - could be cause they are undocumented */
  240. nsapi_servact_uri2path = NULL;
  241. nsapi_servact_pathchecks = NULL;
  242. nsapi_servact_fileinfo = NULL;
  243. nsapi_servact_service = NULL;
  244. }
  245. #endif
  246. }
  247. /* }}} */
  248. /* {{{ php_nsapi_init_globals
  249. */
  250. static void php_nsapi_init_globals(zend_nsapi_globals *nsapi_globals)
  251. {
  252. nsapi_globals->read_timeout = 60;
  253. }
  254. /* }}} */
  255. /* {{{ PHP_MINIT_FUNCTION
  256. */
  257. PHP_MINIT_FUNCTION(nsapi)
  258. {
  259. php_nsapi_init_dynamic_symbols();
  260. ZEND_INIT_MODULE_GLOBALS(nsapi, php_nsapi_init_globals, NULL);
  261. REGISTER_INI_ENTRIES();
  262. return SUCCESS;
  263. }
  264. /* }}} */
  265. /* {{{ PHP_MSHUTDOWN_FUNCTION
  266. */
  267. PHP_MSHUTDOWN_FUNCTION(nsapi)
  268. {
  269. UNREGISTER_INI_ENTRIES();
  270. return SUCCESS;
  271. }
  272. /* }}} */
  273. /* {{{ PHP_MINFO_FUNCTION
  274. */
  275. PHP_MINFO_FUNCTION(nsapi)
  276. {
  277. php_info_print_table_start();
  278. php_info_print_table_row(2, "NSAPI Module Revision", "$Revision$");
  279. php_info_print_table_row(2, "Server Software", system_version());
  280. php_info_print_table_row(2, "Sub-requests with nsapi_virtual()",
  281. (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" );
  282. php_info_print_table_end();
  283. DISPLAY_INI_ENTRIES();
  284. }
  285. /* }}} */
  286. /* {{{ proto bool nsapi_virtual(string uri)
  287. Perform an NSAPI sub-request */
  288. /* This function is equivalent to <!--#include virtual...-->
  289. * in SSI. It does an NSAPI sub-request. It is useful
  290. * for including CGI scripts or .shtml files, or anything else
  291. * that you'd parse through webserver.
  292. */
  293. PHP_FUNCTION(nsapi_virtual)
  294. {
  295. pval **uri;
  296. int rv;
  297. char *value;
  298. Request *rq;
  299. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  300. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &uri) == FAILURE) {
  301. WRONG_PARAM_COUNT;
  302. }
  303. convert_to_string_ex(uri);
  304. if (!nsapi_servact_service) {
  305. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - Sub-requests not supported on this platform", (*uri)->value.str.val);
  306. RETURN_FALSE;
  307. } else if (zend_ini_long("zlib.output_compression", sizeof("zlib.output_compression"), 0)) {
  308. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - Sub-requests do not work with zlib.output_compression", (*uri)->value.str.val);
  309. RETURN_FALSE;
  310. } else {
  311. php_end_ob_buffers(1 TSRMLS_CC);
  312. php_header(TSRMLS_C);
  313. /* do the sub-request */
  314. /* thanks to Chris Elving from Sun for this code sniplet */
  315. if ((rq = request_restart_internal((*uri)->value.str.val, NULL)) == NULL) {
  316. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - Internal request creation failed", (*uri)->value.str.val);
  317. RETURN_FALSE;
  318. }
  319. /* insert host of current request to get page from same vhost */
  320. param_free(pblock_remove("host", rq->headers));
  321. if (value = pblock_findval("host", rc->rq->headers)) {
  322. pblock_nvinsert("host", value, rq->headers);
  323. }
  324. /* go through the normal request stages as given in obj.conf,
  325. but leave out the logging/error section */
  326. do {
  327. rv = (*nsapi_servact_uri2path)(rc->sn, rq);
  328. if (rv != REQ_PROCEED) {
  329. continue;
  330. }
  331. rv = (*nsapi_servact_pathchecks)(rc->sn, rq);
  332. if (rv != REQ_PROCEED) {
  333. continue;
  334. }
  335. rv = (*nsapi_servact_fileinfo)(rc->sn, rq);
  336. if (rv != REQ_PROCEED) {
  337. continue;
  338. }
  339. rv = (*nsapi_servact_service)(rc->sn, rq);
  340. } while (rv == REQ_RESTART);
  341. if (rq->status_num != 200) {
  342. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - HTTP status code %d during subrequest", (*uri)->value.str.val, rq->status_num);
  343. request_free(rq);
  344. RETURN_FALSE;
  345. }
  346. request_free(rq);
  347. RETURN_TRUE;
  348. }
  349. }
  350. /* }}} */
  351. /* {{{ proto array nsapi_request_headers(void)
  352. Get all headers from the request */
  353. PHP_FUNCTION(nsapi_request_headers)
  354. {
  355. register int i;
  356. struct pb_entry *entry;
  357. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  358. array_init(return_value);
  359. for (i=0; i < rc->rq->headers->hsize; i++) {
  360. entry=rc->rq->headers->ht[i];
  361. while (entry) {
  362. if (!PG(safe_mode) || strncasecmp(entry->param->name, "authorization", 13)) {
  363. add_assoc_string(return_value, entry->param->name, entry->param->value, 1);
  364. }
  365. entry=entry->next;
  366. }
  367. }
  368. }
  369. /* }}} */
  370. /* {{{ proto array nsapi_response_headers(void)
  371. Get all headers from the response */
  372. PHP_FUNCTION(nsapi_response_headers)
  373. {
  374. register int i;
  375. struct pb_entry *entry;
  376. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  377. array_init(return_value);
  378. php_header(TSRMLS_C);
  379. for (i=0; i < rc->rq->srvhdrs->hsize; i++) {
  380. entry=rc->rq->srvhdrs->ht[i];
  381. while (entry) {
  382. add_assoc_string(return_value, entry->param->name, entry->param->value, 1);
  383. entry=entry->next;
  384. }
  385. }
  386. }
  387. /* }}} */
  388. /*************/
  389. /* SAPI part */
  390. /*************/
  391. static int sapi_nsapi_ub_write(const char *str, unsigned int str_length TSRMLS_DC)
  392. {
  393. int retval;
  394. nsapi_request_context *rc;
  395. rc = (nsapi_request_context *)SG(server_context);
  396. retval = net_write(rc->sn->csd, (char *)str, str_length);
  397. if (retval == IO_ERROR /* -1 */ || retval == IO_EOF /* 0 */) {
  398. php_handle_aborted_connection();
  399. }
  400. return retval;
  401. }
  402. static int sapi_nsapi_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC)
  403. {
  404. char *header_name, *header_content, *p;
  405. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  406. header_name = sapi_header->header;
  407. header_content = p = strchr(header_name, ':');
  408. if (p == NULL) {
  409. efree(sapi_header->header);
  410. return 0;
  411. }
  412. *p = 0;
  413. do {
  414. header_content++;
  415. } while (*header_content == ' ');
  416. if (!strcasecmp(header_name, "Content-Type")) {
  417. param_free(pblock_remove("content-type", rc->rq->srvhdrs));
  418. pblock_nvinsert("content-type", header_content, rc->rq->srvhdrs);
  419. } else {
  420. /* to lower case because NSAPI reformats the headers and wants lowercase */
  421. for (p=header_name; *p; p++) {
  422. *p=tolower(*p);
  423. }
  424. if (sapi_header->replace) param_free(pblock_remove(header_name, rc->rq->srvhdrs));
  425. pblock_nvinsert(header_name, header_content, rc->rq->srvhdrs);
  426. }
  427. sapi_free_header(sapi_header);
  428. return 0; /* don't use the default SAPI mechanism, NSAPI duplicates this functionality */
  429. }
  430. static int sapi_nsapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
  431. {
  432. int retval;
  433. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  434. if (SG(sapi_headers).send_default_content_type) {
  435. char *hd;
  436. param_free(pblock_remove("content-type", rc->rq->srvhdrs));
  437. hd = sapi_get_default_content_type(TSRMLS_C);
  438. pblock_nvinsert("content-type", hd, rc->rq->srvhdrs);
  439. efree(hd);
  440. }
  441. protocol_status(rc->sn, rc->rq, SG(sapi_headers).http_response_code, NULL);
  442. retval = protocol_start_response(rc->sn, rc->rq);
  443. if (retval == REQ_PROCEED || retval == REQ_NOACTION) {
  444. return SAPI_HEADER_SENT_SUCCESSFULLY;
  445. } else {
  446. return SAPI_HEADER_SEND_FAILED;
  447. }
  448. }
  449. static int sapi_nsapi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
  450. {
  451. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  452. char *read_ptr = buffer, *content_length_str = NULL;
  453. uint bytes_read = 0;
  454. int length, content_length = 0;
  455. netbuf *nbuf = rc->sn->inbuf;
  456. /*
  457. * Yesss!
  458. */
  459. count_bytes = MIN(count_bytes, SG(request_info).content_length-rc->read_post_bytes);
  460. content_length = SG(request_info).content_length;
  461. if (content_length <= 0) {
  462. return 0;
  463. }
  464. /*
  465. * Gobble any pending data in the netbuf.
  466. */
  467. length = nbuf->cursize - nbuf->pos;
  468. length = MIN(count_bytes, length);
  469. if (length > 0) {
  470. memcpy(read_ptr, nbuf->inbuf + nbuf->pos, length);
  471. bytes_read += length;
  472. read_ptr += length;
  473. content_length -= length;
  474. nbuf->pos += length;
  475. }
  476. /*
  477. * Read the remaining from the socket.
  478. */
  479. while (content_length > 0 && bytes_read < count_bytes) {
  480. int bytes_to_read = count_bytes - bytes_read;
  481. if (content_length < bytes_to_read) {
  482. bytes_to_read = content_length;
  483. }
  484. length = net_read(rc->sn->csd, read_ptr, bytes_to_read, NSAPI_G(read_timeout));
  485. if (length == IO_ERROR || length == IO_EOF) {
  486. break;
  487. }
  488. bytes_read += length;
  489. read_ptr += length;
  490. content_length -= length;
  491. }
  492. if ( bytes_read > 0 ) {
  493. rc->read_post_bytes += bytes_read;
  494. }
  495. return bytes_read;
  496. }
  497. static char *sapi_nsapi_read_cookies(TSRMLS_D)
  498. {
  499. char *cookie_string;
  500. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  501. cookie_string = pblock_findval("cookie", rc->rq->headers);
  502. return cookie_string;
  503. }
  504. static void sapi_nsapi_register_server_variables(zval *track_vars_array TSRMLS_DC)
  505. {
  506. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  507. register size_t i;
  508. int pos;
  509. char *value,*p;
  510. char buf[NS_BUF_SIZE + 1];
  511. struct pb_entry *entry;
  512. for (i = 0; i < nsapi_reqpb_size; i++) {
  513. value = pblock_findval(nsapi_reqpb[i].nsapi_eq, rc->rq->reqpb);
  514. if (value) {
  515. php_register_variable((char *)nsapi_reqpb[i].env_var, value, track_vars_array TSRMLS_CC);
  516. }
  517. }
  518. for (i=0; i < rc->rq->headers->hsize; i++) {
  519. entry=rc->rq->headers->ht[i];
  520. while (entry) {
  521. if (!PG(safe_mode) || strncasecmp(entry->param->name, "authorization", 13)) {
  522. if (strcasecmp(entry->param->name, "content-length")==0 || strcasecmp(entry->param->name, "content-type")==0) {
  523. strlcpy(buf, entry->param->name, NS_BUF_SIZE);
  524. pos = 0;
  525. } else {
  526. snprintf(buf, NS_BUF_SIZE, "HTTP_%s", entry->param->name);
  527. pos = 5;
  528. }
  529. buf[NS_BUF_SIZE]='\0';
  530. for(p = buf + pos; *p; p++) {
  531. *p = toupper(*p);
  532. if (*p < 'A' || *p > 'Z') {
  533. *p = '_';
  534. }
  535. }
  536. php_register_variable(buf, entry->param->value, track_vars_array TSRMLS_CC);
  537. }
  538. entry=entry->next;
  539. }
  540. }
  541. for (i = 0; i < nsapi_vars_size; i++) {
  542. value = pblock_findval(nsapi_vars[i].nsapi_eq, rc->rq->vars);
  543. if (value) {
  544. php_register_variable((char *)nsapi_vars[i].env_var, value, track_vars_array TSRMLS_CC);
  545. }
  546. }
  547. for (i = 0; i < nsapi_client_size; i++) {
  548. value = pblock_findval(nsapi_client[i].nsapi_eq, rc->sn->client);
  549. if (value) {
  550. php_register_variable((char *)nsapi_client[i].env_var, value, track_vars_array TSRMLS_CC);
  551. }
  552. }
  553. if (value = session_dns(rc->sn)) {
  554. php_register_variable("REMOTE_HOST", value, track_vars_array TSRMLS_CC);
  555. nsapi_free(value);
  556. }
  557. sprintf(buf, "%d", conf_getglobals()->Vport);
  558. php_register_variable("SERVER_PORT", buf, track_vars_array TSRMLS_CC);
  559. php_register_variable("SERVER_NAME", conf_getglobals()->Vserver_hostname, track_vars_array TSRMLS_CC);
  560. value = http_uri2url_dynamic("", "", rc->sn, rc->rq);
  561. php_register_variable("SERVER_URL", value, track_vars_array TSRMLS_CC);
  562. nsapi_free(value);
  563. php_register_variable("SERVER_SOFTWARE", system_version(), track_vars_array TSRMLS_CC);
  564. php_register_variable("HTTPS", (security_active ? "ON" : "OFF"), track_vars_array TSRMLS_CC);
  565. php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
  566. /* DOCUMENT_ROOT */
  567. if (value = request_translate_uri("/", rc->sn)) {
  568. value[strlen(value) - 1] = '\0';
  569. php_register_variable("DOCUMENT_ROOT", value, track_vars_array TSRMLS_CC);
  570. nsapi_free(value);
  571. }
  572. /* PATH_INFO / PATH_TRANSLATED */
  573. if (rc->path_info) {
  574. if (value = request_translate_uri(rc->path_info, rc->sn)) {
  575. php_register_variable("PATH_TRANSLATED", value, track_vars_array TSRMLS_CC);
  576. nsapi_free(value);
  577. }
  578. php_register_variable("PATH_INFO", rc->path_info, track_vars_array TSRMLS_CC);
  579. }
  580. /* Create full Request-URI & Script-Name */
  581. if (SG(request_info).request_uri) {
  582. strlcpy(buf, SG(request_info).request_uri, NS_BUF_SIZE);
  583. if (SG(request_info).query_string) {
  584. p = strchr(buf, 0);
  585. snprintf(p, NS_BUF_SIZE-(p-buf), "?%s", SG(request_info).query_string);
  586. buf[NS_BUF_SIZE]='\0';
  587. }
  588. php_register_variable("REQUEST_URI", buf, track_vars_array TSRMLS_CC);
  589. strlcpy(buf, SG(request_info).request_uri, NS_BUF_SIZE);
  590. if (rc->path_info) {
  591. pos = strlen(SG(request_info).request_uri) - strlen(rc->path_info);
  592. if (pos>=0 && pos<=NS_BUF_SIZE && rc->path_info) {
  593. buf[pos] = '\0';
  594. } else {
  595. buf[0]='\0';
  596. }
  597. }
  598. php_register_variable("SCRIPT_NAME", buf, track_vars_array TSRMLS_CC);
  599. }
  600. php_register_variable("SCRIPT_FILENAME", SG(request_info).path_translated, track_vars_array TSRMLS_CC);
  601. /* special variables in error mode */
  602. if (rc->http_error) {
  603. sprintf(buf, "%d", rc->http_error);
  604. php_register_variable("ERROR_TYPE", buf, track_vars_array TSRMLS_CC);
  605. }
  606. }
  607. static void nsapi_log_message(char *message)
  608. {
  609. TSRMLS_FETCH();
  610. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  611. log_error(LOG_INFORM, pblock_findval("fn", rc->pb), rc->sn, rc->rq, "%s", message);
  612. }
  613. static time_t sapi_nsapi_get_request_time(TSRMLS_D)
  614. {
  615. return REQ_TIME( ((nsapi_request_context *)SG(server_context))->rq );
  616. }
  617. static int php_nsapi_startup(sapi_module_struct *sapi_module)
  618. {
  619. if (php_module_startup(sapi_module, &nsapi_module_entry, 1)==FAILURE) {
  620. return FAILURE;
  621. }
  622. return SUCCESS;
  623. }
  624. static sapi_module_struct nsapi_sapi_module = {
  625. "nsapi", /* name */
  626. "NSAPI", /* pretty name */
  627. php_nsapi_startup, /* startup */
  628. php_module_shutdown_wrapper, /* shutdown */
  629. NULL, /* activate */
  630. NULL, /* deactivate */
  631. sapi_nsapi_ub_write, /* unbuffered write */
  632. NULL, /* flush */
  633. NULL, /* get uid */
  634. NULL, /* getenv */
  635. php_error, /* error handler */
  636. sapi_nsapi_header_handler, /* header handler */
  637. sapi_nsapi_send_headers, /* send headers handler */
  638. NULL, /* send header handler */
  639. sapi_nsapi_read_post, /* read POST data */
  640. sapi_nsapi_read_cookies, /* read Cookies */
  641. sapi_nsapi_register_server_variables, /* register server variables */
  642. nsapi_log_message, /* Log message */
  643. sapi_nsapi_get_request_time, /* Get request time */
  644. NULL, /* Block interruptions */
  645. NULL, /* Unblock interruptions */
  646. STANDARD_SAPI_MODULE_PROPERTIES
  647. };
  648. static void nsapi_php_ini_entries(NSLS_D TSRMLS_DC)
  649. {
  650. struct pb_entry *entry;
  651. register int i,j,ok;
  652. for (i=0; i < NSG(pb)->hsize; i++) {
  653. entry=NSG(pb)->ht[i];
  654. while (entry) {
  655. /* exclude standard entries given to "Service" which should not go into ini entries */
  656. ok=1;
  657. for (j=0; nsapi_exclude_from_ini_entries[j]; j++) {
  658. ok&=(strcasecmp(entry->param->name, nsapi_exclude_from_ini_entries[j])!=0);
  659. }
  660. if (ok) {
  661. /* change the ini entry */
  662. if (zend_alter_ini_entry(entry->param->name, strlen(entry->param->name)+1,
  663. entry->param->value, strlen(entry->param->value),
  664. PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE)==FAILURE) {
  665. 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);
  666. }
  667. }
  668. entry=entry->next;
  669. }
  670. }
  671. }
  672. void NSAPI_PUBLIC php5_close(void *vparam)
  673. {
  674. if (nsapi_sapi_module.shutdown) {
  675. nsapi_sapi_module.shutdown(&nsapi_sapi_module);
  676. }
  677. if (nsapi_sapi_module.php_ini_path_override) {
  678. free(nsapi_sapi_module.php_ini_path_override);
  679. }
  680. #ifdef PHP_WIN32
  681. if (nsapi_dll) {
  682. free(nsapi_dll);
  683. nsapi_dll = NULL;
  684. }
  685. #endif
  686. tsrm_shutdown();
  687. log_error(LOG_INFORM, "php5_close", NULL, NULL, "Shutdown PHP Module");
  688. }
  689. /*********************************************************
  690. / init SAF
  691. /
  692. / Init fn="php5_init" [php_ini="/path/to/php.ini"] [server_lib="ns-httpdXX.dll"]
  693. / Initialize the NSAPI module in magnus.conf
  694. /
  695. / php_ini: gives path to php.ini file
  696. / server_lib: (only Win32) gives name of DLL (without path) to look for
  697. / servact_* functions
  698. /
  699. /*********************************************************/
  700. int NSAPI_PUBLIC php5_init(pblock *pb, Session *sn, Request *rq)
  701. {
  702. php_core_globals *core_globals;
  703. char *strval;
  704. int threads=128; /* default for server */
  705. /* fetch max threads from NSAPI and initialize TSRM with it */
  706. #if defined(pool_maxthreads)
  707. threads=pool_maxthreads;
  708. if (threads<1) {
  709. threads=128; /* default for server */
  710. }
  711. #endif
  712. tsrm_startup(threads, 1, 0, NULL);
  713. core_globals = ts_resource(core_globals_id);
  714. /* look if php_ini parameter is given to php5_init */
  715. if (strval = pblock_findval("php_ini", pb)) {
  716. nsapi_sapi_module.php_ini_path_override = strdup(strval);
  717. }
  718. #ifdef PHP_WIN32
  719. /* look if server_lib parameter is given to php5_init
  720. * (this disables the automatic search for the newest ns-httpdXX.dll) */
  721. if (strval = pblock_findval("server_lib", pb)) {
  722. nsapi_dll = strdup(strval);
  723. }
  724. #endif
  725. /* start SAPI */
  726. sapi_startup(&nsapi_sapi_module);
  727. nsapi_sapi_module.startup(&nsapi_sapi_module);
  728. daemon_atrestart(&php5_close, NULL);
  729. log_error(LOG_INFORM, pblock_findval("fn", pb), sn, rq, "Initialized PHP Module (%d threads exspected)", threads);
  730. return REQ_PROCEED;
  731. }
  732. /*********************************************************
  733. / normal use in Service directive:
  734. /
  735. / Service fn="php5_execute" type=... method=... [inikey=inivalue inikey=inivalue...]
  736. /
  737. / use in Service for a directory to supply a php-made directory listing instead of server default:
  738. /
  739. / Service fn="php5_execute" type="magnus-internal/directory" script="/path/to/script.php" [inikey=inivalue inikey=inivalue...]
  740. /
  741. / use in Error SAF to display php script as error page:
  742. /
  743. / Error fn="php5_execute" code=XXX script="/path/to/script.php" [inikey=inivalue inikey=inivalue...]
  744. / Error fn="php5_execute" reason="Reason" script="/path/to/script.php" [inikey=inivalue inikey=inivalue...]
  745. /
  746. /*********************************************************/
  747. int NSAPI_PUBLIC php5_execute(pblock *pb, Session *sn, Request *rq)
  748. {
  749. int retval;
  750. nsapi_request_context *request_context;
  751. zend_file_handle file_handle = {0};
  752. struct stat fst;
  753. char *path_info;
  754. char *query_string = pblock_findval("query", rq->reqpb);
  755. char *uri = pblock_findval("uri", rq->reqpb);
  756. char *request_method = pblock_findval("method", rq->reqpb);
  757. char *content_type = pblock_findval("content-type", rq->headers);
  758. char *content_length = pblock_findval("content-length", rq->headers);
  759. char *directive = pblock_findval("Directive", pb);
  760. int error_directive = (directive && !strcasecmp(directive, "error"));
  761. int fixed_script = 1;
  762. /* try to use script parameter -> Error or Service for directory listing */
  763. char *path_translated = pblock_findval("script", pb);
  764. TSRMLS_FETCH();
  765. /* if script parameter is missing: normal use as Service SAF */
  766. if (!path_translated) {
  767. path_translated = pblock_findval("path", rq->vars);
  768. path_info = pblock_findval("path-info", rq->vars);
  769. fixed_script = 0;
  770. if (error_directive) {
  771. /* go to next error directive if script parameter is missing */
  772. log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Missing 'script' parameter");
  773. return REQ_NOACTION;
  774. }
  775. } else {
  776. /* in error the path_info is the uri to the requested page */
  777. path_info = pblock_findval("uri", rq->reqpb);
  778. }
  779. /* check if this uri was included in an other PHP script with nsapi_virtual()
  780. by looking for a request context in the current thread */
  781. if (SG(server_context)) {
  782. /* send 500 internal server error */
  783. log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Cannot make nesting PHP requests with nsapi_virtual()");
  784. if (error_directive) {
  785. return REQ_NOACTION;
  786. } else {
  787. protocol_status(sn, rq, 500, NULL);
  788. return REQ_ABORTED;
  789. }
  790. }
  791. request_context = (nsapi_request_context *)MALLOC(sizeof(nsapi_request_context));
  792. request_context->pb = pb;
  793. request_context->sn = sn;
  794. request_context->rq = rq;
  795. request_context->read_post_bytes = 0;
  796. request_context->fixed_script = fixed_script;
  797. request_context->http_error = (error_directive) ? rq->status_num : 0;
  798. request_context->path_info = nsapi_strdup(path_info);
  799. SG(server_context) = request_context;
  800. SG(request_info).query_string = nsapi_strdup(query_string);
  801. SG(request_info).request_uri = nsapi_strdup(uri);
  802. SG(request_info).request_method = nsapi_strdup(request_method);
  803. SG(request_info).path_translated = nsapi_strdup(path_translated);
  804. SG(request_info).content_type = nsapi_strdup(content_type);
  805. SG(request_info).content_length = (content_length == NULL) ? 0 : strtoul(content_length, 0, 0);
  806. SG(sapi_headers).http_response_code = (error_directive) ? rq->status_num : 200;
  807. nsapi_php_ini_entries(NSLS_C TSRMLS_CC);
  808. if (!PG(safe_mode)) php_handle_auth_data(pblock_findval("authorization", rq->headers) TSRMLS_CC);
  809. file_handle.type = ZEND_HANDLE_FILENAME;
  810. file_handle.filename = SG(request_info).path_translated;
  811. file_handle.free_filename = 0;
  812. file_handle.opened_path = NULL;
  813. if (stat(SG(request_info).path_translated, &fst)==0 && S_ISREG(fst.st_mode)) {
  814. if (php_request_startup(TSRMLS_C) == SUCCESS) {
  815. php_execute_script(&file_handle TSRMLS_CC);
  816. php_request_shutdown(NULL);
  817. retval=REQ_PROCEED;
  818. } else {
  819. /* send 500 internal server error */
  820. log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Cannot prepare PHP engine!");
  821. if (error_directive) {
  822. retval=REQ_NOACTION;
  823. } else {
  824. protocol_status(sn, rq, 500, NULL);
  825. retval=REQ_ABORTED;
  826. }
  827. }
  828. } else {
  829. /* send 404 because file not found */
  830. log_error(LOG_WARN, pblock_findval("fn", pb), sn, rq, "Cannot execute PHP script: %s (File not found)", SG(request_info).path_translated);
  831. if (error_directive) {
  832. retval=REQ_NOACTION;
  833. } else {
  834. protocol_status(sn, rq, 404, NULL);
  835. retval=REQ_ABORTED;
  836. }
  837. }
  838. nsapi_free(request_context->path_info);
  839. nsapi_free(SG(request_info).query_string);
  840. nsapi_free(SG(request_info).request_uri);
  841. nsapi_free((void*)(SG(request_info).request_method));
  842. nsapi_free(SG(request_info).path_translated);
  843. nsapi_free((void*)(SG(request_info).content_type));
  844. FREE(request_context);
  845. SG(server_context) = NULL;
  846. return retval;
  847. }
  848. /*********************************************************
  849. / authentication
  850. /
  851. / we have to make a 'fake' authenticator for netscape so it
  852. / will pass authentication through to php, and allow us to
  853. / check authentication with our scripts.
  854. /
  855. / php5_auth_trans
  856. / main function called from netscape server to authenticate
  857. / a line in obj.conf:
  858. / funcs=php5_auth_trans shlib="path/to/this/phpnsapi.dll"
  859. / and:
  860. / <Object ppath="path/to/be/authenticated/by/php/*">
  861. / AuthTrans fn="php5_auth_trans"
  862. /*********************************************************/
  863. int NSAPI_PUBLIC php5_auth_trans(pblock * pb, Session * sn, Request * rq)
  864. {
  865. /* This is a DO NOTHING function that allows authentication
  866. * information
  867. * to be passed through to PHP scripts.
  868. */
  869. return REQ_PROCEED;
  870. }
  871. /*
  872. * Local variables:
  873. * tab-width: 4
  874. * c-basic-offset: 4
  875. * End:
  876. * vim600: sw=4 ts=4 fdm=marker
  877. * vim<600: sw=4 ts=4
  878. */