summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sapi/nsapi/Makefile.in5
-rw-r--r--sapi/nsapi/config.m426
-rw-r--r--sapi/nsapi/nsapi.c522
3 files changed, 553 insertions, 0 deletions
diff --git a/sapi/nsapi/Makefile.in b/sapi/nsapi/Makefile.in
new file mode 100644
index 0000000000..8299911313
--- /dev/null
+++ b/sapi/nsapi/Makefile.in
@@ -0,0 +1,5 @@
+
+LTLIBRARY_NAME = libsapi.la
+LTLIBRARY_SOURCES = nsapi.c
+
+include $(top_srcdir)/build/ltlib.mk
diff --git a/sapi/nsapi/config.m4 b/sapi/nsapi/config.m4
new file mode 100644
index 0000000000..202e4ad9f8
--- /dev/null
+++ b/sapi/nsapi/config.m4
@@ -0,0 +1,26 @@
+dnl ## $Id$ -*- sh -*-
+
+AC_MSG_CHECKING(for NSAPI support)
+AC_ARG_WITH(nsapi,
+[ --with-nsapi=DIR Specify path to the installed Netscape],[
+ PHP_NSAPI=$withval
+],[
+ PHP_NSAPI=no
+])
+AC_MSG_RESULT($PHP_NSAPI)
+
+if test "$PHP_NSAPI" != "no"; then
+ if test ! -d $PHP_NSAPI/bin ; then
+ AC_MSG_ERROR(Please specify the path to the root of your Netscape server using --with-nsapi=DIR)
+ fi
+ PHP_BUILD_THREAD_SAFE
+ AC_ADD_INCLUDE($PHP_NSAPI/include)
+ AC_DEFINE(HAVE_NSAPI,1,[Whether you have a Netscape Server])
+ PHP_SAPI=nsapi
+ PHP_BUILD_SHARED
+ INSTALL_IT="\$(INSTALL) -m 0755 $SAPI_SHARED $PHP_NSAPI/bin/"
+fi
+
+dnl ## Local Variables:
+dnl ## tab-width: 4
+dnl ## End:
diff --git a/sapi/nsapi/nsapi.c b/sapi/nsapi/nsapi.c
new file mode 100644
index 0000000000..3ceb29c0ae
--- /dev/null
+++ b/sapi/nsapi/nsapi.c
@@ -0,0 +1,522 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.01 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_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: Jayakumar Muthukumarasamy <jk@kasenna.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/*
+ * PHP includes
+ */
+#include "php.h"
+
+#include "ext/standard/info.h"
+
+#include "php_ini.h"
+#include "php_globals.h"
+#include "SAPI.h"
+#include "main.h"
+#include "php_version.h"
+
+/*
+ * NSAPI includes
+ */
+#include "nsapi.h"
+#include "base/pblock.h"
+#include "base/session.h"
+#include "frame/req.h"
+#include "frame/protocol.h" /* protocol_start_response */
+#include "base/util.h" /* is_mozilla, getline */
+#include "frame/log.h" /* log_error */
+
+/*
+ * Timeout for net_read(). This should probably go into php.ini
+ */
+#define NSAPI_READ_TIMEOUT 60 /* 60 seconds */
+
+#define NSLS_D struct nsapi_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)
+
+/*
+ * Currently, this doesn't work with ZTS.
+ */
+#if defined(ZTS)
+ #define IF_ZTS(a) a
+ #define IF_NOT_ZTS(a)
+#else
+ #define IF_ZTS(a)
+ #define IF_NOT_ZTS(a) a
+ static CRITICAL php_mutex;
+#endif
+
+/*
+ * Structure to encapsulate the NSAPI request in SAPI
+ */
+typedef struct nsapi_request_context {
+ pblock *pb;
+ Session *sn;
+ Request *rq;
+} nsapi_request_context;
+
+/*
+ * Mappings between NSAPI names and environment variables. This
+ * mapping was obtained from the sample programs at the iplanet
+ * website.
+ */
+typedef struct nsapi_equiv {
+ const char *env_var;
+ const char *nsapi_eq;
+} nsapi_equiv;
+
+static nsapi_equiv nsapi_headers[] = {
+ { "CONTENT_LENGTH", "content-length" },
+ { "CONTENT_TYPE", "content-type" },
+ { "HTTP_ACCEPT", "accept" },
+ { "HTTP_ACCEPT_ENCODING", "accept-encoding" },
+ { "HTTP_ACCEPT_LANGUAGE", "accept-language" },
+ { "HTTP_AUTHORIZATION", "authorization" },
+ { "HTTP_COOKIE", "cookie" },
+ { "HTTP_IF_MODIFIED_SINCE", "if-modified-since" },
+ { "HTTP_REFERER", "referer" },
+ { "HTTP_USER_AGENT", "user-agent" },
+ { "HTTP_USER_DEFINED", "user-defined" }
+};
+static size_t nsapi_headers_size = sizeof(nsapi_headers)/sizeof(nsapi_headers[0]);
+
+static nsapi_equiv nsapi_reqpb[] = {
+ { "QUERY_STRING", "query" },
+ { "REQUEST_LINE", "clf-request" },
+ { "REQUEST_METHOD", "method" },
+ { "SCRIPT_NAME", "uri" },
+ { "SCRIPT_PROTOCOL", "protocol" }
+};
+static size_t nsapi_reqpb_size = sizeof(nsapi_reqpb)/sizeof(nsapi_reqpb[0]);
+
+static nsapi_equiv nsapi_vars[] = {
+ { "AUTH_TYPE", "auth-type" },
+ { "PATH_INFO", "path-info" },
+ { "REMOTE_USER", "auth-user" }
+};
+static size_t nsapi_vars_size = sizeof(nsapi_vars)/sizeof(nsapi_vars[0]);
+
+static nsapi_equiv nsapi_client[] = {
+ { "HTTPS_KEYSIZE", "keysize" },
+ { "HTTPS_SECRETSIZE", "secret-keysize" },
+ { "REMOTE_ADDR", "ip" }
+};
+static size_t nsapi_client_size = sizeof(nsapi_client)/sizeof(nsapi_client[0]);
+
+static int
+sapi_nsapi_ub_write(const char *str, unsigned int str_length)
+{
+ int retval;
+ nsapi_request_context *rc;
+
+ SLS_FETCH();
+ rc = (nsapi_request_context *)SG(server_context);
+ retval = net_write(rc->sn->csd, str, str_length);
+ if (retval == IO_ERROR /*-1*/ || retval == IO_EOF /*0*/)
+ return -1;
+ else
+ return retval;
+}
+
+static int
+sapi_nsapi_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers SLS_DC)
+{
+ char *header_name, *header_content, *p;
+ nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
+
+ header_name = sapi_header->header;
+ header_content = p = strchr(header_name, ':');
+ if (p == NULL) {
+ return 0;
+ }
+
+ *p = 0;
+ do {
+ header_content++;
+ } while (*header_content==' ');
+
+ if (!strcasecmp(header_name, "Content-Type")) {
+ param_free(pblock_remove("content-type", rc->rq->srvhdrs));
+ pblock_nvinsert("content-type", header_content, rc->rq->srvhdrs);
+ } else if (!strcasecmp(header_name, "Set-Cookie")) {
+ pblock_nvinsert("set-cookie", header_content, rc->rq->srvhdrs);
+ } else {
+ pblock_nvinsert(header_name, header_content, rc->rq->srvhdrs);
+ }
+
+ *p = ':'; /* restore '*p' */
+
+ efree(sapi_header->header);
+
+ return 0; /* don't use the default SAPI mechanism, NSAPI duplicates this functionality */
+}
+
+static int
+sapi_nsapi_send_headers(sapi_headers_struct *sapi_headers SLS_DC)
+{
+ int retval;
+ nsapi_request_context *rc = (nsapi_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) {
+ param_free(pblock_remove("content-type", rc->rq->srvhdrs));
+ pblock_nvinsert("content-type", "text/html", rc->rq->srvhdrs);
+ }
+
+ protocol_status(rc->sn, rc->rq, SG(sapi_headers).http_response_code, NULL);
+ retval = protocol_start_response(rc->sn, rc->rq);
+ if (retval == REQ_PROCEED || retval == REQ_NOACTION)
+ return SAPI_HEADER_SENT_SUCCESSFULLY;
+ else
+ return SAPI_HEADER_SEND_FAILED;
+}
+
+static int
+sapi_nsapi_read_post(char *buffer, uint count_bytes SLS_DC)
+{
+ nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
+ char *read_ptr = buffer, *content_length_str = NULL;
+ uint bytes_read = 0;
+ int length, content_length = 0;
+ netbuf *nbuf = rc->sn->inbuf;
+
+ /*
+ * Determine the content-length. This will tell us the limit we can read.
+ */
+ content_length_str = pblock_findval("content-length", rc->rq->headers);
+ if (content_length_str != NULL) {
+ content_length = strtol(content_length_str, 0, 0);
+ }
+
+ if (content_length <= 0)
+ return 0;
+
+ /*
+ * Gobble any pending data in the netbuf.
+ */
+ length = nbuf->cursize - nbuf->pos;
+ if (length > 0) {
+ memcpy(read_ptr, nbuf->inbuf + nbuf->pos, length);
+ bytes_read += length;
+ read_ptr += length;
+ content_length -= length;
+ }
+
+ /*
+ * Read the remaining from the socket.
+ */
+ while (content_length > 0 && bytes_read < count_bytes) {
+ int bytes_to_read = count_bytes - bytes_read;
+ if (content_length < bytes_to_read)
+ bytes_to_read = content_length;
+
+ length = net_read(rc->sn->csd, read_ptr, bytes_to_read, NSAPI_READ_TIMEOUT);
+ if (length == IO_ERROR || length == IO_EOF)
+ break;
+
+ bytes_read += length;
+ read_ptr += length;
+ content_length -= length;
+ }
+
+ return bytes_read;
+}
+
+static char *
+sapi_nsapi_read_cookies(SLS_D)
+{
+ char *cookie_string;
+ nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
+
+ cookie_string = pblock_findval("cookie", rc->rq->headers);
+ return cookie_string;
+}
+
+static sapi_module_struct nsapi_sapi_module = {
+ "NSAPI", /* name */
+
+ php_module_startup, /* startup */
+ php_module_shutdown_wrapper, /* shutdown */
+
+ NULL, /* activate */
+ NULL, /* deactivate */
+
+ sapi_nsapi_ub_write, /* unbuffered write */
+ NULL, /* flush */
+ NULL, /* get uid */
+ NULL, /* getenv */
+
+ php_error, /* error handler */
+
+ sapi_nsapi_header_handler, /* header handler */
+ sapi_nsapi_send_headers, /* send headers handler */
+ NULL, /* send header handler */
+
+ sapi_nsapi_read_post, /* read POST data */
+ sapi_nsapi_read_cookies, /* read Cookies */
+
+ NULL, /* register server variables */
+ NULL, /* Log message */
+
+ NULL, /* Block interruptions */
+ NULL, /* Unblock interruptions */
+
+ STANDARD_SAPI_MODULE_PROPERTIES
+};
+
+static char *
+nsapi_strdup(char *str)
+{
+ if (str != NULL)
+ return strdup(str);
+ return NULL;
+}
+
+static void
+nsapi_free(void *addr)
+{
+ if (addr != NULL)
+ free(addr);
+}
+
+/*
+ * Add symbols to the interpreter.
+ */
+static void
+nsapi_add_string(const char *name, const char *buf)
+{
+ zval *pval;
+ ELS_FETCH();
+
+ if (buf == NULL)
+ buf = "";
+
+ 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, strlen(name) + 1, &pval, sizeof(zval *), NULL);
+}
+
+static void
+nsapi_hash_environment(NSLS_D SLS_DC)
+{
+ size_t i;
+ const char *remote_host = NULL, *server_url = NULL, *path_translated = NULL;
+ char *value = NULL, buf[128];
+
+ remote_host = session_dns(NSG(sn));
+ server_url = http_uri2url("", "");
+ path_translated = SG(request_info).path_translated;
+
+ *buf = 0;
+
+ for (i = 0; i < nsapi_headers_size; i++) {
+ if ((value = pblock_findval(nsapi_headers[i].nsapi_eq, NSG(rq)->headers)) == NULL) {
+ value = buf;
+ }
+ nsapi_add_string(nsapi_headers[i].env_var, value);
+ }
+
+ for (i = 0; i < nsapi_reqpb_size; i++) {
+ if ((value = pblock_findval(nsapi_reqpb[i].nsapi_eq, NSG(rq)->reqpb)) == NULL) {
+ value = buf;
+ }
+ nsapi_add_string(nsapi_reqpb[i].env_var, value);
+ }
+
+ for (i = 0; i < nsapi_vars_size; i++) {
+ if ((value = pblock_findval(nsapi_vars[i].nsapi_eq, NSG(rq)->vars)) == NULL) {
+ value = buf;
+ }
+ nsapi_add_string(nsapi_vars[i].env_var, value);
+ }
+
+ for (i = 0; i < nsapi_client_size; i++) {
+ if ((value = pblock_findval(nsapi_client[i].nsapi_eq, NSG(sn)->client)) == NULL) {
+ value = buf;
+ }
+ nsapi_add_string(nsapi_client[i].env_var, value);
+ }
+
+ sprintf(buf, "%d", conf_getglobals()->Vport);
+ nsapi_add_string("SERVER_PORT", buf);
+
+ nsapi_add_string("HTTPS", (security_active ? "ON" : "OFF"));
+ nsapi_add_string("SERVER_NAME", server_hostname);
+ nsapi_add_string("REMOTE_HOST", remote_host);
+ nsapi_add_string("SERVER_URL", server_url);
+/* nsapi_add_string("SERVER_SOFTWARE", MAGNUS_VERSION_STRING); */
+ nsapi_add_string("PATH_TRANSLATED", path_translated);
+}
+
+static void
+nsapi_request_ctor(NSLS_D SLS_DC)
+{
+ char *query_string = pblock_findval("query", NSG(rq)->reqpb);
+ char *uri = pblock_findval("uri", NSG(rq)->reqpb);
+ char *path_info = pblock_findval("path-info", NSG(rq)->vars);
+ char *path_translated = NULL;
+ char *request_method = pblock_findval("method", NSG(rq)->reqpb);
+ char *content_type = pblock_findval("content-type", NSG(rq)->headers);
+ char *content_length = pblock_findval("content-length", NSG(rq)->headers);
+
+ if (uri != NULL)
+ path_translated = request_translate_uri(uri, NSG(sn));
+
+#if 0
+ log_error(LOG_INFORM, "nsapi_request_ctor", NSG(sn), NSG(rq),
+ "query_string = %s, "
+ "uri = %s, "
+ "path_info = %s, "
+ "path_translated = %s, "
+ "request_method = %s, "
+ "content_type = %s, "
+ "content_length = %s",
+ query_string,
+ uri,
+ path_info,
+ path_translated,
+ request_method,
+ content_type,
+ content_length);
+#endif
+
+ SG(request_info).query_string = nsapi_strdup(query_string);
+ SG(request_info).request_uri = nsapi_strdup(path_info);
+ SG(request_info).request_method = nsapi_strdup(request_method);
+ SG(request_info).path_translated = nsapi_strdup(path_translated);
+ SG(request_info).content_type = nsapi_strdup(content_type);
+ SG(request_info).content_length = (content_length == NULL) ? 0 : strtoul(content_length, 0, 0);
+}
+
+static void
+nsapi_request_dtor(NSLS_D SLS_DC)
+{
+ nsapi_free(SG(request_info).query_string);
+ nsapi_free(SG(request_info).request_uri);
+ nsapi_free(SG(request_info).request_method);
+ nsapi_free(SG(request_info).path_translated);
+ nsapi_free(SG(request_info).content_type);
+}
+
+static int
+nsapi_module_main(NSLS_D SLS_DC)
+{
+ int result;
+ zend_file_handle file_handle;
+
+ CLS_FETCH();
+ ELS_FETCH();
+ PLS_FETCH();
+
+ if (php_request_startup(CLS_C ELS_CC PLS_CC SLS_CC) == FAILURE) {
+ return FAILURE;
+ }
+
+ file_handle.type = ZEND_HANDLE_FILENAME;
+ file_handle.filename = SG(request_info).path_translated;
+ file_handle.free_filename = 0;
+
+#if 0
+ log_error(LOG_INFORM, "nsapi_module_main", NSG(sn), NSG(rq),
+ "Parsing [%s]", SG(request_info).path_translated);
+#endif
+
+ result = php_request_startup(CLS_C ELS_CC PLS_CC SLS_CC);
+ if (result == FAILURE) {
+ return FAILURE;
+ }
+
+ nsapi_hash_environment(NSLS_C SLS_CC);
+ php_execute_script(&file_handle CLS_CC ELS_CC PLS_CC);
+ php_request_shutdown(NULL);
+
+ return SUCCESS;
+}
+
+int
+php4_init(pblock *pb, Session *sn, Request *rq)
+{
+ PLS_FETCH();
+
+ /*
+ * TSRM has not been tested.
+ */
+ IF_ZTS(
+ tsrm_startup(1, 1, 0);
+ )
+
+ sapi_startup(&nsapi_sapi_module);
+ sapi_module.startup(&nsapi_sapi_module);
+
+ PG(expose_php) = 0;
+
+ IF_NOT_ZTS(
+ php_mutex = crit_init();
+ )
+
+ log_error(LOG_INFORM, "php4_init", sn, rq, "Initialized PHP Module\n");
+ return REQ_PROCEED;
+}
+
+int
+php4_execute(pblock *pb, Session *sn, Request *rq)
+{
+ int retval;
+ nsapi_request_context *request_context;
+
+ SLS_FETCH();
+
+ request_context = (nsapi_request_context *)malloc(sizeof(nsapi_request_context));
+ request_context->pb = pb;
+ request_context->sn = sn;
+ request_context->rq = rq;
+
+ /*
+ * Single thread the execution, if ZTS is not enabled. Need to
+ * understand the behavior of Netscape server when the client
+ * cancels a request when it is in progress. This could cause
+ * a deadlock if the thread handling the specific client is not
+ * cancelled because the php_mutex will likely remain locked
+ * until the request that was cancelled completes. The behavior
+ * is also going to be platform specific.
+ */
+ IF_NOT_ZTS(
+ crit_enter(php_mutex);
+ )
+
+ SG(server_context) = request_context;
+
+ nsapi_request_ctor(NSLS_C SLS_CC);
+ retval = nsapi_module_main(NSLS_C SLS_CC);
+ nsapi_request_dtor(NSLS_C SLS_CC);
+
+ IF_NOT_ZTS(
+ crit_exit(php_mutex);
+ )
+
+ free(request_context);
+
+ return (retval == SUCCESS) ? REQ_PROCEED : REQ_EXIT;
+}