10Sigor@sysoev.ru 20Sigor@sysoev.ru /* 386Smax.romanov@nginx.com * Copyright (C) Max Romanov 40Sigor@sysoev.ru * Copyright (C) Valentin V. Bartenev 50Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 60Sigor@sysoev.ru */ 70Sigor@sysoev.ru 80Sigor@sysoev.ru #include "php.h" 90Sigor@sysoev.ru #include "SAPI.h" 100Sigor@sysoev.ru #include "php_main.h" 110Sigor@sysoev.ru #include "php_variables.h" 120Sigor@sysoev.ru 130Sigor@sysoev.ru #include <nxt_main.h> 14446Sigor@sysoev.ru #include <nxt_router.h> 150Sigor@sysoev.ru 160Sigor@sysoev.ru 17142Smax.romanov@nginx.com static nxt_int_t nxt_php_init(nxt_task_t *task, nxt_common_app_conf_t *conf); 180Sigor@sysoev.ru 1986Smax.romanov@nginx.com static nxt_int_t nxt_php_run(nxt_task_t *task, 2086Smax.romanov@nginx.com nxt_app_rmsg_t *rmsg, nxt_app_wmsg_t *wmsg); 210Sigor@sysoev.ru 2286Smax.romanov@nginx.com #if PHP_MAJOR_VERSION >= 7 2386Smax.romanov@nginx.com # define NXT_PHP7 1 2486Smax.romanov@nginx.com # if PHP_MINOR_VERSION >= 1 2586Smax.romanov@nginx.com # define NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE 1 2686Smax.romanov@nginx.com # else 2786Smax.romanov@nginx.com # define NXT_HAVE_PHP_INTERRUPTS 1 2886Smax.romanov@nginx.com # endif 2986Smax.romanov@nginx.com # define NXT_HAVE_PHP_IGNORE_CWD 1 3086Smax.romanov@nginx.com #else 3186Smax.romanov@nginx.com # define NXT_HAVE_PHP_INTERRUPTS 1 3286Smax.romanov@nginx.com # if PHP_MINOR_VERSION >= 4 3386Smax.romanov@nginx.com # define NXT_HAVE_PHP_IGNORE_CWD 1 3486Smax.romanov@nginx.com # endif 3586Smax.romanov@nginx.com #endif 360Sigor@sysoev.ru 370Sigor@sysoev.ru static int nxt_php_startup(sapi_module_struct *sapi_module); 380Sigor@sysoev.ru static int nxt_php_send_headers(sapi_headers_struct *sapi_headers); 390Sigor@sysoev.ru static char *nxt_php_read_cookies(void); 400Sigor@sysoev.ru static void nxt_php_register_variables(zval *track_vars_array); 4186Smax.romanov@nginx.com static void nxt_php_log_message(char *message 4286Smax.romanov@nginx.com #ifdef NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE 4386Smax.romanov@nginx.com , int syslog_type_int 4486Smax.romanov@nginx.com #endif 4586Smax.romanov@nginx.com ); 460Sigor@sysoev.ru 470Sigor@sysoev.ru #ifdef NXT_PHP7 480Sigor@sysoev.ru static size_t nxt_php_unbuffered_write(const char *str, 490Sigor@sysoev.ru size_t str_length TSRMLS_DC); 500Sigor@sysoev.ru static size_t nxt_php_read_post(char *buffer, size_t count_bytes TSRMLS_DC); 510Sigor@sysoev.ru #else 520Sigor@sysoev.ru static int nxt_php_unbuffered_write(const char *str, uint str_length TSRMLS_DC); 530Sigor@sysoev.ru static int nxt_php_read_post(char *buffer, uint count_bytes TSRMLS_DC); 540Sigor@sysoev.ru #endif 550Sigor@sysoev.ru 56114Smax.romanov@nginx.com static void nxt_php_flush(void *server_context); 57114Smax.romanov@nginx.com 580Sigor@sysoev.ru 590Sigor@sysoev.ru static sapi_module_struct nxt_php_sapi_module = 600Sigor@sysoev.ru { 610Sigor@sysoev.ru (char *) "cli-server", 62259Sigor@sysoev.ru (char *) "unit", 630Sigor@sysoev.ru 640Sigor@sysoev.ru nxt_php_startup, /* startup */ 650Sigor@sysoev.ru php_module_shutdown_wrapper, /* shutdown */ 660Sigor@sysoev.ru 670Sigor@sysoev.ru NULL, /* activate */ 680Sigor@sysoev.ru NULL, /* deactivate */ 690Sigor@sysoev.ru 700Sigor@sysoev.ru nxt_php_unbuffered_write, /* unbuffered write */ 71114Smax.romanov@nginx.com nxt_php_flush, /* flush */ 720Sigor@sysoev.ru NULL, /* get uid */ 730Sigor@sysoev.ru NULL, /* getenv */ 740Sigor@sysoev.ru 750Sigor@sysoev.ru php_error, /* error handler */ 760Sigor@sysoev.ru 770Sigor@sysoev.ru NULL, /* header handler */ 780Sigor@sysoev.ru nxt_php_send_headers, /* send headers handler */ 790Sigor@sysoev.ru NULL, /* send header handler */ 800Sigor@sysoev.ru 810Sigor@sysoev.ru nxt_php_read_post, /* read POST data */ 820Sigor@sysoev.ru nxt_php_read_cookies, /* read Cookies */ 830Sigor@sysoev.ru 840Sigor@sysoev.ru nxt_php_register_variables, /* register server variables */ 850Sigor@sysoev.ru nxt_php_log_message, /* log message */ 8686Smax.romanov@nginx.com NULL, /* get request time */ 8786Smax.romanov@nginx.com NULL, /* terminate process */ 880Sigor@sysoev.ru 8986Smax.romanov@nginx.com NULL, /* php_ini_path_override */ 9086Smax.romanov@nginx.com #ifdef NXT_HAVE_PHP_INTERRUPTS 9186Smax.romanov@nginx.com NULL, /* block_interruptions */ 9286Smax.romanov@nginx.com NULL, /* unblock_interruptions */ 9386Smax.romanov@nginx.com #endif 9486Smax.romanov@nginx.com NULL, /* default_post_reader */ 9586Smax.romanov@nginx.com NULL, /* treat_data */ 9686Smax.romanov@nginx.com NULL, /* executable_location */ 9786Smax.romanov@nginx.com 9886Smax.romanov@nginx.com 0, /* php_ini_ignore */ 9986Smax.romanov@nginx.com #ifdef NXT_HAVE_PHP_IGNORE_CWD 10086Smax.romanov@nginx.com 0, /* php_ini_ignore_cwd */ 10186Smax.romanov@nginx.com #endif 10286Smax.romanov@nginx.com NULL, /* get_fd */ 10386Smax.romanov@nginx.com 10486Smax.romanov@nginx.com NULL, /* force_http_10 */ 10586Smax.romanov@nginx.com 10686Smax.romanov@nginx.com NULL, /* get_target_uid */ 10786Smax.romanov@nginx.com NULL, /* get_target_gid */ 10886Smax.romanov@nginx.com 10986Smax.romanov@nginx.com NULL, /* input_filter */ 11086Smax.romanov@nginx.com 11186Smax.romanov@nginx.com NULL, /* ini_defaults */ 11286Smax.romanov@nginx.com 0, /* phpinfo_as_text */ 11386Smax.romanov@nginx.com 11486Smax.romanov@nginx.com NULL, /* ini_entries */ 11586Smax.romanov@nginx.com NULL, /* additional_functions */ 11686Smax.romanov@nginx.com NULL /* input_filter_init */ 1170Sigor@sysoev.ru }; 1180Sigor@sysoev.ru 11986Smax.romanov@nginx.com typedef struct { 12086Smax.romanov@nginx.com nxt_task_t *task; 12186Smax.romanov@nginx.com nxt_app_rmsg_t *rmsg; 12286Smax.romanov@nginx.com nxt_app_request_t r; 12386Smax.romanov@nginx.com nxt_str_t script; 12486Smax.romanov@nginx.com nxt_app_wmsg_t *wmsg; 125206Smax.romanov@nginx.com 126206Smax.romanov@nginx.com size_t body_preread_size; 12786Smax.romanov@nginx.com } nxt_php_run_ctx_t; 12886Smax.romanov@nginx.com 12986Smax.romanov@nginx.com nxt_inline nxt_int_t nxt_php_write(nxt_php_run_ctx_t *ctx, 13086Smax.romanov@nginx.com const u_char *data, size_t len, 13186Smax.romanov@nginx.com nxt_bool_t flush, nxt_bool_t last); 13286Smax.romanov@nginx.com 1330Sigor@sysoev.ru 1340Sigor@sysoev.ru static nxt_str_t nxt_php_path; 1350Sigor@sysoev.ru static nxt_str_t nxt_php_root; 1360Sigor@sysoev.ru static nxt_str_t nxt_php_script; 137142Smax.romanov@nginx.com static nxt_str_t nxt_php_index = nxt_string("index.php"); 138142Smax.romanov@nginx.com 139142Smax.romanov@nginx.com 140142Smax.romanov@nginx.com static void 141142Smax.romanov@nginx.com nxt_php_str_trim_trail(nxt_str_t *str, u_char t) 142142Smax.romanov@nginx.com { 143142Smax.romanov@nginx.com while (str->length > 0 && str->start[str->length - 1] == t) { 144142Smax.romanov@nginx.com str->length--; 145142Smax.romanov@nginx.com } 146142Smax.romanov@nginx.com 147142Smax.romanov@nginx.com str->start[str->length] = '\0'; 148142Smax.romanov@nginx.com } 149142Smax.romanov@nginx.com 150142Smax.romanov@nginx.com 151142Smax.romanov@nginx.com static void 152142Smax.romanov@nginx.com nxt_php_str_trim_lead(nxt_str_t *str, u_char t) 153142Smax.romanov@nginx.com { 154142Smax.romanov@nginx.com while (str->length > 0 && str->start[0] == t) { 155142Smax.romanov@nginx.com str->length--; 156142Smax.romanov@nginx.com str->start++; 157142Smax.romanov@nginx.com } 158142Smax.romanov@nginx.com } 1590Sigor@sysoev.ru 160258Sigor@sysoev.ru static uint32_t compat[] = { 161360Sigor@sysoev.ru NXT_VERNUM, NXT_DEBUG, 162258Sigor@sysoev.ru }; 163258Sigor@sysoev.ru 1640Sigor@sysoev.ru 165216Sigor@sysoev.ru NXT_EXPORT nxt_application_module_t nxt_app_module = { 166258Sigor@sysoev.ru sizeof(compat), 167258Sigor@sysoev.ru compat, 168216Sigor@sysoev.ru nxt_string("php"), 169216Sigor@sysoev.ru nxt_string(PHP_VERSION), 17086Smax.romanov@nginx.com nxt_php_init, 171216Sigor@sysoev.ru nxt_php_run, 172421Smax.romanov@nginx.com NULL, 17386Smax.romanov@nginx.com }; 1740Sigor@sysoev.ru 1750Sigor@sysoev.ru 176*462Smax.romanov@nginx.com nxt_inline u_char * 177*462Smax.romanov@nginx.com nxt_realpath(const void *c) 178*462Smax.romanov@nginx.com { 179*462Smax.romanov@nginx.com return (u_char *) realpath(c, NULL); 180*462Smax.romanov@nginx.com } 181*462Smax.romanov@nginx.com 182*462Smax.romanov@nginx.com 18386Smax.romanov@nginx.com static nxt_int_t 184142Smax.romanov@nginx.com nxt_php_init(nxt_task_t *task, nxt_common_app_conf_t *conf) 1850Sigor@sysoev.ru { 186*462Smax.romanov@nginx.com u_char *p; 187*462Smax.romanov@nginx.com nxt_str_t rpath; 188142Smax.romanov@nginx.com nxt_str_t *root, *path, *script, *index; 189142Smax.romanov@nginx.com nxt_php_app_conf_t *c; 190142Smax.romanov@nginx.com 191142Smax.romanov@nginx.com c = &conf->u.php; 192142Smax.romanov@nginx.com 193*462Smax.romanov@nginx.com if (c->root == NULL) { 194142Smax.romanov@nginx.com nxt_log_emerg(task->log, "php root is empty"); 195142Smax.romanov@nginx.com return NXT_ERROR; 196142Smax.romanov@nginx.com } 197142Smax.romanov@nginx.com 198142Smax.romanov@nginx.com root = &nxt_php_root; 199142Smax.romanov@nginx.com path = &nxt_php_path; 200142Smax.romanov@nginx.com script = &nxt_php_script; 201142Smax.romanov@nginx.com index = &nxt_php_index; 202142Smax.romanov@nginx.com 203*462Smax.romanov@nginx.com root->start = nxt_realpath(c->root); 204*462Smax.romanov@nginx.com if (nxt_slow_path(root->start == NULL)) { 205*462Smax.romanov@nginx.com nxt_log_emerg(task->log, "root realpath(%s) failed %E", 206*462Smax.romanov@nginx.com c->root, nxt_errno); 207*462Smax.romanov@nginx.com return NXT_ERROR; 208*462Smax.romanov@nginx.com } 209*462Smax.romanov@nginx.com 210*462Smax.romanov@nginx.com root->length = nxt_strlen(root->start); 211142Smax.romanov@nginx.com 212142Smax.romanov@nginx.com nxt_php_str_trim_trail(root, '/'); 213142Smax.romanov@nginx.com 214142Smax.romanov@nginx.com if (c->script.length > 0) { 215142Smax.romanov@nginx.com nxt_php_str_trim_lead(&c->script, '/'); 216142Smax.romanov@nginx.com 217*462Smax.romanov@nginx.com path->length = root->length + 1 + c->script.length; 218*462Smax.romanov@nginx.com path->start = nxt_malloc(path->length); 219*462Smax.romanov@nginx.com if (nxt_slow_path(path->start == NULL)) { 220*462Smax.romanov@nginx.com return NXT_ERROR; 221*462Smax.romanov@nginx.com } 222142Smax.romanov@nginx.com 223*462Smax.romanov@nginx.com p = nxt_cpymem(path->start, root->start, root->length); 224*462Smax.romanov@nginx.com *p++ = '/'; 225*462Smax.romanov@nginx.com 226*462Smax.romanov@nginx.com nxt_memcpy(p, c->script.start, c->script.length); 227142Smax.romanov@nginx.com 228*462Smax.romanov@nginx.com rpath.start = nxt_realpath(path->start); 229*462Smax.romanov@nginx.com if (nxt_slow_path(rpath.start == NULL)) { 230*462Smax.romanov@nginx.com nxt_log_emerg(task->log, "script realpath(%V) failed %E", 231*462Smax.romanov@nginx.com path, nxt_errno); 232*462Smax.romanov@nginx.com return NXT_ERROR; 233*462Smax.romanov@nginx.com } 234*462Smax.romanov@nginx.com 235*462Smax.romanov@nginx.com rpath.length = nxt_strlen(rpath.start); 236142Smax.romanov@nginx.com 237*462Smax.romanov@nginx.com if (!nxt_str_start(&rpath, root->start, root->length)) { 238*462Smax.romanov@nginx.com nxt_log_emerg(task->log, "script is not under php root"); 239*462Smax.romanov@nginx.com return NXT_ERROR; 240*462Smax.romanov@nginx.com } 241142Smax.romanov@nginx.com 242*462Smax.romanov@nginx.com nxt_free(path->start); 243*462Smax.romanov@nginx.com 244*462Smax.romanov@nginx.com *path = rpath; 245142Smax.romanov@nginx.com 246142Smax.romanov@nginx.com script->length = c->script.length + 1; 247*462Smax.romanov@nginx.com script->start = nxt_malloc(script->length); 248*462Smax.romanov@nginx.com if (nxt_slow_path(script->start == NULL)) { 249*462Smax.romanov@nginx.com return NXT_ERROR; 250*462Smax.romanov@nginx.com } 251*462Smax.romanov@nginx.com 252142Smax.romanov@nginx.com script->start[0] = '/'; 253142Smax.romanov@nginx.com nxt_memcpy(script->start + 1, c->script.start, c->script.length); 254142Smax.romanov@nginx.com 255142Smax.romanov@nginx.com nxt_log_error(NXT_LOG_INFO, task->log, 256142Smax.romanov@nginx.com "(ABS_MODE) php script \"%V\" root: \"%V\"", 257142Smax.romanov@nginx.com script, root); 258277Sigor@sysoev.ru 259142Smax.romanov@nginx.com } else { 260142Smax.romanov@nginx.com nxt_log_error(NXT_LOG_INFO, task->log, 261142Smax.romanov@nginx.com "(non ABS_MODE) php root: \"%V\"", root); 262142Smax.romanov@nginx.com } 263142Smax.romanov@nginx.com 264142Smax.romanov@nginx.com if (c->index.length > 0) { 265*462Smax.romanov@nginx.com index->length = c->index.length; 266*462Smax.romanov@nginx.com index->start = nxt_malloc(index->length); 267*462Smax.romanov@nginx.com if (nxt_slow_path(index->start == NULL)) { 268*462Smax.romanov@nginx.com return NXT_ERROR; 269*462Smax.romanov@nginx.com } 270*462Smax.romanov@nginx.com 271*462Smax.romanov@nginx.com nxt_memcpy(index->start, c->index.start, c->index.length); 272142Smax.romanov@nginx.com } 273142Smax.romanov@nginx.com 274142Smax.romanov@nginx.com sapi_startup(&nxt_php_sapi_module); 275142Smax.romanov@nginx.com nxt_php_startup(&nxt_php_sapi_module); 276142Smax.romanov@nginx.com 2770Sigor@sysoev.ru return NXT_OK; 2780Sigor@sysoev.ru } 2790Sigor@sysoev.ru 2800Sigor@sysoev.ru 28186Smax.romanov@nginx.com static nxt_int_t 28286Smax.romanov@nginx.com nxt_php_read_request(nxt_task_t *task, nxt_app_rmsg_t *rmsg, 28386Smax.romanov@nginx.com nxt_php_run_ctx_t *ctx) 2840Sigor@sysoev.ru { 28586Smax.romanov@nginx.com u_char *p; 28686Smax.romanov@nginx.com size_t s; 287114Smax.romanov@nginx.com nxt_int_t rc; 28894Smax.romanov@nginx.com nxt_str_t script_name; 28986Smax.romanov@nginx.com nxt_app_request_header_t *h; 2900Sigor@sysoev.ru 29186Smax.romanov@nginx.com h = &ctx->r.header; 2920Sigor@sysoev.ru 293114Smax.romanov@nginx.com #define RC(S) \ 294114Smax.romanov@nginx.com do { \ 295114Smax.romanov@nginx.com rc = (S); \ 296114Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { \ 297114Smax.romanov@nginx.com goto fail; \ 298114Smax.romanov@nginx.com } \ 299114Smax.romanov@nginx.com } while(0) 3000Sigor@sysoev.ru 301114Smax.romanov@nginx.com #define NXT_READ(dst) \ 302114Smax.romanov@nginx.com RC(nxt_app_msg_read_str(task, rmsg, (dst))) 303114Smax.romanov@nginx.com 304114Smax.romanov@nginx.com NXT_READ(&h->method); 305114Smax.romanov@nginx.com NXT_READ(&h->target); 306114Smax.romanov@nginx.com NXT_READ(&h->path); 307114Smax.romanov@nginx.com 308114Smax.romanov@nginx.com RC(nxt_app_msg_read_size(task, rmsg, &s)); 30986Smax.romanov@nginx.com if (s > 0) { 31086Smax.romanov@nginx.com s--; 311112Smax.romanov@nginx.com h->query.start = h->target.start + s; 312112Smax.romanov@nginx.com h->query.length = h->target.length - s; 3130Sigor@sysoev.ru 314112Smax.romanov@nginx.com if (h->path.start == NULL) { 315112Smax.romanov@nginx.com h->path.start = h->target.start; 316112Smax.romanov@nginx.com h->path.length = s - 1; 31786Smax.romanov@nginx.com } 3180Sigor@sysoev.ru } 3190Sigor@sysoev.ru 320112Smax.romanov@nginx.com if (h->path.start == NULL) { 321112Smax.romanov@nginx.com h->path = h->target; 322112Smax.romanov@nginx.com } 323112Smax.romanov@nginx.com 32486Smax.romanov@nginx.com if (nxt_php_path.start == NULL) { 325112Smax.romanov@nginx.com if (h->path.start[h->path.length - 1] == '/') { 326142Smax.romanov@nginx.com script_name = nxt_php_index; 327277Sigor@sysoev.ru 32894Smax.romanov@nginx.com } else { 32994Smax.romanov@nginx.com script_name.length = 0; 33094Smax.romanov@nginx.com } 33194Smax.romanov@nginx.com 332112Smax.romanov@nginx.com ctx->script.length = nxt_php_root.length + h->path.length + 33394Smax.romanov@nginx.com script_name.length; 334*462Smax.romanov@nginx.com p = ctx->script.start = nxt_malloc(ctx->script.length); 335*462Smax.romanov@nginx.com if (nxt_slow_path(p == NULL)) { 336*462Smax.romanov@nginx.com return NXT_ERROR; 337*462Smax.romanov@nginx.com } 33886Smax.romanov@nginx.com 339*462Smax.romanov@nginx.com p = nxt_cpymem(p, nxt_php_root.start, nxt_php_root.length); 340*462Smax.romanov@nginx.com p = nxt_cpymem(p, h->path.start, h->path.length); 34194Smax.romanov@nginx.com 34294Smax.romanov@nginx.com if (script_name.length > 0) { 34394Smax.romanov@nginx.com nxt_memcpy(p, script_name.start, script_name.length); 34494Smax.romanov@nginx.com } 34594Smax.romanov@nginx.com 34686Smax.romanov@nginx.com } else { 34786Smax.romanov@nginx.com ctx->script = nxt_php_path; 34886Smax.romanov@nginx.com } 34986Smax.romanov@nginx.com 350114Smax.romanov@nginx.com NXT_READ(&h->version); 351114Smax.romanov@nginx.com 352114Smax.romanov@nginx.com NXT_READ(&ctx->r.remote); 353268Sigor@sysoev.ru NXT_READ(&ctx->r.local); 35486Smax.romanov@nginx.com 355114Smax.romanov@nginx.com NXT_READ(&h->host); 356114Smax.romanov@nginx.com NXT_READ(&h->cookie); 357114Smax.romanov@nginx.com NXT_READ(&h->content_type); 358114Smax.romanov@nginx.com NXT_READ(&h->content_length); 35986Smax.romanov@nginx.com 360114Smax.romanov@nginx.com RC(nxt_app_msg_read_size(task, rmsg, &s)); 36186Smax.romanov@nginx.com h->parsed_content_length = s; 36286Smax.romanov@nginx.com 363305Smax.romanov@nginx.com RC(nxt_app_msg_read_size(task, ctx->rmsg, &ctx->body_preread_size)); 364305Smax.romanov@nginx.com 365114Smax.romanov@nginx.com #undef NXT_READ 366114Smax.romanov@nginx.com #undef RC 36794Smax.romanov@nginx.com 36886Smax.romanov@nginx.com /* Further headers read moved to nxt_php_register_variables. */ 3690Sigor@sysoev.ru return NXT_OK; 370114Smax.romanov@nginx.com 371114Smax.romanov@nginx.com fail: 372114Smax.romanov@nginx.com 373114Smax.romanov@nginx.com return rc; 3740Sigor@sysoev.ru } 3750Sigor@sysoev.ru 3760Sigor@sysoev.ru 37786Smax.romanov@nginx.com static nxt_int_t 37886Smax.romanov@nginx.com nxt_php_run(nxt_task_t *task, 37986Smax.romanov@nginx.com nxt_app_rmsg_t *rmsg, nxt_app_wmsg_t *wmsg) 3800Sigor@sysoev.ru { 381114Smax.romanov@nginx.com nxt_int_t rc; 38286Smax.romanov@nginx.com zend_file_handle file_handle; 38386Smax.romanov@nginx.com nxt_php_run_ctx_t run_ctx; 38486Smax.romanov@nginx.com nxt_app_request_header_t *h; 3850Sigor@sysoev.ru 38686Smax.romanov@nginx.com nxt_memzero(&run_ctx, sizeof(run_ctx)); 38786Smax.romanov@nginx.com 38886Smax.romanov@nginx.com run_ctx.task = task; 38986Smax.romanov@nginx.com run_ctx.rmsg = rmsg; 39086Smax.romanov@nginx.com run_ctx.wmsg = wmsg; 39186Smax.romanov@nginx.com 39286Smax.romanov@nginx.com h = &run_ctx.r.header; 39386Smax.romanov@nginx.com 394114Smax.romanov@nginx.com rc = nxt_php_read_request(task, rmsg, &run_ctx); 395114Smax.romanov@nginx.com 396114Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 397114Smax.romanov@nginx.com goto fail; 398114Smax.romanov@nginx.com } 39986Smax.romanov@nginx.com 40086Smax.romanov@nginx.com SG(server_context) = &run_ctx; 401112Smax.romanov@nginx.com SG(request_info).request_uri = (char *) h->target.start; 40286Smax.romanov@nginx.com SG(request_info).request_method = (char *) h->method.start; 4030Sigor@sysoev.ru 4040Sigor@sysoev.ru SG(request_info).proto_num = 1001; 4050Sigor@sysoev.ru 40686Smax.romanov@nginx.com SG(request_info).query_string = (char *) h->query.start; 40786Smax.romanov@nginx.com SG(request_info).content_length = h->parsed_content_length; 4080Sigor@sysoev.ru 40986Smax.romanov@nginx.com if (h->content_type.start != NULL) { 41086Smax.romanov@nginx.com SG(request_info).content_type = (char *) h->content_type.start; 4110Sigor@sysoev.ru } 4120Sigor@sysoev.ru 4130Sigor@sysoev.ru SG(sapi_headers).http_response_code = 200; 4140Sigor@sysoev.ru 4150Sigor@sysoev.ru SG(request_info).path_translated = NULL; 4160Sigor@sysoev.ru 4170Sigor@sysoev.ru file_handle.type = ZEND_HANDLE_FILENAME; 41886Smax.romanov@nginx.com file_handle.filename = (char *) run_ctx.script.start; 4190Sigor@sysoev.ru file_handle.free_filename = 0; 4200Sigor@sysoev.ru file_handle.opened_path = NULL; 4210Sigor@sysoev.ru 422142Smax.romanov@nginx.com nxt_debug(task, "handle.filename = '%s'", run_ctx.script.start); 423142Smax.romanov@nginx.com 42486Smax.romanov@nginx.com if (nxt_php_path.start != NULL) { 42586Smax.romanov@nginx.com nxt_debug(task, "run script %V in absolute mode", &nxt_php_path); 426277Sigor@sysoev.ru 42786Smax.romanov@nginx.com } else { 42886Smax.romanov@nginx.com nxt_debug(task, "run script %V", &run_ctx.script); 42986Smax.romanov@nginx.com } 4300Sigor@sysoev.ru 4310Sigor@sysoev.ru if (nxt_slow_path(php_request_startup() == FAILURE)) { 432142Smax.romanov@nginx.com nxt_debug(task, "php_request_startup() failed"); 433*462Smax.romanov@nginx.com rc = NXT_ERROR; 43486Smax.romanov@nginx.com goto fail; 4350Sigor@sysoev.ru } 4360Sigor@sysoev.ru 4370Sigor@sysoev.ru php_execute_script(&file_handle TSRMLS_CC); 4380Sigor@sysoev.ru php_request_shutdown(NULL); 4390Sigor@sysoev.ru 44086Smax.romanov@nginx.com nxt_app_msg_flush(task, wmsg, 1); 44186Smax.romanov@nginx.com 442*462Smax.romanov@nginx.com rc = NXT_OK; 44386Smax.romanov@nginx.com 44486Smax.romanov@nginx.com fail: 44586Smax.romanov@nginx.com 446*462Smax.romanov@nginx.com if (run_ctx.script.start != nxt_php_path.start) { 447*462Smax.romanov@nginx.com nxt_free(run_ctx.script.start); 448*462Smax.romanov@nginx.com } 44986Smax.romanov@nginx.com 450*462Smax.romanov@nginx.com return rc; 45186Smax.romanov@nginx.com } 45286Smax.romanov@nginx.com 45386Smax.romanov@nginx.com 45486Smax.romanov@nginx.com nxt_inline nxt_int_t 45586Smax.romanov@nginx.com nxt_php_write(nxt_php_run_ctx_t *ctx, const u_char *data, size_t len, 45686Smax.romanov@nginx.com nxt_bool_t flush, nxt_bool_t last) 45786Smax.romanov@nginx.com { 45886Smax.romanov@nginx.com nxt_int_t rc; 45986Smax.romanov@nginx.com 460114Smax.romanov@nginx.com if (len > 0) { 461114Smax.romanov@nginx.com rc = nxt_app_msg_write_raw(ctx->task, ctx->wmsg, data, len); 462277Sigor@sysoev.ru 463114Smax.romanov@nginx.com } else { 464114Smax.romanov@nginx.com rc = NXT_OK; 465114Smax.romanov@nginx.com } 46686Smax.romanov@nginx.com 46786Smax.romanov@nginx.com if (flush || last) { 46886Smax.romanov@nginx.com rc = nxt_app_msg_flush(ctx->task, ctx->wmsg, last); 46986Smax.romanov@nginx.com } 47086Smax.romanov@nginx.com 47186Smax.romanov@nginx.com return rc; 4720Sigor@sysoev.ru } 4730Sigor@sysoev.ru 4740Sigor@sysoev.ru 4750Sigor@sysoev.ru static int 4760Sigor@sysoev.ru nxt_php_startup(sapi_module_struct *sapi_module) 4770Sigor@sysoev.ru { 4780Sigor@sysoev.ru return php_module_startup(sapi_module, NULL, 0); 4790Sigor@sysoev.ru } 4800Sigor@sysoev.ru 4810Sigor@sysoev.ru 4820Sigor@sysoev.ru #ifdef NXT_PHP7 4830Sigor@sysoev.ru static size_t 4840Sigor@sysoev.ru nxt_php_unbuffered_write(const char *str, size_t str_length TSRMLS_DC) 4850Sigor@sysoev.ru #else 4860Sigor@sysoev.ru static int 4870Sigor@sysoev.ru nxt_php_unbuffered_write(const char *str, uint str_length TSRMLS_DC) 4880Sigor@sysoev.ru #endif 4890Sigor@sysoev.ru { 490114Smax.romanov@nginx.com nxt_int_t rc; 49186Smax.romanov@nginx.com nxt_php_run_ctx_t *ctx; 4920Sigor@sysoev.ru 49386Smax.romanov@nginx.com ctx = SG(server_context); 4940Sigor@sysoev.ru 495114Smax.romanov@nginx.com rc = nxt_php_write(ctx, (u_char *) str, str_length, 1, 0); 496114Smax.romanov@nginx.com 497114Smax.romanov@nginx.com if (nxt_fast_path(rc == NXT_OK)) { 498114Smax.romanov@nginx.com return str_length; 499114Smax.romanov@nginx.com } 5000Sigor@sysoev.ru 501114Smax.romanov@nginx.com // TODO handle NXT_AGAIN 502114Smax.romanov@nginx.com php_handle_aborted_connection(); 503114Smax.romanov@nginx.com return 0; 504114Smax.romanov@nginx.com } 505114Smax.romanov@nginx.com 506114Smax.romanov@nginx.com 507114Smax.romanov@nginx.com static void 508114Smax.romanov@nginx.com nxt_php_flush(void *server_context) 509114Smax.romanov@nginx.com { 510114Smax.romanov@nginx.com nxt_php_run_ctx_t *ctx; 511114Smax.romanov@nginx.com 512114Smax.romanov@nginx.com ctx = server_context; 513114Smax.romanov@nginx.com 514114Smax.romanov@nginx.com (void) nxt_app_msg_flush(ctx->task, ctx->wmsg, 0); 5150Sigor@sysoev.ru } 5160Sigor@sysoev.ru 5170Sigor@sysoev.ru 5180Sigor@sysoev.ru static int 5190Sigor@sysoev.ru nxt_php_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) 5200Sigor@sysoev.ru { 5210Sigor@sysoev.ru size_t len; 522114Smax.romanov@nginx.com u_char *status, buf[64]; 523114Smax.romanov@nginx.com nxt_int_t rc; 524114Smax.romanov@nginx.com nxt_php_run_ctx_t *ctx; 5250Sigor@sysoev.ru sapi_header_struct *h; 5260Sigor@sysoev.ru zend_llist_position zpos; 5270Sigor@sysoev.ru 5280Sigor@sysoev.ru static const u_char default_repsonse[] 529431Sigor@sysoev.ru = "Status: 200\r\n" 5300Sigor@sysoev.ru "\r\n"; 5310Sigor@sysoev.ru 532431Sigor@sysoev.ru static const u_char status_200[] = "Status: 200"; 53386Smax.romanov@nginx.com static const u_char cr_lf[] = "\r\n"; 53486Smax.romanov@nginx.com 53586Smax.romanov@nginx.com ctx = SG(server_context); 5360Sigor@sysoev.ru 537114Smax.romanov@nginx.com #define RC(S) \ 538114Smax.romanov@nginx.com do { \ 539114Smax.romanov@nginx.com rc = (S); \ 540114Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { \ 541114Smax.romanov@nginx.com goto fail; \ 542114Smax.romanov@nginx.com } \ 543114Smax.romanov@nginx.com } while(0) 544114Smax.romanov@nginx.com 5450Sigor@sysoev.ru if (SG(request_info).no_headers == 1) { 546114Smax.romanov@nginx.com RC(nxt_php_write(ctx, default_repsonse, sizeof(default_repsonse) - 1, 547114Smax.romanov@nginx.com 1, 0)); 5480Sigor@sysoev.ru return SAPI_HEADER_SENT_SUCCESSFULLY; 5490Sigor@sysoev.ru } 5500Sigor@sysoev.ru 5510Sigor@sysoev.ru if (SG(sapi_headers).http_status_line) { 552114Smax.romanov@nginx.com status = (u_char *) SG(sapi_headers).http_status_line; 5530Sigor@sysoev.ru len = nxt_strlen(status); 5540Sigor@sysoev.ru 555431Sigor@sysoev.ru if (len < 12) { 556431Sigor@sysoev.ru goto fail; 557431Sigor@sysoev.ru } 558431Sigor@sysoev.ru 559431Sigor@sysoev.ru RC(nxt_php_write(ctx, status_200, sizeof(status_200) - 4, 0, 0)); 560431Sigor@sysoev.ru RC(nxt_php_write(ctx, status + 9, 3, 0, 0)); 5610Sigor@sysoev.ru 5620Sigor@sysoev.ru } else if (SG(sapi_headers).http_response_code) { 56386Smax.romanov@nginx.com status = nxt_sprintf(buf, buf + sizeof(buf), "%03d", 5640Sigor@sysoev.ru SG(sapi_headers).http_response_code); 56586Smax.romanov@nginx.com len = status - buf; 56686Smax.romanov@nginx.com 567431Sigor@sysoev.ru RC(nxt_php_write(ctx, status_200, sizeof(status_200) - 4, 0, 0)); 568114Smax.romanov@nginx.com RC(nxt_php_write(ctx, buf, len, 0, 0)); 5690Sigor@sysoev.ru 5700Sigor@sysoev.ru } else { 571431Sigor@sysoev.ru RC(nxt_php_write(ctx, status_200, sizeof(status_200) - 1, 0, 0)); 5720Sigor@sysoev.ru } 5730Sigor@sysoev.ru 574114Smax.romanov@nginx.com RC(nxt_php_write(ctx, cr_lf, sizeof(cr_lf) - 1, 0, 0)); 5750Sigor@sysoev.ru 5760Sigor@sysoev.ru h = zend_llist_get_first_ex(&sapi_headers->headers, &zpos); 5770Sigor@sysoev.ru 5780Sigor@sysoev.ru while (h) { 579114Smax.romanov@nginx.com RC(nxt_php_write(ctx, (u_char *) h->header, h->header_len, 0, 0)); 580114Smax.romanov@nginx.com RC(nxt_php_write(ctx, cr_lf, sizeof(cr_lf) - 1, 0, 0)); 5810Sigor@sysoev.ru 5820Sigor@sysoev.ru h = zend_llist_get_next_ex(&sapi_headers->headers, &zpos); 5830Sigor@sysoev.ru } 5840Sigor@sysoev.ru 585114Smax.romanov@nginx.com RC(nxt_php_write(ctx, cr_lf, sizeof(cr_lf) - 1, 1, 0)); 586114Smax.romanov@nginx.com 587114Smax.romanov@nginx.com #undef RC 5880Sigor@sysoev.ru 5890Sigor@sysoev.ru return SAPI_HEADER_SENT_SUCCESSFULLY; 590114Smax.romanov@nginx.com 591114Smax.romanov@nginx.com fail: 592114Smax.romanov@nginx.com 593114Smax.romanov@nginx.com // TODO handle NXT_AGAIN 594114Smax.romanov@nginx.com return SAPI_HEADER_SEND_FAILED; 5950Sigor@sysoev.ru } 5960Sigor@sysoev.ru 5970Sigor@sysoev.ru 5980Sigor@sysoev.ru #ifdef NXT_PHP7 5990Sigor@sysoev.ru static size_t 6000Sigor@sysoev.ru nxt_php_read_post(char *buffer, size_t count_bytes TSRMLS_DC) 6010Sigor@sysoev.ru #else 6020Sigor@sysoev.ru static int 6030Sigor@sysoev.ru nxt_php_read_post(char *buffer, uint count_bytes TSRMLS_DC) 6040Sigor@sysoev.ru #endif 6050Sigor@sysoev.ru { 606206Smax.romanov@nginx.com size_t size, rest; 60786Smax.romanov@nginx.com nxt_php_run_ctx_t *ctx; 60886Smax.romanov@nginx.com nxt_app_request_header_t *h; 6090Sigor@sysoev.ru 61086Smax.romanov@nginx.com ctx = SG(server_context); 61186Smax.romanov@nginx.com h = &ctx->r.header; 6120Sigor@sysoev.ru 613206Smax.romanov@nginx.com rest = (size_t) h->parsed_content_length - SG(read_post_bytes); 61486Smax.romanov@nginx.com 61586Smax.romanov@nginx.com nxt_debug(ctx->task, "nxt_php_read_post %O", rest); 6160Sigor@sysoev.ru 6170Sigor@sysoev.ru if (rest == 0) { 6180Sigor@sysoev.ru return 0; 6190Sigor@sysoev.ru } 6200Sigor@sysoev.ru 621206Smax.romanov@nginx.com rest = nxt_min(ctx->body_preread_size, (size_t) count_bytes); 622206Smax.romanov@nginx.com size = nxt_app_msg_read_raw(ctx->task, ctx->rmsg, buffer, rest); 6230Sigor@sysoev.ru 624206Smax.romanov@nginx.com ctx->body_preread_size -= size; 6250Sigor@sysoev.ru 62686Smax.romanov@nginx.com return size; 6270Sigor@sysoev.ru } 6280Sigor@sysoev.ru 6290Sigor@sysoev.ru 6300Sigor@sysoev.ru static char * 6310Sigor@sysoev.ru nxt_php_read_cookies(TSRMLS_D) 6320Sigor@sysoev.ru { 63386Smax.romanov@nginx.com nxt_php_run_ctx_t *ctx; 6340Sigor@sysoev.ru 63586Smax.romanov@nginx.com ctx = SG(server_context); 6360Sigor@sysoev.ru 63794Smax.romanov@nginx.com nxt_debug(ctx->task, "nxt_php_read_cookies"); 63894Smax.romanov@nginx.com 63986Smax.romanov@nginx.com return (char *) ctx->r.header.cookie.start; 6400Sigor@sysoev.ru } 6410Sigor@sysoev.ru 6420Sigor@sysoev.ru 6430Sigor@sysoev.ru static void 6440Sigor@sysoev.ru nxt_php_register_variables(zval *track_vars_array TSRMLS_DC) 6450Sigor@sysoev.ru { 646114Smax.romanov@nginx.com u_char *colon; 64786Smax.romanov@nginx.com nxt_str_t n, v; 64886Smax.romanov@nginx.com nxt_int_t rc; 649114Smax.romanov@nginx.com nxt_str_t host, server_name, server_port; 65086Smax.romanov@nginx.com nxt_task_t *task; 65186Smax.romanov@nginx.com nxt_php_run_ctx_t *ctx; 65286Smax.romanov@nginx.com nxt_app_request_header_t *h; 6530Sigor@sysoev.ru 654114Smax.romanov@nginx.com static nxt_str_t def_host = nxt_string("localhost"); 655114Smax.romanov@nginx.com static nxt_str_t def_port = nxt_string("80"); 656114Smax.romanov@nginx.com 65786Smax.romanov@nginx.com ctx = SG(server_context); 6580Sigor@sysoev.ru 65986Smax.romanov@nginx.com h = &ctx->r.header; 66086Smax.romanov@nginx.com task = ctx->task; 6610Sigor@sysoev.ru 66286Smax.romanov@nginx.com nxt_debug(task, "php register variables"); 6630Sigor@sysoev.ru 664114Smax.romanov@nginx.com #define NXT_PHP_SET(n, v) \ 665142Smax.romanov@nginx.com nxt_debug(task, "php: register %s='%V'", n, &v); \ 666114Smax.romanov@nginx.com php_register_variable_safe((char *) (n), (char *) (v).start, \ 667114Smax.romanov@nginx.com (v).length, track_vars_array TSRMLS_CC) \ 668114Smax.romanov@nginx.com 669114Smax.romanov@nginx.com NXT_PHP_SET("SERVER_PROTOCOL", h->version); 67086Smax.romanov@nginx.com 67186Smax.romanov@nginx.com /* 67286Smax.romanov@nginx.com * 'SCRIPT_NAME' 67386Smax.romanov@nginx.com * Contains the current script's path. This is useful for pages which need to 67486Smax.romanov@nginx.com * point to themselves. The __FILE__ constant contains the full path and 67586Smax.romanov@nginx.com * filename of the current (i.e. included) file. 67686Smax.romanov@nginx.com */ 67786Smax.romanov@nginx.com 67886Smax.romanov@nginx.com /* 67986Smax.romanov@nginx.com * 'SCRIPT_FILENAME' 68086Smax.romanov@nginx.com * The absolute pathname of the currently executing script. 68186Smax.romanov@nginx.com */ 68286Smax.romanov@nginx.com 68386Smax.romanov@nginx.com /* 68486Smax.romanov@nginx.com * 'DOCUMENT_ROOT' 68586Smax.romanov@nginx.com * The document root directory under which the current script is executing, 68686Smax.romanov@nginx.com * as defined in the server's configuration file. 68786Smax.romanov@nginx.com */ 6880Sigor@sysoev.ru 68986Smax.romanov@nginx.com if (nxt_php_script.start != NULL) { 69086Smax.romanov@nginx.com // ABS_MODE 69186Smax.romanov@nginx.com /* 69286Smax.romanov@nginx.com * 'PHP_SELF' 69386Smax.romanov@nginx.com * The filename of the currently executing script, relative to the document 69486Smax.romanov@nginx.com * root. For instance, $_SERVER['PHP_SELF'] in a script at the address 69586Smax.romanov@nginx.com * http://example.com/foo/bar.php would be /foo/bar.php. The __FILE__ constant 69686Smax.romanov@nginx.com * contains the full path and filename of the current (i.e. included) file. 69786Smax.romanov@nginx.com * If PHP is running as a command-line processor this variable contains the 69886Smax.romanov@nginx.com * script name since PHP 4.3.0. Previously it was not available. 69986Smax.romanov@nginx.com */ 700114Smax.romanov@nginx.com NXT_PHP_SET("PHP_SELF", nxt_php_script); 701114Smax.romanov@nginx.com NXT_PHP_SET("SCRIPT_NAME", nxt_php_script); 702277Sigor@sysoev.ru 70386Smax.romanov@nginx.com } else { 704114Smax.romanov@nginx.com NXT_PHP_SET("PHP_SELF", h->path); 705114Smax.romanov@nginx.com NXT_PHP_SET("SCRIPT_NAME", h->path); 70686Smax.romanov@nginx.com } 7070Sigor@sysoev.ru 708114Smax.romanov@nginx.com NXT_PHP_SET("SCRIPT_FILENAME", ctx->script); 709114Smax.romanov@nginx.com NXT_PHP_SET("DOCUMENT_ROOT", nxt_php_root); 7100Sigor@sysoev.ru 711114Smax.romanov@nginx.com NXT_PHP_SET("REQUEST_METHOD", h->method); 712114Smax.romanov@nginx.com NXT_PHP_SET("REQUEST_URI", h->target); 7130Sigor@sysoev.ru 71486Smax.romanov@nginx.com if (h->query.start != NULL) { 715114Smax.romanov@nginx.com NXT_PHP_SET("QUERY_STRING", h->query); 7160Sigor@sysoev.ru } 7170Sigor@sysoev.ru 71886Smax.romanov@nginx.com if (h->content_type.start != NULL) { 719114Smax.romanov@nginx.com NXT_PHP_SET("CONTENT_TYPE", h->content_type); 7200Sigor@sysoev.ru } 7210Sigor@sysoev.ru 72286Smax.romanov@nginx.com if (h->content_length.start != NULL) { 723114Smax.romanov@nginx.com NXT_PHP_SET("CONTENT_LENGTH", h->content_length); 724114Smax.romanov@nginx.com } 725114Smax.romanov@nginx.com 726114Smax.romanov@nginx.com host = h->host; 727114Smax.romanov@nginx.com if (host.length == 0) { 728114Smax.romanov@nginx.com host = def_host; 72986Smax.romanov@nginx.com } 7300Sigor@sysoev.ru 731114Smax.romanov@nginx.com server_name = host; 732114Smax.romanov@nginx.com colon = nxt_memchr(host.start, ':', host.length); 733114Smax.romanov@nginx.com 734114Smax.romanov@nginx.com if (colon != NULL) { 735114Smax.romanov@nginx.com server_name.length = colon - host.start; 736114Smax.romanov@nginx.com 737114Smax.romanov@nginx.com server_port.start = colon + 1; 738114Smax.romanov@nginx.com server_port.length = host.length - server_name.length - 1; 739277Sigor@sysoev.ru 740114Smax.romanov@nginx.com } else { 741114Smax.romanov@nginx.com server_port = def_port; 742114Smax.romanov@nginx.com } 743114Smax.romanov@nginx.com 744114Smax.romanov@nginx.com NXT_PHP_SET("SERVER_NAME", server_name); 745114Smax.romanov@nginx.com NXT_PHP_SET("SERVER_PORT", server_port); 746114Smax.romanov@nginx.com 747114Smax.romanov@nginx.com NXT_PHP_SET("REMOTE_ADDR", ctx->r.remote); 748268Sigor@sysoev.ru NXT_PHP_SET("SERVER_ADDR", ctx->r.local); 749114Smax.romanov@nginx.com 75094Smax.romanov@nginx.com while (nxt_app_msg_read_str(task, ctx->rmsg, &n) == NXT_OK) { 75186Smax.romanov@nginx.com if (nxt_slow_path(n.length == 0)) { 75286Smax.romanov@nginx.com break; 7530Sigor@sysoev.ru } 7540Sigor@sysoev.ru 75594Smax.romanov@nginx.com rc = nxt_app_msg_read_str(task, ctx->rmsg, &v); 75694Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 75794Smax.romanov@nginx.com break; 75894Smax.romanov@nginx.com } 75994Smax.romanov@nginx.com 760114Smax.romanov@nginx.com NXT_PHP_SET(n.start, v); 7610Sigor@sysoev.ru } 762114Smax.romanov@nginx.com 763114Smax.romanov@nginx.com #undef NXT_PHP_SET 7640Sigor@sysoev.ru } 7650Sigor@sysoev.ru 7660Sigor@sysoev.ru 7670Sigor@sysoev.ru static void 76886Smax.romanov@nginx.com nxt_php_log_message(char *message 76986Smax.romanov@nginx.com #ifdef NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE 77086Smax.romanov@nginx.com , int syslog_type_int 77186Smax.romanov@nginx.com #endif 77286Smax.romanov@nginx.com ) 7730Sigor@sysoev.ru { 774*462Smax.romanov@nginx.com nxt_php_run_ctx_t *ctx; 775*462Smax.romanov@nginx.com 776*462Smax.romanov@nginx.com ctx = SG(server_context); 777*462Smax.romanov@nginx.com 778*462Smax.romanov@nginx.com nxt_log(ctx->task, NXT_LOG_NOTICE, "php message: %s", message); 7790Sigor@sysoev.ru } 780