"Fossies" - the Fresh Open Source Software Archive

Member "mod_sqlinclude-1.4/mod_sqlinclude.c" (13 Feb 2002, 13160 Bytes) of package /linux/www/apache_httpd_modules/old/mod_sqlinclude-1.4.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 
    2 /*
    3  * $Id: mod_sqlinclude.c,v 1.15 2002/02/13 23:19:59 carlos Exp $
    4  * 
    5  * (C) 2001-2002 by Marcin Orlowski <carlos@webnet.pl>
    6  *
    7  * Homepage: http://webnet.pl/~carlos/
    8  *
    9  * This module implements Include-like command, but
   10  * instead of including content of specified files,
   11  * it gets the data from the MySQL database, based
   12  * upon user specified query 
   13  *
   14  * Source code written using VIM with tabstop = 3
   15  *
   16  */
   17 
   18 #define MYVERSION   "1.4"
   19 #define MYNAME      "SQLInclude"
   20 #define MYURL           "http://freshmeat.net/projects/mod_sqlinclude/"
   21 
   22 //#define   MODULE_DEBUG
   23 
   24 #include "httpd.h"
   25 #include "http_config.h"
   26 #include "http_request.h"
   27 #include "http_core.h"
   28 #include "http_protocol.h"
   29 #include "http_main.h"
   30 #include "http_log.h"
   31 #include "util_script.h"
   32 #include "http_conf_globals.h"
   33 
   34 #include <mysql/mysql.h>
   35 
   36 /* TT: pulled from mod_rewrite.h */
   37 #ifndef FALSE
   38 #define FALSE 0
   39 #define TRUE  !FALSE
   40 #endif
   41 
   42 
   43 module MODULE_VAR_EXPORT sqlinclude_module;
   44 
   45 #define VERBOSE_LEVEL_QUIET     0
   46 #define VERBOSE_LEVEL_BASIC     1
   47 #define VERBOSE_LEVEL_TALK          2
   48 #define VERBOSE_LEVEL_DETAILS       3
   49 #define VERBOSE_LEVEL_DEBUG     4
   50 #define VERBOSE_LEVEL_HARDCORE  5
   51 
   52 //  SQL_VHost module config structure
   53 
   54 #define SQL_SERVER_LEN      256
   55 #define SQL_USER_LEN             80
   56 #define SQL_PASSWORD_LEN     80
   57 #define SQL_DB_LEN           80
   58 
   59 typedef struct {
   60     char    sql_server[ SQL_SERVER_LEN ];
   61     int sql_port;
   62     char    sql_user[ SQL_USER_LEN ];
   63     char    sql_password[ SQL_PASSWORD_LEN ];
   64     char    sql_db[ SQL_DB_LEN ];
   65     int UseNameColumn;
   66     int AbortOnError;
   67     int Verbose;
   68     
   69     char    *SocketFile;
   70     MYSQL   real_mysql;
   71 
   72 } sqli_server_conf;    
   73 
   74 
   75 // 
   76 void LogModuleSignature( server_rec *s )
   77 {
   78     ap_log_error( APLOG_MARK, APLOG_INFO | APLOG_NOERRNO, s,
   79         "%s: v%s by Marcin Orlowski <carlos@webnet.pl>", MYNAME, MYVERSION );
   80     ap_log_error( APLOG_MARK, APLOG_INFO | APLOG_NOERRNO, s,
   81         "%s: Project's home: %s", MYNAME, MYURL );
   82 }
   83 
   84 // getstr function to 'read' from returned row instead of real file
   85 // parm is useless for us
   86 int GetLine( char *dest, size_t dest_size, char **src_ptr )
   87 {
   88     int i;
   89     char *src = *src_ptr;
   90 
   91     // let's 'read' the src data till closest LF or \0
   92     for( i=0; i<dest_size; i++, src++ )
   93     {
   94         switch( *src )
   95             {
   96             case '\0':
   97                 dest[i] = '\0';
   98 #ifdef MODULE_DEBUG
   99                 fprintf( stderr, "'%s'\n", dest );
  100 #endif
  101                 *src_ptr = src;
  102                 if( i==0 )
  103                     return(0);      // EOF
  104                 else
  105                     return(1);      // we need to do so, otherwise last line
  106                                         // wouldn't be processed at all
  107                 break;
  108 
  109             case '\n':
  110                 dest[i] = '\0';
  111 #ifdef MODULE_DEBUG
  112                 fprintf( stderr, "'%s'\n", dest );
  113 #endif
  114                 *src_ptr = src+1;   // storing source pointer back for further
  115                                         //   reads
  116                 return(1);          // We'll be back here...
  117                 break;
  118 
  119             default:
  120                 dest[i] = *src;
  121                 break;
  122           }
  123     }
  124 
  125 #ifdef MODULE_DEBUG
  126     fprintf( stderr, "'%s'\n", dest );
  127 #endif
  128 
  129     return( 0 );    // shouldn't happen
  130 }
  131 
  132 // include holds plain ascii taken from SQL base.
  133 int ProcessEntry( server_rec *s, pool *p, pool *ptemp, 
  134                         MYSQL_ROW row, int row_number 
  135                      )
  136 {
  137 #define INCLUDE_NAME_LEN 50
  138 
  139     cmd_parms       parms  = {NULL, 0, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
  140     configfile_t    *new_cfg;
  141     const char      *errmsg;
  142     char                *row_name = ap_palloc( p, INCLUDE_NAME_LEN );
  143 
  144     char *record_ptr = (char *)row[0];      // working data pointer - we need to remember where
  145                                                         //   we have finished 'within' the data last time
  146                                                         //   we read the line of
  147                 
  148     // let's find our config data
  149     sqli_server_conf *conf = (sqli_server_conf *) ap_get_module_config( s->module_config, &sqlinclude_module );
  150     
  151     if( conf->UseNameColumn )
  152         snprintf( row_name, INCLUDE_NAME_LEN, "SQLI: %s", row[1] );
  153     else
  154         snprintf( row_name, INCLUDE_NAME_LEN, "SQLI: #%ld", row_number );
  155 
  156     if( conf->Verbose >= VERBOSE_LEVEL_DEBUG )
  157         {
  158         ap_log_error( APLOG_MARK, APLOG_INFO | APLOG_NOERRNO, s,
  159             "%s: Processing config row #%ld: '%s'", 
  160             MYNAME, row_number, row_name );
  161         }
  162 
  163     // it'd be best to call ap_pcfg_openfile() but it can't live w/o
  164     // the real file given. Maybe one day I do the trick and fool
  165     // it with something ;)  Ripped from mentioned function (1.3.19):
  166     new_cfg = ap_palloc(p, sizeof(*new_cfg));
  167     new_cfg->getstr = (void *)GetLine;  // our getstring function
  168     new_cfg->param = &record_ptr;           // data we gonna parse
  169     new_cfg->line_number = 0;
  170 
  171     parms.pool = p;
  172     parms.temp_pool = ptemp;
  173     parms.server = s;
  174     parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT);   // probably useless here
  175 
  176     new_cfg->name = row_name;
  177     parms.config_file = new_cfg;
  178 
  179     // this uses Apache core config file parser. All we have to do is to feed it
  180     // with the data, which is done using GetLine()
  181     errmsg = ap_srm_command_loop( &parms, s->lookup_defaults );
  182     if( errmsg )
  183         {
  184         ap_log_error( APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, s,
  185             "%s: Syntax error in row #%d, '%s', line %d", 
  186             MYNAME, row_number, row_name, parms.config_file->line_number );
  187         ap_log_error( APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, s,
  188             "%s: %s\n",
  189             MYNAME, errmsg );
  190         //  exit(1);
  191         return(0);
  192         }
  193 
  194     return(1);
  195 }
  196 
  197 
  198 
  199 /*
  200  * Fetches VHosts from the table
  201  */
  202 static const char *cmd_sqli_include( cmd_parms *cmd, void *dummy, char *arg )
  203 {
  204     MYSQL       *mysql = NULL;
  205     MYSQL_RES   *result;
  206     MYSQL_ROW   row;
  207 
  208     char            buf[ 1024 ];
  209     int         err, num, len;
  210     int i;
  211 
  212 
  213     // let's find our config data
  214     server_rec *s = cmd->server;
  215     sqli_server_conf *conf = (sqli_server_conf *) ap_get_module_config( s->module_config, &sqlinclude_module );
  216 
  217    // Let's sign off ;)
  218     LogModuleSignature( s );
  219 
  220 
  221     if( conf->Verbose >= VERBOSE_LEVEL_BASIC )
  222         {
  223         ap_log_error( APLOG_MARK, APLOG_INFO | APLOG_NOERRNO, s,
  224                     "%s: Attempting to SQL Include...", MYNAME );
  225         ap_log_error( APLOG_MARK, APLOG_INFO | APLOG_NOERRNO, s,
  226                     "%s: Config specifies User@Server:Port = %s@%s:%ld", MYNAME, 
  227                     conf->sql_user, conf->sql_server, conf->sql_port );
  228         }
  229 
  230 // connecting to DB
  231     for( i=0; i<=2; i++ )   // Try it a few times
  232         {
  233         mysql_init( &conf->real_mysql );
  234         mysql = mysql_real_connect( &conf->real_mysql, conf->sql_server, conf->sql_user, 
  235                              conf->sql_password, conf->sql_db, conf->sql_port, conf->SocketFile, 0 );
  236     
  237         if( mysql )
  238             {
  239             if( conf->Verbose >= VERBOSE_LEVEL_BASIC )
  240                 {
  241                 ap_log_error( APLOG_MARK, APLOG_INFO | APLOG_NOERRNO, s,
  242                                      "%s: Connection to '%s' established...", 
  243                                      MYNAME, conf->sql_server );
  244                 }
  245             break;
  246             }
  247         else
  248             {
  249             ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_NOERRNO, s,
  250                                  "%s: Connection to server %s timeouted. Retrying %ld time...",
  251                                  MYNAME, conf->sql_server, (i+1) );
  252             sleep(3);
  253             }
  254         }
  255 
  256     // no connection no fun...
  257     if( !mysql )
  258         {
  259         ap_log_error( APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, s, 
  260                                 "%s: Can't connect to '%s' server as user '%s'", 
  261                                 MYNAME, conf->sql_server, conf->sql_user );
  262         return( 0 );
  263         }
  264 
  265     // time to fetch some data using supplied user query
  266     if( (mysql_query( mysql, arg ) < 0) || ( !(result = mysql_store_result( mysql )) ) )
  267         {
  268         ap_log_error( APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, s, "%s: Querying data from SQL base: FAILED...", MYNAME );
  269         return( 0 );
  270         }
  271 
  272     num = mysql_num_rows(result);
  273     if( conf->Verbose >= VERBOSE_LEVEL_BASIC )
  274         ap_log_error( APLOG_MARK, APLOG_INFO | APLOG_NOERRNO, s,
  275             "%s: SQL query successed: %ld rows fetched", MYNAME, num );
  276   
  277     // let's loop and process all the rows
  278     i = 0;
  279     while( row = mysql_fetch_row(result) )
  280         {
  281         if( row[0] == NULL )
  282             {
  283             num = 0;
  284             goto error_exit;
  285             }
  286         else
  287             {
  288             if( ( ProcessEntry( cmd->server, cmd->pool, cmd->temp_pool, row, i ) == 0 ) &&
  289                  ( conf->AbortOnError == TRUE )
  290               )
  291                     {
  292                     goto error_exit;    // no further processing till this error is gone
  293                     }
  294             }   
  295 
  296         i++;
  297         }
  298 
  299 
  300 error_exit:
  301     mysql_free_result( result );
  302     if( mysql != NULL )
  303         {
  304         ap_log_error(APLOG_MARK, APLOG_INFO | APLOG_NOERRNO, s,
  305             "%s: Done.", MYNAME );
  306 
  307         mysql_close( mysql );
  308         }
  309 
  310     return( NULL );
  311 }
  312 
  313 
  314 // sets sql server name
  315 static const char *cmd_sqli_servername( cmd_parms *cmd, void *dummy, char *arg )
  316 {
  317     server_rec *s = cmd->server;
  318     sqli_server_conf *conf = (sqli_server_conf *) ap_get_module_config(s->module_config, &sqlinclude_module);
  319 
  320     strncpy( conf->sql_server, arg, SQL_SERVER_LEN );
  321     return(NULL);
  322 }
  323 // sets sql server port
  324 static const char *cmd_sqli_serverport( cmd_parms *cmd, void *dummy, char *arg )
  325 {
  326     server_rec *s = cmd->server;
  327     sqli_server_conf *conf = (sqli_server_conf *) ap_get_module_config(s->module_config, &sqlinclude_module);
  328 
  329     conf->sql_port = atoi( arg );
  330     return(NULL);
  331 }
  332 // sets sql user name
  333 static const char *cmd_sqli_sqluser( cmd_parms *cmd, void *dummy, char *arg )
  334 {
  335     server_rec *s = cmd->server;
  336     sqli_server_conf *conf = (sqli_server_conf *) ap_get_module_config(s->module_config, &sqlinclude_module);
  337 
  338     strncpy( conf->sql_user, arg, SQL_USER_LEN );
  339     return(NULL);
  340 }
  341 // sets sql user's password
  342 static const char *cmd_sqli_sqlpassword( cmd_parms *cmd, void *dummy, char *arg )
  343 {
  344     server_rec *s = cmd->server;
  345     sqli_server_conf *conf = (sqli_server_conf *) ap_get_module_config(s->module_config, &sqlinclude_module);
  346 
  347     strncpy( conf->sql_password, arg, SQL_PASSWORD_LEN );
  348     return(NULL);
  349 }
  350 
  351 // sets sql database name
  352 static const char *cmd_sqli_sqldb( cmd_parms *cmd, void *dummy, char *arg )
  353 {
  354     server_rec *s = cmd->server;
  355     sqli_server_conf *conf = (sqli_server_conf *) ap_get_module_config(s->module_config, &sqlinclude_module);
  356 
  357     strncpy( conf->sql_db, arg, SQL_DB_LEN );
  358 //  conf->sql_db = conf->sql_db_name;
  359     return(NULL);
  360 }
  361                       
  362 
  363 // sets AbortOnError switch 
  364 static const char *cmd_sqli_abortonerror( cmd_parms *cmd, void *dummy, int arg )
  365 {
  366     server_rec *s = cmd->server;
  367     sqli_server_conf *conf = (sqli_server_conf *) ap_get_module_config(s->module_config, &sqlinclude_module);
  368 
  369     conf->AbortOnError = arg;
  370     return(NULL);
  371 }
  372 
  373 // sets UseNameColumn switch 
  374 static const char *cmd_sql_usenamecolumn( cmd_parms *cmd, void *dummy, int arg )
  375 {
  376     server_rec *s = cmd->server;
  377     sqli_server_conf *conf = (sqli_server_conf *) ap_get_module_config(s->module_config, &sqlinclude_module);
  378 
  379     conf->UseNameColumn = arg;
  380     return(NULL);
  381 }
  382 
  383 // sets Verbose switch 
  384 static const char *cmd_sql_verbose( cmd_parms *cmd, void *dummy, char *arg )
  385 {
  386     server_rec *s = cmd->server;
  387     sqli_server_conf *conf = (sqli_server_conf *) ap_get_module_config(s->module_config, &sqlinclude_module);
  388 
  389     conf->Verbose = atoi( arg );
  390     if( conf->Verbose < VERBOSE_LEVEL_QUIET )
  391         conf->Verbose = VERBOSE_LEVEL_QUIET;
  392     else
  393         if( conf->Verbose > VERBOSE_LEVEL_HARDCORE )
  394             conf->Verbose = VERBOSE_LEVEL_HARDCORE;
  395     
  396     return(NULL);
  397 }
  398 
  399 /*
  400 ** Let's allocate module config struct and fill with defaults
  401 */
  402 static void *create_sqli_config( pool *p, server_rec *s )
  403 {
  404     sqli_server_conf *c = (sqli_server_conf *) ap_pcalloc( p, sizeof( sqli_server_conf ) );
  405 
  406     if( c )
  407         {
  408         // setting up defaults...
  409         strcpy( c->sql_server  , "localhost" );
  410         c->sql_port = 0;
  411         strcpy( c->sql_user    , "sqlinclude" );
  412         strcpy( c->sql_password, "" );
  413         strcpy( c->sql_db , "" );
  414 
  415         c->SocketFile = NULL;
  416         c->UseNameColumn = TRUE;
  417         c->AbortOnError = FALSE;
  418         c->Verbose = VERBOSE_LEVEL_BASIC;
  419         }
  420 
  421     return c;
  422 }
  423 
  424 
  425 /*
  426 ** Hare are the config directives our module implements
  427 */
  428 static const command_rec sqli_cmds[] =
  429 {
  430     { "SQL_ServerName", cmd_sqli_servername, NULL, RSRC_CONF, TAKE1,
  431             "the MySQL server, the module shall connect to. Default is 'localhost'" },
  432     { "SQL_ServerPort", cmd_sqli_serverport, NULL, RSRC_CONF, TAKE1,
  433             "the MySQL server port, the module shall connect to. If none, default port is used" },
  434     { "SQL_SQLUser", cmd_sqli_sqluser, NULL, RSRC_CONF, TAKE1,
  435             "the MySQL user modules shall authenticate as. Default 'sqlinclude'" },
  436     { "SQL_SQLPassword", cmd_sqli_sqlpassword, NULL, RSRC_CONF, TAKE1,
  437             "the MySQL password for SQLI_User. No default" },
  438     { "SQL_SQLDB", cmd_sqli_sqldb, NULL, RSRC_CONF, TAKE1,
  439             "the MySQL database the module shall use. Default 'sqlinclude'" },
  440                   
  441    { "SQL_Include", cmd_sqli_include, NULL, RSRC_CONF, TAKE1,
  442             "valid SQL query. Data returned in 1st column will be passed to Apache" },
  443 
  444     { "SQL_AbortOnError", cmd_sqli_abortonerror, NULL, RSRC_CONF, FLAG,
  445             "if 'On' row process will be aborted on syntax error. Default 'Off'" },
  446     { "SQL_UseNameColumn", cmd_sql_usenamecolumn, NULL, RSRC_CONF, FLAG,
  447         "On/Off - specifies if you want to use 2nd column as data description" },
  448     { "SQL_Verbose", cmd_sql_verbose, NULL, RSRC_CONF, TAKE1,
  449         "0,1,2,3,4,5 - level of module talkative. 0-nothing but errors, 5-speak up baby. Default is 1" },
  450 
  451     { NULL }
  452 };
  453 
  454 
  455 
  456 
  457 module MODULE_VAR_EXPORT sqlinclude_module =
  458 {
  459     STANDARD_MODULE_STUFF,
  460     NULL,           /* initializer */
  461     NULL,           /* dir config creater */
  462     NULL,           /* dir merger --- default is to override */
  463     create_sqli_config,     /* server config */
  464     NULL,           /* merge server config */
  465     sqli_cmds,      /* command table */
  466     NULL,           /* handlers */
  467     NULL,           /* filename translation */
  468     NULL,           /* check_user_id */
  469     NULL,           /* check auth */
  470     NULL,           /* check access */
  471     NULL,           /* type_checker */
  472     NULL,           /* fixups */
  473     NULL,           /* logger */
  474     NULL,           /* header parser */
  475     NULL,           /* child_init */
  476     NULL,           /* child_exit */
  477     NULL                /* post read-request */
  478 };