mirror of
https://github.com/php/php-src.git
synced 2024-11-29 21:04:10 +08:00
552 lines
15 KiB
C
552 lines
15 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| 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: Jayakumar Muthukumarasamy <jk@kasenna.com> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
/*
|
|
* PHP includes
|
|
*/
|
|
#define NSAPI 1
|
|
|
|
#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
|
|
|
|
/*
|
|
* 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)
|
|
|
|
/*
|
|
* 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;
|
|
int read_post_bytes;
|
|
} 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_ACCEPT_CHARSET", "accept-charset" },
|
|
{ "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" },
|
|
{ "SERVER_PROTOCOL", "protocol" }
|
|
};
|
|
static size_t nsapi_reqpb_size = sizeof(nsapi_reqpb)/sizeof(nsapi_reqpb[0]);
|
|
|
|
static nsapi_equiv nsapi_vars[] = {
|
|
{ "PATH_INFO", "path-info" },
|
|
{ "PATH_TRANSLATED", "path" },
|
|
{ "AUTH_TYPE", "auth-type" },
|
|
{ "CLIENT_CERT", "auth-cert" },
|
|
{ "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 TSRMLS_DC)
|
|
{
|
|
int retval;
|
|
nsapi_request_context *rc;
|
|
|
|
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*/)
|
|
php_handle_aborted_connection();
|
|
return retval;
|
|
}
|
|
|
|
static int
|
|
sapi_nsapi_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_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) {
|
|
efree(sapi_header->header);
|
|
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 TSRMLS_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 TSRMLS_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;
|
|
|
|
/*
|
|
* Yesss!
|
|
*/
|
|
count_bytes = MIN(count_bytes, SG(request_info).content_length-rc->read_post_bytes);
|
|
content_length = SG(request_info).content_length;
|
|
|
|
#if 0
|
|
/*
|
|
* 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);
|
|
}
|
|
#endif
|
|
|
|
if (content_length <= 0)
|
|
return 0;
|
|
|
|
/*
|
|
* Gobble any pending data in the netbuf.
|
|
*/
|
|
length = nbuf->cursize - nbuf->pos;
|
|
length = MIN(count_bytes, length);
|
|
if (length > 0) {
|
|
memcpy(read_ptr, nbuf->inbuf + nbuf->pos, length);
|
|
bytes_read += length;
|
|
read_ptr += length;
|
|
content_length -= length;
|
|
nbuf->pos += 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;
|
|
}
|
|
|
|
if ( bytes_read > 0 )
|
|
rc->read_post_bytes += bytes_read;
|
|
return bytes_read;
|
|
}
|
|
|
|
static char *sapi_nsapi_read_cookies(TSRMLS_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 TSRMLS_DC)
|
|
{
|
|
nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
|
|
size_t i;
|
|
char *value;
|
|
char buf[128];
|
|
|
|
for (i = 0; i < nsapi_reqpb_size; i++) {
|
|
value = pblock_findval(nsapi_reqpb[i].nsapi_eq, rc->rq->reqpb);
|
|
if (value) {
|
|
php_register_variable( (char *)nsapi_reqpb[i].env_var, value, track_vars_array TSRMLS_CC );
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < nsapi_headers_size; i++) {
|
|
value = pblock_findval(nsapi_headers[i].nsapi_eq, rc->rq->headers);
|
|
if (value) {
|
|
php_register_variable( (char *)nsapi_headers[i].env_var, value, track_vars_array TSRMLS_CC );
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < nsapi_vars_size; i++) {
|
|
value = pblock_findval(nsapi_vars[i].nsapi_eq, rc->rq->vars);
|
|
if (value) {
|
|
php_register_variable( (char *)nsapi_vars[i].env_var, value, track_vars_array TSRMLS_CC );
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < nsapi_client_size; i++) {
|
|
value = pblock_findval(nsapi_client[i].nsapi_eq, rc->sn->client);
|
|
if (value) {
|
|
php_register_variable( (char *)nsapi_client[i].env_var, value, track_vars_array TSRMLS_CC );
|
|
}
|
|
}
|
|
|
|
value = session_dns(rc->sn);
|
|
if (value) {
|
|
php_register_variable("REMOTE_HOST", value, track_vars_array TSRMLS_CC );
|
|
}
|
|
sprintf(buf, "%d", conf_getglobals()->Vport);
|
|
php_register_variable("SERVER_PORT", buf, track_vars_array TSRMLS_CC );
|
|
if ((value = util_hostname())) {
|
|
php_register_variable("SERVER_NAME", value, track_vars_array TSRMLS_CC );
|
|
}
|
|
php_register_variable("SERVER_URL", http_uri2url("", ""), track_vars_array TSRMLS_CC );
|
|
php_register_variable("HTTPS", (security_active ? "ON" : "OFF"), track_vars_array TSRMLS_CC );
|
|
/* php_register_variable("SERVER_SOFTWARE", MAGNUS_VERSION_STRING, track_vars_array TSRMLS_CC ); */
|
|
|
|
/*
|
|
* Special PHP_SELF variable.
|
|
*/
|
|
value = pblock_findval("uri", rc->rq->reqpb);
|
|
if ( value != NULL ) {
|
|
php_register_variable("PHP_SELF", value, track_vars_array TSRMLS_CC );
|
|
}
|
|
}
|
|
|
|
static void
|
|
nsapi_log_message(char *message)
|
|
{
|
|
TSRMLS_FETCH();
|
|
nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
|
|
log_error(LOG_INFORM, "PHP_log_message", rc->sn, rc->rq,
|
|
"%s", message);
|
|
}
|
|
|
|
|
|
static int php_nsapi_startup(sapi_module_struct *sapi_module)
|
|
{
|
|
if (php_module_startup(sapi_module, NULL, 0)==FAILURE) {
|
|
return FAILURE;
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
|
|
|
|
static sapi_module_struct nsapi_sapi_module = {
|
|
"nsapi", /* name */
|
|
"NSAPI", /* pretty name */
|
|
|
|
php_nsapi_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 */
|
|
nsapi_log_message, /* Log message */
|
|
|
|
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);
|
|
}
|
|
|
|
static void
|
|
nsapi_request_ctor(NSLS_D TSRMLS_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 = pblock_findval("path", NSG(rq)->vars);
|
|
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 ((path_translated == NULL) && (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(uri);
|
|
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);
|
|
SG(sapi_headers).http_response_code = 200;
|
|
}
|
|
|
|
static void
|
|
nsapi_request_dtor(NSLS_D TSRMLS_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 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;
|
|
|
|
#if defined(NSAPI_DEBUG)
|
|
log_error(LOG_INFORM, "nsapi_module_main", NSG(sn), NSG(rq),
|
|
"Parsing [%s]", SG(request_info).path_translated);
|
|
#endif
|
|
|
|
php_execute_script(&file_handle TSRMLS_CC);
|
|
php_request_shutdown(NULL);
|
|
|
|
#if defined(NSAPI_DEBUG)
|
|
log_error(LOG_INFORM, "nsapi_module_main", NSG(sn), NSG(rq),
|
|
"PHP request finished Ok");
|
|
#endif
|
|
return SUCCESS;
|
|
}
|
|
|
|
void NSAPI_PUBLIC
|
|
php4_close(void *vparam)
|
|
{
|
|
if (nsapi_sapi_module.shutdown) {
|
|
nsapi_sapi_module.shutdown(&nsapi_sapi_module);
|
|
}
|
|
tsrm_shutdown();
|
|
}
|
|
|
|
int NSAPI_PUBLIC
|
|
php4_init(pblock *pb, Session *sn, Request *rq)
|
|
{
|
|
php_core_globals *core_globals;
|
|
|
|
tsrm_startup(1, 1, 0, NULL);
|
|
core_globals = ts_resource(core_globals_id);
|
|
|
|
sapi_startup(&nsapi_sapi_module);
|
|
nsapi_sapi_module.startup(&nsapi_sapi_module);
|
|
|
|
log_error(LOG_INFORM, "php4_init", sn, rq, "Initialized PHP Module\n");
|
|
return REQ_PROCEED;
|
|
}
|
|
|
|
int NSAPI_PUBLIC
|
|
php4_execute(pblock *pb, Session *sn, Request *rq)
|
|
{
|
|
int retval;
|
|
nsapi_request_context *request_context;
|
|
|
|
TSRMLS_FETCH();
|
|
|
|
request_context = (nsapi_request_context *)MALLOC(sizeof(nsapi_request_context));
|
|
request_context->pb = pb;
|
|
request_context->sn = sn;
|
|
request_context->rq = rq;
|
|
request_context->read_post_bytes = 0;
|
|
|
|
SG(server_context) = request_context;
|
|
|
|
nsapi_request_ctor(NSLS_C TSRMLS_CC);
|
|
retval = nsapi_module_main(NSLS_C TSRMLS_CC);
|
|
nsapi_request_dtor(NSLS_C TSRMLS_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 NSAPI_PUBLIC
|
|
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;
|
|
}
|