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

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

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