Annotation of embedaddon/php/sapi/apache2filter/sapi_apache2.c, revision 1.1.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>