1
0
mirror of https://github.com/php/php-src.git synced 2026-04-08 16:43:44 +02:00
Files
archived-php-src/sapi/nsapi/nsapi.c
Anthony Whitehead c6449f307a Altered NSAPI autoconf to check for location of include files automatically, tested for Netscape 3.x and iPlanet 4.x.
Added very basic variable support for usefull things such as PHP_SELF. I'll extend this to supply this rest of the variables soon.
Commited a patch to activate ZTS in the NSAPI module, this patch comes from
Jayakumar Muthukumarasamy.
2000-05-30 13:20:18 +00:00

569 lines
15 KiB
C

/*
+----------------------------------------------------------------------+
| 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: Jayakumar Muthukumarasamy <jk@kasenna.com> |
+----------------------------------------------------------------------+
*/
/*
* PHP includes
*/
#define NSAPI 1
#define XP_UNIX
#include "php.h"
#include "php_variables.h"
#include "ext/standard/info.h"
#include "php_ini.h"
#include "php_globals.h"
#include "SAPI.h"
#include "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
/*
* 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 */
/* for unix */
#ifndef WINAPI
#define WINAPI
#endif
/*
* 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)
/*
* ZTS needs to be defined for NSAPI to work
*/
#if !defined(ZTS)
#error "NSAPI module needs ZTS to be defined"
#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, (char *)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 void
sapi_nsapi_register_server_variables(zval *track_vars_array ELS_DC SLS_DC PLS_DC)
{
nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
size_t i;
char *value = NULL;
char buf[128];
*buf = 0;
for (i = 0; i < nsapi_reqpb_size; i++) {
if ((value = pblock_findval(nsapi_reqpb[i].nsapi_eq, rc->rq->reqpb)) == NULL) {
value = buf;
}
php_register_variable( (char *)nsapi_reqpb[i].env_var, value, track_vars_array ELS_CC PLS_CC );
}
/*
* Special PHP_SELF variable.
*/
value = pblock_findval( "uri", rc->rq->reqpb );
if( value != NULL ) {
php_register_variable( "PHP_SELF", value, track_vars_array ELS_CC PLS_CC );
}
}
static sapi_module_struct 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 */
sapi_nsapi_register_server_variables, /* 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), (char *)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 defined(NSAPI_DEBUG)
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);
}
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 defined(NSAPI_DEBUG)
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;
}
void WINAPI
php4_close(void *vparam)
{
if (sapi_module.shutdown) {
sapi_module.shutdown(&sapi_module);
}
tsrm_shutdown();
}
int WINAPI
php4_init(pblock *pb, Session *sn, Request *rq)
{
php_core_globals *core_globals;
tsrm_startup(1, 1, 0);
core_globals = ts_resource(core_globals_id);
sapi_startup(&sapi_module);
sapi_module.startup(&sapi_module);
log_error(LOG_INFORM, "php4_init", sn, rq, "Initialized PHP Module\n");
return REQ_PROCEED;
}
int WINAPI
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;
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);
free(request_context);
return (retval == SUCCESS) ? REQ_PROCEED : REQ_EXIT;
}
/*********************************************************
/ authentication
/
/ we have to make a 'fake' authenticator for netscape so it
/ will pass authentication through to php, and allow us to
/ check authentication with our scripts.
/
/ php4_auth_trans
/ main function called from netscape server to authenticate
/ a line in obj.conf:
/ funcs=php4_auth_trans shlib="path/to/this/phpnsapi.dll"
/ and:
/ <Object ppath="path/to/be/authenticated/by/php/*">
/ AuthTrans fn="php4_auth_trans"
/*********************************************************/
int WINAPI
php4_auth_trans(pblock * pb, Session * sn, Request * rq)
{
/*This is a DO NOTHING function that allows authentication information
to be passed through to PHP scripts.*/
return REQ_PROCEED;
}