Annotation of embedaddon/php/sapi/apache2filter/sapi_apache2.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: | Authors: Sascha Schumann <sascha@schumann.cx> |
! 16: | Parts based on Apache 1.3 SAPI module by |
! 17: | Rasmus Lerdorf and Zeev Suraski |
! 18: +----------------------------------------------------------------------+
! 19: */
! 20:
! 21: /* $Id: sapi_apache2.c 321634 2012-01-01 13:15:04Z felipe $ */
! 22:
! 23: #include <fcntl.h>
! 24:
! 25: #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
! 26:
! 27: #include "php.h"
! 28: #include "php_main.h"
! 29: #include "php_ini.h"
! 30: #include "php_variables.h"
! 31: #include "SAPI.h"
! 32:
! 33: #include "ext/standard/php_smart_str.h"
! 34: #ifndef NETWARE
! 35: #include "ext/standard/php_standard.h"
! 36: #else
! 37: #include "ext/standard/basic_functions.h"
! 38: #endif
! 39:
! 40: #include "apr_strings.h"
! 41: #include "ap_config.h"
! 42: #include "apr_buckets.h"
! 43: #include "util_filter.h"
! 44: #include "httpd.h"
! 45: #include "http_config.h"
! 46: #include "http_request.h"
! 47: #include "http_core.h"
! 48: #include "http_protocol.h"
! 49: #include "http_log.h"
! 50: #include "http_main.h"
! 51: #include "util_script.h"
! 52: #include "http_core.h"
! 53: #include "ap_mpm.h"
! 54:
! 55: #include "php_apache.h"
! 56:
! 57: /* UnixWare and Netware define shutdown to _shutdown, which causes problems later
! 58: * on when using a structure member named shutdown. Since this source
! 59: * file does not use the system call shutdown, it is safe to #undef it.
! 60: */
! 61: #undef shutdown
! 62:
! 63: /* A way to specify the location of the php.ini dir in an apache directive */
! 64: char *apache2_php_ini_path_override = NULL;
! 65:
! 66: static int
! 67: php_apache_sapi_ub_write(const char *str, uint str_length TSRMLS_DC)
! 68: {
! 69: apr_bucket *b;
! 70: apr_bucket_brigade *bb;
! 71: apr_bucket_alloc_t *ba;
! 72: ap_filter_t *f; /* remaining output filters */
! 73: php_struct *ctx;
! 74:
! 75: ctx = SG(server_context);
! 76: f = ctx->f;
! 77:
! 78: if (str_length == 0) return 0;
! 79:
! 80: ba = f->c->bucket_alloc;
! 81: bb = apr_brigade_create(ctx->r->pool, ba);
! 82:
! 83: b = apr_bucket_transient_create(str, str_length, ba);
! 84: APR_BRIGADE_INSERT_TAIL(bb, b);
! 85:
! 86: if (ap_pass_brigade(f->next, bb) != APR_SUCCESS || ctx->r->connection->aborted) {
! 87: php_handle_aborted_connection();
! 88: }
! 89:
! 90: return str_length; /* we always consume all the data passed to us. */
! 91: }
! 92:
! 93: static int
! 94: php_apache_sapi_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC)
! 95: {
! 96: php_struct *ctx;
! 97: ap_filter_t *f;
! 98: char *val, *ptr;
! 99:
! 100: ctx = SG(server_context);
! 101: f = ctx->r->output_filters;
! 102:
! 103: switch(op) {
! 104: case SAPI_HEADER_DELETE:
! 105: apr_table_unset(ctx->r->headers_out, sapi_header->header);
! 106: return 0;
! 107:
! 108: case SAPI_HEADER_DELETE_ALL:
! 109: apr_table_clear(ctx->r->headers_out);
! 110: return 0;
! 111:
! 112: case SAPI_HEADER_ADD:
! 113: case SAPI_HEADER_REPLACE:
! 114: val = strchr(sapi_header->header, ':');
! 115:
! 116: if (!val) {
! 117: sapi_free_header(sapi_header);
! 118: return 0;
! 119: }
! 120: ptr = val;
! 121:
! 122: *val = '\0';
! 123:
! 124: do {
! 125: val++;
! 126: } while (*val == ' ');
! 127:
! 128: if (!strcasecmp(sapi_header->header, "content-type"))
! 129: ctx->r->content_type = apr_pstrdup(ctx->r->pool, val);
! 130: else if (!strcasecmp(sapi_header->header, "content-length"))
! 131: ap_set_content_length(ctx->r, strtol(val, (char **)NULL, 10));
! 132: else if (op == SAPI_HEADER_REPLACE)
! 133: apr_table_set(ctx->r->headers_out, sapi_header->header, val);
! 134: else
! 135: apr_table_add(ctx->r->headers_out, sapi_header->header, val);
! 136:
! 137: *ptr = ':';
! 138: return SAPI_HEADER_ADD;
! 139:
! 140: default:
! 141: return 0;
! 142: }
! 143: }
! 144:
! 145: static int
! 146: php_apache_sapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
! 147: {
! 148: php_struct *ctx = SG(server_context);
! 149:
! 150: ctx->r->status = SG(sapi_headers).http_response_code;
! 151:
! 152: return SAPI_HEADER_SENT_SUCCESSFULLY;
! 153: }
! 154:
! 155: static int
! 156: php_apache_sapi_read_post(char *buf, uint count_bytes TSRMLS_DC)
! 157: {
! 158: int n;
! 159: int to_read;
! 160: php_struct *ctx = SG(server_context);
! 161:
! 162: to_read = ctx->post_len - ctx->post_idx;
! 163: n = MIN(to_read, count_bytes);
! 164:
! 165: if (n > 0) {
! 166: memcpy(buf, ctx->post_data + ctx->post_idx, n);
! 167: ctx->post_idx += n;
! 168: } else {
! 169: if (ctx->post_data) free(ctx->post_data);
! 170: ctx->post_data = NULL;
! 171: }
! 172:
! 173: return n;
! 174: }
! 175:
! 176: static struct stat*
! 177: php_apache_sapi_get_stat(TSRMLS_D)
! 178: {
! 179: php_struct *ctx = SG(server_context);
! 180:
! 181: ctx->finfo.st_uid = ctx->r->finfo.user;
! 182: ctx->finfo.st_gid = ctx->r->finfo.group;
! 183: ctx->finfo.st_dev = ctx->r->finfo.device;
! 184: ctx->finfo.st_ino = ctx->r->finfo.inode;
! 185: #ifdef NETWARE
! 186: ctx->finfo.st_atime.tv_sec = apr_time_sec(ctx->r->finfo.atime);
! 187: ctx->finfo.st_mtime.tv_sec = apr_time_sec(ctx->r->finfo.mtime);
! 188: ctx->finfo.st_ctime.tv_sec = apr_time_sec(ctx->r->finfo.ctime);
! 189: #else
! 190: ctx->finfo.st_atime = apr_time_sec(ctx->r->finfo.atime);
! 191: ctx->finfo.st_mtime = apr_time_sec(ctx->r->finfo.mtime);
! 192: ctx->finfo.st_ctime = apr_time_sec(ctx->r->finfo.ctime);
! 193: #endif
! 194:
! 195: ctx->finfo.st_size = ctx->r->finfo.size;
! 196: ctx->finfo.st_nlink = ctx->r->finfo.nlink;
! 197:
! 198: return &ctx->finfo;
! 199: }
! 200:
! 201: static char *
! 202: php_apache_sapi_read_cookies(TSRMLS_D)
! 203: {
! 204: php_struct *ctx = SG(server_context);
! 205: const char *http_cookie;
! 206:
! 207: http_cookie = apr_table_get(ctx->r->headers_in, "cookie");
! 208:
! 209: /* The SAPI interface should use 'const char *' */
! 210: return (char *) http_cookie;
! 211: }
! 212:
! 213: static char *
! 214: php_apache_sapi_getenv(char *name, size_t name_len TSRMLS_DC)
! 215: {
! 216: php_struct *ctx = SG(server_context);
! 217: const char *env_var;
! 218:
! 219: env_var = apr_table_get(ctx->r->subprocess_env, name);
! 220:
! 221: return (char *) env_var;
! 222: }
! 223:
! 224: static void
! 225: php_apache_sapi_register_variables(zval *track_vars_array TSRMLS_DC)
! 226: {
! 227: php_struct *ctx = SG(server_context);
! 228: const apr_array_header_t *arr = apr_table_elts(ctx->r->subprocess_env);
! 229: char *key, *val;
! 230: unsigned int new_val_len;
! 231:
! 232: APR_ARRAY_FOREACH_OPEN(arr, key, val)
! 233: if (!val) {
! 234: val = "";
! 235: }
! 236: if (sapi_module.input_filter(PARSE_SERVER, key, &val, strlen(val), &new_val_len TSRMLS_CC)) {
! 237: php_register_variable_safe(key, val, new_val_len, track_vars_array TSRMLS_CC);
! 238: }
! 239: APR_ARRAY_FOREACH_CLOSE()
! 240:
! 241: php_register_variable("PHP_SELF", ctx->r->uri, track_vars_array TSRMLS_CC);
! 242: if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &ctx->r->uri, strlen(ctx->r->uri), &new_val_len TSRMLS_CC)) {
! 243: php_register_variable_safe("PHP_SELF", ctx->r->uri, new_val_len, track_vars_array TSRMLS_CC);
! 244: }
! 245: }
! 246:
! 247: static void
! 248: php_apache_sapi_flush(void *server_context)
! 249: {
! 250: php_struct *ctx;
! 251: apr_bucket_brigade *bb;
! 252: apr_bucket_alloc_t *ba;
! 253: apr_bucket *b;
! 254: ap_filter_t *f; /* output filters */
! 255: TSRMLS_FETCH();
! 256:
! 257: ctx = server_context;
! 258:
! 259: /* If we haven't registered a server_context yet,
! 260: * then don't bother flushing. */
! 261: if (!server_context)
! 262: return;
! 263:
! 264: sapi_send_headers(TSRMLS_C);
! 265:
! 266: ctx->r->status = SG(sapi_headers).http_response_code;
! 267: SG(headers_sent) = 1;
! 268:
! 269: f = ctx->f;
! 270:
! 271: /* Send a flush bucket down the filter chain. The current default
! 272: * handler seems to act on the first flush bucket, but ignores
! 273: * all further flush buckets.
! 274: */
! 275:
! 276: ba = ctx->r->connection->bucket_alloc;
! 277: bb = apr_brigade_create(ctx->r->pool, ba);
! 278: b = apr_bucket_flush_create(ba);
! 279: APR_BRIGADE_INSERT_TAIL(bb, b);
! 280: if (ap_pass_brigade(f->next, bb) != APR_SUCCESS || ctx->r->connection->aborted) {
! 281: php_handle_aborted_connection();
! 282: }
! 283: }
! 284:
! 285: static void php_apache_sapi_log_message(char *msg)
! 286: {
! 287: php_struct *ctx;
! 288: TSRMLS_FETCH();
! 289:
! 290: ctx = SG(server_context);
! 291:
! 292: if (ctx == NULL) { /* we haven't initialized our ctx yet, oh well */
! 293: ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, 0, NULL, "%s", msg);
! 294: }
! 295: else {
! 296: ap_log_error(APLOG_MARK, APLOG_ERR, 0, ctx->r->server, "%s", msg);
! 297: }
! 298: }
! 299:
! 300: static int
! 301: php_apache_disable_caching(ap_filter_t *f)
! 302: {
! 303: /* Identify PHP scripts as non-cacheable, thus preventing
! 304: * Apache from sending a 304 status when the browser sends
! 305: * If-Modified-Since header.
! 306: */
! 307: f->r->no_local_copy = 1;
! 308:
! 309: return OK;
! 310: }
! 311:
! 312: static time_t php_apache_sapi_get_request_time(TSRMLS_D)
! 313: {
! 314: php_struct *ctx = SG(server_context);
! 315: return apr_time_sec(ctx->r->request_time);
! 316: }
! 317:
! 318: extern zend_module_entry php_apache_module;
! 319:
! 320: static int php_apache2_startup(sapi_module_struct *sapi_module)
! 321: {
! 322: if (php_module_startup(sapi_module, &php_apache_module, 1)==FAILURE) {
! 323: return FAILURE;
! 324: }
! 325: return SUCCESS;
! 326: }
! 327:
! 328: static sapi_module_struct apache2_sapi_module = {
! 329: "apache2filter",
! 330: "Apache 2.0 Filter",
! 331:
! 332: php_apache2_startup, /* startup */
! 333: php_module_shutdown_wrapper, /* shutdown */
! 334:
! 335: NULL, /* activate */
! 336: NULL, /* deactivate */
! 337:
! 338: php_apache_sapi_ub_write, /* unbuffered write */
! 339: php_apache_sapi_flush, /* flush */
! 340: php_apache_sapi_get_stat, /* get uid */
! 341: php_apache_sapi_getenv, /* getenv */
! 342:
! 343: php_error, /* error handler */
! 344:
! 345: php_apache_sapi_header_handler, /* header handler */
! 346: php_apache_sapi_send_headers, /* send headers handler */
! 347: NULL, /* send header handler */
! 348:
! 349: php_apache_sapi_read_post, /* read POST data */
! 350: php_apache_sapi_read_cookies, /* read Cookies */
! 351:
! 352: php_apache_sapi_register_variables,
! 353: php_apache_sapi_log_message, /* Log message */
! 354: php_apache_sapi_get_request_time, /* Get Request Time */
! 355: NULL, /* Child terminate */
! 356:
! 357: STANDARD_SAPI_MODULE_PROPERTIES
! 358: };
! 359:
! 360: static int php_input_filter(ap_filter_t *f, apr_bucket_brigade *bb,
! 361: ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
! 362: {
! 363: php_struct *ctx;
! 364: long old_index;
! 365: apr_bucket *b;
! 366: const char *str;
! 367: apr_size_t n;
! 368: apr_status_t rv;
! 369: TSRMLS_FETCH();
! 370:
! 371: if (f->r->proxyreq) {
! 372: return ap_get_brigade(f->next, bb, mode, block, readbytes);
! 373: }
! 374:
! 375: ctx = SG(server_context);
! 376: if (ctx == NULL) {
! 377: ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
! 378: "php failed to get server context");
! 379: return HTTP_INTERNAL_SERVER_ERROR;
! 380: }
! 381:
! 382: if ((rv = ap_get_brigade(f->next, bb, mode, block, readbytes)) != APR_SUCCESS) {
! 383: return rv;
! 384: }
! 385:
! 386: for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) {
! 387: apr_bucket_read(b, &str, &n, APR_NONBLOCK_READ);
! 388: if (n > 0) {
! 389: old_index = ctx->post_len;
! 390: ctx->post_len += n;
! 391: ctx->post_data = realloc(ctx->post_data, ctx->post_len + 1);
! 392: memcpy(ctx->post_data + old_index, str, n);
! 393: }
! 394: }
! 395: return APR_SUCCESS;
! 396: }
! 397:
! 398: static void php_apache_request_ctor(ap_filter_t *f, php_struct *ctx TSRMLS_DC)
! 399: {
! 400: char *content_type;
! 401: char *content_length;
! 402: const char *auth;
! 403:
! 404: PG(during_request_startup) = 0;
! 405: SG(sapi_headers).http_response_code = !f->r->status ? HTTP_OK : f->r->status;
! 406: SG(request_info).content_type = apr_table_get(f->r->headers_in, "Content-Type");
! 407: #undef safe_strdup
! 408: #define safe_strdup(x) ((x)?strdup((x)):NULL)
! 409: SG(request_info).query_string = safe_strdup(f->r->args);
! 410: SG(request_info).request_method = f->r->method;
! 411: SG(request_info).proto_num = f->r->proto_num;
! 412: SG(request_info).request_uri = safe_strdup(f->r->uri);
! 413: SG(request_info).path_translated = safe_strdup(f->r->filename);
! 414: f->r->no_local_copy = 1;
! 415: content_type = sapi_get_default_content_type(TSRMLS_C);
! 416: f->r->content_type = apr_pstrdup(f->r->pool, content_type);
! 417: SG(request_info).post_data = ctx->post_data;
! 418: SG(request_info).post_data_length = ctx->post_len;
! 419:
! 420: efree(content_type);
! 421:
! 422: content_length = (char *) apr_table_get(f->r->headers_in, "Content-Length");
! 423: SG(request_info).content_length = (content_length ? atol(content_length) : 0);
! 424:
! 425: apr_table_unset(f->r->headers_out, "Content-Length");
! 426: apr_table_unset(f->r->headers_out, "Last-Modified");
! 427: apr_table_unset(f->r->headers_out, "Expires");
! 428: apr_table_unset(f->r->headers_out, "ETag");
! 429: if (!PG(safe_mode) || (PG(safe_mode) && !ap_auth_type(f->r))) {
! 430: auth = apr_table_get(f->r->headers_in, "Authorization");
! 431: php_handle_auth_data(auth TSRMLS_CC);
! 432: if (SG(request_info).auth_user == NULL && f->r->user) {
! 433: SG(request_info).auth_user = estrdup(f->r->user);
! 434: }
! 435: ctx->r->user = apr_pstrdup(ctx->r->pool, SG(request_info).auth_user);
! 436: } else {
! 437: SG(request_info).auth_user = NULL;
! 438: SG(request_info).auth_password = NULL;
! 439: }
! 440: php_request_startup(TSRMLS_C);
! 441: }
! 442:
! 443: static void php_apache_request_dtor(ap_filter_t *f TSRMLS_DC)
! 444: {
! 445: php_apr_bucket_brigade *pbb = (php_apr_bucket_brigade *)f->ctx;
! 446:
! 447: php_request_shutdown(NULL);
! 448:
! 449: if (SG(request_info).query_string) {
! 450: free(SG(request_info).query_string);
! 451: }
! 452: if (SG(request_info).request_uri) {
! 453: free(SG(request_info).request_uri);
! 454: }
! 455: if (SG(request_info).path_translated) {
! 456: free(SG(request_info).path_translated);
! 457: }
! 458:
! 459: apr_brigade_destroy(pbb->bb);
! 460: }
! 461:
! 462: static int php_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
! 463: {
! 464: php_struct *ctx;
! 465: void *conf = ap_get_module_config(f->r->per_dir_config, &php5_module);
! 466: char *p = get_php_config(conf, "engine", sizeof("engine"));
! 467: zend_file_handle zfd;
! 468: php_apr_bucket_brigade *pbb;
! 469: apr_bucket *b;
! 470: TSRMLS_FETCH();
! 471:
! 472: if (f->r->proxyreq) {
! 473: zend_try {
! 474: zend_ini_deactivate(TSRMLS_C);
! 475: } zend_end_try();
! 476: return ap_pass_brigade(f->next, bb);
! 477: }
! 478:
! 479: /* handle situations where user turns the engine off */
! 480: if (*p == '0') {
! 481: zend_try {
! 482: zend_ini_deactivate(TSRMLS_C);
! 483: } zend_end_try();
! 484: return ap_pass_brigade(f->next, bb);
! 485: }
! 486:
! 487: if(f->ctx) {
! 488: pbb = (php_apr_bucket_brigade *)f->ctx;
! 489: } else {
! 490: pbb = f->ctx = apr_palloc(f->r->pool, sizeof(*pbb));
! 491: pbb->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
! 492: }
! 493:
! 494: if(ap_save_brigade(NULL, &pbb->bb, &bb, f->r->pool) != APR_SUCCESS) {
! 495: /* Bad */
! 496: }
! 497:
! 498: apr_brigade_cleanup(bb);
! 499:
! 500: /* Check to see if the last bucket in this brigade, it not
! 501: * we have to wait until then. */
! 502: if(!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(pbb->bb))) {
! 503: return 0;
! 504: }
! 505:
! 506: /* Setup the CGI variables if this is the main request.. */
! 507: if (f->r->main == NULL ||
! 508: /* .. or if the sub-request envinronment differs from the main-request. */
! 509: f->r->subprocess_env != f->r->main->subprocess_env
! 510: ) {
! 511: /* setup standard CGI variables */
! 512: ap_add_common_vars(f->r);
! 513: ap_add_cgi_vars(f->r);
! 514: }
! 515:
! 516: ctx = SG(server_context);
! 517: if (ctx == NULL) {
! 518: ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
! 519: "php failed to get server context");
! 520: zend_try {
! 521: zend_ini_deactivate(TSRMLS_C);
! 522: } zend_end_try();
! 523: return HTTP_INTERNAL_SERVER_ERROR;
! 524: }
! 525:
! 526: ctx->f = f->next; /* save whatever filters are after us in the chain. */
! 527:
! 528: if (ctx->request_processed) {
! 529: zend_try {
! 530: zend_ini_deactivate(TSRMLS_C);
! 531: } zend_end_try();
! 532: return ap_pass_brigade(f->next, bb);
! 533: }
! 534:
! 535: apply_config(conf);
! 536: php_apache_request_ctor(f, ctx TSRMLS_CC);
! 537:
! 538: /* It'd be nice if we could highlight based of a zend_file_handle here....
! 539: * ...but we can't. */
! 540:
! 541: zfd.type = ZEND_HANDLE_STREAM;
! 542:
! 543: zfd.handle.stream.handle = pbb;
! 544: zfd.handle.stream.reader = php_apache_read_stream;
! 545: zfd.handle.stream.closer = NULL;
! 546: zfd.handle.stream.fsizer = php_apache_fsizer_stream;
! 547: zfd.handle.stream.isatty = 0;
! 548:
! 549: zfd.filename = f->r->filename;
! 550: zfd.opened_path = NULL;
! 551: zfd.free_filename = 0;
! 552:
! 553: php_execute_script(&zfd TSRMLS_CC);
! 554:
! 555: apr_table_set(ctx->r->notes, "mod_php_memory_usage",
! 556: apr_psprintf(ctx->r->pool, "%u", zend_memory_peak_usage(1 TSRMLS_CC)));
! 557:
! 558: php_apache_request_dtor(f TSRMLS_CC);
! 559:
! 560: if (!f->r->main) {
! 561: ctx->request_processed = 1;
! 562: }
! 563:
! 564: b = apr_bucket_eos_create(f->c->bucket_alloc);
! 565: APR_BRIGADE_INSERT_TAIL(pbb->bb, b);
! 566:
! 567: /* Pass whatever is left on the brigade. */
! 568: return ap_pass_brigade(f->next, pbb->bb);
! 569: }
! 570:
! 571: static apr_status_t
! 572: php_apache_server_shutdown(void *tmp)
! 573: {
! 574: apache2_sapi_module.shutdown(&apache2_sapi_module);
! 575: sapi_shutdown();
! 576: #ifdef ZTS
! 577: tsrm_shutdown();
! 578: #endif
! 579: return APR_SUCCESS;
! 580: }
! 581:
! 582: static void php_apache_add_version(apr_pool_t *p)
! 583: {
! 584: TSRMLS_FETCH();
! 585: if (PG(expose_php)) {
! 586: #if SUHOSIN_PATCH
! 587: ap_add_version_component(p, "PHP/" PHP_VERSION " with Suhosin-Patch");
! 588: #else
! 589: ap_add_version_component(p, "PHP/" PHP_VERSION);
! 590: #endif
! 591: }
! 592: }
! 593:
! 594: static int php_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
! 595: {
! 596: #ifndef ZTS
! 597: int threaded_mpm;
! 598:
! 599: ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded_mpm);
! 600: if(threaded_mpm) {
! 601: ap_log_error(APLOG_MARK, APLOG_CRIT, 0, 0, "Apache is running a threaded MPM, but your PHP Module is not compiled to be threadsafe. You need to recompile PHP.");
! 602: return DONE;
! 603: }
! 604: #endif
! 605: /* When this is NULL, apache won't override the hard-coded default
! 606: * php.ini path setting. */
! 607: apache2_php_ini_path_override = NULL;
! 608: return OK;
! 609: }
! 610:
! 611: static int
! 612: php_apache_server_startup(apr_pool_t *pconf, apr_pool_t *plog,
! 613: apr_pool_t *ptemp, server_rec *s)
! 614: {
! 615: void *data = NULL;
! 616: const char *userdata_key = "apache2filter_post_config";
! 617:
! 618: /* Apache will load, unload and then reload a DSO module. This
! 619: * prevents us from starting PHP until the second load. */
! 620: apr_pool_userdata_get(&data, userdata_key, s->process->pool);
! 621: if (data == NULL) {
! 622: /* We must use set() here and *not* setn(), otherwise the
! 623: * static string pointed to by userdata_key will be mapped
! 624: * to a different location when the DSO is reloaded and the
! 625: * pointers won't match, causing get() to return NULL when
! 626: * we expected it to return non-NULL. */
! 627: apr_pool_userdata_set((const void *)1, userdata_key,
! 628: apr_pool_cleanup_null, s->process->pool);
! 629: return OK;
! 630: }
! 631:
! 632: /* Set up our overridden path. */
! 633: if (apache2_php_ini_path_override) {
! 634: apache2_sapi_module.php_ini_path_override = apache2_php_ini_path_override;
! 635: }
! 636: #ifdef ZTS
! 637: tsrm_startup(1, 1, 0, NULL);
! 638: #endif
! 639: sapi_startup(&apache2_sapi_module);
! 640: apache2_sapi_module.startup(&apache2_sapi_module);
! 641: apr_pool_cleanup_register(pconf, NULL, php_apache_server_shutdown, apr_pool_cleanup_null);
! 642: php_apache_add_version(pconf);
! 643:
! 644: return OK;
! 645: }
! 646:
! 647: static void php_add_filter(request_rec *r, ap_filter_t *f)
! 648: {
! 649: int output = (f == r->output_filters);
! 650:
! 651: /* for those who still have Set*Filter PHP configured */
! 652: while (f) {
! 653: if (strcmp(f->frec->name, "PHP") == 0) {
! 654: ap_log_error(APLOG_MARK, APLOG_WARNING,
! 655: 0, r->server,
! 656: "\"Set%sFilter PHP\" already configured for %s",
! 657: output ? "Output" : "Input", r->uri);
! 658: return;
! 659: }
! 660: f = f->next;
! 661: }
! 662:
! 663: if (output) {
! 664: ap_add_output_filter("PHP", NULL, r, r->connection);
! 665: } else {
! 666: ap_add_input_filter("PHP", NULL, r, r->connection);
! 667: }
! 668: }
! 669:
! 670: static void php_insert_filter(request_rec *r)
! 671: {
! 672: int content_type_len = strlen("application/x-httpd-php");
! 673:
! 674: if (r->content_type && !strncmp(r->content_type, "application/x-httpd-php", content_type_len-1)) {
! 675: if (r->content_type[content_type_len] == '\0' || !strncmp(r->content_type+content_type_len, "-source", sizeof("-source"))) {
! 676: php_add_filter(r, r->output_filters);
! 677: php_add_filter(r, r->input_filters);
! 678: }
! 679: }
! 680: }
! 681:
! 682: static apr_status_t php_server_context_cleanup(void *data_)
! 683: {
! 684: void **data = data_;
! 685: *data = NULL;
! 686: return APR_SUCCESS;
! 687: }
! 688:
! 689: static int php_post_read_request(request_rec *r)
! 690: {
! 691: php_struct *ctx;
! 692: TSRMLS_FETCH();
! 693:
! 694: /* Initialize filter context */
! 695: SG(server_context) = ctx = apr_pcalloc(r->pool, sizeof(*ctx));
! 696:
! 697: /* register a cleanup so we clear out the SG(server_context)
! 698: * after each request. Note: We pass in the pointer to the
! 699: * server_context in case this is handled by a different thread. */
! 700: apr_pool_cleanup_register(r->pool, (void *)&SG(server_context),
! 701: php_server_context_cleanup,
! 702: apr_pool_cleanup_null);
! 703:
! 704: /* Save the entire request, so we can get the input or output
! 705: * filters if we need them. */
! 706: ctx->r = r;
! 707:
! 708: return OK;
! 709: }
! 710:
! 711: static void php_register_hook(apr_pool_t *p)
! 712: {
! 713: ap_hook_pre_config(php_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
! 714: ap_hook_post_config(php_apache_server_startup, NULL, NULL, APR_HOOK_MIDDLE);
! 715: ap_hook_insert_filter(php_insert_filter, NULL, NULL, APR_HOOK_MIDDLE);
! 716: ap_hook_post_read_request(php_post_read_request, NULL, NULL, APR_HOOK_MIDDLE);
! 717: ap_register_output_filter("PHP", php_output_filter, php_apache_disable_caching, AP_FTYPE_RESOURCE);
! 718: ap_register_input_filter("PHP", php_input_filter, php_apache_disable_caching, AP_FTYPE_RESOURCE);
! 719: }
! 720:
! 721: static size_t php_apache_read_stream(void *handle, char *buf, size_t wantlen TSRMLS_DC)
! 722: {
! 723: php_apr_bucket_brigade *pbb = (php_apr_bucket_brigade *)handle;
! 724: apr_bucket_brigade *rbb;
! 725: apr_size_t readlen;
! 726: apr_bucket *b = NULL;
! 727:
! 728: rbb = pbb->bb;
! 729:
! 730: if((apr_brigade_partition(pbb->bb, wantlen, &b) == APR_SUCCESS) && b){
! 731: pbb->bb = apr_brigade_split(rbb, b);
! 732: }
! 733:
! 734: readlen = wantlen;
! 735: apr_brigade_flatten(rbb, buf, &readlen);
! 736: apr_brigade_cleanup(rbb);
! 737:
! 738: return readlen;
! 739: }
! 740:
! 741: static size_t php_apache_fsizer_stream(void *handle TSRMLS_DC)
! 742: {
! 743: php_apr_bucket_brigade *pbb = (php_apr_bucket_brigade *)handle;
! 744: apr_off_t actual = 0;
! 745:
! 746: if (apr_brigade_length(pbb->bb, 1, &actual) == APR_SUCCESS) {
! 747: return actual;
! 748: }
! 749:
! 750: return 0;
! 751: }
! 752:
! 753: AP_MODULE_DECLARE_DATA module php5_module = {
! 754: STANDARD20_MODULE_STUFF,
! 755: create_php_config, /* create per-directory config structure */
! 756: merge_php_config, /* merge per-directory config structures */
! 757: NULL, /* create per-server config structure */
! 758: NULL, /* merge per-server config structures */
! 759: php_dir_cmds, /* command apr_table_t */
! 760: php_register_hook /* register hooks */
! 761: };
! 762:
! 763: /*
! 764: * Local variables:
! 765: * tab-width: 4
! 766: * c-basic-offset: 4
! 767: * End:
! 768: * vim600: sw=4 ts=4 fdm=marker
! 769: * vim<600: sw=4 ts=4
! 770: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>