Annotation of embedaddon/php/sapi/tux/php_tux.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.2 ! 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:    | Author: Sascha Schumann <sascha@schumann.cx>                         |
                     16:    +----------------------------------------------------------------------+
                     17: */
                     18: 
                     19: #include "php.h"
                     20: #include "SAPI.h"
                     21: #include "php_main.h"
                     22: #include "php_variables.h"
                     23: 
                     24: #include "ext/standard/php_smart_str.h"
                     25: 
                     26: #include "tuxmodule.h"
                     27: 
                     28: #include <sys/uio.h>
                     29: 
                     30: #if 0
                     31: #include <pthread.h>
                     32: #endif
                     33: 
                     34: void tux_closed_conn(int fd);
                     35: 
                     36: enum {
                     37:        PHP_TUX_BACKGROUND_CONN = 1
                     38: };
                     39: 
                     40: typedef struct {
                     41:        user_req_t *req;
                     42:        void (*on_close)(int);
                     43:        int tux_action;
                     44:        struct iovec *header_vec;
                     45:        int number_vec;
                     46: } php_tux_globals;
                     47: 
                     48: static php_tux_globals tux_globals;
                     49: 
                     50: #define TG(v) (tux_globals.v)
                     51: 
                     52: static int sapi_tux_ub_write(const char *str, uint str_length TSRMLS_DC)
                     53: {
                     54:        int n;
                     55:        int m;
                     56:        const char *estr;
                     57:        
                     58:        /* combine headers and body */
                     59:        if (TG(number_vec)) {
                     60:                struct iovec *vec = TG(header_vec);
                     61:                
                     62:                n = TG(number_vec);
                     63:                vec[n].iov_base = (void *) str;
                     64:                vec[n++].iov_len = str_length;
                     65:                
                     66:                /* XXX: this might need more complete error handling */
                     67:                if ((m = writev(TG(req)->sock, vec, n)) == -1 && errno == EPIPE)
                     68:                        php_handle_aborted_connection();
                     69: 
                     70:                if (m > 0)
                     71:                        TG(req)->bytes_sent += str_length;
                     72: 
                     73:                TG(number_vec) = 0;
                     74:                return str_length;
                     75:        }
                     76: 
                     77:        estr = str + str_length;
                     78:        
                     79:        while (str < estr) {
                     80:                n = send(TG(req)->sock, str, estr - str, 0);
                     81: 
                     82:                if (n == -1 && errno == EPIPE)
                     83:                        php_handle_aborted_connection();
                     84:                if (n == -1 && errno == EAGAIN)
                     85:                        continue;
                     86:                if (n <= 0) 
                     87:                        return n;
                     88: 
                     89:                str += n;
                     90:        }
                     91: 
                     92:        n = str_length - (estr - str);
                     93:        
                     94:        TG(req)->bytes_sent += n;
                     95: 
                     96:        return n;
                     97: }
                     98: 
                     99: static int sapi_tux_send_headers(sapi_headers_struct *sapi_headers)
                    100: {
                    101:        char buf[1024];
                    102:        struct iovec *vec;
                    103:        int n;
                    104:        int max_headers;
                    105:        zend_llist_position pos;
                    106:        sapi_header_struct *h;
                    107:        size_t len;
                    108:        char *status_line;
                    109:        int locate_cl;
                    110:        TSRMLS_FETCH();
                    111:        
                    112:        max_headers = 30;
                    113:        n = 1;
                    114:        
                    115:        vec = malloc(sizeof(struct iovec) * max_headers);
                    116:        status_line = malloc(30);
                    117:        
                    118:        /* safe sprintf use */
                    119:        len = slprintf(status_line, 30, "HTTP/1.1 %d NA\r\n", SG(sapi_headers).http_response_code);
                    120:        
                    121:        vec[0].iov_base = status_line;
                    122:        vec[0].iov_len = len;
                    123:        
                    124:        TG(req)->http_status = SG(sapi_headers).http_response_code;
                    125: 
                    126:        if (TG(tux_action) == TUX_ACTION_FINISH_CLOSE_REQ && TG(req)->http_version == HTTP_1_1)
                    127:                locate_cl = 1;
                    128:        else
                    129:                locate_cl = 0;
                    130:        
                    131:        h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
                    132:        while (h) {
                    133:                if (locate_cl 
                    134:                                && strncasecmp(h->header, "Content-length:", sizeof("Content-length:")-1) == 0) {
                    135:                        TG(tux_action) = TUX_ACTION_FINISH_REQ;
                    136:                        locate_cl = 0;
                    137:                }
                    138:                        
                    139:                vec[n].iov_base = h->header;
                    140:                vec[n++].iov_len = h->header_len;
                    141:                if (n >= max_headers - 3) {
                    142:                        max_headers *= 2;
                    143:                        vec = realloc(vec, sizeof(struct iovec) * max_headers);
                    144:                }
                    145:                vec[n].iov_base = "\r\n";
                    146:                vec[n++].iov_len = 2;
                    147:                
                    148:                h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
                    149:        }
                    150: 
                    151:        vec[n].iov_base = "\r\n";
                    152:        vec[n++].iov_len = 2;
                    153: 
                    154:        TG(number_vec) = n;
                    155:        TG(header_vec) = vec;
                    156: 
                    157:        
                    158:        return SAPI_HEADER_SENT_SUCCESSFULLY;
                    159: }
                    160: 
                    161: static int sapi_tux_read_post(char *buffer, uint count_bytes)
                    162: {
                    163: #if 0
                    164:        int amount = 0;
                    165:        TSRMLS_FETCH();
                    166: 
                    167:        TG(req)->objectlen = count_bytes;
                    168:        TG(req)->object_addr = buffer;
                    169:        if (tux(TUX_ACTION_READ_POST_DATA, TG(req)))
                    170:                return 0;
                    171: 
                    172:        TG(read_post_data) = 1;
                    173:        
                    174:        return TG(req)->objectlen;
                    175: #else
                    176:        return 0;
                    177: #endif
                    178: }
                    179: 
                    180: static char *sapi_tux_read_cookies(void)
                    181: {
                    182:        TSRMLS_FETCH();
                    183:        
                    184:        return TG(req)->cookies;
                    185: }
                    186: 
                    187: #define BUF_SIZE 512
                    188: #define ADD_STRING(name)                                                                               \
                    189:        php_register_variable(name, buf, track_vars_array TSRMLS_CC)
                    190: 
                    191: static void sapi_tux_register_variables(zval *track_vars_array TSRMLS_DC)
                    192: {
                    193:        char buf[BUF_SIZE + 1];
                    194:        char *p;
                    195:        sapi_header_line ctr = {0};
                    196:        
                    197:        ctr.line = buf;
                    198:        ctr.line_len = slprintf(buf, sizeof(buf), "Server: %s", TUXAPI_version);
                    199:        sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
                    200:        
                    201:        php_register_variable("PHP_SELF", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
                    202:        php_register_variable("SERVER_SOFTWARE", TUXAPI_version, track_vars_array TSRMLS_CC);
                    203:        php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
                    204:        php_register_variable("REQUEST_METHOD", (char *) SG(request_info).request_method, track_vars_array TSRMLS_CC);
                    205:        php_register_variable("DOCUMENT_ROOT", TUXAPI_docroot, track_vars_array TSRMLS_CC);
                    206:        php_register_variable("SERVER_NAME", TUXAPI_servername, track_vars_array TSRMLS_CC);
                    207:        php_register_variable("REQUEST_URI", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
                    208:        php_register_variable("PATH_TRANSLATED", SG(request_info).path_translated, track_vars_array TSRMLS_CC);
                    209: 
                    210:        p = inet_ntoa(TG(req)->client_host);
                    211:        /* string representation of IPs are never larger than 512 bytes */
                    212:        if (p) {
                    213:                memcpy(buf, p, strlen(p) + 1);
                    214:                ADD_STRING("REMOTE_ADDR");
                    215:                ADD_STRING("REMOTE_HOST");
                    216:        }
                    217: 
                    218:        snprintf(buf, sizeof(buf), "%d", CGI_SERVER_PORT(TG(req)));
                    219:        ADD_STRING("SERVER_PORT");
                    220: 
                    221: #if 0
                    222:        snprintf(buf, BUF_SIZE, "/%s", TG(hc)->pathinfo);
                    223:        ADD_STRING("PATH_INFO");
                    224: 
                    225:        snprintf(buf, BUF_SIZE, "/%s", TG(hc)->origfilename);
                    226:        ADD_STRING("SCRIPT_NAME");
                    227: #endif
                    228: 
                    229: #define CONDADD(name, field)                                                   \
                    230:        if (TG(req)->field[0]) {                                                                \
                    231:                php_register_variable(#name, TG(req)->field, track_vars_array TSRMLS_CC); \
                    232:        }
                    233: 
                    234:        CONDADD(HTTP_REFERER, referer);
                    235:        CONDADD(HTTP_USER_AGENT, user_agent);
                    236:        CONDADD(HTTP_ACCEPT, accept);
                    237:        CONDADD(HTTP_ACCEPT_ENCODING, accept_encoding);
                    238:        CONDADD(HTTP_ACCEPT_LANGUAGE, accept_language);
                    239:        CONDADD(HTTP_COOKIE, cookies);
                    240:        CONDADD(CONTENT_TYPE, content_type);
                    241: 
                    242: #if 0
                    243:        if (TG(hc)->contentlength != -1) {
                    244:                snprintf(buf, sizeof(buf), "%ld", (long) TG(hc)->contentlength);
                    245:                ADD_STRING("CONTENT_LENGTH");
                    246:        }
                    247: #endif
                    248: 
                    249: #if 0
                    250:        if (TG(hc)->authorization[0])
                    251:                php_register_variable("AUTH_TYPE", "Basic", track_vars_array TSRMLS_CC);
                    252: #endif
                    253: }
                    254: 
                    255: 
                    256: static int php_tux_startup(sapi_module_struct *sapi_module)
                    257: {
                    258:        if (php_module_startup(sapi_module, NULL, 0)==FAILURE) {
                    259:                return FAILURE;
                    260:        } else {
                    261:                return SUCCESS;
                    262:        }
                    263: }
                    264: 
                    265: static sapi_module_struct tux_sapi_module = {
                    266:        "tux",
                    267:        "tux",
                    268:        
                    269:        php_tux_startup,
                    270:        php_module_shutdown_wrapper,
                    271:        
                    272:        NULL,                                                                   /* activate */
                    273:        NULL,                                                                   /* deactivate */
                    274: 
                    275:        sapi_tux_ub_write,
                    276:        NULL,
                    277:        NULL,                                                                   /* get uid */
                    278:        NULL,                                                                   /* getenv */
                    279: 
                    280:        php_error,
                    281:        
                    282:        NULL,
                    283:        sapi_tux_send_headers,
                    284:        NULL,
                    285:        sapi_tux_read_post,
                    286:        sapi_tux_read_cookies,
                    287: 
                    288:        sapi_tux_register_variables,
                    289:        NULL,                                                                   /* Log message */
                    290:        NULL,                                                                   /* Get request time */
                    291:        NULL,                                                                   /* Child terminate */
                    292: 
                    293:        STANDARD_SAPI_MODULE_PROPERTIES
                    294: };
                    295: 
                    296: static void tux_module_main(TSRMLS_D)
                    297: {
                    298:        zend_file_handle file_handle;
                    299: 
                    300:        file_handle.type = ZEND_HANDLE_FILENAME;
                    301:        file_handle.filename = SG(request_info).path_translated;
                    302:        file_handle.free_filename = 0;
                    303:        file_handle.opened_path = NULL;
                    304: 
                    305:        if (php_request_startup(TSRMLS_C) == FAILURE) {
                    306:                return;
                    307:        }
                    308:        
                    309:        php_execute_script(&file_handle TSRMLS_CC);
                    310:        php_request_shutdown(NULL);
                    311: }
                    312: 
                    313: static void tux_request_ctor(TSRMLS_D)
                    314: {
                    315:        char buf[1024];
                    316:        int offset;
                    317:        size_t filename_len;
                    318:        size_t cwd_len;
                    319:        smart_str s = {0};
                    320:        char *p;
                    321: 
                    322:        TG(number_vec) = 0;     
                    323:        TG(header_vec) = NULL;
                    324:        SG(request_info).query_string = strdup(TG(req)->query);
                    325: 
                    326:        smart_str_appends_ex(&s, "/", 1);
                    327:        smart_str_appends_ex(&s, TG(req)->query, 1);
                    328:        smart_str_0(&s);
                    329:        p = strchr(s.c, '&');
                    330:        if (p)
                    331:                *p = '\0';
                    332:        SG(request_info).path_translated = s.c;
                    333:        
                    334:        s.c = NULL;
                    335:        smart_str_appendc_ex(&s, '/', 1);
                    336:        smart_str_appends_ex(&s, TG(req)->objectname, 1);
                    337:        smart_str_0(&s);
                    338:        SG(request_info).request_uri = s.c;
                    339:        SG(request_info).request_method = CGI_REQUEST_METHOD(TG(req));
                    340:        if(TG(req)->http_version == HTTP_1_1) SG(request_info).proto_num = 1001;
                    341:        else SG(request_info).proto_num = 1000;
                    342:        SG(sapi_headers).http_response_code = 200;
                    343:        SG(request_info).content_type = TG(req)->content_type;
                    344:        SG(request_info).content_length = 0; /* TG(req)->contentlength; */
                    345: 
                    346: #if 0
                    347:        php_handle_auth_data(TG(hc)->authorization TSRMLS_CC);
                    348: #endif
                    349: }
                    350: 
                    351: static void tux_request_dtor(TSRMLS_D)
                    352: {
                    353:        if (TG(header_vec)) {
                    354:                /* free status_line */
                    355:                free(TG(header_vec)[0].iov_base);
                    356:                free(TG(header_vec));
                    357:        }
                    358:        if (SG(request_info).query_string)
                    359:                free(SG(request_info).query_string);
                    360:        free(SG(request_info).request_uri);
                    361:        free(SG(request_info).path_translated);
                    362: }
                    363: 
                    364: #if 0
                    365: static void *separate_thread(void *bla)
                    366: {
                    367:        int fd;
                    368:        int i = 0;
                    369:        
                    370:        fd = (int) bla;
                    371: 
                    372:        while (i++ < 5) {
                    373:                send(fd, "test<br />\n", 9, 0);
                    374:                sleep(1);
                    375:        }
                    376:        
                    377:        tux(TUX_ACTION_CONTINUE_REQ, (user_req_t *) fd);
                    378:        /* We HAVE to trigger some event on the fd. Otherwise
                    379:           fast_thread won't wake up, so that the eventloop
                    380:           won't be entered -> TUX hangs */
                    381:        shutdown(fd, 2);
                    382:        pthread_exit(NULL);
                    383: }
                    384: #endif
                    385: 
                    386: int TUXAPI_handle_events(user_req_t *req)
                    387: {
                    388:        TSRMLS_FETCH();
                    389: 
                    390:        if (req->event == PHP_TUX_BACKGROUND_CONN) {
                    391:                tux_closed_conn(req->sock);
                    392:                return tux(TUX_ACTION_FINISH_CLOSE_REQ, req);
                    393:        }
                    394:        
                    395:        TG(req) = req;
                    396:        TG(tux_action) = TUX_ACTION_FINISH_CLOSE_REQ;
                    397:        
                    398:        tux_request_ctor(TSRMLS_C);
                    399: 
                    400:        tux_module_main(TSRMLS_C);
                    401: 
                    402:        tux_request_dtor(TSRMLS_C);
                    403: 
                    404:        return tux(TG(tux_action), req);
                    405: }
                    406: 
                    407: void tux_register_on_close(void (*arg)(int)) 
                    408: {
                    409:        TG(on_close) = arg;
                    410: }
                    411: 
                    412: void tux_closed_conn(int fd)
                    413: {
                    414:        TSRMLS_FETCH();
                    415: 
                    416:        if (TG(on_close)) TG(on_close)(fd);
                    417: }
                    418: 
                    419: int tux_get_fd(void)
                    420: {
                    421:        TSRMLS_FETCH();
                    422:        
                    423:        return TG(req)->sock;
                    424: }
                    425: 
                    426: void tux_set_dont_close(void)
                    427: {
                    428:        TSRMLS_FETCH();
                    429: 
                    430:        TG(req)->event = PHP_TUX_BACKGROUND_CONN;
                    431:        tux(TUX_ACTION_POSTPONE_REQ, TG(req));
                    432:        TG(tux_action) = TUX_ACTION_EVENTLOOP;
                    433: }
                    434: 
                    435: void TUXAPI_init(void)
                    436: {
                    437:        sapi_startup(&tux_sapi_module);
                    438:        tux_sapi_module.startup(&tux_sapi_module);
                    439:        SG(server_context) = (void *) 1;
                    440: }
                    441: 
                    442: void doesnotmatter_fini(void)
                    443: {
                    444:        if (SG(server_context) != NULL) {
                    445:                tux_sapi_module.shutdown(&tux_sapi_module);
                    446:                sapi_shutdown();
                    447:        }
                    448: }
                    449: 
                    450: /*
                    451:  * Local variables:
                    452:  * tab-width: 4
                    453:  * c-basic-offset: 4
                    454:  * End:
                    455:  * vim600: sw=4 ts=4 fdm=marker
                    456:  * vim<600: sw=4 ts=4
                    457:  */

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