--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997, 1998, 1999 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.0 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_0.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"
+#include "main.h"
+#include "php_thttpd.h"
+#include "version.h"
+
+typedef struct {
+ httpd_conn *hc;
+ int post_off;
+} 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)
+{
+ TLS_FETCH();
+
+ return send(TG(hc)->conn_fd, str, str_length, 0);
+}
+
+static int sapi_thttpd_send_headers(sapi_headers_struct *sapi_headers SLS_DC)
+{
+ char buf[1024];
+
+ if (!SG(sapi_headers).http_status_line) {
+ snprintf(buf, 1023, "HTTP/1.0 %d Something\r\n", SG(sapi_headers).http_response_code);
+ send(TG(hc)->conn_fd, buf, strlen(buf), 0);
+ }
+
+ return SAPI_HEADER_DO_SEND;
+}
+
+static void sapi_thttpd_send_header(sapi_header_struct *sapi_header, void *server_context)
+{
+ TLS_FETCH();
+
+ if (sapi_header)
+ send(TG(hc)->conn_fd, sapi_header->header, sapi_header->header_len, 0);
+ send(TG(hc)->conn_fd, "\r\n", sizeof("\r\n") - 1, 0);
+}
+
+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;
+}
+
+static sapi_module_struct sapi_module = {
+ "PHP Language",
+
+ php_module_startup,
+ php_module_shutdown_wrapper,
+
+ sapi_thttpd_ub_write,
+ php_error,
+
+ NULL,
+ sapi_thttpd_send_headers,
+ sapi_thttpd_send_header,
+ sapi_thttpd_read_post,
+ sapi_thttpd_read_cookies,
+
+ STANDARD_SAPI_MODULE_PROPERTIES
+};
+
+#define BUF_SIZE 512
+#define ADD_STRING(name) \
+ MAKE_STD_ZVAL(pval); \
+ pval->type = IS_STRING; \
+ pval->value.str.len = strlen(buf); \
+ pval->value.str.val = estrndup(buf, pval->value.str.len); \
+ zend_hash_update(&EG(symbol_table), name, sizeof(name), \
+ &pval, sizeof(zval *), NULL)
+
+static void thttpd_hash_environment(void)
+{
+ char buf[BUF_SIZE + 1];
+ zval *pval;
+
+ buf[BUF_SIZE] = '\0';
+
+ strncpy(buf, SERVER_SOFTWARE, BUF_SIZE);
+ ADD_STRING("SERVER_SOFTWARE");
+
+ strncpy(buf, "CGI/1.1", BUF_SIZE);
+ ADD_STRING("GATEWAY_INTERFACE");
+
+ snprintf(buf, BUF_SIZE, "%d", TG(hc)->hs->port);
+ ADD_STRING("SERVER_PORT");
+
+ strncpy(buf, SG(request_info).request_method, BUF_SIZE);
+ ADD_STRING("REQUEST_METHOD");
+
+ strncpy(buf, SG(request_info).request_uri, BUF_SIZE);
+ ADD_STRING("REQUEST_URI");
+
+ snprintf(buf, BUF_SIZE, "/%s", TG(hc)->pathinfo);
+ ADD_STRING("PATH_INFO");
+
+ strncpy(buf, SG(request_info).path_translated, BUF_SIZE);
+ ADD_STRING("PATH_TRANSLATED");
+
+ snprintf(buf, BUF_SIZE, "/%s", TG(hc)->origfilename);
+ ADD_STRING("SCRIPT_NAME");
+
+ strncpy(buf, inet_ntoa(TG(hc)->client_addr), BUF_SIZE);
+ ADD_STRING("REMOTE_ADDR");
+ ADD_STRING("REMOTE_HOST");
+
+#define CONDADD(name, field) \
+ if (TG(hc)->field[0]) { \
+ strncpy(buf, TG(hc)->field, BUF_SIZE); \
+ ADD_STRING(#name); \
+ }
+
+ 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]) {
+ strcpy(buf, "Basic");
+ ADD_STRING("AUTH_TYPE");
+ }
+}
+
+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 = TG(hc)->expnfilename;
+ file_handle.free_filename = 0;
+
+ if (php_request_startup(CLS_C ELS_CC PLS_CC SLS_CC) == FAILURE) {
+ return;
+ }
+
+ thttpd_hash_environment();
+ 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 *cp2;
+ int l;
+ char buf[1024];
+ int offset;
+ size_t pathinfo_len;
+ size_t cwd_len;
+
+ pathinfo_len = strlen(TG(hc)->pathinfo);
+ cwd_len = strlen(TG(hc)->hs->cwd);
+
+ SG(request_info).query_string = TG(hc)->query;
+
+ l = cwd_len + pathinfo_len + 1;
+ cp2 = (char *) malloc(l);
+ sprintf(cp2, "%s%s", TG(hc)->hs->cwd, TG(hc)->pathinfo);
+ SG(request_info).path_translated = cp2;
+
+ 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(request_info).content_type = TG(hc)->contenttype;
+ SG(request_info).content_length = TG(hc)->contentlength;
+
+ SG(request_info).auth_user = NULL;
+ SG(request_info).auth_password = NULL;
+
+ 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)
+{
+ 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;
+
+ 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_php_init(void)
+{
+ sapi_startup(&sapi_module);
+ sapi_module.startup(&sapi_module);
+ SG(server_context) = (void *) 1;
+}
+
+void thttpd_php_shutdown(void)
+{
+ sapi_module.shutdown(&sapi_module);
+ sapi_shutdown();
+}
--- /dev/null
+diff -ur thttpd-2.10/Makefile.in thttpd-2.10-php/Makefile.in
+--- thttpd-2.10/Makefile.in Mon Oct 11 20:45:38 1999
++++ thttpd-2.10-php/Makefile.in Mon Dec 20 01:37:49 1999
+@@ -46,13 +46,15 @@
+
+ # You shouldn't need to edit anything below here.
+
++include php_makefile
++
+ CC = @CC@
+ CCOPT = @V_CCOPT@
+ DEFS = @DEFS@
+ INCLS = -I.
+ CFLAGS = $(CCOPT) $(DEFS) $(INCLS)
+-LDFLAGS = @LDFLAGS@
+-LIBS = @LIBS@
++LDFLAGS = @LDFLAGS@ $(PHP_LDFLAGS)
++LIBS = @LIBS@ $(PHP_LIBS)
+ NETLIBS = @V_NETLIBS@
+ INSTALL = @INSTALL@
+
+diff -ur thttpd-2.10/libhttpd.c thttpd-2.10-php/libhttpd.c
+--- thttpd-2.10/libhttpd.c Wed Dec 15 23:22:50 1999
++++ thttpd-2.10-php/libhttpd.c Mon Dec 20 01:05:47 1999
+@@ -75,6 +75,8 @@
+ #include "match.h"
+ #include "tdate_parse.h"
+
++#include "php_thttpd.h"
++
+ #ifndef STDIN_FILENO
+ #define STDIN_FILENO 0
+ #endif
+@@ -211,7 +213,11 @@
+ free( (void*) hs->cwd );
+ if ( hs->cgi_pattern != (char*) 0 )
+ free( (void*) hs->cgi_pattern );
++ if ( hs->php_pattern != (char*) 0 )
++ free( (void *) hs->php_pattern );
+ free( (void*) hs );
++
++ thttpd_php_shutdown();
+ }
+
+
+@@ -244,6 +250,7 @@
+ else
+ hs->hostname = strdup( hostname );
+ hs->port = port;
++ hs->php_pattern = strdup("*.php");
+ if ( cgi_pattern == (char*) 0 )
+ hs->cgi_pattern = (char*) 0;
+ else
+@@ -272,6 +279,8 @@
+ hs->no_symlinks = no_symlinks;
+ hs->vhost = vhost;
+
++ thttpd_php_init();
++
+ /* Create socket. */
+ hs->listen_fd = socket( AF_INET, SOCK_STREAM, 0 );
+ if ( hs->listen_fd < 0 )
+@@ -3129,6 +3138,11 @@
+ ( hc->sb.st_mode & S_IXOTH ) &&
+ match( hc->hs->cgi_pattern, hc->expnfilename ) )
+ return cgi( hc );
++
++ if ( hc->hs->php_pattern != (char*) 0 &&
++ match( hc->hs->php_pattern, hc->expnfilename)) {
++ return thttpd_php_request( hc );
++ }
+
+ /* It's not CGI. If it's executable or there's pathinfo, someone's
+ ** trying to either serve or run a non-CGI file as CGI. Either case
+diff -ur thttpd-2.10/libhttpd.h thttpd-2.10-php/libhttpd.h
+--- thttpd-2.10/libhttpd.h Wed Dec 8 19:53:34 1999
++++ thttpd-2.10-php/libhttpd.h Mon Dec 20 01:06:09 1999
+@@ -57,6 +57,7 @@
+ struct in_addr host_addr;
+ int port;
+ char* cgi_pattern;
++ char* php_pattern;
+ char* cwd;
+ int listen_fd;
+ FILE* logfp;