/*
* Copyright 1995, 1998 Perforce Software.
*
* This file is part of WebKeeper, a perforce client apache module.
*
* License is hereby granted to use this software and distribute it
* freely, as long as this copyright notice is retained and modifications
* are clearly marked.
*
* ALL WARRANTIES ARE HEREBY DISCLAIMED.
*
* $Id: //guest/eric_scouten/webkeeper/mod_webkeep.c#1 $
*/
/*
* mod_webkeep.c: the apache side glue (in C) to the Perforce client
*
* This module by Perforce Software, from a template by the Apache Group.
*/
#include "httpd.h"
#include "http_config.h"
#include "mod_webkeep.h"
typedef struct {
char *real;
char *fake;
} alias_entry;
typedef struct {
array_header *aliases;
WebKeepConnect p4;
} alias_server_conf;
module webkeep_module;
static
void *create_webkeep_config (pool *p, server_rec *s)
{
alias_server_conf *a;
a = (alias_server_conf *)pcalloc (p, sizeof(alias_server_conf));
a->aliases = make_array (p, 20, sizeof(alias_entry));
a->p4.port = 0;
a->p4.user = 0;
a->p4.pass = 0;
a->p4.client = 0;
return a;
}
static
void *merge_webkeep_config (pool *p, void *basev, void *overridesv)
{
alias_server_conf *a, *b, *o;
a = (alias_server_conf *)pcalloc (p, sizeof(alias_server_conf));
b = (alias_server_conf *)basev;
o = (alias_server_conf *)overridesv;
a->aliases = append_arrays (p, o->aliases, b->aliases);
a->p4.port = o->p4.port ? o->p4.port : a->p4.port ? a->p4.port : b->p4.port;
a->p4.user = o->p4.user ? o->p4.user : a->p4.user ? a->p4.user : b->p4.user;
a->p4.pass = o->p4.pass ? o->p4.pass : a->p4.pass ? a->p4.pass : b->p4.pass;
a->p4.client = o->p4.client ? o->p4.client : a->p4.client ? a->p4.client : b->p4.client;
return a;
}
static
const char *add_webkeep(cmd_parms *cmd, void *dummy, char *f, char *r)
{
server_rec *s = cmd->server;
alias_server_conf *conf;
alias_entry *new;
conf = (alias_server_conf *)
get_module_config(s->module_config,&webkeep_module);
new = push_array (conf->aliases);
/* XX r can NOT be relative to DocumentRoot here... compat bug. */
new->fake = f;
new->real = r;
return NULL;
}
static
const char *port_webkeep(cmd_parms *cmd, void *d, char *f)
{
server_rec *s = cmd->server;
alias_server_conf *conf;
conf = (alias_server_conf *)
get_module_config(s->module_config,&webkeep_module);
conf->p4.port = f;
return NULL;
}
static
const char *user_webkeep(cmd_parms *cmd, void *d, char *f)
{
server_rec *s = cmd->server;
alias_server_conf *conf;
conf = (alias_server_conf *)
get_module_config(s->module_config,&webkeep_module);
conf->p4.user = f;
return NULL;
}
static
const char *passwd_webkeep(cmd_parms *cmd, void *d, char *f)
{
server_rec *s = cmd->server;
alias_server_conf *conf;
conf = (alias_server_conf *)
get_module_config(s->module_config,&webkeep_module);
conf->p4.pass = f;
return NULL;
}
static
const char *client_webkeep(cmd_parms *cmd, void *d, char *f)
{
server_rec *s = cmd->server;
alias_server_conf *conf;
conf = (alias_server_conf *)
get_module_config(s->module_config,&webkeep_module);
conf->p4.client = f;
return NULL;
}
static
command_rec alias_cmds[] = {
{ "WebKeepAlias", add_webkeep, NULL, RSRC_CONF, TAKE2,
"a fakename and a depot name"},
{ "WebKeepPort", port_webkeep, NULL, RSRC_CONF, TAKE1,
"a TCP/IP host:port"},
{ "WebKeepUser", user_webkeep, NULL, RSRC_CONF, TAKE1,
"a Perforce user name"},
{ "WebKeepPasswd", passwd_webkeep, NULL, RSRC_CONF, TAKE1,
"a Perforce user password"},
{ "WebKeepClient", client_webkeep, NULL, RSRC_CONF, TAKE1,
"a Perforce client name"},
{ NULL }
};
static
int alias_matches (char *uri, char *alias_fakename)
{
char *end_fakename = alias_fakename + strlen (alias_fakename);
char *aliasp = alias_fakename, *urip = uri;
while (aliasp < end_fakename) {
if (*aliasp == '/') {
/* any number of '/' in the alias matches any number in
* the supplied URI, but there must be at least one...
*/
if (*urip != '/') return 0;
while (*aliasp == '/') ++ aliasp;
while (*urip == '/') ++ urip;
}
else if ( aliasp == end_fakename - 1 && *aliasp == '$') {
/* a $ at the end of the fakename means it must match
* the IRI exactly: i.e. no initial substring match.
*/
if (*urip != 0) return 0;
++ aliasp;
}
else {
/* Other characters are compared literally */
if (*urip++ != *aliasp++) return 0;
}
}
/* Check last alias path component matched all the way */
if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/')
return 0;
/* Return number of characters from URI which matched (may be
* greater than length of alias, since we may have matched
* doubled slashes)
*/
return urip - uri;
}
static
int translate_webkeep(request_rec *r)
{
int i;
void *sconf;
alias_server_conf *conf;
alias_entry *entries;
if (r->uri[0] != '/' && r->uri[0] != '\0')
return BAD_REQUEST;
sconf = r->server->module_config;
conf = (alias_server_conf *)get_module_config(sconf, &webkeep_module);
entries = (alias_entry *)conf->aliases->elts;
for (i = 0; i < conf->aliases->nelts; ++i) {
alias_entry *p = &entries[i];
int l = alias_matches (r->uri, p->fake);
if (l > 0)
{
/*
* We stash this under webkeep-path, instead of r->filename,
* because (a) we have to communicate to our handle_webkeep
* that this is one of ours and (b) because filename gets
* mangled by the access checking code. There must be a
* way around this, but it is buried in the minds of the
* apache writers.
*/
table_set( r->notes, "webkeep-path",
pstrcat(r->pool, p->real, r->uri + l, NULL) );
return OK;
}
}
return DECLINED;
}
/* Webkeeper glue */
/*
* Expected protocol:
*
* Success:
* data block with filename/type
* one or more text blocks
*
* Error:
* error block
*/
void
webKeepData( WebKeepPrinter *printer, int isBinary )
{
request_rec *r = (request_rec *)printer->closure;
if( !r->content_type && isBinary )
r->content_type = "application/octet-stream";
/* Now that we've seen the header, we clear the status */
printer->status = OK;
send_http_header( r );
}
void
webKeepError( WebKeepPrinter *printer, char *buf )
{
request_rec *r = (request_rec *)printer->closure;
log_reason(buf, r->uri, r);
printer->status = NOT_FOUND;
}
void
webKeepText( WebKeepPrinter *printer, char *buf, int len )
{
request_rec *r = (request_rec *)printer->closure;
while( len-- )
rputc( *buf++, r );
}
/* The formal handler... */
static
int handle_webkeep (request_rec *r)
{
void *sconf;
alias_server_conf *conf;
WebKeepPrinter printer;
char *depotPath;
/* For us? */
if (r->method_number != M_GET) return DECLINED;
if (!( depotPath = table_get(r->notes, "webkeep-path") ) )
return DECLINED;
/* The mulberry bush. */
sconf = r->server->module_config;
conf = (alias_server_conf *)get_module_config(sconf, &webkeep_module);
/* Start off with NOT_FOUND; cleared once we get the data block */
printer.status = NOT_FOUND;
printer.closure = (void *)r;
printer.data = webKeepData;
printer.text = webKeepText;
printer.error = webKeepError;
webKeepPrint( &conf->p4, depotPath, &printer );
return printer.status;
}
handler_rec webkeep_handlers[] = {
{ "*/*", handle_webkeep },
{ NULL }
};
module webkeep_module = {
STANDARD_MODULE_STUFF,
NULL, /* initializer */
NULL, /* dir config creater */
NULL, /* dir merger --- default is to override */
create_webkeep_config, /* server config */
merge_webkeep_config, /* merge server configs */
alias_cmds, /* command table */
webkeep_handlers, /* handlers */
translate_webkeep, /* filename translation */
NULL, /* check_user_id */
NULL, /* check auth */
NULL, /* check access */
NULL, /* type_checker */
NULL, /* fixups */
NULL /* logger */
};