Back to index

php5  5.3.10
sapi_apache2.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Sascha Schumann <sascha@schumann.cx>                        |
00016    |          Parts based on Apache 1.3 SAPI module by                    |
00017    |          Rasmus Lerdorf and Zeev Suraski                             |
00018    +----------------------------------------------------------------------+
00019  */
00020 
00021 /* $Id: sapi_apache2.c 321634 2012-01-01 13:15:04Z felipe $ */
00022 
00023 #include <fcntl.h>
00024 
00025 #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
00026 
00027 #include "php.h"
00028 #include "php_main.h"
00029 #include "php_ini.h"
00030 #include "php_variables.h"
00031 #include "SAPI.h"
00032 
00033 #include "ext/standard/php_smart_str.h"
00034 #ifndef NETWARE
00035 #include "ext/standard/php_standard.h"
00036 #else
00037 #include "ext/standard/basic_functions.h"
00038 #endif
00039 
00040 #include "apr_strings.h"
00041 #include "ap_config.h"
00042 #include "apr_buckets.h"
00043 #include "util_filter.h"
00044 #include "httpd.h"
00045 #include "http_config.h"
00046 #include "http_request.h"
00047 #include "http_core.h"
00048 #include "http_protocol.h"
00049 #include "http_log.h"
00050 #include "http_main.h"
00051 #include "util_script.h"
00052 #include "http_core.h"                         
00053 #include "ap_mpm.h"
00054 
00055 #include "php_apache.h"
00056 
00057 /* UnixWare and Netware define shutdown to _shutdown, which causes problems later
00058  * on when using a structure member named shutdown. Since this source
00059  * file does not use the system call shutdown, it is safe to #undef it.
00060  */
00061 #undef shutdown
00062 
00063 /* A way to specify the location of the php.ini dir in an apache directive */
00064 char *apache2_php_ini_path_override = NULL;
00065 
00066 static int
00067 php_apache_sapi_ub_write(const char *str, uint str_length TSRMLS_DC)
00068 {
00069        apr_bucket *b;
00070        apr_bucket_brigade *bb;
00071        apr_bucket_alloc_t *ba;
00072        ap_filter_t *f; /* remaining output filters */
00073        php_struct *ctx;
00074 
00075        ctx = SG(server_context);
00076        f = ctx->f;
00077        
00078        if (str_length == 0) return 0;
00079        
00080        ba = f->c->bucket_alloc;
00081        bb = apr_brigade_create(ctx->r->pool, ba);
00082 
00083        b = apr_bucket_transient_create(str, str_length, ba);
00084        APR_BRIGADE_INSERT_TAIL(bb, b);
00085 
00086        if (ap_pass_brigade(f->next, bb) != APR_SUCCESS || ctx->r->connection->aborted) {
00087               php_handle_aborted_connection();
00088        }
00089        
00090        return str_length; /* we always consume all the data passed to us. */
00091 }
00092 
00093 static int
00094 php_apache_sapi_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC)
00095 {
00096        php_struct *ctx;
00097        ap_filter_t *f;
00098        char *val, *ptr;
00099 
00100        ctx = SG(server_context);
00101        f = ctx->r->output_filters;
00102 
00103        switch(op) {
00104               case SAPI_HEADER_DELETE:
00105                      apr_table_unset(ctx->r->headers_out, sapi_header->header);
00106                      return 0;
00107 
00108               case SAPI_HEADER_DELETE_ALL:
00109                      apr_table_clear(ctx->r->headers_out);
00110                      return 0;
00111 
00112               case SAPI_HEADER_ADD:
00113               case SAPI_HEADER_REPLACE:
00114                      val = strchr(sapi_header->header, ':');
00115 
00116                      if (!val) {
00117                             sapi_free_header(sapi_header);
00118                             return 0;
00119                      }
00120                      ptr = val;
00121 
00122                      *val = '\0';
00123                      
00124                      do {
00125                             val++;
00126                      } while (*val == ' ');
00127 
00128                      if (!strcasecmp(sapi_header->header, "content-type"))
00129                             ctx->r->content_type = apr_pstrdup(ctx->r->pool, val);
00130                        else if (!strcasecmp(sapi_header->header, "content-length"))
00131                                ap_set_content_length(ctx->r, strtol(val, (char **)NULL, 10));
00132                      else if (op == SAPI_HEADER_REPLACE)
00133                             apr_table_set(ctx->r->headers_out, sapi_header->header, val);
00134                      else
00135                             apr_table_add(ctx->r->headers_out, sapi_header->header, val);
00136                      
00137                      *ptr = ':';
00138                      return SAPI_HEADER_ADD;
00139 
00140               default:
00141                      return 0;
00142        }
00143 }
00144 
00145 static int
00146 php_apache_sapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
00147 {
00148        php_struct *ctx = SG(server_context);
00149 
00150        ctx->r->status = SG(sapi_headers).http_response_code;
00151 
00152        return SAPI_HEADER_SENT_SUCCESSFULLY;
00153 }
00154 
00155 static int
00156 php_apache_sapi_read_post(char *buf, uint count_bytes TSRMLS_DC)
00157 {
00158        int n;
00159        int to_read;
00160        php_struct *ctx = SG(server_context);
00161 
00162        to_read = ctx->post_len - ctx->post_idx;
00163        n = MIN(to_read, count_bytes);
00164        
00165        if (n > 0) {
00166               memcpy(buf, ctx->post_data + ctx->post_idx, n);
00167               ctx->post_idx += n;
00168        } else {
00169               if (ctx->post_data) free(ctx->post_data);
00170               ctx->post_data = NULL;
00171        }
00172 
00173        return n;
00174 }
00175 
00176 static struct stat*
00177 php_apache_sapi_get_stat(TSRMLS_D)
00178 {
00179        php_struct *ctx = SG(server_context);
00180 
00181        ctx->finfo.st_uid = ctx->r->finfo.user;
00182        ctx->finfo.st_gid = ctx->r->finfo.group;
00183        ctx->finfo.st_dev = ctx->r->finfo.device;
00184        ctx->finfo.st_ino = ctx->r->finfo.inode;
00185 #ifdef NETWARE
00186        ctx->finfo.st_atime.tv_sec = apr_time_sec(ctx->r->finfo.atime);
00187        ctx->finfo.st_mtime.tv_sec = apr_time_sec(ctx->r->finfo.mtime);
00188        ctx->finfo.st_ctime.tv_sec = apr_time_sec(ctx->r->finfo.ctime);
00189 #else
00190        ctx->finfo.st_atime = apr_time_sec(ctx->r->finfo.atime);
00191        ctx->finfo.st_mtime = apr_time_sec(ctx->r->finfo.mtime);
00192        ctx->finfo.st_ctime = apr_time_sec(ctx->r->finfo.ctime);
00193 #endif
00194 
00195        ctx->finfo.st_size = ctx->r->finfo.size;
00196        ctx->finfo.st_nlink = ctx->r->finfo.nlink;
00197 
00198        return &ctx->finfo;
00199 }
00200 
00201 static char *
00202 php_apache_sapi_read_cookies(TSRMLS_D)
00203 {
00204        php_struct *ctx = SG(server_context);
00205        const char *http_cookie;
00206 
00207        http_cookie = apr_table_get(ctx->r->headers_in, "cookie");
00208 
00209        /* The SAPI interface should use 'const char *' */
00210        return (char *) http_cookie;
00211 }
00212 
00213 static char *
00214 php_apache_sapi_getenv(char *name, size_t name_len TSRMLS_DC)
00215 {
00216        php_struct *ctx = SG(server_context);
00217        const char *env_var;
00218        
00219        env_var = apr_table_get(ctx->r->subprocess_env, name);
00220 
00221        return (char *) env_var;
00222 }
00223 
00224 static void
00225 php_apache_sapi_register_variables(zval *track_vars_array TSRMLS_DC)
00226 {
00227        php_struct *ctx = SG(server_context);
00228        const apr_array_header_t *arr = apr_table_elts(ctx->r->subprocess_env);
00229        char *key, *val;
00230        unsigned int new_val_len;
00231        
00232        APR_ARRAY_FOREACH_OPEN(arr, key, val)
00233               if (!val) {
00234                      val = "";
00235               }
00236               if (sapi_module.input_filter(PARSE_SERVER, key, &val, strlen(val), &new_val_len TSRMLS_CC)) {
00237                      php_register_variable_safe(key, val, new_val_len, track_vars_array TSRMLS_CC);
00238               }
00239        APR_ARRAY_FOREACH_CLOSE()
00240               
00241        php_register_variable("PHP_SELF", ctx->r->uri, track_vars_array TSRMLS_CC);
00242        if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &ctx->r->uri, strlen(ctx->r->uri), &new_val_len TSRMLS_CC)) {
00243               php_register_variable_safe("PHP_SELF", ctx->r->uri, new_val_len, track_vars_array TSRMLS_CC);
00244        }
00245 }
00246 
00247 static void
00248 php_apache_sapi_flush(void *server_context)
00249 {
00250        php_struct *ctx;
00251        apr_bucket_brigade *bb;
00252        apr_bucket_alloc_t *ba;
00253        apr_bucket *b;
00254        ap_filter_t *f; /* output filters */
00255        TSRMLS_FETCH();
00256 
00257        ctx = server_context;
00258 
00259        /* If we haven't registered a server_context yet,
00260         * then don't bother flushing. */
00261        if (!server_context)
00262               return;
00263 
00264        sapi_send_headers(TSRMLS_C);
00265 
00266        ctx->r->status = SG(sapi_headers).http_response_code;
00267        SG(headers_sent) = 1;
00268 
00269        f = ctx->f;
00270 
00271        /* Send a flush bucket down the filter chain. The current default
00272         * handler seems to act on the first flush bucket, but ignores
00273         * all further flush buckets.
00274         */
00275        
00276        ba = ctx->r->connection->bucket_alloc;
00277        bb = apr_brigade_create(ctx->r->pool, ba);
00278        b = apr_bucket_flush_create(ba);
00279        APR_BRIGADE_INSERT_TAIL(bb, b);
00280        if (ap_pass_brigade(f->next, bb) != APR_SUCCESS || ctx->r->connection->aborted) {
00281               php_handle_aborted_connection();
00282        }
00283 }
00284 
00285 static void php_apache_sapi_log_message(char *msg)
00286 {
00287        php_struct *ctx;
00288        TSRMLS_FETCH();
00289 
00290        ctx = SG(server_context);
00291    
00292        if (ctx == NULL) { /* we haven't initialized our ctx yet, oh well */
00293               ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, 0, NULL, "%s", msg);
00294        }
00295        else {
00296               ap_log_error(APLOG_MARK, APLOG_ERR, 0, ctx->r->server, "%s", msg);
00297        }
00298 }
00299 
00300 static int
00301 php_apache_disable_caching(ap_filter_t *f)
00302 {
00303        /* Identify PHP scripts as non-cacheable, thus preventing 
00304         * Apache from sending a 304 status when the browser sends
00305         * If-Modified-Since header.
00306         */
00307        f->r->no_local_copy = 1;
00308        
00309        return OK;
00310 }
00311 
00312 static time_t php_apache_sapi_get_request_time(TSRMLS_D)
00313 {
00314        php_struct *ctx = SG(server_context);
00315        return apr_time_sec(ctx->r->request_time);
00316 }
00317 
00318 extern zend_module_entry php_apache_module;
00319 
00320 static int php_apache2_startup(sapi_module_struct *sapi_module)
00321 {
00322        if (php_module_startup(sapi_module, &php_apache_module, 1)==FAILURE) {
00323               return FAILURE;
00324        }
00325        return SUCCESS;
00326 }
00327 
00328 static sapi_module_struct apache2_sapi_module = {
00329        "apache2filter",
00330        "Apache 2.0 Filter",
00331 
00332        php_apache2_startup,                                    /* startup */
00333        php_module_shutdown_wrapper,                     /* shutdown */
00334 
00335        NULL,                                                          /* activate */
00336        NULL,                                                          /* deactivate */
00337 
00338        php_apache_sapi_ub_write,                        /* unbuffered write */
00339        php_apache_sapi_flush,                                  /* flush */
00340        php_apache_sapi_get_stat,                                      /* get uid */
00341        php_apache_sapi_getenv,                                 /* getenv */
00342 
00343        php_error,                                                     /* error handler */
00344 
00345        php_apache_sapi_header_handler,                  /* header handler */
00346        php_apache_sapi_send_headers,                    /* send headers handler */
00347        NULL,                                                          /* send header handler */
00348 
00349        php_apache_sapi_read_post,                       /* read POST data */
00350        php_apache_sapi_read_cookies,                    /* read Cookies */
00351 
00352        php_apache_sapi_register_variables,
00353        php_apache_sapi_log_message,                     /* Log message */
00354        php_apache_sapi_get_request_time,         /* Get Request Time */
00355        NULL,                                     /* Child terminate */
00356 
00357        STANDARD_SAPI_MODULE_PROPERTIES
00358 };
00359 
00360 static int php_input_filter(ap_filter_t *f, apr_bucket_brigade *bb, 
00361               ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
00362 {
00363        php_struct *ctx;
00364        long old_index;
00365        apr_bucket *b;
00366        const char *str;
00367        apr_size_t n;
00368        apr_status_t rv;
00369        TSRMLS_FETCH();
00370 
00371        if (f->r->proxyreq) {
00372               return ap_get_brigade(f->next, bb, mode, block, readbytes);
00373        }
00374 
00375        ctx = SG(server_context);
00376        if (ctx == NULL) {
00377               ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
00378                                     "php failed to get server context");
00379               return HTTP_INTERNAL_SERVER_ERROR;
00380        }
00381 
00382        if ((rv = ap_get_brigade(f->next, bb, mode, block, readbytes)) != APR_SUCCESS) {
00383               return rv;
00384        }
00385 
00386        for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) {
00387               apr_bucket_read(b, &str, &n, APR_NONBLOCK_READ);
00388               if (n > 0) {
00389                      old_index = ctx->post_len;
00390                      ctx->post_len += n;
00391                      ctx->post_data = realloc(ctx->post_data, ctx->post_len + 1);
00392                      memcpy(ctx->post_data + old_index, str, n);
00393               }
00394        }
00395        return APR_SUCCESS;
00396 }
00397 
00398 static void php_apache_request_ctor(ap_filter_t *f, php_struct *ctx TSRMLS_DC)
00399 {
00400        char *content_type;
00401        char *content_length;
00402        const char *auth;
00403 
00404        PG(during_request_startup) = 0;
00405        SG(sapi_headers).http_response_code = !f->r->status ? HTTP_OK : f->r->status;
00406        SG(request_info).content_type = apr_table_get(f->r->headers_in, "Content-Type");
00407 #undef safe_strdup
00408 #define safe_strdup(x) ((x)?strdup((x)):NULL)    
00409        SG(request_info).query_string = safe_strdup(f->r->args);
00410        SG(request_info).request_method = f->r->method;
00411        SG(request_info).proto_num = f->r->proto_num;
00412        SG(request_info).request_uri = safe_strdup(f->r->uri);
00413        SG(request_info).path_translated = safe_strdup(f->r->filename);
00414        f->r->no_local_copy = 1;
00415        content_type = sapi_get_default_content_type(TSRMLS_C);
00416        f->r->content_type = apr_pstrdup(f->r->pool, content_type);
00417        SG(request_info).post_data = ctx->post_data;
00418        SG(request_info).post_data_length = ctx->post_len;
00419 
00420        efree(content_type);
00421 
00422        content_length = (char *) apr_table_get(f->r->headers_in, "Content-Length");
00423        SG(request_info).content_length = (content_length ? atol(content_length) : 0);
00424        
00425        apr_table_unset(f->r->headers_out, "Content-Length");
00426        apr_table_unset(f->r->headers_out, "Last-Modified");
00427        apr_table_unset(f->r->headers_out, "Expires");
00428        apr_table_unset(f->r->headers_out, "ETag");
00429        if (!PG(safe_mode) || (PG(safe_mode) && !ap_auth_type(f->r))) {
00430               auth = apr_table_get(f->r->headers_in, "Authorization");
00431               php_handle_auth_data(auth TSRMLS_CC);
00432               if (SG(request_info).auth_user == NULL && f->r->user) {
00433                      SG(request_info).auth_user = estrdup(f->r->user);
00434               }
00435               ctx->r->user = apr_pstrdup(ctx->r->pool, SG(request_info).auth_user);
00436        } else {
00437               SG(request_info).auth_user = NULL;
00438               SG(request_info).auth_password = NULL;
00439        }
00440        php_request_startup(TSRMLS_C);
00441 }
00442 
00443 static void php_apache_request_dtor(ap_filter_t *f TSRMLS_DC)
00444 {
00445        php_apr_bucket_brigade *pbb = (php_apr_bucket_brigade *)f->ctx;
00446        
00447        php_request_shutdown(NULL);
00448 
00449        if (SG(request_info).query_string) {
00450               free(SG(request_info).query_string);
00451        }
00452        if (SG(request_info).request_uri) {
00453               free(SG(request_info).request_uri);
00454        }
00455        if (SG(request_info).path_translated) {
00456               free(SG(request_info).path_translated);
00457        }
00458        
00459        apr_brigade_destroy(pbb->bb);
00460 }
00461 
00462 static int php_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
00463 {
00464        php_struct *ctx;
00465        void *conf = ap_get_module_config(f->r->per_dir_config, &php5_module);
00466        char *p = get_php_config(conf, "engine", sizeof("engine"));
00467        zend_file_handle zfd;
00468        php_apr_bucket_brigade *pbb;
00469        apr_bucket *b;
00470        TSRMLS_FETCH();
00471        
00472        if (f->r->proxyreq) {
00473               zend_try {
00474                      zend_ini_deactivate(TSRMLS_C);
00475               } zend_end_try();
00476               return ap_pass_brigade(f->next, bb);
00477        }
00478        
00479        /* handle situations where user turns the engine off */
00480        if (*p == '0') {
00481               zend_try {
00482                      zend_ini_deactivate(TSRMLS_C);
00483               } zend_end_try();
00484               return ap_pass_brigade(f->next, bb);
00485        }      
00486        
00487        if(f->ctx) {
00488               pbb = (php_apr_bucket_brigade *)f->ctx;
00489        } else {
00490               pbb = f->ctx = apr_palloc(f->r->pool, sizeof(*pbb));
00491               pbb->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
00492        }
00493 
00494        if(ap_save_brigade(NULL, &pbb->bb, &bb, f->r->pool) != APR_SUCCESS) {
00495               /* Bad */
00496        }
00497        
00498        apr_brigade_cleanup(bb);
00499        
00500        /* Check to see if the last bucket in this brigade, it not
00501         * we have to wait until then. */
00502        if(!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(pbb->bb))) {
00503               return 0;
00504        }      
00505        
00506        /* Setup the CGI variables if this is the main request.. */
00507        if (f->r->main == NULL || 
00508               /* .. or if the sub-request envinronment differs from the main-request. */
00509               f->r->subprocess_env != f->r->main->subprocess_env
00510        ) {
00511               /* setup standard CGI variables */
00512               ap_add_common_vars(f->r);
00513               ap_add_cgi_vars(f->r);
00514        }
00515        
00516        ctx = SG(server_context);
00517        if (ctx == NULL) {
00518               ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
00519                                     "php failed to get server context");
00520               zend_try {
00521                      zend_ini_deactivate(TSRMLS_C);
00522               } zend_end_try();
00523         return HTTP_INTERNAL_SERVER_ERROR;
00524        }
00525        
00526        ctx->f = f->next; /* save whatever filters are after us in the chain. */
00527 
00528        if (ctx->request_processed) {
00529               zend_try {
00530                      zend_ini_deactivate(TSRMLS_C);
00531               } zend_end_try();
00532               return ap_pass_brigade(f->next, bb);
00533        }
00534 
00535        apply_config(conf);
00536        php_apache_request_ctor(f, ctx TSRMLS_CC);
00537        
00538        /* It'd be nice if we could highlight based of a zend_file_handle here....
00539         * ...but we can't. */
00540        
00541        zfd.type = ZEND_HANDLE_STREAM;
00542        
00543        zfd.handle.stream.handle = pbb;
00544        zfd.handle.stream.reader = php_apache_read_stream;
00545        zfd.handle.stream.closer = NULL;
00546        zfd.handle.stream.fsizer = php_apache_fsizer_stream;
00547        zfd.handle.stream.isatty = 0;
00548        
00549        zfd.filename = f->r->filename;
00550        zfd.opened_path = NULL;
00551        zfd.free_filename = 0;
00552        
00553        php_execute_script(&zfd TSRMLS_CC);
00554 
00555        apr_table_set(ctx->r->notes, "mod_php_memory_usage",
00556               apr_psprintf(ctx->r->pool, "%u", zend_memory_peak_usage(1 TSRMLS_CC)));
00557               
00558        php_apache_request_dtor(f TSRMLS_CC);
00559               
00560        if (!f->r->main) {
00561               ctx->request_processed = 1;
00562        }
00563        
00564        b = apr_bucket_eos_create(f->c->bucket_alloc);
00565        APR_BRIGADE_INSERT_TAIL(pbb->bb,  b);
00566        
00567        /* Pass whatever is left on the brigade. */
00568        return ap_pass_brigade(f->next, pbb->bb);
00569 }
00570 
00571 static apr_status_t
00572 php_apache_server_shutdown(void *tmp)
00573 {
00574        apache2_sapi_module.shutdown(&apache2_sapi_module);
00575        sapi_shutdown();
00576 #ifdef ZTS
00577        tsrm_shutdown();
00578 #endif
00579        return APR_SUCCESS;
00580 }
00581 
00582 static void php_apache_add_version(apr_pool_t *p)
00583 {
00584        TSRMLS_FETCH();
00585        if (PG(expose_php)) {
00586               ap_add_version_component(p, "PHP/" PHP_VERSION);
00587        }
00588 }
00589 
00590 static int php_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
00591 {
00592 #ifndef ZTS
00593        int threaded_mpm;
00594 
00595        ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded_mpm);
00596        if(threaded_mpm) {
00597               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.");
00598               return DONE;
00599        }
00600 #endif
00601     /* When this is NULL, apache won't override the hard-coded default
00602      * php.ini path setting. */
00603     apache2_php_ini_path_override = NULL;
00604     return OK;
00605 }
00606 
00607 static int
00608 php_apache_server_startup(apr_pool_t *pconf, apr_pool_t *plog,
00609                           apr_pool_t *ptemp, server_rec *s)
00610 {
00611        void *data = NULL;
00612        const char *userdata_key = "apache2filter_post_config";
00613 
00614        /* Apache will load, unload and then reload a DSO module. This
00615         * prevents us from starting PHP until the second load. */
00616        apr_pool_userdata_get(&data, userdata_key, s->process->pool);
00617        if (data == NULL) {
00618               /* We must use set() here and *not* setn(), otherwise the
00619                * static string pointed to by userdata_key will be mapped
00620                * to a different location when the DSO is reloaded and the
00621                * pointers won't match, causing get() to return NULL when
00622                * we expected it to return non-NULL. */
00623               apr_pool_userdata_set((const void *)1, userdata_key,
00624                                                    apr_pool_cleanup_null, s->process->pool);
00625               return OK;
00626        }
00627 
00628        /* Set up our overridden path. */
00629        if (apache2_php_ini_path_override) {
00630               apache2_sapi_module.php_ini_path_override = apache2_php_ini_path_override;
00631        }
00632 #ifdef ZTS
00633        tsrm_startup(1, 1, 0, NULL);
00634 #endif
00635        sapi_startup(&apache2_sapi_module);
00636        apache2_sapi_module.startup(&apache2_sapi_module);
00637        apr_pool_cleanup_register(pconf, NULL, php_apache_server_shutdown, apr_pool_cleanup_null);
00638        php_apache_add_version(pconf);
00639 
00640        return OK;
00641 }
00642 
00643 static void php_add_filter(request_rec *r, ap_filter_t *f)
00644 {
00645        int output = (f == r->output_filters);
00646 
00647        /* for those who still have Set*Filter PHP configured */
00648        while (f) {
00649               if (strcmp(f->frec->name, "PHP") == 0) {
00650                      ap_log_error(APLOG_MARK, APLOG_WARNING,
00651                                  0, r->server,
00652                                  "\"Set%sFilter PHP\" already configured for %s",
00653                                  output ? "Output" : "Input", r->uri);
00654                      return;
00655               }
00656               f = f->next;
00657        }
00658 
00659        if (output) {
00660               ap_add_output_filter("PHP", NULL, r, r->connection);
00661        } else {
00662               ap_add_input_filter("PHP", NULL, r, r->connection);
00663        }
00664 }
00665 
00666 static void php_insert_filter(request_rec *r)
00667 {
00668        int content_type_len = strlen("application/x-httpd-php");
00669 
00670        if (r->content_type && !strncmp(r->content_type, "application/x-httpd-php", content_type_len-1)) {
00671               if (r->content_type[content_type_len] == '\0' || !strncmp(r->content_type+content_type_len, "-source", sizeof("-source"))) { 
00672                      php_add_filter(r, r->output_filters);
00673                      php_add_filter(r, r->input_filters);
00674               }      
00675        }
00676 }
00677 
00678 static apr_status_t php_server_context_cleanup(void *data_)
00679 {
00680        void **data = data_;
00681        *data = NULL;
00682        return APR_SUCCESS;
00683 }
00684 
00685 static int php_post_read_request(request_rec *r)
00686 {
00687        php_struct *ctx;
00688        TSRMLS_FETCH();
00689 
00690        /* Initialize filter context */
00691        SG(server_context) = ctx = apr_pcalloc(r->pool, sizeof(*ctx));
00692 
00693        /* register a cleanup so we clear out the SG(server_context)
00694         * after each request. Note: We pass in the pointer to the
00695         * server_context in case this is handled by a different thread. */
00696        apr_pool_cleanup_register(r->pool, (void *)&SG(server_context),
00697                                                    php_server_context_cleanup,
00698                                                    apr_pool_cleanup_null);
00699 
00700        /* Save the entire request, so we can get the input or output
00701         * filters if we need them. */
00702        ctx->r = r;
00703 
00704        return OK;
00705 }
00706 
00707 static void php_register_hook(apr_pool_t *p)
00708 {
00709        ap_hook_pre_config(php_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
00710        ap_hook_post_config(php_apache_server_startup, NULL, NULL, APR_HOOK_MIDDLE);
00711        ap_hook_insert_filter(php_insert_filter, NULL, NULL, APR_HOOK_MIDDLE);
00712        ap_hook_post_read_request(php_post_read_request, NULL, NULL, APR_HOOK_MIDDLE);
00713        ap_register_output_filter("PHP", php_output_filter, php_apache_disable_caching, AP_FTYPE_RESOURCE);
00714        ap_register_input_filter("PHP", php_input_filter, php_apache_disable_caching, AP_FTYPE_RESOURCE);
00715 }
00716 
00717 static size_t php_apache_read_stream(void *handle, char *buf, size_t wantlen TSRMLS_DC)
00718 {
00719        php_apr_bucket_brigade *pbb = (php_apr_bucket_brigade *)handle;
00720        apr_bucket_brigade *rbb;
00721        apr_size_t readlen;
00722        apr_bucket *b = NULL;
00723        
00724        rbb = pbb->bb;
00725        
00726        if((apr_brigade_partition(pbb->bb, wantlen, &b) == APR_SUCCESS) && b){
00727               pbb->bb = apr_brigade_split(rbb, b);
00728        }      
00729 
00730        readlen = wantlen;
00731        apr_brigade_flatten(rbb, buf, &readlen);
00732        apr_brigade_cleanup(rbb);
00733        
00734        return readlen;
00735 }
00736 
00737 static size_t php_apache_fsizer_stream(void *handle TSRMLS_DC)
00738 {
00739        php_apr_bucket_brigade *pbb = (php_apr_bucket_brigade *)handle;
00740        apr_off_t actual = 0;
00741 
00742        if (apr_brigade_length(pbb->bb, 1, &actual) == APR_SUCCESS) {
00743               return actual;
00744        }
00745 
00746        return 0;
00747 }
00748 
00749 AP_MODULE_DECLARE_DATA module php5_module = {
00750        STANDARD20_MODULE_STUFF,
00751        create_php_config,          /* create per-directory config structure */
00752        merge_php_config,           /* merge per-directory config structures */
00753        NULL,                              /* create per-server config structure */
00754        NULL,                              /* merge per-server config structures */
00755        php_dir_cmds,               /* command apr_table_t */
00756        php_register_hook           /* register hooks */
00757 };
00758 
00759 /*
00760  * Local variables:
00761  * tab-width: 4
00762  * c-basic-offset: 4
00763  * End:
00764  * vim600: sw=4 ts=4 fdm=marker
00765  * vim<600: sw=4 ts=4
00766  */