Back to index

php5  5.3.10
php_tux.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Sascha Schumann <sascha@schumann.cx>                         |
00016    +----------------------------------------------------------------------+
00017 */
00018 
00019 #include "php.h"
00020 #include "SAPI.h"
00021 #include "php_main.h"
00022 #include "php_variables.h"
00023 
00024 #include "ext/standard/php_smart_str.h"
00025 
00026 #include "tuxmodule.h"
00027 
00028 #include <sys/uio.h>
00029 
00030 #if 0
00031 #include <pthread.h>
00032 #endif
00033 
00034 void tux_closed_conn(int fd);
00035 
00036 enum {
00037        PHP_TUX_BACKGROUND_CONN = 1
00038 };
00039 
00040 typedef struct {
00041        user_req_t *req;
00042        void (*on_close)(int);
00043        int tux_action;
00044        struct iovec *header_vec;
00045        int number_vec;
00046 } php_tux_globals;
00047 
00048 static php_tux_globals tux_globals;
00049 
00050 #define TG(v) (tux_globals.v)
00051 
00052 static int sapi_tux_ub_write(const char *str, uint str_length TSRMLS_DC)
00053 {
00054        int n;
00055        int m;
00056        const char *estr;
00057        
00058        /* combine headers and body */
00059        if (TG(number_vec)) {
00060               struct iovec *vec = TG(header_vec);
00061               
00062               n = TG(number_vec);
00063               vec[n].iov_base = (void *) str;
00064               vec[n++].iov_len = str_length;
00065               
00066               /* XXX: this might need more complete error handling */
00067               if ((m = writev(TG(req)->sock, vec, n)) == -1 && errno == EPIPE)
00068                      php_handle_aborted_connection();
00069 
00070               if (m > 0)
00071                      TG(req)->bytes_sent += str_length;
00072 
00073               TG(number_vec) = 0;
00074               return str_length;
00075        }
00076 
00077        estr = str + str_length;
00078        
00079        while (str < estr) {
00080               n = send(TG(req)->sock, str, estr - str, 0);
00081 
00082               if (n == -1 && errno == EPIPE)
00083                      php_handle_aborted_connection();
00084               if (n == -1 && errno == EAGAIN)
00085                      continue;
00086               if (n <= 0) 
00087                      return n;
00088 
00089               str += n;
00090        }
00091 
00092        n = str_length - (estr - str);
00093        
00094        TG(req)->bytes_sent += n;
00095 
00096        return n;
00097 }
00098 
00099 static int sapi_tux_send_headers(sapi_headers_struct *sapi_headers)
00100 {
00101        char buf[1024];
00102        struct iovec *vec;
00103        int n;
00104        int max_headers;
00105        zend_llist_position pos;
00106        sapi_header_struct *h;
00107        size_t len;
00108        char *status_line;
00109        int locate_cl;
00110        TSRMLS_FETCH();
00111        
00112        max_headers = 30;
00113        n = 1;
00114        
00115        vec = malloc(sizeof(struct iovec) * max_headers);
00116        status_line = malloc(30);
00117        
00118        /* safe sprintf use */
00119        len = slprintf(status_line, 30, "HTTP/1.1 %d NA\r\n", SG(sapi_headers).http_response_code);
00120        
00121        vec[0].iov_base = status_line;
00122        vec[0].iov_len = len;
00123        
00124        TG(req)->http_status = SG(sapi_headers).http_response_code;
00125 
00126        if (TG(tux_action) == TUX_ACTION_FINISH_CLOSE_REQ && TG(req)->http_version == HTTP_1_1)
00127               locate_cl = 1;
00128        else
00129               locate_cl = 0;
00130        
00131        h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
00132        while (h) {
00133               if (locate_cl 
00134                             && strncasecmp(h->header, "Content-length:", sizeof("Content-length:")-1) == 0) {
00135                      TG(tux_action) = TUX_ACTION_FINISH_REQ;
00136                      locate_cl = 0;
00137               }
00138                      
00139               vec[n].iov_base = h->header;
00140               vec[n++].iov_len = h->header_len;
00141               if (n >= max_headers - 3) {
00142                      max_headers *= 2;
00143                      vec = realloc(vec, sizeof(struct iovec) * max_headers);
00144               }
00145               vec[n].iov_base = "\r\n";
00146               vec[n++].iov_len = 2;
00147               
00148               h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
00149        }
00150 
00151        vec[n].iov_base = "\r\n";
00152        vec[n++].iov_len = 2;
00153 
00154        TG(number_vec) = n;
00155        TG(header_vec) = vec;
00156 
00157        
00158        return SAPI_HEADER_SENT_SUCCESSFULLY;
00159 }
00160 
00161 static int sapi_tux_read_post(char *buffer, uint count_bytes)
00162 {
00163 #if 0
00164        int amount = 0;
00165        TSRMLS_FETCH();
00166 
00167        TG(req)->objectlen = count_bytes;
00168        TG(req)->object_addr = buffer;
00169        if (tux(TUX_ACTION_READ_POST_DATA, TG(req)))
00170               return 0;
00171 
00172        TG(read_post_data) = 1;
00173        
00174        return TG(req)->objectlen;
00175 #else
00176        return 0;
00177 #endif
00178 }
00179 
00180 static char *sapi_tux_read_cookies(void)
00181 {
00182        TSRMLS_FETCH();
00183        
00184        return TG(req)->cookies;
00185 }
00186 
00187 #define BUF_SIZE 512
00188 #define ADD_STRING(name)                                                                   \
00189        php_register_variable(name, buf, track_vars_array TSRMLS_CC)
00190 
00191 static void sapi_tux_register_variables(zval *track_vars_array TSRMLS_DC)
00192 {
00193        char buf[BUF_SIZE + 1];
00194        char *p;
00195        sapi_header_line ctr = {0};
00196        
00197        ctr.line = buf;
00198        ctr.line_len = slprintf(buf, sizeof(buf), "Server: %s", TUXAPI_version);
00199        sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
00200        
00201        php_register_variable("PHP_SELF", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
00202        php_register_variable("SERVER_SOFTWARE", TUXAPI_version, track_vars_array TSRMLS_CC);
00203        php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
00204        php_register_variable("REQUEST_METHOD", (char *) SG(request_info).request_method, track_vars_array TSRMLS_CC);
00205        php_register_variable("DOCUMENT_ROOT", TUXAPI_docroot, track_vars_array TSRMLS_CC);
00206        php_register_variable("SERVER_NAME", TUXAPI_servername, track_vars_array TSRMLS_CC);
00207        php_register_variable("REQUEST_URI", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
00208        php_register_variable("PATH_TRANSLATED", SG(request_info).path_translated, track_vars_array TSRMLS_CC);
00209 
00210        p = inet_ntoa(TG(req)->client_host);
00211        /* string representation of IPs are never larger than 512 bytes */
00212        if (p) {
00213               memcpy(buf, p, strlen(p) + 1);
00214               ADD_STRING("REMOTE_ADDR");
00215               ADD_STRING("REMOTE_HOST");
00216        }
00217 
00218        snprintf(buf, sizeof(buf), "%d", CGI_SERVER_PORT(TG(req)));
00219        ADD_STRING("SERVER_PORT");
00220 
00221 #if 0
00222        snprintf(buf, BUF_SIZE, "/%s", TG(hc)->pathinfo);
00223        ADD_STRING("PATH_INFO");
00224 
00225        snprintf(buf, BUF_SIZE, "/%s", TG(hc)->origfilename);
00226        ADD_STRING("SCRIPT_NAME");
00227 #endif
00228 
00229 #define CONDADD(name, field)                                                 \
00230        if (TG(req)->field[0]) {                                                     \
00231               php_register_variable(#name, TG(req)->field, track_vars_array TSRMLS_CC); \
00232        }
00233 
00234        CONDADD(HTTP_REFERER, referer);
00235        CONDADD(HTTP_USER_AGENT, user_agent);
00236        CONDADD(HTTP_ACCEPT, accept);
00237        CONDADD(HTTP_ACCEPT_ENCODING, accept_encoding);
00238        CONDADD(HTTP_ACCEPT_LANGUAGE, accept_language);
00239        CONDADD(HTTP_COOKIE, cookies);
00240        CONDADD(CONTENT_TYPE, content_type);
00241 
00242 #if 0
00243        if (TG(hc)->contentlength != -1) {
00244               snprintf(buf, sizeof(buf), "%ld", (long) TG(hc)->contentlength);
00245               ADD_STRING("CONTENT_LENGTH");
00246        }
00247 #endif
00248 
00249 #if 0
00250        if (TG(hc)->authorization[0])
00251               php_register_variable("AUTH_TYPE", "Basic", track_vars_array TSRMLS_CC);
00252 #endif
00253 }
00254 
00255 
00256 static int php_tux_startup(sapi_module_struct *sapi_module)
00257 {
00258        if (php_module_startup(sapi_module, NULL, 0)==FAILURE) {
00259               return FAILURE;
00260        } else {
00261               return SUCCESS;
00262        }
00263 }
00264 
00265 static sapi_module_struct tux_sapi_module = {
00266        "tux",
00267        "tux",
00268        
00269        php_tux_startup,
00270        php_module_shutdown_wrapper,
00271        
00272        NULL,                                                          /* activate */
00273        NULL,                                                          /* deactivate */
00274 
00275        sapi_tux_ub_write,
00276        NULL,
00277        NULL,                                                          /* get uid */
00278        NULL,                                                          /* getenv */
00279 
00280        php_error,
00281        
00282        NULL,
00283        sapi_tux_send_headers,
00284        NULL,
00285        sapi_tux_read_post,
00286        sapi_tux_read_cookies,
00287 
00288        sapi_tux_register_variables,
00289        NULL,                                                          /* Log message */
00290        NULL,                                                          /* Get request time */
00291        NULL,                                                          /* Child terminate */
00292 
00293        STANDARD_SAPI_MODULE_PROPERTIES
00294 };
00295 
00296 static void tux_module_main(TSRMLS_D)
00297 {
00298        zend_file_handle file_handle;
00299 
00300        file_handle.type = ZEND_HANDLE_FILENAME;
00301        file_handle.filename = SG(request_info).path_translated;
00302        file_handle.free_filename = 0;
00303        file_handle.opened_path = NULL;
00304 
00305        if (php_request_startup(TSRMLS_C) == FAILURE) {
00306               return;
00307        }
00308        
00309        php_execute_script(&file_handle TSRMLS_CC);
00310        php_request_shutdown(NULL);
00311 }
00312 
00313 static void tux_request_ctor(TSRMLS_D)
00314 {
00315        char buf[1024];
00316        int offset;
00317        size_t filename_len;
00318        size_t cwd_len;
00319        smart_str s = {0};
00320        char *p;
00321 
00322        TG(number_vec) = 0;  
00323        TG(header_vec) = NULL;
00324        SG(request_info).query_string = strdup(TG(req)->query);
00325 
00326        smart_str_appends_ex(&s, "/", 1);
00327        smart_str_appends_ex(&s, TG(req)->query, 1);
00328        smart_str_0(&s);
00329        p = strchr(s.c, '&');
00330        if (p)
00331               *p = '\0';
00332        SG(request_info).path_translated = s.c;
00333        
00334        s.c = NULL;
00335        smart_str_appendc_ex(&s, '/', 1);
00336        smart_str_appends_ex(&s, TG(req)->objectname, 1);
00337        smart_str_0(&s);
00338        SG(request_info).request_uri = s.c;
00339        SG(request_info).request_method = CGI_REQUEST_METHOD(TG(req));
00340        if(TG(req)->http_version == HTTP_1_1) SG(request_info).proto_num = 1001;
00341        else SG(request_info).proto_num = 1000;
00342        SG(sapi_headers).http_response_code = 200;
00343        SG(request_info).content_type = TG(req)->content_type;
00344        SG(request_info).content_length = 0; /* TG(req)->contentlength; */
00345 
00346 #if 0
00347        php_handle_auth_data(TG(hc)->authorization TSRMLS_CC);
00348 #endif
00349 }
00350 
00351 static void tux_request_dtor(TSRMLS_D)
00352 {
00353        if (TG(header_vec)) {
00354               /* free status_line */
00355               free(TG(header_vec)[0].iov_base);
00356               free(TG(header_vec));
00357        }
00358        if (SG(request_info).query_string)
00359               free(SG(request_info).query_string);
00360        free(SG(request_info).request_uri);
00361        free(SG(request_info).path_translated);
00362 }
00363 
00364 #if 0
00365 static void *separate_thread(void *bla)
00366 {
00367        int fd;
00368        int i = 0;
00369        
00370        fd = (int) bla;
00371 
00372        while (i++ < 5) {
00373               send(fd, "test<br />\n", 9, 0);
00374               sleep(1);
00375        }
00376        
00377        tux(TUX_ACTION_CONTINUE_REQ, (user_req_t *) fd);
00378        /* We HAVE to trigger some event on the fd. Otherwise
00379           fast_thread won't wake up, so that the eventloop
00380           won't be entered -> TUX hangs */
00381        shutdown(fd, 2);
00382        pthread_exit(NULL);
00383 }
00384 #endif
00385 
00386 int TUXAPI_handle_events(user_req_t *req)
00387 {
00388        TSRMLS_FETCH();
00389 
00390        if (req->event == PHP_TUX_BACKGROUND_CONN) {
00391               tux_closed_conn(req->sock);
00392               return tux(TUX_ACTION_FINISH_CLOSE_REQ, req);
00393        }
00394        
00395        TG(req) = req;
00396        TG(tux_action) = TUX_ACTION_FINISH_CLOSE_REQ;
00397        
00398        tux_request_ctor(TSRMLS_C);
00399 
00400        tux_module_main(TSRMLS_C);
00401 
00402        tux_request_dtor(TSRMLS_C);
00403 
00404        return tux(TG(tux_action), req);
00405 }
00406 
00407 void tux_register_on_close(void (*arg)(int)) 
00408 {
00409        TG(on_close) = arg;
00410 }
00411 
00412 void tux_closed_conn(int fd)
00413 {
00414        TSRMLS_FETCH();
00415 
00416        if (TG(on_close)) TG(on_close)(fd);
00417 }
00418 
00419 int tux_get_fd(void)
00420 {
00421        TSRMLS_FETCH();
00422        
00423        return TG(req)->sock;
00424 }
00425 
00426 void tux_set_dont_close(void)
00427 {
00428        TSRMLS_FETCH();
00429 
00430        TG(req)->event = PHP_TUX_BACKGROUND_CONN;
00431        tux(TUX_ACTION_POSTPONE_REQ, TG(req));
00432        TG(tux_action) = TUX_ACTION_EVENTLOOP;
00433 }
00434 
00435 void TUXAPI_init(void)
00436 {
00437        sapi_startup(&tux_sapi_module);
00438        tux_sapi_module.startup(&tux_sapi_module);
00439        SG(server_context) = (void *) 1;
00440 }
00441 
00442 void doesnotmatter_fini(void)
00443 {
00444        if (SG(server_context) != NULL) {
00445               tux_sapi_module.shutdown(&tux_sapi_module);
00446               sapi_shutdown();
00447        }
00448 }
00449 
00450 /*
00451  * Local variables:
00452  * tab-width: 4
00453  * c-basic-offset: 4
00454  * End:
00455  * vim600: sw=4 ts=4 fdm=marker
00456  * vim<600: sw=4 ts=4
00457  */