/*
##--------------------------------------------------------------------------
##
##  Copyright (c) 2001 Gerald Richter / ecos gmbh www.ecos.de
##
##  You may distribute under the terms of either the GNU General Public 
##  License or the Artistic License, as specified in the Perl README file.
## 
##  THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED 
##  WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 
##  MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
##
##  $Id: mod_aimproxy.c,v 1.1 2001/08/13 06:26:24 richter Exp $
##
##--------------------------------------------------------------------------
*/


#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_request.h"
#include "util_md5.h"



static void *aimproxySrvConfig(pool *p, char *d) ;
static const char * aimproxyCmdCacheDir(cmd_parms *cmd, void *config, char *val) ;
static const char * aimproxyCmdProxyPass(cmd_parms *cmd, void *config, char *val1, char * val2) ;
static int aimproxyHandler (request_rec *r) ;


    /* the table of commands we provide */
static const command_rec command_table[] = {
    { "AIMCacheDir",   aimproxyCmdCacheDir,   NULL, RSRC_CONF, TAKE1,
      "Gives the cache directory for Apache::ImageMagick Proxy" },
    { "AIMProxyPassTo",   aimproxyCmdProxyPass,   NULL, RSRC_CONF, TAKE2,
      "Gives the destination host for images not cached" },
};


    /* the main config structure */
module MODULE_VAR_EXPORT aimproxy_module = {
   STANDARD_MODULE_STUFF,
   NULL,                        /* module initializer                  */
   NULL,			/* create per-dir    config structures */
   NULL,			/* merge  per-dir    config structures */
   aimproxySrvConfig,		/* create per-server config structures */
   NULL,			/* merge  per-server config structures */
   command_table,               /* table of config file commands       */
   NULL,                        /* [#8] MIME-typed-dispatched handlers */
   NULL,                        /* [#1] URI to filename translation    */
   NULL,                        /* [#4] validate user id from request  */
   NULL,                        /* [#5] check if the user is ok _here_ */
   NULL,                        /* [#3] check access by host address   */
   NULL,                        /* [#6] determine MIME type            */
   aimproxyHandler,             /* [#7] pre-run fixups                 */
   NULL,                        /* [#9] log a transaction              */
   NULL,                        /* [#2] header parser                  */
   NULL,                        /* child_init                          */
   NULL,                        /* child_exit                          */
   NULL                         /* [#0] post read-request              */
};


struct aimconfig
    {
    char * cachedir ;
    array_header * pass ;
    } ;

struct aimpass
    {
    char * proxysrc ;
    int    proxysrclen ;
    char * proxyhost ;
    } ;

typedef struct aimconfig aimconfig ;
typedef struct aimpass aimpass ;


static int aimproxyHandler (request_rec *r)
    {
    char * args ;
    char * path_info ;
    char * file ;
    char * uri ;
    char * md5 ;
    char * ext ;
    char * cachefn  ;
    char * cachedir  ;
    char * cachepath  ;
    aimconfig * c ;
    struct stat finfo ;
    int i, len;
    int n ;
    aimpass *ent ;
    int found = 0 ;
    char * proxyhost ;

    if (r->proxyreq != NOT_PROXY) 
	{ /* someone has already set up the proxy */
	return DECLINED ;
	}

    c = (aimconfig *) ap_get_module_config(r->server->module_config, &aimproxy_module);
    
    ent = (aimpass *) c->pass->elts;
    uri  = r -> uri ;
    n    = c -> pass -> nelts ;
    for (i = 0; i < n; i++) 
	{
        if (strncmp (uri, ent[i].proxysrc, ent[i].proxysrclen) == 0)
	    {
	    /*fprintf(stderr, "found %s -> %s\n" , ent[i].proxysrc, ent[i].proxyhost) ;*/
	    found = 1 ;
	    break ;
	    }
	}

    if (!found)
	{
        /*fprintf(stderr, "aimproxy not found %s\n" , uri) ;*/
	return DECLINED ; /* is not our request */
	}
    proxyhost = ent[i].proxyhost ;

    args = r -> args ;
    path_info = r -> path_info ;

    /* If the file exists and there are no transformation arguments
       just decline the transaction.  It will be handled as usual. */
    /*fprintf(stderr, "uri %s  args %s  path_info %s\n" , uri, args, path_info) ;*/
    /*fprintf(stderr, "r -> finfo.st_mode %d\n" , r -> finfo.st_mode) ;*/
    if ((!args || !*args) && (!path_info || !*path_info) && r -> finfo.st_mode)  
	return DECLINED ;

    /* calculate name of cache file */
    file = r->filename;
    md5  = ap_md5 (r -> pool, ap_pstrcat (r -> pool, uri, args, NULL)) ;
    ext  = strchr (file, '.') ;
    if (ext)
	ext++ ;
    else
	ext = "" ;
    cachefn = ap_pstrcat (r -> pool, md5, ".", ext, NULL) ;
    /*fprintf(stderr, "cachefn = %s\n" , cachefn) ;*/
    cachedir  = c -> cachedir ;
    cachepath = ap_pstrcat (r -> pool, cachedir, "/", cachefn, NULL) ;
    
    /*fprintf(stderr, "cachepath = %s\n" , cachepath) ;*/
    if (stat (cachepath, &finfo) == 0)
        { /* let apache do the rest if image already exists */
        r -> filename = cachepath ;
        r -> path_info = "" ;
        memcpy (&r -> finfo, &finfo, sizeof (r -> finfo)) ;
	return OK ;
        }

   /* otherwise send it to the backend */

   r->filename = ap_pstrcat(r->pool, "proxy:http://", proxyhost, r-> uri, NULL);
   r->handler = "proxy-server";
   r->proxyreq = PROXY_PASS;

   /*fprintf(stderr, "proxy to = %s\n" , r->filename) ;*/

   return OK;
   }



static void *aimproxySrvConfig(pool *p, char *d)
    {
    aimconfig *rec = (aimconfig *) ap_pcalloc(p, sizeof(aimconfig));
    memset (rec, 0, sizeof(aimconfig)) ;
    rec->pass = ap_make_array(p, 10, sizeof(aimpass));
    return rec;
    }


static const char * aimproxyCmdCacheDir(cmd_parms *cmd, void *config, char *val)
    {
    server_rec *s = cmd->server;
    aimconfig * c = (aimconfig *) ap_get_module_config(s->module_config, &aimproxy_module);

    c -> cachedir = val ;

    return NULL;
    }


static const char * aimproxyCmdProxyPass(cmd_parms *cmd, void *config, char *val1, char * val2)
    {
    server_rec *s = cmd->server;
    aimconfig * c = (aimconfig *) ap_get_module_config(s->module_config, &aimproxy_module);
    aimpass *   p = (aimpass *)ap_push_array(c->pass);
    p -> proxyhost = val2 ;
    p -> proxysrc  = val1 ;
    p -> proxysrclen = strlen (p -> proxysrc) ;

    return NULL;
    }