mod_isapi.c revision b4c8a80f7dbfc9b56dbe03bdc28f0b5eb5f23697
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering/* ====================================================================
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * Copyright (c) 1995-1999 The Apache Group. All rights reserved.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * Redistribution and use in source and binary forms, with or without
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * modification, are permitted provided that the following conditions
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * 1. Redistributions of source code must retain the above copyright
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * notice, this list of conditions and the following disclaimer.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * 2. Redistributions in binary form must reproduce the above copyright
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * notice, this list of conditions and the following disclaimer in
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * the documentation and/or other materials provided with the
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * distribution.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * 3. All advertising materials mentioning features or use of this
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * software must display the following acknowledgment:
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * "This product includes software developed by the Apache Group
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * for use in the Apache HTTP server project (http://www.apache.org/)."
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * 4. The names "Apache Server" and "Apache Group" must not be used to
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * endorse or promote products derived from this software without
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * prior written permission. For written permission, please contact
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * apache@apache.org.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * 5. Products derived from this software may not be called "Apache"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * nor may "Apache" appear in their names without prior written
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * permission of the Apache Group.
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering * 6. Redistributions of any form whatsoever must retain the following
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * acknowledgment:
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * "This product includes software developed by the Apache Group
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * for use in the Apache HTTP server project (http://www.apache.org/)."
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * OF THE POSSIBILITY OF SUCH DAMAGE.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * ====================================================================
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * This software consists of voluntary contributions made by many
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * individuals on behalf of the Apache Group and was originally based
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * on public domain software written at the National Center for
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * Supercomputing Applications, University of Illinois, Urbana-Champaign.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * For more information on the Apache Group and the Apache HTTP server
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * project, please see <http://www.apache.org/>.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * mod_isapi.c - Internet Server Application (ISA) module for Apache
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * by Alexei Kosut <akosut@apache.org>
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * This module implements Microsoft's ISAPI, allowing Apache (when running
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * under Windows) to load Internet Server Applications (ISAPI extensions).
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * It implements all of the ISAPI 2.0 specification, except for the
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * "Microsoft-only" extensions dealing with asynchronous I/O. All ISAPI
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * extensions that use only synchronous I/O and are compatible with the
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * ISAPI 2.0 specification should work (most ISAPI 1.0 extensions should
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * function as well).
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering * To load, simply place the ISA in a location in the document tree.
c30a0c62fdbf6f11902be9db64ade99fb508adfdLennart Poettering * Then add an "AddHandler isapi ap_context_t sa dll" into your config file.
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering * You should now be able to load ISAPI DLLs just be reffering to their
c30a0c62fdbf6f11902be9db64ade99fb508adfdLennart Poettering * URLs. Make sure the ExecCGI option is active in the directory
c30a0c62fdbf6f11902be9db64ade99fb508adfdLennart Poettering * the ISA is in.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering/* We use the exact same header file as the original */
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering/* Seems IIS does not enforce the requirement for \r\n termination on HSE_REQ_SEND_RESPONSE_HEADER,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering define this to conform */
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering/* Our "Connection ID" structure */
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringtypedef struct {
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer/* Declare the ISAPI functions */
3c56cab44150ad47323970cfadfb0257c6305a74Ben WolsiefferBOOL WINAPI GetServerVariable (HCONN hConn, LPSTR lpszVariableName,
3c56cab44150ad47323970cfadfb0257c6305a74Ben WolsiefferBOOL WINAPI WriteClient (HCONN ConnID, LPVOID Buffer, LPDWORD lpwdwBytes,
3c56cab44150ad47323970cfadfb0257c6305a74Ben WolsiefferBOOL WINAPI ReadClient (HCONN ConnID, LPVOID lpvBuffer, LPDWORD lpdwSize);
3c56cab44150ad47323970cfadfb0257c6305a74Ben WolsiefferBOOL WINAPI ServerSupportFunction (HCONN hConn, DWORD dwHSERequest,
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering The optimiser blows it totally here. What happens is that autos are addressed relative to the
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering stack pointer, which, of course, moves around. The optimiser seems to lose track of it somewhere
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering between setting isapi_entry and calling through it. We work around the problem by forcing it to
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering use frame pointers.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering ap_pcalloc(r->pool, sizeof(struct _EXTENSION_CONTROL_BLOCK));
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering HSE_VERSION_INFO *pVer = ap_pcalloc(r->pool, sizeof(HSE_VERSION_INFO));
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering BOOL (*isapi_version)(HSE_VERSION_INFO *); /* entry point 1 */
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering DWORD (*isapi_entry)(LPEXTENSION_CONTROL_BLOCK); /* entry point 2 */
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering BOOL (*isapi_term)(DWORD); /* optional entry point 3 */
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering isapi_cid *cid = ap_pcalloc(r->pool, sizeof(isapi_cid));
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering /* Use similar restrictions as CGIs */
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering if (!(ap_allow_options(r) & OPT_EXECCGI))
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* Load the module */
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (!(isapi_handle = LoadLibraryEx(r->filename, NULL,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering ap_log_rerror(APLOG_MARK, APLOG_ALERT, r,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering (void *)(GetProcAddress(isapi_handle, "GetExtensionVersion")))) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering ap_log_rerror(APLOG_MARK, APLOG_ALERT, r,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering "DLL could not load GetExtensionVersion(): %s", r->filename);
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek (void *)(GetProcAddress(isapi_handle, "HttpExtensionProc")))) {
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poettering ap_log_rerror(APLOG_MARK, APLOG_ALERT, r,
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering "DLL could not load HttpExtensionProc(): %s", r->filename);
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering isapi_term = (void *)(GetProcAddress(isapi_handle, "TerminateExtension"));
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering /* Run GetExtensionVersion() */
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek ap_log_rerror(APLOG_MARK, APLOG_ALERT, r,
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek "ISAPI GetExtensionVersion() failed: %s", r->filename);
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poettering /* Set up variables */
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek /* Set up connection ID */
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering ecb->cbSize = sizeof(struct _EXTENSION_CONTROL_BLOCK);
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek ecb->lpszQueryString = ap_table_get(e, "QUERY_STRING");
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek ecb->lpszPathInfo = ap_table_get(e, "PATH_INFO");
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek ecb->lpszPathTranslated = ap_table_get(e, "PATH_TRANSLATED");
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek ecb->lpszContentType = ap_table_get(e, "CONTENT_TYPE");
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering /* Set up client input */
3c56cab44150ad47323970cfadfb0257c6305a74Ben Wolsieffer if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering if (isapi_term) (*isapi_term)(HSE_TERM_MUST_UNLOAD);
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering /* Unlike IIS, which limits this to 48k, we read the whole
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering * sucker in. I suppose this could be bad for memory if someone
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering * uploaded the complete works of Shakespeare. Well, WebSite
65b5116220a8ebf8a260716152409aa05377aaccLennart Poettering * does the same thing.
65b5116220a8ebf8a260716152409aa05377aaccLennart Poettering long to_read = atol(ap_table_get(e, "CONTENT_LENGTH"));
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek /* Actually, let's cap it at 48k, until we figure out what
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek * to do with this... we don't want a Content-Length: 1000000000
c485437f50450c0087bae3df4aed462e4a86ee83Zbigniew Jędrzejewski-Szmek * taking out the machine.
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering if (isapi_term) (*isapi_term)(HSE_TERM_MUST_UNLOAD);
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering ecb->lpbData = ap_pcalloc(r->pool, 1 + to_read);
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering if ((read = ap_get_client_block(r, ecb->lpbData, to_read)) < 0) {
2d62c530d2b4c2730abff715b7342f1402114513Lennart Poettering if (isapi_term) (*isapi_term)(HSE_TERM_MUST_UNLOAD);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering /* Although its not to spec, IIS seems to null-terminate
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * its lpdData string. So we will too. To make sure
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering * cbAvailable matches cbTotalBytes, we'll up the latter
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering * and equalize them.
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering ecb->cbAvailable = ecb->cbTotalBytes = read + 1;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* Set up the callbacks */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering ecb->GetServerVariable = &GetServerVariable;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering ecb->ServerSupportFunction = &ServerSupportFunction;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* All right... try and load the sucker */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* Set the status (for logging) */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* Check for a log message - and log it */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (ecb->lpszLogData && strcmp(ecb->lpszLogData, ""))
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering "%s: %s", ecb->lpszLogData, r->filename);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* All done with the DLL... get rid of it */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (isapi_term) (*isapi_term)(HSE_TERM_MUST_UNLOAD);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* Ignore the keepalive stuff; Apache handles it just fine without
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering * the ISA's "advice".
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering if (cid->status) /* We have a special status to return */
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering case HSE_STATUS_PENDING: /* We don't support this */
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering ap_log_rerror(APLOG_MARK, APLOG_WARNING, r,
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart Poettering "ISAPI asynchronous I/O not supported: %s", r->filename);
ed4ba7e4f652150310d062ffbdfefb4521ce1054Lennart PoetteringBOOL WINAPI GetServerVariable (HCONN hConn, LPSTR lpszVariableName,
65b5116220a8ebf8a260716152409aa05377aaccLennart Poettering LPVOID lpvBuffer, LPDWORD lpdwSizeofBuffer) {
const char *result;
if (result) {
return FALSE;
return TRUE;
return FALSE;
return FALSE;
return FALSE;
return TRUE;
return TRUE;
char *data;
switch (dwHSERequest) {
return TRUE;
case HSE_REQ_SEND_URL:
if (r->remaining > 0) {
return TRUE;
if (!lpdwDataType) {
return TRUE;
while (*data) {
#ifdef RELAX_HEADER_RULE
if (lf)
return FALSE;
#ifdef RELAX_HEADER_RULE
if (lf)
return FALSE;
char *tmp;
#ifdef RELAX_HEADER_RULE
if (!lf) {
data += p;
return TRUE;
case HSE_REQ_MAP_URL_TO_PATH:
*lpdwSize), r);
return TRUE;
return TRUE;
case HSE_REQ_IO_COMPLETION:
case HSE_REQ_TRANSMIT_FILE:
return FALSE;
{ NULL}