]> granicus.if.org Git - php/commitdiff
New SAPI module for Continuity HTTP server (ashpool.com)
authorAlex Leigh <aleigh@php.net>
Mon, 8 Dec 2003 16:54:18 +0000 (16:54 +0000)
committerAlex Leigh <aleigh@php.net>
Mon, 8 Dec 2003 16:54:18 +0000 (16:54 +0000)
sapi/continuity/CREDITS [new file with mode: 0644]
sapi/continuity/capi.c [new file with mode: 0644]
sapi/continuity/config.m4 [new file with mode: 0644]

diff --git a/sapi/continuity/CREDITS b/sapi/continuity/CREDITS
new file mode 100644 (file)
index 0000000..12cab23
--- /dev/null
@@ -0,0 +1,2 @@
+CAPI
+Alex Leigh
diff --git a/sapi/continuity/capi.c b/sapi/continuity/capi.c
new file mode 100644 (file)
index 0000000..078ffc5
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 4                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2003 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: Alex Leigh <aleigh at tessier dot com>                       |
+   +----------------------------------------------------------------------+
+*/
+
+/* For more information on Continuity: http://www.ashpool.com/ */
+
+/*
+ * This code is based on the PHP4 SAPI module for NSAPI by Jayakumar
+ * Muthukumarasamy
+ */
+
+/* PHP includes */
+#define CONTINUITY 1
+#define CAPI_DEBUG
+
+/* Define for CDP specific extensions */
+#undef CONTINUITY_CDPEXT
+
+#include "php.h"
+#include "php_variables.h"
+#include "ext/standard/info.h"
+#include "php_ini.h"
+#include "php_globals.h"
+#include "SAPI.h"
+#include "php_main.h"
+#include "php_version.h"
+#include "TSRM.h"
+#include "ext/standard/php_standard.h"
+
+/*
+ * If neither XP_UNIX not XP_WIN32 is defined, try to guess which one.
+ * Ideally, this should be done by the configure script.
+ */
+#if !defined(XP_UNIX) && !defined(XP_WIN32)
+#if defined(WIN32)
+#define XP_WIN32
+#else
+#define XP_UNIX
+#endif
+#endif
+
+/*
+ * CAPI includes
+ */
+#include <continuity.h>
+#include <http.h>
+
+#define NSLS_D         struct capi_request_context *request_context
+#define NSLS_DC                , NSLS_D
+#define NSLS_C         request_context
+#define NSLS_CC                , NSLS_C
+#define NSG(v)         (request_context->v)
+
+/*
+ * ZTS needs to be defined for CAPI to work
+ */
+#if !defined(ZTS)
+#error "CAPI module needs ZTS to be defined"
+#endif
+
+/*
+ * Structure to encapsulate the CAPI request in SAPI
+ */
+typedef struct capi_request_context {
+   httpTtrans *t;
+   int read_post_bytes;
+} capi_request_context;
+
+/**************/
+
+PHP_MINIT_FUNCTION(continuity);
+PHP_MSHUTDOWN_FUNCTION(continuity);
+PHP_RINIT_FUNCTION(continuity);
+PHP_RSHUTDOWN_FUNCTION(continuity);
+PHP_MINFO_FUNCTION(continuity);
+        
+PHP_FUNCTION(continuity_virtual);
+PHP_FUNCTION(continuity_request_headers);
+PHP_FUNCTION(continuity_response_headers);
+
+function_entry continuity_functions[] = {
+        {NULL, NULL, NULL}
+};
+
+zend_module_entry continuity_module_entry = {
+        STANDARD_MODULE_HEADER,
+        "continuity",
+        continuity_functions,   
+        PHP_MINIT(continuity),
+        PHP_MSHUTDOWN(continuity),
+        NULL,
+        NULL,
+        PHP_MINFO(continuity),
+        "$Revision$",
+        STANDARD_MODULE_PROPERTIES
+};
+
+PHP_MINIT_FUNCTION(continuity)
+{
+        return SUCCESS;
+}
+
+PHP_MSHUTDOWN_FUNCTION(continuity)
+{
+        return SUCCESS;
+}
+
+PHP_MINFO_FUNCTION(continuity)
+{
+        php_info_print_table_start();
+        php_info_print_table_row(2, "Continuity Module Version", continuity_module_entry.version);
+        php_info_print_table_row(2, "Server Version", conFget_build());
+#ifdef CONTINUITY_CDPEXT
+       php_info_print_table_row(2,"CDP Extensions", "enabled");
+#else
+       php_info_print_table_row(2,"CDP Extensions", "disabled");
+#endif
+        php_info_print_table_end();
+        
+/*        DISPLAY_INI_ENTRIES(); */
+}
+
+/**************/
+
+/*
+ * sapi_capi_ub_write: Write len bytes to the connection output.
+ */
+static int sapi_capi_ub_write(const char *str, unsigned int str_length TSRMLS_DC)
+{
+   int retval;
+   capi_request_context *rc;
+
+   rc = (capi_request_context *) SG(server_context);
+   retval = httpFwrite(rc->t, (char *) str, str_length);
+   if (retval == -1 || retval == 0)
+      php_handle_aborted_connection();
+   return retval;
+}
+
+/*
+ * sapi_capi_header_handler: Add/update response headers with those provided
+ * by the PHP engine.
+ */
+static int sapi_capi_header_handler(sapi_header_struct * sapi_header, sapi_headers_struct * sapi_headers TSRMLS_DC)
+{
+   char *header_name, *header_content, *p;
+   capi_request_context *rc = (capi_request_context *) SG(server_context);
+
+   lstFset_delete_key(rc->t->res_hdrs, "content-type");
+
+   header_name = sapi_header->header;
+   header_content = p = strchr(header_name, ':');
+   if (p == NULL) {
+      return 0;
+   }
+   *p = 0;
+   do {
+      header_content++;
+   } while (*header_content == ' ');
+
+   lstFset_add(rc->t->res_hdrs, header_name, header_content);
+
+   *p = ':';                   /* restore '*p' */
+
+   efree(sapi_header->header);
+
+   return 0;                   /* don't use the default SAPI mechanism, CAPI
+                                * duplicates this functionality */
+}
+
+/*
+ * sapi_capi_send_headers: Transmit the headers to the client. This has the
+ * effect of starting the response under Continuity.
+ */
+static int sapi_capi_send_headers(sapi_headers_struct * sapi_headers TSRMLS_DC)
+{
+   int retval;
+   capi_request_context *rc = (capi_request_context *) SG(server_context);
+
+   /*
+    * We could probably just do this in the header_handler. But, I don't know
+    * what the implication of doing it there is.
+    */
+
+   if (SG(sapi_headers).send_default_content_type) {
+      /* lstFset_delete_key(rc->t->res_hdrs, "content-type"); */
+      lstFset_update(rc->t->res_hdrs, "content-type", "text/html");
+   }
+   httpFset_status(rc->t, SG(sapi_headers).http_response_code, NULL);
+   httpFstart_response(rc->t);
+
+   return SAPI_HEADER_SENT_SUCCESSFULLY;
+
+}
+
+static int sapi_capi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
+{
+   unsigned int max_read, total_read = 0;
+   capi_request_context *rc = (capi_request_context *) SG(server_context);
+
+   if (rc->read_post_bytes == -1) {
+      max_read = MIN(count_bytes, SG(request_info).content_length);
+   } else {
+      if (rc->read_post_bytes == 0)
+        return 0;
+      max_read = MIN(count_bytes, (SG(request_info).content_length - rc->read_post_bytes));
+   }
+
+   total_read = httpFread(rc->t, buffer, max_read);
+
+   if (total_read < 0)
+      total_read = -1;
+   else
+      rc->read_post_bytes = total_read;
+
+   return total_read;
+}
+
+/*
+ * sapi_capi_read_cookies: Return cookie information into PHP.
+ */
+static char *sapi_capi_read_cookies(TSRMLS_D)
+{
+   char *cookie_string;
+   capi_request_context *rc = (capi_request_context *) SG(server_context);
+
+   cookie_string = lstFset_get(rc->t->req_hdrs, "cookie");
+   return cookie_string;
+}
+
+static void sapi_capi_register_server_variables(zval * track_vars_array TSRMLS_DC)
+{
+   capi_request_context *rc = (capi_request_context *) SG(server_context);
+   size_t i;
+   char *value;
+   char buf[128];
+
+   /* PHP_SELF and REQUEST_URI */
+   value = lstFset_get(rc->t->vars, "uri");
+   if (value != NULL) {
+      php_register_variable("PHP_SELF", value, track_vars_array TSRMLS_CC);
+      php_register_variable("REQUEST_URI", value, track_vars_array TSRMLS_CC);
+   }
+/* COUNTRY CODE */
+   value = lstFset_get(rc->t->vars, "ccode");
+   if(value!=NULL)
+     php_register_variable("COUNTRY_CODE", value, track_vars_array TSRMLS_CC);
+
+   /* argv */
+   value = lstFset_get(rc->t->vars, "query");
+   if (value != NULL)
+      php_register_variable("argv", value, track_vars_array TSRMLS_CC);
+
+   /* GATEWAY_INTERFACE */
+   php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
+
+   /* SERVER_NAME and HTTP_HOST */
+   value = lstFset_get(rc->t->req_hdrs, "host");
+   if (value != NULL) {
+      php_register_variable("HTTP_HOST", value, track_vars_array TSRMLS_CC);
+      /* TODO: This should probably scrub the port value if one is present. */
+      php_register_variable("SERVER_NAME", value, track_vars_array TSRMLS_CC);
+   }
+   /* SERVER_SOFTWARE */
+   value = lstFset_get(rc->t->res_hdrs, "server");
+   if (value != NULL)
+      php_register_variable("SERVER_SOFTWARE", value, track_vars_array TSRMLS_CC);
+
+   /* SERVER_PROTOCOL */
+   value = lstFset_get(rc->t->vars, "protocol");
+   if (value != NULL)
+      php_register_variable("SERVER_PROTOCOL", value, track_vars_array TSRMLS_CC);
+
+   /* REQUEST_METHOD */
+   value = lstFset_get(rc->t->vars, "method");
+   if (value != NULL)
+      php_register_variable("REQUEST_METHOD", value, track_vars_array TSRMLS_CC);
+
+   /* QUERY_STRING */
+   value = lstFset_get(rc->t->vars, "query");
+   if (value != NULL)
+      php_register_variable("QUERY_STRING", value, track_vars_array TSRMLS_CC);
+
+   /* DOCUMENT_ROOT */
+   value = lstFset_get(rc->t->vars, "docroot");
+   if (value != NULL)
+      php_register_variable("DOCUMENT_ROOT", value, track_vars_array TSRMLS_CC);
+
+   /* HTTP_ACCEPT */
+   value = lstFset_get(rc->t->req_hdrs, "accept");
+   if (value != NULL)
+      php_register_variable("HTTP_ACCEPT", value, track_vars_array TSRMLS_CC);
+
+   /* HTTP_ACCEPT_CHARSET */
+   value = lstFset_get(rc->t->req_hdrs, "accept-charset");
+   if (value != NULL)
+      php_register_variable("HTTP_ACCEPT_CHARSET", value, track_vars_array TSRMLS_CC);
+
+   /* HTTP_ACCEPT_ENCODING */
+   value = lstFset_get(rc->t->req_hdrs, "accept-encoding");
+   if (value != NULL)
+      php_register_variable("HTTP_ACCEPT_ENCODING", value, track_vars_array TSRMLS_CC);
+
+   /* HTTP_ACCEPT_LANGUAGE */
+   value = lstFset_get(rc->t->req_hdrs, "accept-language");
+   if (value != NULL)
+      php_register_variable("HTTP_ACCEPT_LANGUAGE", value, track_vars_array TSRMLS_CC);
+
+   /* HTTP_CONNECTION */
+   value = lstFset_get(rc->t->req_hdrs, "connection");
+   if (value != NULL)
+      php_register_variable("HTTP_CONNECTION", value, track_vars_array TSRMLS_CC);
+
+   /* HTTP_REFERER */
+   value = lstFset_get(rc->t->req_hdrs, "referer");
+   if (value != NULL)
+      php_register_variable("HTTP_REFERER", value, track_vars_array TSRMLS_CC);
+
+   /* HTTP_USER_AGENT */
+   value = lstFset_get(rc->t->req_hdrs, "user-agent");
+   if (value != NULL)
+      php_register_variable("HTTP_USER_AGENT", value, track_vars_array TSRMLS_CC);
+
+   /* REMOTE_ADDR */
+   utlFip_to_str(rc->t->cli_ipv4_addr, buf, sizeof(buf));
+   php_register_variable("REMOTE_ADDR", buf, track_vars_array TSRMLS_CC);
+
+   /* REMOTE_PORT */
+
+   /* SCRIPT_FILENAME and PATH_TRANSLATED */
+   value = lstFset_get(rc->t->vars, "path");
+   if (value != NULL) {
+      php_register_variable("SCRIPT_FILENAME", value, track_vars_array TSRMLS_CC);
+      php_register_variable("PATH_TRANSLATED", value, track_vars_array TSRMLS_CC);
+   }
+   /* SERVER_ADMIN */
+   /* Not applicable */
+
+   /* SERVER_PORT */
+
+}
+
+static void capi_log_message(char *message)
+{
+   TSRMLS_FETCH();
+   capi_request_context *rc = (capi_request_context *) SG(server_context);
+   logFmsg(0, "mod/php: %s", message);
+}
+
+static int php_capi_startup(sapi_module_struct *sapi_module);
+
+sapi_module_struct capi_sapi_module = {
+   "Continuity",                       /* name */
+   "Continuity Server Enterprise Edition",     /* pretty name */
+
+   php_capi_startup,           /* startup */
+   php_module_shutdown_wrapper,        /* shutdown */
+
+   NULL,                       /* activate */
+   NULL,                       /* deactivate */
+
+   sapi_capi_ub_write,         /* unbuffered write */
+   NULL,                       /* flush */
+   NULL,                       /* get uid */
+   NULL,                       /* getenv */
+
+   php_error,                  /* error handler */
+
+   sapi_capi_header_handler,   /* header handler */
+   sapi_capi_send_headers,     /* send headers handler */
+   NULL,                       /* send header handler */
+
+   sapi_capi_read_post,                /* read POST data */
+   sapi_capi_read_cookies,     /* read Cookies */
+
+   sapi_capi_register_server_variables,        /* register server variables */
+   capi_log_message,           /* Log message */
+
+   NULL,                       /* Block interruptions */
+   NULL,                       /* Unblock interruptions */
+
+   STANDARD_SAPI_MODULE_PROPERTIES
+};
+
+static int php_capi_startup(sapi_module_struct *sapi_module) {
+  if(php_module_startup(sapi_module,&continuity_module_entry,1)==FAILURE) {
+    return FAILURE;
+  }
+  return SUCCESS;
+}
+
+
+static char *
+ capi_strdup(char *str)
+{
+   if (str != NULL)
+      return strFcopy(str);
+   return NULL;
+}
+
+static void capi_free(void *addr)
+{
+   if (addr != NULL)
+      free(addr);
+}
+
+static void capi_request_ctor(NSLS_D TSRMLS_DC)
+{
+   char *query_string = lstFset_get(NSG(t->vars), "query");
+   char *uri = lstFset_get(NSG(t->vars), "uri");
+   char *path_info = lstFset_get(NSG(t->vars), "path-info");
+   char *path_translated = lstFset_get(NSG(t->vars), "path");
+   char *request_method = lstFset_get(NSG(t->vars), "method");
+   char *content_type = lstFset_get(NSG(t->req_hdrs), "content-type");
+   char *content_length = lstFset_get(NSG(t->req_hdrs), "content-length");
+
+   SG(request_info).query_string = capi_strdup(query_string);
+   SG(request_info).request_uri = capi_strdup(uri);
+   SG(request_info).request_method = capi_strdup(request_method);
+   SG(request_info).path_translated = capi_strdup(path_translated);
+   SG(request_info).content_type = capi_strdup(content_type);
+   SG(request_info).content_length = (content_length == NULL) ? 0 : strtoul(content_length, 0, 0);
+   SG(sapi_headers).http_response_code = 200;
+}
+
+static void capi_request_dtor(NSLS_D TSRMLS_DC)
+{
+   capi_free(SG(request_info).query_string);
+   capi_free(SG(request_info).request_uri);
+   capi_free(SG(request_info).request_method);
+   capi_free(SG(request_info).path_translated);
+   capi_free(SG(request_info).content_type);
+}
+
+int capi_module_main(NSLS_D TSRMLS_DC)
+{
+   zend_file_handle file_handle;
+
+   if (php_request_startup(TSRMLS_C) == FAILURE) {
+      return FAILURE;
+   }
+   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);
+
+   return SUCCESS;
+}
+
+void php4_close(void *vparam)
+{
+   if (capi_sapi_module.shutdown) {
+      capi_sapi_module.shutdown(&capi_sapi_module);
+   }
+   tsrm_shutdown();
+}
+
+int phpFinit(lstTset * opt)
+{
+   php_core_globals *core_globals;
+
+   tsrm_startup(128, 1, 0, NULL);
+   core_globals = ts_resource(core_globals_id);
+
+   logFmsg(0, "mod/php: PHP Interface v3 (module)");
+   logFmsg(0, "mod/php: Copyright (c) 1999, 2000 The PHP Group. All rights reserved.");
+
+   sapi_startup(&capi_sapi_module);
+   capi_sapi_module.startup(&capi_sapi_module);
+
+   return STATUS_PROCEED;
+}
+
+int phpFservice(httpTtrans * t, lstTset * opts)
+{
+   int retval;
+   capi_request_context *request_context;
+
+   TSRMLS_FETCH();
+
+   request_context = (capi_request_context *) malloc(sizeof(capi_request_context));
+   request_context->t = t;
+   request_context->read_post_bytes = -1;
+
+   SG(server_context) = request_context;
+
+   capi_request_ctor(NSLS_C TSRMLS_CC);
+   retval = capi_module_main(NSLS_C TSRMLS_CC);
+   capi_request_dtor(NSLS_C TSRMLS_CC);
+
+   free(request_context);
+
+   /*
+    * This call is ostensibly provided to free the memory from PHP/TSRM when
+    * the thread terminated, but, it leaks a structure in some hash list
+    * according to the developers. Not calling this will leak the entire
+    * interpreter, around 100k, but calling it and then terminating the
+    * thread will leak the struct (around a k). The only answer with the
+    * current TSRM implementation is to reuse the threads that allocate TSRM
+    * resources.
+    */
+   /* ts_free_thread(); */
+
+   if (retval == SUCCESS) {
+      return STATUS_EXIT;
+   } else {
+      return STATUS_ERROR;
+   }
+}
diff --git a/sapi/continuity/config.m4 b/sapi/continuity/config.m4
new file mode 100644 (file)
index 0000000..e95f2b4
--- /dev/null
@@ -0,0 +1,35 @@
+dnl ## $Id$ -*- sh -*-
+
+AC_MSG_CHECKING(for Continuity support)
+AC_ARG_WITH(continuity,
+[  --with-continuity=DIR        Specify path to the installed Continuity Server],[
+  PHP_CONTINUITY=$withval
+],[
+  PHP_CONTINUITY=no
+])
+AC_MSG_RESULT($PHP_CONTINUITY)
+
+if test "$PHP_CONTINUITY" != "no"; then
+
+  if test ! -d $PHP_CONTINUITY; then
+    AC_MSG_ERROR(Please specify the path to the root of your Continuity server using --with-continuity=DIR)
+  fi
+  AC_MSG_CHECKING(for Continuity include files)
+  if test -d $PHP_CONTINUITY/include ; then
+    CAPI_INCLUDE=$PHP_CONTINUITY/include
+    AC_MSG_RESULT(Continuity Binary Distribution)
+  else
+    AC_MSG_ERROR(Cannot find your CAPI include files in either DIR/src or DIR/include)
+  fi
+
+  PHP_SELECT_SAPI(continuity,shared,capi.c)
+  PHP_ADD_INCLUDE($CAPI_INCLUDE)
+  PHP_BUILD_THREAD_SAFE
+  AC_DEFINE(HAVE_CONTINUITY,1,[Whether you have a Continuity Server])
+  INSTALL_IT="\$(INSTALL) -m 0755 $SAPI_SHARED \$(INSTALL_ROOT)$PHP_CONTINUITY/lib/"
+fi
+
+
+dnl ## Local Variables:
+dnl ## tab-width: 4
+dnl ## End: