Annotation of embedaddon/php/sapi/apache2filter/sapi_apache2.c, revision 1.1.1.3

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.3 ! misho       5:    | Copyright (c) 1997-2013 The PHP Group                                |
1.1       misho       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: 
1.1.1.2   misho      21: /* $Id$ */
1.1       misho      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: 
1.1.1.2   misho     285: static void php_apache_sapi_log_message(char *msg TSRMLS_DC)
1.1       misho     286: {
                    287:        php_struct *ctx;
                    288: 
                    289:        ctx = SG(server_context);
                    290:    
                    291:        if (ctx == NULL) { /* we haven't initialized our ctx yet, oh well */
                    292:                ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, 0, NULL, "%s", msg);
                    293:        }
                    294:        else {
                    295:                ap_log_error(APLOG_MARK, APLOG_ERR, 0, ctx->r->server, "%s", msg);
                    296:        }
                    297: }
                    298: 
                    299: static int
                    300: php_apache_disable_caching(ap_filter_t *f)
                    301: {
                    302:        /* Identify PHP scripts as non-cacheable, thus preventing 
                    303:         * Apache from sending a 304 status when the browser sends
                    304:         * If-Modified-Since header.
                    305:         */
                    306:        f->r->no_local_copy = 1;
                    307:        
                    308:        return OK;
                    309: }
                    310: 
1.1.1.2   misho     311: static double php_apache_sapi_get_request_time(TSRMLS_D)
1.1       misho     312: {
                    313:        php_struct *ctx = SG(server_context);
1.1.1.3 ! misho     314:        return ((double) apr_time_as_msec(ctx->r->request_time)) / 1000.0;
1.1       misho     315: }
                    316: 
                    317: extern zend_module_entry php_apache_module;
                    318: 
                    319: static int php_apache2_startup(sapi_module_struct *sapi_module)
                    320: {
                    321:        if (php_module_startup(sapi_module, &php_apache_module, 1)==FAILURE) {
                    322:                return FAILURE;
                    323:        }
                    324:        return SUCCESS;
                    325: }
                    326: 
                    327: static sapi_module_struct apache2_sapi_module = {
                    328:        "apache2filter",
                    329:        "Apache 2.0 Filter",
                    330: 
                    331:        php_apache2_startup,                                            /* startup */
                    332:        php_module_shutdown_wrapper,                    /* shutdown */
                    333: 
                    334:        NULL,                                                                   /* activate */
                    335:        NULL,                                                                   /* deactivate */
                    336: 
                    337:        php_apache_sapi_ub_write,                               /* unbuffered write */
                    338:        php_apache_sapi_flush,                                  /* flush */
                    339:        php_apache_sapi_get_stat,                                               /* get uid */
                    340:        php_apache_sapi_getenv,                                 /* getenv */
                    341: 
                    342:        php_error,                                                              /* error handler */
                    343: 
                    344:        php_apache_sapi_header_handler,                 /* header handler */
                    345:        php_apache_sapi_send_headers,                   /* send headers handler */
                    346:        NULL,                                                                   /* send header handler */
                    347: 
                    348:        php_apache_sapi_read_post,                              /* read POST data */
                    349:        php_apache_sapi_read_cookies,                   /* read Cookies */
                    350: 
                    351:        php_apache_sapi_register_variables,
                    352:        php_apache_sapi_log_message,                    /* Log message */
                    353:        php_apache_sapi_get_request_time,               /* Get Request Time */
                    354:        NULL,                                           /* Child terminate */
                    355: 
                    356:        STANDARD_SAPI_MODULE_PROPERTIES
                    357: };
                    358: 
                    359: static int php_input_filter(ap_filter_t *f, apr_bucket_brigade *bb, 
                    360:                ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
                    361: {
                    362:        php_struct *ctx;
                    363:        long old_index;
                    364:        apr_bucket *b;
                    365:        const char *str;
                    366:        apr_size_t n;
                    367:        apr_status_t rv;
                    368:        TSRMLS_FETCH();
                    369: 
                    370:        if (f->r->proxyreq) {
                    371:                return ap_get_brigade(f->next, bb, mode, block, readbytes);
                    372:        }
                    373: 
                    374:        ctx = SG(server_context);
                    375:        if (ctx == NULL) {
                    376:                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
                    377:                                         "php failed to get server context");
                    378:                return HTTP_INTERNAL_SERVER_ERROR;
                    379:        }
                    380: 
                    381:        if ((rv = ap_get_brigade(f->next, bb, mode, block, readbytes)) != APR_SUCCESS) {
                    382:                return rv;
                    383:        }
                    384: 
                    385:        for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) {
                    386:                apr_bucket_read(b, &str, &n, APR_NONBLOCK_READ);
                    387:                if (n > 0) {
                    388:                        old_index = ctx->post_len;
                    389:                        ctx->post_len += n;
                    390:                        ctx->post_data = realloc(ctx->post_data, ctx->post_len + 1);
                    391:                        memcpy(ctx->post_data + old_index, str, n);
                    392:                }
                    393:        }
                    394:        return APR_SUCCESS;
                    395: }
                    396: 
                    397: static void php_apache_request_ctor(ap_filter_t *f, php_struct *ctx TSRMLS_DC)
                    398: {
                    399:        char *content_type;
                    400:        char *content_length;
                    401:        const char *auth;
                    402: 
                    403:        PG(during_request_startup) = 0;
                    404:        SG(sapi_headers).http_response_code = !f->r->status ? HTTP_OK : f->r->status;
                    405:        SG(request_info).content_type = apr_table_get(f->r->headers_in, "Content-Type");
                    406: #undef safe_strdup
                    407: #define safe_strdup(x) ((x)?strdup((x)):NULL)  
                    408:        SG(request_info).query_string = safe_strdup(f->r->args);
                    409:        SG(request_info).request_method = f->r->method;
                    410:        SG(request_info).proto_num = f->r->proto_num;
                    411:        SG(request_info).request_uri = safe_strdup(f->r->uri);
                    412:        SG(request_info).path_translated = safe_strdup(f->r->filename);
                    413:        f->r->no_local_copy = 1;
                    414:        content_type = sapi_get_default_content_type(TSRMLS_C);
                    415:        f->r->content_type = apr_pstrdup(f->r->pool, content_type);
                    416:        SG(request_info).post_data = ctx->post_data;
                    417:        SG(request_info).post_data_length = ctx->post_len;
                    418: 
                    419:        efree(content_type);
                    420: 
                    421:        content_length = (char *) apr_table_get(f->r->headers_in, "Content-Length");
                    422:        SG(request_info).content_length = (content_length ? atol(content_length) : 0);
                    423:        
                    424:        apr_table_unset(f->r->headers_out, "Content-Length");
                    425:        apr_table_unset(f->r->headers_out, "Last-Modified");
                    426:        apr_table_unset(f->r->headers_out, "Expires");
                    427:        apr_table_unset(f->r->headers_out, "ETag");
1.1.1.2   misho     428: 
                    429:        auth = apr_table_get(f->r->headers_in, "Authorization");
                    430:        php_handle_auth_data(auth TSRMLS_CC);
                    431: 
                    432:        if (SG(request_info).auth_user == NULL && f->r->user) {
                    433:                SG(request_info).auth_user = estrdup(f->r->user);
1.1       misho     434:        }
1.1.1.2   misho     435: 
                    436:        ctx->r->user = apr_pstrdup(ctx->r->pool, SG(request_info).auth_user);
                    437: 
1.1       misho     438:        php_request_startup(TSRMLS_C);
                    439: }
                    440: 
                    441: static void php_apache_request_dtor(ap_filter_t *f TSRMLS_DC)
                    442: {
                    443:        php_apr_bucket_brigade *pbb = (php_apr_bucket_brigade *)f->ctx;
                    444:        
                    445:        php_request_shutdown(NULL);
                    446: 
                    447:        if (SG(request_info).query_string) {
                    448:                free(SG(request_info).query_string);
                    449:        }
                    450:        if (SG(request_info).request_uri) {
                    451:                free(SG(request_info).request_uri);
                    452:        }
                    453:        if (SG(request_info).path_translated) {
                    454:                free(SG(request_info).path_translated);
                    455:        }
                    456:        
                    457:        apr_brigade_destroy(pbb->bb);
                    458: }
                    459: 
                    460: static int php_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
                    461: {
                    462:        php_struct *ctx;
                    463:        void *conf = ap_get_module_config(f->r->per_dir_config, &php5_module);
                    464:        char *p = get_php_config(conf, "engine", sizeof("engine"));
                    465:        zend_file_handle zfd;
                    466:        php_apr_bucket_brigade *pbb;
                    467:        apr_bucket *b;
                    468:        TSRMLS_FETCH();
                    469:        
                    470:        if (f->r->proxyreq) {
                    471:                zend_try {
                    472:                        zend_ini_deactivate(TSRMLS_C);
                    473:                } zend_end_try();
                    474:                return ap_pass_brigade(f->next, bb);
                    475:        }
                    476:        
                    477:        /* handle situations where user turns the engine off */
                    478:        if (*p == '0') {
                    479:                zend_try {
                    480:                        zend_ini_deactivate(TSRMLS_C);
                    481:                } zend_end_try();
                    482:                return ap_pass_brigade(f->next, bb);
                    483:        }       
                    484:        
                    485:        if(f->ctx) {
                    486:                pbb = (php_apr_bucket_brigade *)f->ctx;
                    487:        } else {
                    488:                pbb = f->ctx = apr_palloc(f->r->pool, sizeof(*pbb));
                    489:                pbb->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
                    490:        }
                    491: 
                    492:        if(ap_save_brigade(NULL, &pbb->bb, &bb, f->r->pool) != APR_SUCCESS) {
                    493:                /* Bad */
                    494:        }
                    495:        
                    496:        apr_brigade_cleanup(bb);
                    497:        
                    498:        /* Check to see if the last bucket in this brigade, it not
                    499:         * we have to wait until then. */
                    500:        if(!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(pbb->bb))) {
                    501:                return 0;
                    502:        }       
                    503:        
                    504:        /* Setup the CGI variables if this is the main request.. */
                    505:        if (f->r->main == NULL || 
                    506:                /* .. or if the sub-request envinronment differs from the main-request. */
                    507:                f->r->subprocess_env != f->r->main->subprocess_env
                    508:        ) {
                    509:                /* setup standard CGI variables */
                    510:                ap_add_common_vars(f->r);
                    511:                ap_add_cgi_vars(f->r);
                    512:        }
                    513:        
                    514:        ctx = SG(server_context);
                    515:        if (ctx == NULL) {
                    516:                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
                    517:                                         "php failed to get server context");
                    518:                zend_try {
                    519:                        zend_ini_deactivate(TSRMLS_C);
                    520:                } zend_end_try();
                    521:         return HTTP_INTERNAL_SERVER_ERROR;
                    522:        }
                    523:        
                    524:        ctx->f = f->next; /* save whatever filters are after us in the chain. */
                    525: 
                    526:        if (ctx->request_processed) {
                    527:                zend_try {
                    528:                        zend_ini_deactivate(TSRMLS_C);
                    529:                } zend_end_try();
                    530:                return ap_pass_brigade(f->next, bb);
                    531:        }
                    532: 
                    533:        apply_config(conf);
                    534:        php_apache_request_ctor(f, ctx TSRMLS_CC);
                    535:        
                    536:        /* It'd be nice if we could highlight based of a zend_file_handle here....
                    537:         * ...but we can't. */
                    538:        
                    539:        zfd.type = ZEND_HANDLE_STREAM;
                    540:        
                    541:        zfd.handle.stream.handle = pbb;
                    542:        zfd.handle.stream.reader = php_apache_read_stream;
                    543:        zfd.handle.stream.closer = NULL;
                    544:        zfd.handle.stream.fsizer = php_apache_fsizer_stream;
                    545:        zfd.handle.stream.isatty = 0;
                    546:        
                    547:        zfd.filename = f->r->filename;
                    548:        zfd.opened_path = NULL;
                    549:        zfd.free_filename = 0;
                    550:        
                    551:        php_execute_script(&zfd TSRMLS_CC);
                    552: 
                    553:        apr_table_set(ctx->r->notes, "mod_php_memory_usage",
                    554:                apr_psprintf(ctx->r->pool, "%u", zend_memory_peak_usage(1 TSRMLS_CC)));
                    555:                
                    556:        php_apache_request_dtor(f TSRMLS_CC);
                    557:                
                    558:        if (!f->r->main) {
                    559:                ctx->request_processed = 1;
                    560:        }
                    561:        
                    562:        b = apr_bucket_eos_create(f->c->bucket_alloc);
                    563:        APR_BRIGADE_INSERT_TAIL(pbb->bb,  b);
                    564:        
                    565:        /* Pass whatever is left on the brigade. */
                    566:        return ap_pass_brigade(f->next, pbb->bb);
                    567: }
                    568: 
                    569: static apr_status_t
                    570: php_apache_server_shutdown(void *tmp)
                    571: {
                    572:        apache2_sapi_module.shutdown(&apache2_sapi_module);
                    573:        sapi_shutdown();
                    574: #ifdef ZTS
                    575:        tsrm_shutdown();
                    576: #endif
                    577:        return APR_SUCCESS;
                    578: }
                    579: 
                    580: static void php_apache_add_version(apr_pool_t *p)
                    581: {
                    582:        TSRMLS_FETCH();
                    583:        if (PG(expose_php)) {
                    584:                ap_add_version_component(p, "PHP/" PHP_VERSION);
                    585:        }
                    586: }
                    587: 
                    588: static int php_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
                    589: {
                    590: #ifndef ZTS
                    591:        int threaded_mpm;
                    592: 
                    593:        ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded_mpm);
                    594:        if(threaded_mpm) {
                    595:                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.");
                    596:                return DONE;
                    597:        }
                    598: #endif
                    599:     /* When this is NULL, apache won't override the hard-coded default
                    600:      * php.ini path setting. */
                    601:     apache2_php_ini_path_override = NULL;
                    602:     return OK;
                    603: }
                    604: 
                    605: static int
                    606: php_apache_server_startup(apr_pool_t *pconf, apr_pool_t *plog,
                    607:                           apr_pool_t *ptemp, server_rec *s)
                    608: {
                    609:        void *data = NULL;
                    610:        const char *userdata_key = "apache2filter_post_config";
                    611: 
                    612:        /* Apache will load, unload and then reload a DSO module. This
                    613:         * prevents us from starting PHP until the second load. */
                    614:        apr_pool_userdata_get(&data, userdata_key, s->process->pool);
                    615:        if (data == NULL) {
                    616:                /* We must use set() here and *not* setn(), otherwise the
                    617:                 * static string pointed to by userdata_key will be mapped
                    618:                 * to a different location when the DSO is reloaded and the
                    619:                 * pointers won't match, causing get() to return NULL when
                    620:                 * we expected it to return non-NULL. */
                    621:                apr_pool_userdata_set((const void *)1, userdata_key,
                    622:                                                          apr_pool_cleanup_null, s->process->pool);
                    623:                return OK;
                    624:        }
                    625: 
                    626:        /* Set up our overridden path. */
                    627:        if (apache2_php_ini_path_override) {
                    628:                apache2_sapi_module.php_ini_path_override = apache2_php_ini_path_override;
                    629:        }
                    630: #ifdef ZTS
                    631:        tsrm_startup(1, 1, 0, NULL);
                    632: #endif
                    633:        sapi_startup(&apache2_sapi_module);
                    634:        apache2_sapi_module.startup(&apache2_sapi_module);
                    635:        apr_pool_cleanup_register(pconf, NULL, php_apache_server_shutdown, apr_pool_cleanup_null);
                    636:        php_apache_add_version(pconf);
                    637: 
                    638:        return OK;
                    639: }
                    640: 
                    641: static void php_add_filter(request_rec *r, ap_filter_t *f)
                    642: {
                    643:        int output = (f == r->output_filters);
                    644: 
                    645:        /* for those who still have Set*Filter PHP configured */
                    646:        while (f) {
                    647:                if (strcmp(f->frec->name, "PHP") == 0) {
                    648:                        ap_log_error(APLOG_MARK, APLOG_WARNING,
                    649:                                     0, r->server,
                    650:                                     "\"Set%sFilter PHP\" already configured for %s",
                    651:                                     output ? "Output" : "Input", r->uri);
                    652:                        return;
                    653:                }
                    654:                f = f->next;
                    655:        }
                    656: 
                    657:        if (output) {
                    658:                ap_add_output_filter("PHP", NULL, r, r->connection);
                    659:        } else {
                    660:                ap_add_input_filter("PHP", NULL, r, r->connection);
                    661:        }
                    662: }
                    663: 
                    664: static void php_insert_filter(request_rec *r)
                    665: {
                    666:        int content_type_len = strlen("application/x-httpd-php");
                    667: 
                    668:        if (r->content_type && !strncmp(r->content_type, "application/x-httpd-php", content_type_len-1)) {
                    669:                if (r->content_type[content_type_len] == '\0' || !strncmp(r->content_type+content_type_len, "-source", sizeof("-source"))) { 
                    670:                        php_add_filter(r, r->output_filters);
                    671:                        php_add_filter(r, r->input_filters);
                    672:                }       
                    673:        }
                    674: }
                    675: 
                    676: static apr_status_t php_server_context_cleanup(void *data_)
                    677: {
                    678:        void **data = data_;
                    679:        *data = NULL;
                    680:        return APR_SUCCESS;
                    681: }
                    682: 
                    683: static int php_post_read_request(request_rec *r)
                    684: {
                    685:        php_struct *ctx;
                    686:        TSRMLS_FETCH();
                    687: 
                    688:        /* Initialize filter context */
                    689:        SG(server_context) = ctx = apr_pcalloc(r->pool, sizeof(*ctx));
                    690: 
                    691:        /* register a cleanup so we clear out the SG(server_context)
                    692:         * after each request. Note: We pass in the pointer to the
                    693:         * server_context in case this is handled by a different thread. */
                    694:        apr_pool_cleanup_register(r->pool, (void *)&SG(server_context),
                    695:                                                          php_server_context_cleanup,
                    696:                                                          apr_pool_cleanup_null);
                    697: 
                    698:        /* Save the entire request, so we can get the input or output
                    699:         * filters if we need them. */
                    700:        ctx->r = r;
                    701: 
                    702:        return OK;
                    703: }
                    704: 
                    705: static void php_register_hook(apr_pool_t *p)
                    706: {
                    707:        ap_hook_pre_config(php_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
                    708:        ap_hook_post_config(php_apache_server_startup, NULL, NULL, APR_HOOK_MIDDLE);
                    709:        ap_hook_insert_filter(php_insert_filter, NULL, NULL, APR_HOOK_MIDDLE);
                    710:        ap_hook_post_read_request(php_post_read_request, NULL, NULL, APR_HOOK_MIDDLE);
                    711:        ap_register_output_filter("PHP", php_output_filter, php_apache_disable_caching, AP_FTYPE_RESOURCE);
                    712:        ap_register_input_filter("PHP", php_input_filter, php_apache_disable_caching, AP_FTYPE_RESOURCE);
                    713: }
                    714: 
                    715: static size_t php_apache_read_stream(void *handle, char *buf, size_t wantlen TSRMLS_DC)
                    716: {
                    717:        php_apr_bucket_brigade *pbb = (php_apr_bucket_brigade *)handle;
                    718:        apr_bucket_brigade *rbb;
                    719:        apr_size_t readlen;
                    720:        apr_bucket *b = NULL;
                    721:        
                    722:        rbb = pbb->bb;
                    723:        
                    724:        if((apr_brigade_partition(pbb->bb, wantlen, &b) == APR_SUCCESS) && b){
                    725:                pbb->bb = apr_brigade_split(rbb, b);
                    726:        }       
                    727: 
                    728:        readlen = wantlen;
                    729:        apr_brigade_flatten(rbb, buf, &readlen);
                    730:        apr_brigade_cleanup(rbb);
                    731:        
                    732:        return readlen;
                    733: }
                    734: 
                    735: static size_t php_apache_fsizer_stream(void *handle TSRMLS_DC)
                    736: {
                    737:        php_apr_bucket_brigade *pbb = (php_apr_bucket_brigade *)handle;
                    738:        apr_off_t actual = 0;
                    739: 
                    740:        if (apr_brigade_length(pbb->bb, 1, &actual) == APR_SUCCESS) {
                    741:                return actual;
                    742:        }
                    743: 
                    744:        return 0;
                    745: }
                    746: 
                    747: AP_MODULE_DECLARE_DATA module php5_module = {
                    748:        STANDARD20_MODULE_STUFF,
                    749:        create_php_config,              /* create per-directory config structure */
                    750:        merge_php_config,               /* merge per-directory config structures */
                    751:        NULL,                                   /* create per-server config structure */
                    752:        NULL,                                   /* merge per-server config structures */
                    753:        php_dir_cmds,                   /* command apr_table_t */
                    754:        php_register_hook               /* register hooks */
                    755: };
                    756: 
                    757: /*
                    758:  * Local variables:
                    759:  * tab-width: 4
                    760:  * c-basic-offset: 4
                    761:  * End:
                    762:  * vim600: sw=4 ts=4 fdm=marker
                    763:  * vim<600: sw=4 ts=4
                    764:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>