root/sapi/apache2filter/sapi_apache2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_apache_sapi_ub_write
  2. php_apache_sapi_header_handler
  3. php_apache_sapi_send_headers
  4. php_apache_sapi_read_post
  5. php_apache_sapi_get_stat
  6. php_apache_sapi_read_cookies
  7. php_apache_sapi_getenv
  8. php_apache_sapi_register_variables
  9. php_apache_sapi_flush
  10. php_apache_sapi_log_message
  11. php_apache_disable_caching
  12. php_apache_sapi_get_request_time
  13. php_apache2_startup
  14. php_input_filter
  15. php_apache_request_ctor
  16. php_apache_request_dtor
  17. php_output_filter
  18. php_apache_server_shutdown
  19. php_apache_add_version
  20. php_pre_config
  21. php_apache_server_startup
  22. php_add_filter
  23. php_insert_filter
  24. php_server_context_cleanup
  25. php_post_read_request
  26. php_register_hook
  27. php_apache_read_stream
  28. php_apache_fsizer_stream

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

/* [<][>][^][v][top][bottom][index][help] */