php-src/sapi/thttpd/thttpd.c

347 lines
8.6 KiB
C
Raw Normal View History

/*
+----------------------------------------------------------------------+
| PHP version 4.0 |
+----------------------------------------------------------------------+
| Copyright (c) 1997, 1998, 1999, 2000 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 2.02 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available at through the world-wide-web at |
| http://www.php.net/license/2_02.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: Sascha Schumann <sascha@schumann.cx> |
+----------------------------------------------------------------------+
*/
#include "php.h"
#include "SAPI.h"
2000-06-06 07:24:42 +08:00
#include "php_main.h"
#include "php_thttpd.h"
#include "php_variables.h"
#include "version.h"
typedef struct {
httpd_conn *hc;
int post_off;
void (*on_close)(int);
} php_thttpd_globals;
static php_thttpd_globals thttpd_globals;
#define TLS_D
#define TLS_DC
#define TLS_C
#define TLS_CC
#define TG(v) (thttpd_globals.v)
#define TLS_FETCH()
static int sapi_thttpd_ub_write(const char *str, uint str_length)
{
2000-10-30 00:01:02 +08:00
int n;
uint sent = 0;
TLS_FETCH();
while (str_length > 0) {
n = send(TG(hc)->conn_fd, str, str_length, 0);
2000-10-30 00:01:02 +08:00
if (n == -1 && errno == EPIPE)
php_handle_aborted_connection();
if (n == -1 && errno == EAGAIN)
continue;
if (n <= 0)
return n;
2000-10-30 00:01:02 +08:00
TG(hc)->bytes += n;
str += n;
sent += n;
str_length -= n;
}
return sent;
}
static int sapi_thttpd_send_headers(sapi_headers_struct *sapi_headers SLS_DC)
{
char buf[1024];
if (!SG(sapi_headers).http_status_line) {
size_t len;
snprintf(buf, 1023, "HTTP/1.0 %d Something\r\n", SG(sapi_headers).http_response_code);
len = strlen(buf);
send(TG(hc)->conn_fd, buf, len, 0);
TG(hc)->status = SG(sapi_headers).http_response_code;
TG(hc)->bytes += len;
}
return SAPI_HEADER_DO_SEND;
}
static void sapi_thttpd_send_header(sapi_header_struct *sapi_header, void *server_context)
{
struct iovec vec[2];
int n = 0;
TLS_FETCH();
if (sapi_header) {
vec[n].iov_base = sapi_header->header;
vec[n++].iov_len = sapi_header->header_len;
TG(hc)->bytes += sapi_header->header_len;
}
vec[n].iov_base = "\r\n";
vec[n++].iov_len = 2;
TG(hc)->bytes += 2;
writev(TG(hc)->conn_fd, vec, n);
}
static int sapi_thttpd_read_post(char *buffer, uint count_bytes SLS_DC)
{
size_t read_bytes = 0, tmp;
int c;
TLS_FETCH();
/* to understand this, read cgi_interpose_input() in libhttpd.c */
c = TG(hc)->read_idx - TG(hc)->checked_idx;
if (c > 0) {
read_bytes = MIN(c, count_bytes);
memcpy(buffer, TG(hc)->read_buf + TG(hc)->checked_idx, read_bytes);
TG(hc)->checked_idx += read_bytes;
count_bytes -= read_bytes;
}
count_bytes = MIN(count_bytes,
SG(request_info).content_length - SG(read_post_bytes) - TG(post_off));
while (read_bytes < count_bytes) {
tmp = recv(TG(hc)->conn_fd, buffer + read_bytes,
count_bytes - read_bytes, 0);
if (tmp <= 0)
break;
read_bytes += tmp;
}
return read_bytes;
}
static char *sapi_thttpd_read_cookies(SLS_D)
{
TLS_FETCH();
return TG(hc)->cookie;
}
#define BUF_SIZE 512
#define ADD_STRING(name) \
2000-08-25 17:15:00 +08:00
php_register_variable(name, buf, track_vars_array ELS_CC PLS_CC)
static void sapi_thttpd_register_variables(zval *track_vars_array ELS_DC SLS_DC PLS_DC)
{
char buf[BUF_SIZE + 1];
TLS_FETCH();
php_register_variable("PHP_SELF", SG(request_info).request_uri, track_vars_array ELS_CC PLS_CC);
2000-08-25 17:15:00 +08:00
php_register_variable("SERVER_SOFTWARE", SERVER_SOFTWARE, track_vars_array ELS_CC PLS_CC);
php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array ELS_CC PLS_CC);
php_register_variable("REQUEST_METHOD", (char *) SG(request_info).request_method, track_vars_array ELS_CC PLS_CC);
2000-08-25 17:15:00 +08:00
php_register_variable("REQUEST_URI", SG(request_info).request_uri, track_vars_array ELS_CC PLS_CC);
php_register_variable("PATH_TRANSLATED", SG(request_info).path_translated, track_vars_array ELS_CC PLS_CC);
buf[BUF_SIZE] = '\0';
strncpy(buf, inet_ntoa(TG(hc)->client_addr.sa_in.sin_addr), BUF_SIZE);
ADD_STRING("REMOTE_ADDR");
ADD_STRING("REMOTE_HOST");
snprintf(buf, BUF_SIZE, "%d", TG(hc)->hs->port);
ADD_STRING("SERVER_PORT");
snprintf(buf, BUF_SIZE, "/%s", TG(hc)->pathinfo);
ADD_STRING("PATH_INFO");
snprintf(buf, BUF_SIZE, "/%s", TG(hc)->origfilename);
ADD_STRING("SCRIPT_NAME");
#define CONDADD(name, field) \
if (TG(hc)->field[0]) { \
2000-08-25 17:15:00 +08:00
php_register_variable(#name, TG(hc)->field, track_vars_array ELS_CC PLS_C); \
}
CONDADD(HTTP_REFERER, referer);
CONDADD(HTTP_USER_AGENT, useragent);
CONDADD(HTTP_ACCEPT, accept);
CONDADD(HTTP_ACCEPT_ENCODING, accepte);
CONDADD(HTTP_COOKIE, cookie);
CONDADD(CONTENT_TYPE, contenttype);
CONDADD(REMOTE_USER, remoteuser);
CONDADD(SERVER_PROTOCOL, protocol);
if (TG(hc)->contentlength != -1) {
sprintf(buf, "%ld", (long) TG(hc)->contentlength);
ADD_STRING("CONTENT_LENGTH");
}
if (TG(hc)->authorization[0])
2000-08-25 17:15:00 +08:00
php_register_variable("AUTH_TYPE", "Basic", track_vars_array ELS_CC PLS_C);
}
static sapi_module_struct thttpd_sapi_module = {
"thttpd",
"thttpd",
php_module_startup,
php_module_shutdown_wrapper,
NULL, /* activate */
NULL, /* deactivate */
sapi_thttpd_ub_write,
NULL,
NULL, /* get uid */
NULL, /* getenv */
php_error,
NULL,
sapi_thttpd_send_headers,
sapi_thttpd_send_header,
sapi_thttpd_read_post,
sapi_thttpd_read_cookies,
sapi_thttpd_register_variables,
NULL, /* Log message */
NULL, /* Block interruptions */
NULL, /* Unblock interruptions */
STANDARD_SAPI_MODULE_PROPERTIES
};
static void thttpd_module_main(TLS_D SLS_DC)
{
zend_file_handle file_handle;
CLS_FETCH();
ELS_FETCH();
PLS_FETCH();
file_handle.type = ZEND_HANDLE_FILENAME;
file_handle.filename = SG(request_info).path_translated;
file_handle.free_filename = 0;
file_handle.opened_path = NULL;
if (php_request_startup(CLS_C ELS_CC PLS_CC SLS_CC) == FAILURE) {
return;
}
php_execute_script(&file_handle CLS_CC ELS_CC PLS_CC);
php_request_shutdown(NULL);
}
static void thttpd_request_ctor(TLS_D SLS_DC)
{
char *cp;
size_t cp_len;
char buf[1024];
int offset;
size_t filename_len;
size_t cwd_len;
SG(request_info).query_string = TG(hc)->query?strdup(TG(hc)->query):NULL;
filename_len = strlen(TG(hc)->expnfilename);
cwd_len = strlen(TG(hc)->hs->cwd);
cp_len = cwd_len + filename_len;
cp = (char *) malloc(cp_len + 1);
/* cwd always ends in "/", so this is safe */
memcpy(cp, TG(hc)->hs->cwd, cwd_len);
memcpy(cp + cwd_len, TG(hc)->expnfilename, filename_len);
cp[cp_len] = '\0';
SG(request_info).path_translated = cp;
snprintf(buf, 1023, "/%s", TG(hc)->origfilename);
SG(request_info).request_uri = strdup(buf);
SG(request_info).request_method = httpd_method_str(TG(hc)->method);
SG(sapi_headers).http_response_code = 200;
SG(request_info).content_type = TG(hc)->contenttype;
SG(request_info).content_length = TG(hc)->contentlength;
2000-10-27 18:19:06 +08:00
php_handle_auth_data(TG(hc)->authorization SLS_CC);
TG(post_off) = TG(hc)->read_idx - TG(hc)->checked_idx;
/* avoid feeding \r\n from POST data to SAPI */
offset = TG(post_off) - SG(request_info).content_length;
if (offset > 0) {
TG(post_off) -= offset;
TG(hc)->read_idx -= offset;
}
}
static void thttpd_request_dtor(TLS_D SLS_DC)
{
if (SG(request_info).query_string)
free(SG(request_info).query_string);
free(SG(request_info).request_uri);
free(SG(request_info).path_translated);
}
off_t thttpd_php_request(httpd_conn *hc)
{
SLS_FETCH();
TLS_FETCH();
TG(hc) = hc;
hc->bytes = 0;
thttpd_request_ctor(TLS_C SLS_CC);
thttpd_module_main(TLS_C SLS_CC);
thttpd_request_dtor(TLS_C SLS_CC);
return 0;
}
void thttpd_register_on_close(void (*arg)(int))
{
TG(on_close) = arg;
}
void thttpd_closed_conn(int fd)
{
if (TG(on_close)) TG(on_close)(fd);
}
int thttpd_get_fd(void)
{
return TG(hc)->conn_fd;
}
void thttpd_set_dont_close(void)
{
TG(hc)->file_address = (char *) 1;
}
void thttpd_php_init(void)
{
sapi_startup(&thttpd_sapi_module);
thttpd_sapi_module.startup(&thttpd_sapi_module);
SG(server_context) = (void *) 1;
}
void thttpd_php_shutdown(void)
{
if (SG(server_context) != NULL) {
thttpd_sapi_module.shutdown(&thttpd_sapi_module);
sapi_shutdown();
}
}