📄 roxen.c
字号:
/* +----------------------------------------------------------------------+ | PHP Version 4 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2007 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: David Hedbor <neotron@php.net> | | Based on aolserver SAPI by Sascha Schumann <sascha@schumann.cx> | +----------------------------------------------------------------------+ *//* $Id: roxen.c,v 1.53.2.5.6.2 2007/01/01 09:46:52 sebastian Exp $ */#include "php.h"#ifdef HAVE_ROXEN#include "php_ini.h"#include "php_globals.h"#include "SAPI.h"#include "php_main.h" #include "ext/standard/info.h"#include "php_version.h"#ifndef ZTS/* Only valid if thread safety is enabled. */#undef ROXEN_USE_ZTS#endif/* Pike Include Files * * conflicts with pike avoided by only using long names. Requires a new * Pike 0.7 since it was implemented for this interface only. * */#define NO_PIKE_SHORTHAND#include <fdlib.h>#include <program.h>#include <pike_types.h>#include <interpret.h>#include <module_support.h>#include <error.h>#include <array.h>#include <backend.h>#include <stralloc.h>#include <mapping.h>#include <object.h>#include <threads.h>#include <builtin_functions.h>#include <operators.h>#undef HIDE_GLOBAL_VARIABLES#undef REVEAL_GLOBAL_VARIABLES#define HIDE_GLOBAL_VARIABLES()#define REVEAL_GLOBAL_VARIABLES()/* php_roxen_request is per-request object storage */typedef struct{ struct mapping *request_data; struct object *my_fd_obj; int my_fd; char *filename;} php_roxen_request;/* Defines to get to the data supplied when the script is started. */#ifdef ROXEN_USE_ZTS/* ZTS does work now, but it seems like it's faster using the "serialization" * method I previously used. Thus it's not used unless ROXEN_USE_ZTS is defined. *//* Per thread storage area id... */static int roxen_globals_id;# define GET_THIS() php_roxen_request *_request = ts_resource(roxen_globals_id)# define THIS _request#elsestatic php_roxen_request *current_request = NULL;# define GET_THIS() current_request = ((php_roxen_request *)Pike_fp->current_storage)# define THIS current_request#endif/* File descriptor integer. Used to write directly to the FD without * passing Pike */#define MY_FD (THIS->my_fd)/* FD object. Really a PHPScript object from Pike which implements a couple * of functions to handle headers, writing and buffering. */#define MY_FD_OBJ ((struct object *)(THIS->my_fd_obj))/* Mapping with data supplied from the calling Roxen module. Contains * a mapping with headers, an FD object etc. */#define REQUEST_DATA ((struct mapping *)(THIS->request_data))#if defined(_REENTRANT) && !defined(ROXEN_USE_ZTS)/* Lock used to serialize the PHP execution. If ROXEN_USE_ZTS is defined, we * are using the PHP thread safe mechanism instead. */static PIKE_MUTEX_T roxen_php_execution_lock;# define PHP_INIT_LOCK() mt_init(&roxen_php_execution_lock)# define PHP_LOCK(X) THREADS_ALLOW();mt_lock(&roxen_php_execution_lock);THREADS_DISALLOW()# define PHP_UNLOCK(X) mt_unlock(&roxen_php_execution_lock);# define PHP_DESTROY() mt_destroy(&roxen_php_execution_lock)#else /* !_REENTRANT */# define PHP_INIT_LOCK() # define PHP_LOCK(X)# define PHP_UNLOCK(X)# define PHP_DESTROY() #endif /* _REENTRANT */extern int fd_from_object(struct object *o);static unsigned char roxen_php_initialized;/* This allows calling of pike functions from the PHP callbacks, * which requires the Pike interpreter to be locked. */#define THREAD_SAFE_RUN(COMMAND, what) do {\ struct thread_state *state;\ if((state = thread_state_for_id(th_self()))!=NULL) {\ if(!state->swapped) {\ COMMAND;\ } else {\ mt_lock(&interpreter_lock);\ SWAP_IN_THREAD(state);\ COMMAND;\ SWAP_OUT_THREAD(state);\ mt_unlock(&interpreter_lock);\ }\ }\} while(0)struct program *php_program;/* To avoid executing a PHP script from a PHP callback, which would * create a deadlock, a global thread id is used. If the thread calling the * php-script is the same as the current thread, it fails. */static int current_thread = -1;/* Low level header lookup. Basically looks for the named header in the mapping * headers in the supplied options mapping. */ static INLINE struct svalue *lookup_header(char *headername){ struct svalue *headers, *value; struct pike_string *sind;#ifdef ROXEN_USE_ZTS GET_THIS();#endif sind = make_shared_string("env"); headers = low_mapping_string_lookup(REQUEST_DATA, sind); free_string(sind); if(!headers || headers->type != PIKE_T_MAPPING) return NULL; sind = make_shared_string(headername); value = low_mapping_string_lookup(headers->u.mapping, sind); free_string(sind); if(!value) return NULL; return value;}/* Lookup a header in the mapping and return the value as a string, or * return the default if it's missing */INLINE static char *lookup_string_header(char *headername, char *default_value){ struct svalue *head = NULL; THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup"); if(!head || head->type != PIKE_T_STRING) return default_value; return head->u.string->str;}/* Lookup a header in the mapping and return the value as if it's an integer * and otherwise return the default. */INLINE static int lookup_integer_header(char *headername, int default_value){ struct svalue *head = NULL; THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup"); if(!head || head->type != PIKE_T_INT) return default_value; return head->u.integer;}/* * php_roxen_low_ub_write() writes data to the client connection. Might be * rewritten to do more direct IO to save CPU and the need to lock the * * interpreter for better threading. */static intphp_roxen_low_ub_write(const char *str, uint str_length TSRMLS_DC) { int sent_bytes = 0; struct pike_string *to_write = NULL;#ifdef ROXEN_USE_ZTS GET_THIS();#endif if(!MY_FD_OBJ->prog) { PG(connection_status) = PHP_CONNECTION_ABORTED; zend_bailout(); return -1; } to_write = make_shared_binary_string(str, str_length); push_string(to_write); safe_apply(MY_FD_OBJ, "write", 1); if(Pike_sp[-1].type == PIKE_T_INT) sent_bytes = Pike_sp[-1].u.integer; pop_stack(); if(sent_bytes != str_length) { /* This means the connection is closed. Dead. Gone. *sniff* */ php_handle_aborted_connection(); } return sent_bytes;}/* * php_roxen_sapi_ub_write() calls php_roxen_low_ub_write in a Pike thread * safe manner. */static intphp_roxen_sapi_ub_write(const char *str, uint str_length TSRMLS_DC){#ifdef ROXEN_USE_ZTS GET_THIS();#endif int sent_bytes = 0, fd = MY_FD; if(fd) { for(sent_bytes=0;sent_bytes < str_length;) { int written; written = fd_write(fd, str + sent_bytes, str_length - sent_bytes); if(written < 0) { switch(errno) { default: /* This means the connection is closed. Dead. Gone. *sniff* */ PG(connection_status) = PHP_CONNECTION_ABORTED; zend_bailout(); return sent_bytes; case EINTR: case EWOULDBLOCK: continue; } } else { sent_bytes += written; } } } else { THREAD_SAFE_RUN(sent_bytes = php_roxen_low_ub_write(str, str_length TSRMLS_CC), "write"); } return sent_bytes;}/* php_roxen_set_header() sets a header in the header mapping. Called in a * thread safe manner from php_roxen_sapi_header_handler. */static void php_roxen_set_header(char *header_name, char *value, char *p){ struct svalue hsval; struct pike_string *hval, *ind, *hind; struct mapping *headermap; struct svalue *s_headermap;#ifdef ROXEN_USE_ZTS GET_THIS();#endif hval = make_shared_string(value); ind = make_shared_string(" _headers"); hind = make_shared_binary_string(header_name, (int)(p - header_name)); s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind); if(!s_headermap) { struct svalue mappie; mappie.type = PIKE_T_MAPPING; headermap = allocate_mapping(1); mappie.u.mapping = headermap; mapping_string_insert(REQUEST_DATA, ind, &mappie); free_mapping(headermap); } else headermap = s_headermap->u.mapping; hsval.type = PIKE_T_STRING; hsval.u.string = hval; mapping_string_insert(headermap, hind, &hsval); free_string(hval); free_string(ind); free_string(hind);}/* * php_roxen_sapi_header_handler() sets a HTTP reply header to be * sent to the client. */static intphp_roxen_sapi_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC){ char *header_name, *header_content, *p; header_name = sapi_header->header; header_content = p = strchr(header_name, ':'); if(p) { do { header_content++; } while(*header_content == ' '); THREAD_SAFE_RUN(php_roxen_set_header(header_name, header_content, p), "header handler"); } sapi_free_header(sapi_header); return 0;}/* * php_roxen_sapi_send_headers() flushes the headers to the client. * Called before real content is sent by PHP. */static intphp_roxen_low_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC){ struct pike_string *ind; struct svalue *s_headermap;#ifdef ROXEN_USE_ZTS GET_THIS();#endif if(!MY_FD_OBJ->prog) { PG(connection_status) = PHP_CONNECTION_ABORTED; zend_bailout(); return SAPI_HEADER_SEND_FAILED; } ind = make_shared_string(" _headers"); s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind); free_string(ind);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -