"Fossies" - the Fresh Open Source Software Archive 
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 };