mod_isapi.c revision 352acf0115a9590beb714f87038d3bbe174ab92b
a78048ccbdb6256da15e6b0e7e95355e480c2301nd/* Licensed to the Apache Software Foundation (ASF) under one or more
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * contributor license agreements. See the NOTICE file distributed with
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * this work for additional information regarding copyright ownership.
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * The ASF licenses this file to You under the Apache License, Version 2.0
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * (the "License"); you may not use this file except in compliance with
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * the License. You may obtain a copy of the License at
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * Unless required by applicable law or agreed to in writing, software
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * distributed under the License is distributed on an "AS IS" BASIS,
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * See the License for the specific language governing permissions and
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * limitations under the License.
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * mod_isapi.c - Internet Server Application (ISA) module for Apache
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * by Alexei Kosut <akosut@apache.org>, significant overhauls and
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * redesign by William Rowe <wrowe@covalent.net>, and hints from many
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * other developer/users who have hit on specific flaws.
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * This module implements the ISAPI Handler architecture, allowing
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * Apache to load Internet Server Applications (ISAPI extensions),
e609c337f729875bc20e01096c7e610f45356f54nilgun * similar to the support in IIS, Zope, O'Reilly's WebSite and others.
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * It is a complete implementation of the ISAPI 2.0 specification,
4b575a6b6704b516f22d65a3ad35696d7b9ba372rpluem * except for "Microsoft extensions" to the API which provide
4b575a6b6704b516f22d65a3ad35696d7b9ba372rpluem * asynchronous I/O. It is further extended to include additional
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * "Microsoft extentions" through IIS 5.0, with some deficiencies
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * where one-to-one mappings don't exist.
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * Refer to /manual/mod/mod_isapi.html for additional details on
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * configuration and use, but check this source for specific support
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * of the API,
a78048ccbdb6256da15e6b0e7e95355e480c2301nd/* Retry frequency for a failed-to-load isapi .dll */
a78048ccbdb6256da15e6b0e7e95355e480c2301nd/**********************************************************
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * ISAPI Module Configuration
a78048ccbdb6256da15e6b0e7e95355e480c2301nd **********************************************************/
a78048ccbdb6256da15e6b0e7e95355e480c2301nd/* Our isapi per-dir config structure */
a78048ccbdb6256da15e6b0e7e95355e480c2301ndtypedef struct isapi_dir_conf {
a78048ccbdb6256da15e6b0e7e95355e480c2301ndapr_status_t isapi_lookup(apr_pool_t *p, server_rec *s, request_rec *r,
a78048ccbdb6256da15e6b0e7e95355e480c2301ndstatic void *create_isapi_dir_config(apr_pool_t *p, char *dummy)
a78048ccbdb6256da15e6b0e7e95355e480c2301nd isapi_dir_conf *dir = apr_palloc(p, sizeof(isapi_dir_conf));
a78048ccbdb6256da15e6b0e7e95355e480c2301ndstatic void *merge_isapi_dir_configs(apr_pool_t *p, void *base_, void *add_)
a78048ccbdb6256da15e6b0e7e95355e480c2301nd isapi_dir_conf *dir = apr_palloc(p, sizeof(isapi_dir_conf));
ae7dbf2e8aa89e1ec81c293ab3f1066f1cf1401fnd dir->read_ahead_buflen = (add->read_ahead_buflen == ISAPI_UNDEF)
a78048ccbdb6256da15e6b0e7e95355e480c2301nd dir->log_unsupported = (add->log_unsupported == ISAPI_UNDEF)
a78048ccbdb6256da15e6b0e7e95355e480c2301ndstatic const char *isapi_cmd_cachefile(cmd_parms *cmd, void *dummy,
a78048ccbdb6256da15e6b0e7e95355e480c2301nd const char *filename)
a78048ccbdb6256da15e6b0e7e95355e480c2301nd /* ### Just an observation ... it would be terribly cool to be
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * able to use this per-dir, relative to the directory block being
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * defined. The hash result remains global, but shorthand of
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * <Directory "c:/webapps/isapi">
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * ISAPICacheFile myapp.dll anotherapp.dll thirdapp.dll
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * </Directory>
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * would be very convienent.
a78048ccbdb6256da15e6b0e7e95355e480c2301nd ap_log_error(APLOG_MARK, APLOG_WARNING, APR_EBADPATH, cmd->server,
a78048ccbdb6256da15e6b0e7e95355e480c2301nd /* Load the extention as cached (with null request_rec) */
a78048ccbdb6256da15e6b0e7e95355e480c2301nd rv = isapi_lookup(cmd->pool, cmd->server, NULL, fspec, &isa);
a78048ccbdb6256da15e6b0e7e95355e480c2301nd OR_FILEINFO, "Maximum client request body to initially pass to the"
a78048ccbdb6256da15e6b0e7e95355e480c2301nd " ISAPI handler (default: 49152)"),
a78048ccbdb6256da15e6b0e7e95355e480c2301nd OR_FILEINFO, "Log requests not supported by the ISAPI server"
a78048ccbdb6256da15e6b0e7e95355e480c2301nd " on or off (default: off)"),
a78048ccbdb6256da15e6b0e7e95355e480c2301nd OR_FILEINFO, "Send all Append Log requests to the error log"
a78048ccbdb6256da15e6b0e7e95355e480c2301nd " on or off (default: off)"),
a78048ccbdb6256da15e6b0e7e95355e480c2301nd OR_FILEINFO, "Append Log requests are concatinated to the query args"
a78048ccbdb6256da15e6b0e7e95355e480c2301nd " on or off (default: on)"),
a78048ccbdb6256da15e6b0e7e95355e480c2301nd OR_FILEINFO, "Fake Asynchronous support for isapi callbacks"
a78048ccbdb6256da15e6b0e7e95355e480c2301nd " on or off [Experimental] (default: off)"),
a78048ccbdb6256da15e6b0e7e95355e480c2301nd AP_INIT_ITERATE("ISAPICacheFile", isapi_cmd_cachefile, NULL,
a78048ccbdb6256da15e6b0e7e95355e480c2301nd RSRC_CONF, "Cache the specified ISAPI extension in-process"),
a78048ccbdb6256da15e6b0e7e95355e480c2301nd/**********************************************************
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * ISAPI Module Cache handling section
a78048ccbdb6256da15e6b0e7e95355e480c2301nd **********************************************************/
a78048ccbdb6256da15e6b0e7e95355e480c2301nd/* Our isapi global config values */
a78048ccbdb6256da15e6b0e7e95355e480c2301ndstatic struct isapi_global_conf {
727872d18412fc021f03969b8641810d8896820bhumbedooh/* Our loaded isapi module description structure */
0d0ba3a410038e179b695446bb149cce6264e0abnd const char *filename;
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedoohstatic apr_status_t isapi_unload(isapi_loaded *isa, int force)
d229f940abfb2490dee17979e9a5ff31b7012eb5rbowen /* All done with the DLL... get rid of it...
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd * If optionally cached, and we weren't asked to force the unload,
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd * pass HSE_TERM_ADVISORY_UNLOAD, and if it returns 1, unload,
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd * otherwise, leave it alone (it didn't choose to cooperate.)
return APR_SUCCESS;
if (force) {
return APR_EGENERAL;
return APR_SUCCESS;
if (rv)
return rv;
if (rv)
return rv;
if (rv)
return rv;
apr_set_os_error(0);
return rv;
return APR_SUCCESS;
const char *key;
return rv;
if (*isa) {
if (!gainlock) {
return rv;
!= APR_SUCCESS) {
return rv;
return rv;
!= APR_SUCCESS) {
return rv;
return rv;
return rv;
struct isapi_cid {
request_rec *r;
int headers_set;
int response_sent;
void *completion_arg;
char *variable_name,
void *buf_ptr,
const char *result;
if (result) {
void *buf_data,
int res;
if (res < 0) {
return (res >= 0);
const char *stat,
const char *head,
int termarg;
int res;
int old_status;
const char *termch;
statlen = 0;
char *newstat;
if (stat) {
if (res) {
else if (old_status) {
if (!head_present)
if (!termch)
return ate;
void *buf_ptr,
apr_bucket *b;
if (ate < 0) {
if (buf_size) {
void *buf_ptr,
switch (HSE_code) {
case HSE_REQ_SEND_URL:
if (r->remaining > 0) {
if (buf_data)
if (data_type)
(char*) data_type,
if (ate < 0) {
apr_bucket *b;
r->filename);
case HSE_REQ_MAP_URL_TO_PATH:
#ifdef WIN32
case HSE_REQ_GET_SSPI_INFO:
case HSE_APPEND_LOG_PARAMETER:
if (r->args)
(char*) buf_data);
case HSE_REQ_IO_COMPLETION:
case HSE_REQ_TRANSMIT_FILE:
apr_bucket *b;
!= APR_SUCCESS) {
if (ate < 0)
c->bucket_alloc);
case HSE_REQ_IS_KEEP_CONN:
int res;
r->filename);
* sample web/iis/extensions/io/ASyncRead. This potentially
if (res >= 0) {
return (res >= 0);
case HSE_REQ_ABORTIVE_CLOSE:
if (ate < 0) {
apr_bucket *b;
c->bucket_alloc);
apr_table_t *e;
const char *val;
int res;
return DECLINED;
e = r->subprocess_env;
return HTTP_FORBIDDEN;
return HTTP_NOT_FOUND;
return HTTP_FORBIDDEN;
return HTTP_NOT_FOUND;
!= APR_SUCCESS) {
return HTTP_INTERNAL_SERVER_ERROR;
ap_add_cgi_vars(r);
cid->r = r;
r->status = 0;
if (res) {
return res;
if (ap_should_client_block(r)) {
if (r->remaining) {
read = 0;
if (res < 0) {
return HTTP_INTERNAL_SERVER_ERROR;
if (res == 0)
r->pool);
return HTTP_INTERNAL_SERVER_ERROR;
switch(rv) {
case HSE_STATUS_SUCCESS:
case HSE_STATUS_PENDING:
r->filename);
case HSE_STATUS_ERROR:
apr_bucket *b;
return r->status;
return APR_EGENERAL;
return APR_EGENERAL;
return rv;
return OK;