📄 thttpd.c
字号:
php_error, NULL, sapi_thttpd_send_headers, NULL, sapi_thttpd_read_post, sapi_thttpd_read_cookies, sapi_thttpd_register_variables, NULL, /* Log message */ NULL, /* php.ini path override */ NULL, /* Block interruptions */ NULL, /* Unblock interruptions */ NULL, NULL, NULL, 0, sapi_thttpd_get_fd};static void thttpd_module_main(int show_source TSRMLS_DC){ zend_file_handle file_handle = {0}; if (php_request_startup(TSRMLS_C) == FAILURE) { return; } if (show_source) { zend_syntax_highlighter_ini syntax_highlighter_ini; php_get_highlight_struct(&syntax_highlighter_ini); highlight_file(SG(request_info).path_translated, &syntax_highlighter_ini TSRMLS_CC); } else { file_handle.type = ZEND_HANDLE_FILENAME; file_handle.filename = SG(request_info).path_translated; file_handle.free_filename = 0; file_handle.opened_path = NULL; php_execute_script(&file_handle TSRMLS_CC); } php_request_shutdown(NULL);}static void thttpd_request_ctor(TSRMLS_D){ smart_str s = {0}; TG(seen_cl) = 0; TG(seen_cn) = 0; TG(sbuf).c = 0; SG(request_info).query_string = TG(hc)->query?strdup(TG(hc)->query):NULL; smart_str_appends_ex(&s, TG(hc)->hs->cwd, 1); smart_str_appends_ex(&s, TG(hc)->expnfilename, 1); smart_str_0(&s); SG(request_info).path_translated = s.c; s.c = NULL; smart_str_appendc_ex(&s, '/', 1); smart_str_appends_ex(&s, TG(hc)->origfilename, 1); smart_str_0(&s); SG(request_info).request_uri = s.c; SG(request_info).request_method = httpd_method_str(TG(hc)->method); SG(sapi_headers).http_response_code = 200; if (TG(hc)->contenttype) SG(request_info).content_type = strdup(TG(hc)->contenttype); SG(request_info).content_length = TG(hc)->contentlength == -1 ? 0 : TG(hc)->contentlength; TG(unconsumed_length) = SG(request_info).content_length; php_handle_auth_data(TG(hc)->authorization TSRMLS_CC);}static void thttpd_request_dtor(TSRMLS_D){ smart_str_free_ex(&TG(sbuf), 1); if (SG(request_info).query_string) free(SG(request_info).query_string); free(SG(request_info).request_uri); free(SG(request_info).path_translated); if (SG(request_info).content_type) free(SG(request_info).content_type);}#ifdef ZTS#ifdef TSRM_ST#define thread_create_simple_detached(n) st_thread_create(n, NULL, 0, 0)#define thread_usleep(n) st_usleep(n)#define thread_exit() st_thread_exit(NULL)/* No preemption, simple operations are safe */#define thread_atomic_inc(n) (++n)#define thread_atomic_dec(n) (--n)#else#error No thread primitives available#endif/* We might want to replace this with a STAILQ */typedef struct qreq { httpd_conn *hc; struct qreq *next;} qreq_t;static MUTEX_T qr_lock;static qreq_t *queued_requests;static qreq_t *last_qr;static int nr_free_threads;static int nr_threads;static int max_threads = 50;#define HANDLE_STRINGS() { \ HANDLE_STR(encodedurl); \ HANDLE_STR(decodedurl); \ HANDLE_STR(origfilename); \ HANDLE_STR(expnfilename); \ HANDLE_STR(pathinfo); \ HANDLE_STR(query); \ HANDLE_STR(referer); \ HANDLE_STR(useragent); \ HANDLE_STR(accept); \ HANDLE_STR(accepte); \ HANDLE_STR(acceptl); \ HANDLE_STR(cookie); \ HANDLE_STR(contenttype); \ HANDLE_STR(authorization); \ HANDLE_STR(remoteuser); \ }static httpd_conn *duplicate_conn(httpd_conn *hc, httpd_conn *nhc){ memcpy(nhc, hc, sizeof(*nhc));#define HANDLE_STR(m) nhc->m = nhc->m ? strdup(nhc->m) : NULL HANDLE_STRINGS();#undef HANDLE_STR return nhc;}static void destroy_conn(httpd_conn *hc){#define HANDLE_STR(m) if (hc->m) free(hc->m) HANDLE_STRINGS();#undef HANDLE_STR}static httpd_conn *dequeue_request(void){ httpd_conn *ret = NULL; qreq_t *m; tsrm_mutex_lock(qr_lock); if (queued_requests) { m = queued_requests; ret = m->hc; if (!(queued_requests = m->next)) last_qr = NULL; free(m); } tsrm_mutex_unlock(qr_lock); return ret;}static void *worker_thread(void *);static void queue_request(httpd_conn *hc){ qreq_t *m; httpd_conn *nhc; /* Mark as long-running request */ hc->file_address = (char *) 1; /* * We cannot synchronously revoke accesses to hc in the worker * thread, so we need to pass a copy of hc to the worker thread. */ nhc = malloc(sizeof *nhc); duplicate_conn(hc, nhc); /* Allocate request queue container */ m = malloc(sizeof *m); m->hc = nhc; m->next = NULL; tsrm_mutex_lock(qr_lock); /* Create new threads when reaching a certain threshhold */ if (nr_threads < max_threads && nr_free_threads < 2) { nr_threads++; /* protected by qr_lock */ thread_atomic_inc(nr_free_threads); thread_create_simple_detached(worker_thread); } /* Insert container into request queue */ if (queued_requests) last_qr->next = m; else queued_requests = m; last_qr = m; tsrm_mutex_unlock(qr_lock);}static off_t thttpd_real_php_request(httpd_conn *hc, int TSRMLS_DC);static void *worker_thread(void *dummy){ int do_work = 50; httpd_conn *hc; while (do_work) { hc = dequeue_request(); if (!hc) {/* do_work--; */ thread_usleep(500000); continue; }/* do_work = 50; */ thread_atomic_dec(nr_free_threads); thttpd_real_php_request(hc, 0 TSRMLS_CC); shutdown(hc->conn_fd, 0); destroy_conn(hc); free(hc); thread_atomic_inc(nr_free_threads); } thread_atomic_dec(nr_free_threads); thread_atomic_dec(nr_threads); thread_exit();}static void remove_dead_conn(int fd){ qreq_t *m, *prev = NULL; tsrm_mutex_lock(qr_lock); m = queued_requests; while (m) { if (m->hc->conn_fd == fd) { if (prev) if (!(prev->next = m->next)) last_qr = prev; else if (!(queued_requests = m->next)) last_qr = NULL; destroy_conn(m->hc); free(m->hc); free(m); break; } prev = m; m = m->next; } tsrm_mutex_unlock(qr_lock);}#endifstatic off_t thttpd_real_php_request(httpd_conn *hc, int show_source TSRMLS_DC){ TG(hc) = hc; hc->bytes_sent = 0; if (hc->contentlength != -1) { hc->should_linger = 1; hc->do_keep_alive = 0; } if (hc->contentlength != -1 && SIZEOF_UNCONSUMED_BYTES() < hc->contentlength) { hc->read_body_into_mem = 1; return 0; } thttpd_request_ctor(TSRMLS_C); thttpd_module_main(show_source TSRMLS_CC); /* disable kl, if no content-length was seen or Connection: was set */ if (TG(seen_cl) == 0 || TG(seen_cn) == 1) { TG(hc)->do_keep_alive = 0; } if (TG(sbuf).c != 0) { if (TG(hc)->response) free(TG(hc)->response); TG(hc)->response = TG(sbuf).c; TG(hc)->responselen = TG(sbuf).len; TG(hc)->maxresponse = TG(sbuf).a; TG(sbuf).c = 0; TG(sbuf).len = 0; TG(sbuf).a = 0; } thttpd_request_dtor(TSRMLS_C); return 0;}off_t thttpd_php_request(httpd_conn *hc, int show_source){#ifdef ZTS queue_request(hc);#else TSRMLS_FETCH(); return thttpd_real_php_request(hc, show_source TSRMLS_CC);#endif}void thttpd_register_on_close(void (*arg)(int)) { TSRMLS_FETCH(); TG(on_close) = arg;}void thttpd_closed_conn(int fd){ TSRMLS_FETCH(); if (TG(on_close)) TG(on_close)(fd);}int thttpd_get_fd(void){ TSRMLS_FETCH(); return TG(hc)->conn_fd;}void thttpd_set_dont_close(void){ TSRMLS_FETCH();#ifndef PREMIUM_THTTPD TG(hc)->file_address = (char *) 1;#endif}void thttpd_php_init(void){ char *ini;#ifdef ZTS tsrm_startup(1, 1, 0, NULL); ts_allocate_id(&thttpd_globals_id, sizeof(php_thttpd_globals), NULL, NULL); qr_lock = tsrm_mutex_alloc(); thttpd_register_on_close(remove_dead_conn);#endif if ((ini = getenv("PHP_INI_PATH"))) { thttpd_sapi_module.php_ini_path_override = ini; } sapi_startup(&thttpd_sapi_module); thttpd_sapi_module.startup(&thttpd_sapi_module); { TSRMLS_FETCH(); SG(server_context) = (void *) 1; }}void thttpd_php_shutdown(void){ TSRMLS_FETCH(); if (SG(server_context) != NULL) { thttpd_sapi_module.shutdown(&thttpd_sapi_module); sapi_shutdown();#ifdef ZTS tsrm_shutdown();#endif }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -