Directly from the authors of Apache 2.0, I'm very happy to announce that the
WebApp module has now support for the new HTTPD. Thank you to the Covalent
"dream team"...

    Pier

------ Forwarded Message
From: Ryan Bloom <[EMAIL PROTECTED]>
Organization: Covalent Technologies
Reply-To: [EMAIL PROTECTED]
Date: Tue, 21 Aug 2001 09:17:25 -0700
To: "Pier P. Fumagalli" <[EMAIL PROTECTED]>, "Ian Kallen
<[EMAIL PROTECTED]>" <[EMAIL PROTECTED]>
Cc: <[EMAIL PROTECTED]>, Dirk-Willem van Gulik <[EMAIL PROTECTED]>,
[EMAIL PROTECTED]
Subject: Re: mod_webapp with Apache 2.0

Pier,

Here is the C code for mod_webapp for Apache 2.0.  I have it building on my
machine, but APXS is horribly broken, and I haven't had time to fix it yet.
That is on my VERY short list of things to do.  Regardless, I have a hacked
up build system, and this does build for me.  I don't have Tomcat 4.0 setup
though, so I haven't been able to test it yet.  Again, on my VERY short list
of projects.

I'm hoping to have a Makefile that actually works very soon as well.  :-)

Ryan
______________________________________________________________
Ryan Bloom                            [EMAIL PROTECTED]
Covalent Technologies            [EMAIL PROTECTED]
--------------------------------------------------------------
------ End of Forwarded Message

/* ========================================================================= *
 *                                                                           *
 *                 The Apache Software License,  Version 1.1                 *
 *                                                                           *
 *          Copyright (c) 1999-2001 The Apache Software Foundation.          *
 *                           All rights reserved.                            *
 *                                                                           *
 * ========================================================================= *
 *                                                                           *
 * Redistribution and use in source and binary forms,  with or without modi- *
 * fication, are permitted provided that the following conditions are met:   *
 *                                                                           *
 * 1. Redistributions of source code  must retain the above copyright notice *
 *    notice, this list of conditions and the following disclaimer.          *
 *                                                                           *
 * 2. Redistributions  in binary  form  must  reproduce the  above copyright *
 *    notice,  this list of conditions  and the following  disclaimer in the *
 *    documentation and/or other materials provided with the distribution.   *
 *                                                                           *
 * 3. The end-user documentation  included with the redistribution,  if any, *
 *    must include the following acknowlegement:                             *
 *                                                                           *
 *       "This product includes  software developed  by the Apache  Software *
 *        Foundation <http://www.apache.org/>."                              *
 *                                                                           *
 *    Alternately, this acknowlegement may appear in the software itself, if *
 *    and wherever such third-party acknowlegements normally appear.         *
 *                                                                           *
 * 4. The names  "The  Jakarta  Project",  "WebApp",  and  "Apache  Software *
 *    Foundation"  must not be used  to endorse or promote  products derived *
 *    from this  software without  prior  written  permission.  For  written *
 *    permission, please contact <[EMAIL PROTECTED]>.                        *
 *                                                                           *
 * 5. Products derived from this software may not be called "Apache" nor may *
 *    "Apache" appear in their names without prior written permission of the *
 *    Apache Software Foundation.                                            *
 *                                                                           *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES *
 * INCLUDING, BUT NOT LIMITED TO,  THE IMPLIED WARRANTIES OF MERCHANTABILITY *
 * AND FITNESS FOR  A PARTICULAR PURPOSE  ARE DISCLAIMED.  IN NO EVENT SHALL *
 * THE APACHE  SOFTWARE  FOUNDATION OR  ITS CONTRIBUTORS  BE LIABLE  FOR ANY *
 * DIRECT,  INDIRECT,   INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL *
 * DAMAGES (INCLUDING,  BUT NOT LIMITED TO,  PROCUREMENT OF SUBSTITUTE GOODS *
 * OR SERVICES;  LOSS OF USE,  DATA,  OR PROFITS;  OR BUSINESS INTERRUPTION) *
 * HOWEVER CAUSED AND  ON ANY  THEORY  OF  LIABILITY,  WHETHER IN  CONTRACT, *
 * STRICT LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *
 * ANY  WAY  OUT OF  THE  USE OF  THIS  SOFTWARE,  EVEN  IF  ADVISED  OF THE *
 * POSSIBILITY OF SUCH DAMAGE.                                               *
 *                                                                           *
 * ========================================================================= *
 *                                                                           *
 * This software  consists of voluntary  contributions made  by many indivi- *
 * duals on behalf of the  Apache Software Foundation.  For more information *
 * on the Apache Software Foundation, please see <http://www.apache.org/>.   *
 *                                                                           *
 * ========================================================================= */

/**
 * @author  Pier Fumagalli <mailto:[EMAIL PROTECTED]>
 * @version $Id: mod_webapp.c,v 1.23 2001/08/09 20:05:36 pier Exp $
 */

#include <httpd.h>
#include <http_request.h>
#include <http_config.h>
#include <http_core.h>
#include <http_log.h>
#include <http_main.h>
#include <http_protocol.h>
#include <util_script.h>
#include <wa.h>
#include <apr_tables.h>

/* ************************************************************************* */
/* GENERIC DECLARATIONS                                                      */
/* ************************************************************************* */

/* Module declaration */
module AP_MODULE_DECLARE_DATA webapp_module;
/* Wether the WebApp Library has been initialized or not */
static wa_boolean wam_initialized=wa_false;
/* The list of configured connections */
static wa_chain *wam_connections=NULL;
/* The main server using for logging error not related to requests */
static server_rec *server=NULL;

/* ************************************************************************* */
/* MODULE AND LIBRARY INITIALIZATION AND DESTRUCTION                         */
/* ************************************************************************* */

/* Destroy the module and the WebApp Library */
static apr_status_t wam_shutdown(void *data) {//void *nil) {
    if (!wam_initialized) return APR_SUCCESS;
    wa_shutdown();
    wam_initialized=wa_false;
    return APR_SUCCESS;
}

/* Startup the module and the WebApp Library */
static void wam_startup(apr_pool_t *p, server_rec *s) {
    if (!wam_initialized) return;
    server=s;
    wa_startup();
    apr_pool_cleanup_register(p, NULL, wam_shutdown, apr_pool_cleanup_null);
}

/* Initialize the module and the WebApp Library */
static const char *wam_init(apr_pool_t *p) {
    const char *ret=NULL;

    if(wam_initialized==wa_true) return(NULL);
    if ((ret=wa_init())!=NULL) return(ret);
    wam_initialized=wa_true;
    return(NULL);
}

/* ************************************************************************* */
/* CONFIGURATION DIRECTIVES HANDLING                                         */
/* ************************************************************************* */

/* Retrieve or create a wa_virtualhost structure for an Apache server_rec
   and store it as the per-server module configuration */
static const char *wam_server(server_rec *svr, wa_virtualhost **h) {
    wa_virtualhost *host=NULL;
    char *name=svr->server_hostname;
    int port=(int)svr->port;
    const char *ret=NULL;

    /* Attempt to retrieve the wa_virtualhost structure and create it
       if necessary, storing it into the server_rec structure. */
    host=ap_get_module_config(svr->module_config,&webapp_module);

    /* If we already configured the wa_virtualhost, simply return it */
    if (host!=NULL) {
        *h=host;
        return(NULL);
    }

    /* The wa_virtualhost was not found in the per-server module configuration
       so we'll try to create it. */
    ret=wa_cvirtualhost(&host,name,port);
    if (ret!=NULL) {
        *h=NULL;
        return(ret);
    }

    /* We successfully created a wa_virtualhost structure, store it in the
       per-server configuration member and return it. */
    ap_set_module_config(svr->module_config,&webapp_module,host);
    *h=host;
    return(NULL);
}

/* Process the WebAppConnection directive. */
static const char *wam_directive_connection(cmd_parms *cmd, void *mconfig,
                                            const char *name, const char *prov, const char *p) {
    wa_connection *conn=NULL;
    const char *ret=NULL;
    wa_chain *elem=NULL;

    /* Initialize the library */
    if ((ret=wam_init(cmd->pool))!=NULL) return(ret);

    /* Attempt to create a new wa_connection structure */
    if ((ret=wa_cconnection(&conn,name,prov,p))!=NULL) return(ret);

    /* Check if we have a duplicate connection with this name */
    elem=wam_connections;
    while (elem!=NULL) {
        wa_connection *curr=(wa_connection *)elem->curr;
        if (strcasecmp(conn->name,curr->name)==0)
            return("Duplicate connection name");
        elem=elem->next;
    }

    /* We don't have a duplicate connection, store it locally */
    elem=apr_palloc(wa_pool,sizeof(wa_chain));
    elem->curr=conn;
    elem->next=wam_connections;
    wam_connections=elem;
    return(NULL);
}

/* Process the WebAppDeploy directive */
static const char *wam_directive_deploy(cmd_parms *cmd, void *mconfig,
                                      const char *name, const char *cnam, const char *path) {
    wa_virtualhost *host=NULL;
    wa_application *appl=NULL;
    wa_connection *conn=NULL;
    wa_chain *elem=NULL;
    const char *ret=NULL;

    /* Initialize the library and retrieve/create the host structure */
    if ((ret=wam_init(cmd->pool))!=NULL) return(ret);
    if ((ret=wam_server(cmd->server,&host))!=NULL) return(ret);

    /* Retrieve the connection */
    elem=wam_connections;
    while(elem!=NULL) {
        wa_connection *curr=(wa_connection *)elem->curr;
        if (strcasecmp(curr->name,cnam)==0) {
            conn=curr;
            break;
        }
        elem=elem->next;
    }
    if (conn==NULL) return("Specified connection not configured");

    /* Create a new wa_application member */
    if ((ret=wa_capplication(&appl,name,path))!=NULL) return(ret);

    /* Deploy the web application */
    if ((ret=wa_deploy(appl,host,conn))!=NULL) return(ret);

    /* Done */
    return(NULL);
}

/* Process the WebAppInfo directive */
static const char *wam_directive_info(cmd_parms *cmd, void *mconfig,
                                      const char *path) {
    const char *ret;

    /* We simply divert this call to a WebAppConnection and a WebAppDeploy
       calls */
    if ((ret=wam_directive_connection(cmd,mconfig,"_INFO_","info",""))!=NULL)
        return(ret);
    if ((ret=wam_directive_deploy(cmd,mconfig,"_INFO_","_INFO_",path))!=NULL)
        return(ret);

    return(NULL);
}

/* The list of Directives for the WebApp module */
static const command_rec wam_directives[] = {
    AP_INIT_TAKE1(
        "WebAppInfo",               /* directive name */
        wam_directive_info,         /* config action routine */
        NULL,                       /* argument to include in call */
        OR_OPTIONS,                 /* where available */
        "<uri-path>"),
    AP_INIT_TAKE23(
        "WebAppConnection",         /* directive name */
        wam_directive_connection,   /* config action routine */
        NULL,                       /* argument to include in call */
        RSRC_CONF,                  /* where available */
        "<name> <provider> [optional parameter]"),
    AP_INIT_TAKE3(
        "WebAppDeploy",             /* directive name */
        wam_directive_deploy,       /* config action routine */
        NULL,                       /* argument to include in call */
        RSRC_CONF,                  /* where available */
        "<name> <connection> <uri-path>"),
    {NULL}

};

/* ************************************************************************* */
/* CALLBACKS TO WEB SERVER                                                   */
/* ************************************************************************* */

/* Log a generic error */
void wa_log(const char *f, const int l, const char *fmt, ...) {
    va_list ap;
    char buf[1024];
#ifdef DEBUG
    char tmp[1024];
#endif

    va_start(ap,fmt);
#ifdef DEBUG
    apr_vsnprintf(tmp,1024,fmt,ap);
    apr_snprintf(buf,1024,"[%s:%d] %s",f,l,tmp);
#else
    apr_vsnprintf(buf,1024,fmt,ap);
#endif
    va_end(ap);

    ap_log_error(f,l,APLOG_NOERRNO|APLOG_ERR,0,server,"%s",buf);
}

/* Log a message associated with a request */
static void wam_handler_log(wa_request *r, const char *f, const int l, char *msg) {
    request_rec *req=(request_rec *)r->data;
    server_rec *svr=req->server;

    ap_log_error(f,l,APLOG_NOERRNO|APLOG_ERR,0,svr,"%s",msg);
}

/* Set the HTTP status of the response. */
static void wam_handler_setstatus(wa_request *r, int status) {
    request_rec *req=(request_rec *)r->data;

    req->status=status;
}

/* Set the MIME Content-Type of the response. */
static void wam_handler_setctype(wa_request *r, char *type) {
    request_rec *req=(request_rec *)r->data;

    if (type==NULL) return;

    req->content_type=apr_pstrdup(req->pool,type);
    apr_table_add(req->headers_out,"Content-Type",apr_pstrdup(req->pool,type));
}

/* Set a header in the HTTP response. */
static void wam_handler_setheader(wa_request *r, char *name, char *value) {
    request_rec *req=(request_rec *)r->data;

    if (name==NULL) return;
    if (value==NULL) value="";

    apr_table_add(req->headers_out,apr_pstrdup(req->pool,name),
                 apr_pstrdup(req->pool,value));
}

/* Commit the first part of the response (status and headers) */
static void wam_handler_commit(wa_request *r) {
#if 0
/* Modules can completely forget about headers in Apache 2.0, the
 * core server always makes sure they are sent at the correct time. rbb
 */
    request_rec *req=(request_rec *)r->data;

    ap_send_http_header(req);
    ap_rflush(req);
#endif
}

/* Flush all data in the response buffer */
static void wam_handler_flush(wa_request *r) {
    request_rec *req=(request_rec *)r->data;

    ap_rflush(req);
}

/* Read a chunk of text from the request body */
static int wam_handler_read(wa_request *r, char *buf, int len) {
    request_rec *req=(request_rec *)r->data;
    long ret=0;

    /* Check if we have something to read. */
    if (r->clen==0) return(0);

    /* Check if we had an error previously. */
    if (r->rlen==-1) return(-1);

    /* Send HTTP_CONTINUE to client when we're ready to read for the first
       time. */
    if (r->rlen==0) {
        if (ap_should_client_block(req)==0) return(0);
    }

    /* Read some data from the client and fill the buffer. */
    ret=ap_get_client_block(req,buf,len);
    if (ret==-1) {
        r->rlen=-1;
        return(-1);
    }

    /* We did read some bytes, increment the current rlen and return. */
    r->rlen+=ret;
    return((int)ret);
}

/* Write a chunk of text into the response body. */
static int wam_handler_write(wa_request *r, char *buf, int len) {
    request_rec *req=(request_rec *)r->data;

    return(ap_rwrite(buf, len, req));
}

/* The structure holding all callback handling functions for the library */
static wa_handler wam_handler = {
    wam_handler_log,
    wam_handler_setstatus,
    wam_handler_setctype,
    wam_handler_setheader,
    wam_handler_commit,
    wam_handler_flush,
    wam_handler_read,
    wam_handler_write,
};

/* ************************************************************************* */
/* REQUEST HANDLING                                                          */
/* ************************************************************************* */

/* Match an Apache request */
static int wam_match(request_rec *r) {
    wa_virtualhost *host=NULL;
    wa_application *appl=NULL;
    wa_chain *elem=NULL;

    /* Paranoid check */
    if (!wam_initialized) return(DECLINED);

    /* Check if this host was recognized */
    host=ap_get_module_config(r->server->module_config,&webapp_module);
    if (host==NULL) return(DECLINED);

    /* Check if the uri is contained in one of our applications root path */
    elem=host->apps;
    while(elem!=NULL) {
        appl=(wa_application *)elem->curr;
        if (strncmp(appl->rpth,r->uri,strlen(appl->rpth))==0) break;

        appl=NULL;
        elem=elem->next;
    }
    if (appl==NULL) return(DECLINED);

    /* The uri path is matched: set the handler and return */
    r->handler=apr_pstrdup(r->pool,"webapp-handler");

    /* Set the webapp request structure into Apache's request structure */
    ap_set_module_config(r->request_config, &webapp_module, appl);
    return(OK);
}

/* Handle the current request */
static int wam_invoke(request_rec *r) {
    server_rec *svr=r->server;
    conn_rec *con=r->connection;
    wa_application *appl=NULL;
    wa_request *req=NULL;
    const char *msg=NULL;
    char *stmp=NULL;
    char *ctmp=NULL;
    int ret=0;
    apr_port_t port;

    if (strcmp(r->handler, "webapp-handler")) return(DECLINED);

    /* Paranoid check */
    if (!wam_initialized) return(DECLINED);

    /* Try to get a hold on the webapp request structure */
    appl=(wa_application *)ap_get_module_config(r->request_config,
                                                &webapp_module);
    if (appl==NULL) return(DECLINED);

    /* Allocate the webapp request structure */
    if ((msg=wa_ralloc(&req, &wam_handler, r))!=NULL) {
        ap_log_error(APLOG_MARK,APLOG_NOERRNO|APLOG_ERR,0,svr,"%s",msg);
        return(HTTP_INTERNAL_SERVER_ERROR);
    }

    /* Set up the WebApp Library request structure client and server host
       data (from the connection */
    stmp=(char *)r->hostname;
    ctmp=(char *)ap_get_remote_host(con,r->per_dir_config, REMOTE_HOST, NULL);
    if (stmp==NULL) req->serv->host="";
    else req->serv->host=apr_pstrdup(req->pool,stmp);
    if (ctmp==NULL) req->clnt->host="";
    else req->clnt->host=apr_pstrdup(req->pool,ctmp);
    req->serv->addr=apr_pstrdup(req->pool,con->local_ip);
    req->clnt->addr=apr_pstrdup(req->pool,con->remote_ip);
    apr_sockaddr_port_get(&port, con->local_addr);
    req->serv->port=ntohs(port);
    apr_sockaddr_port_get(&port, con->remote_addr);
    req->clnt->port=ntohs(port);

    /* Set up all other members of the request structure */
    req->meth=apr_pstrdup(req->pool,(char *)r->method);
    req->ruri=apr_pstrdup(req->pool,r->uri);
    req->args=apr_pstrdup(req->pool,r->args);
    req->prot=apr_pstrdup(req->pool,r->protocol);
    req->schm=apr_pstrdup(req->pool,ap_http_method(r));
    req->user=apr_pstrdup(req->pool,r->user);
    req->auth=apr_pstrdup(req->pool,r->ap_auth_type);
    req->clen=0;
    req->ctyp="\0";
    req->rlen=0;

    /* Copy headers into webapp request structure */
    if (r->headers_in!=NULL) {
        apr_array_header_t *arr=apr_table_elts(r->headers_in);
        apr_table_entry_t *ele=(apr_table_entry_t *)arr->elts;
        int x=0;

        /* Copy headers one by one */
        for (x=0; x<arr->nelts;x++) {
            if (ele[x].key==NULL) continue;
            if (ele[x].val==NULL) continue;
            apr_table_add(req->hdrs,apr_pstrdup(req->pool,ele[x].key),
                                    apr_pstrdup(req->pool,ele[x].val));
            if (strcasecmp(ele[x].key,"Content-Length")==0)
                req->clen=atol(ele[x].val);
            if (strcasecmp(ele[x].key,"Content-Type")==0)
                req->ctyp=apr_pstrdup(req->pool,ele[x].val);
        }
    }

    /* Check if we can read something from the request */
    ret=ap_setup_client_block(r,REQUEST_CHUNKED_DECHUNK);
    if (ret!=OK) return(ret);

    /* Invoke the request */
    ret=wa_rinvoke(req,appl);

    /* Destroy the request member */
    wa_rfree(req);
    ap_rflush(r);

    return(OK);
}


static void register_hooks(apr_pool_t *p)
{
    ap_hook_handler(wam_invoke, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_translate_name(wam_match, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_child_init(wam_startup, NULL, NULL, APR_HOOK_MIDDLE);
}

/* Apache module declaration */
module AP_MODULE_DECLARE_DATA webapp_module = {
    STANDARD20_MODULE_STUFF,
    NULL,                               /* per-directory config creator */
    NULL,                               /* dir config merger */
    NULL,                               /* server config creator */
    NULL,                               /* server config merger */
    wam_directives,                     /* command table */
    register_hooks
};

Reply via email to