/* * private.h * * Copyright (C) 2003 - 2008 Bojan Smojver, Rexursive * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef __RXV_SPIN_PRIVATE__ #define __RXV_SPIN_PRIVATE__ #include #include #ifdef HAVE_APR_H #include #endif #ifdef HAVE_APR_VERSION_H #include #endif #ifdef HAVE_APR_GENERAL_H #include #endif #ifdef HAVE_APR_LIB_H #include #endif #ifdef HAVE_APR_THREAD_MUTEX_H #include #endif #ifdef HAVE_APR_FILE_IO_H #include #endif #ifdef HAVE_APR_PORTABLE_H #include #endif #ifdef HAVE_APR_RING_H #include #endif #ifdef HAVE_APR_MMAP_H #include #endif #ifdef HAVE_APU_VERSION_H #include #endif #ifdef HAVE_APR_MD5_H #include #endif #ifdef HAVE_APR_RESLIST_H #include #endif #ifdef HAVE_APREQ_MODULE_APACHE2_H #include #endif #ifdef HAVE_AP_MPM_H #include #endif #ifdef HAVE_LIBXML_XMLREADER_H #include #endif #ifdef HAVE_LIBXML_XMLWRITER_H #include #endif #if defined (HAVE_LIBPQ) && defined (HAVE_LIBPQ_FE_H) #include #endif #if defined (HAVE_LIBMYSQLCLIENT_R) && defined (HAVE_MYSQL_H) #include #endif #if defined (HAVE_LIBSQLITE) && defined (HAVE_SQLITE_H) #include #endif #if defined (HAVE_LIBSQLITE3) && defined (HAVE_SQLITE3_H) #include #endif /* * Type definitions */ typedef struct rxv_spin_pool rxv_spin_pool_t; typedef struct rxv_spin_tmpl rxv_spin_tmpl_t; typedef struct rxv_spin_iter rxv_spin_iter_t; typedef struct rxv_spin_node rxv_spin_node_t; typedef struct rxv_spin_root rxv_spin_root_t; typedef struct rxv_spin_txt rxv_spin_txt_t; typedef struct rxv_spin_ref rxv_spin_ref_t; typedef struct rxv_spin_for rxv_spin_for_t; typedef struct rxv_spin_if rxv_spin_if_t; typedef struct rxv_spin_reg rxv_spin_reg_t; typedef struct rxv_spin_lit rxv_spin_lit_t; typedef struct rxv_spin_num rxv_spin_num_t; typedef struct rxv_spin_extra rxv_spin_extra_t; typedef struct rxv_spin_config rxv_spin_config_t; typedef struct rxv_spin_conncf rxv_spin_conncf_t; typedef struct rxv_spin_reqcf rxv_spin_reqcf_t; typedef struct rxv_spin_fltcf rxv_spin_fltcf_t; typedef struct rxv_spin_private rxv_spin_private_t; /* * Generic true and false */ typedef enum{ RXV_SPIN_FALSE, RXV_SPIN_TRUE } rxv_spin_bool_e; /* * Data and context structures */ /* * Data: representation of all data placed in context, be that singles (nul * terminated, counted strings) or rows (hash table of column names pointing * to arrays of data). */ #define RXV_SPIN_ROWS (~(apr_size_t)0) struct rxv_spin_data{ apr_size_t size; /* data size: length of single, ~0 otherwise */ union{ char *data; /* single data */ apr_hash_t *cols; /* columns of rows type */ }; }; struct rxv_spin_iter{ int index; /* current position */ int size; /* number of elements in each array */ rxv_spin_data_t *rows; /* data */ }; struct rxv_spin_curs{ rxv_spin_iter_t *iter; /* rows iterator */ apr_array_header_t *data; /* array of data */ }; struct rxv_spin_ctx{ rxv_spin_data_t *data; /* application prepared data */ request_rec *r; /* raw Apache request */ apreq_handle_t *req; /* parsed request */ rxv_spin_private_t *priv; /* process private data */ rxv_spin_config_t *conf; /* module configration */ rxv_spin_reqcf_t *rcnf; /* request configuration */ rxv_spin_db_t *store; /* store database connection */ char *sesfn; /* session store file name */ rxv_spin_bool_e sdirty:1; /* session store dirty */ rxv_spin_bool_e adirty:1; /* application store dirty */ rxv_spin_bool_e havest:1; /* we have the store */ rxv_spin_bool_e dbstor:1; /* store has database backend */ rxv_spin_bool_e closed:1; /* store still closed */ rxv_spin_bool_e killed:1; /* session was killed */ apr_hash_t *app; /* application store */ apr_hash_t *ses; /* session store */ apr_time_t ptime; /* time configuration was last parsed */ const char *sstore; /* select timestamp and data from store */ const char *ustore; /* update timestamp and data in store */ const char *istore; /* insert timestamp and data into store */ const char *ustamp; /* update timestamp in store */ const char *remove; /* delete session in store */ void *extra; /* extra data placed in context by API user */ }; /* * Database structures */ struct rxv_spin_pool{ APR_RING_ENTRY(rxv_spin_pool) link; /* LRU: ring link */ apr_pool_t *pool; /* connection pool specific pool */ char *cinfo; /* type:connect string */ char *parms; /* connect string */ const apr_dbd_driver_t *driver; /* APR Util database driver */ rxv_spin_private_t *priv; /* process private data */ apr_time_t atime; /* time connection was last accessed */ #if APR_HAS_THREADS union{ apr_reslist_t *list; /* connection resource list */ #endif rxv_spin_db_t *conn; /* single connection (no threads) */ #if APR_HAS_THREADS }; #endif }; struct rxv_spin_db{ apr_pool_t *pool; /* connection specific pool */ rxv_spin_pool_t *cp; /* connection pool for this handle */ apr_dbd_t *handle; /* APR Util database handle */ apr_hash_t *stmts; /* prepared statements */ }; struct rxv_spin_db_txn{ apr_pool_t *pool; /* transaction specific pool */ rxv_spin_db_t *db; /* database assiciated with this transaction */ apr_dbd_transaction_t *txn; /* APR Util transaction */ }; /* * Statement/node types */ typedef enum{ RXV_SPIN_UDF, RXV_SPIN_TXT, RXV_SPIN_REF, RXV_SPIN_FOR, RXV_SPIN_IF, RXV_SPIN_REG, RXV_SPIN_LIT, RXV_SPIN_NUM } rxv_spin_node_e; /* * Text types */ typedef enum{ RXV_SPIN_TXT_BKT, RXV_SPIN_TXT_TXT, RXV_SPIN_TXT_OFF } rxv_spin_txt_e; /* * Reference types */ typedef enum{ RXV_SPIN_REF_REG, RXV_SPIN_REF_SIZ, RXV_SPIN_REF_IND } rxv_spin_ref_e; /* * Conditional types: #if (guaranteed to be 0) and #unless (guaranteed to be 1) */ typedef enum{ RXV_SPIN_IF_IF, RXV_SPIN_IF_UNLESS } rxv_spin_if_e; /* * Comparison operators */ typedef enum{ RXV_SPIN_OP_NONE, RXV_SPIN_OP_MATCH, RXV_SPIN_OP_EQ_LIT, RXV_SPIN_OP_EQ_NUM, RXV_SPIN_OP_EQ_REF, RXV_SPIN_OP_MODULO } rxv_spin_op_e; /* * Maximum nesting depth of the #if/#unless and #for */ #define RXV_SPIN_MAX_DEPTH 32 /* * Maximum/minimum size of scan buffer */ #define RXV_SPIN_SCAN_MIN APR_BUCKET_BUFF_SIZE #define RXV_SPIN_SCAN_MAX (RXV_SPIN_SCAN_MIN*8) /* * Maximum number of buckets to hold before we flush */ #define RXV_SPIN_FLUSH_COUNT 64 /* * Data structures for Abstract Syntax Tree */ struct rxv_spin_node{ rxv_spin_node_e type:3; union{ rxv_spin_txt_e ttyp:2; /* type of text: bucket, text or start/length */ rxv_spin_ref_e rtyp:2; /* type of reference: regular, size or index */ struct{ rxv_spin_if_e ityp:1; /* if: is this actually the unless, not if */ rxv_spin_op_e iopr:3; /* if: what operator is used */ }; }; rxv_spin_node_t *next; }; struct rxv_spin_txt{ rxv_spin_node_t node; union{ apr_bucket *bucket; /* ready to copy bucket */ struct{ union{ const char *text; /* filter will point to scanned text */ apr_off_t start; /* start of mmap()-ed region */ }; apr_size_t length; /* length of scanned text or mmap()-ed region */ }; }; }; struct rxv_spin_ref{ rxv_spin_node_t node; char *name; /* last chunk of the full name */ rxv_spin_ref_t *ref; /* enclosing reference */ rxv_spin_data_t *data; /* data currently associated with this reference */ apr_size_t *ip; /* pointer to actual index of data */ apr_size_t index; /* index of data in a loop */ apr_size_t fixed; /* fixed index of data */ }; struct rxv_spin_for{ rxv_spin_node_t node; rxv_spin_ref_t *ref; /* what to loop around */ rxv_spin_node_t *stmt; /* what to replicate each time */ }; struct rxv_spin_if{ rxv_spin_node_t node; rxv_spin_ref_t *ref; /* the reference we're checking, on the left */ union{ struct{ char *srg; /* string to build regular expression from */ ap_regex_t *reg; /* regular expression to match */ }; rxv_spin_ref_t *rfr; /* the reference to match, on the right */ char *lit; /* literal string */ struct{ unsigned long num; /* number to the right of the operator */ unsigned long res; /* result of the modulo comparison, right of == */ }; }; rxv_spin_node_t *pos; /* statement if ref is not null */ rxv_spin_node_t *neg; /* statement if ref is null */ }; struct rxv_spin_reg{ rxv_spin_node_t node; char *srg; ap_regex_t reg; }; struct rxv_spin_lit{ rxv_spin_node_t node; char *lit; }; struct rxv_spin_num{ rxv_spin_node_t node; unsigned long num; }; /* * Data structures for cached template */ struct rxv_spin_tmpl{ APR_RING_ENTRY(rxv_spin_tmpl) link; /* LRU: ring link */ apr_pool_t *pool; /* template specific pool */ char *key; /* template identifier */ rxv_spin_root_t *root; /* roots */ rxv_spin_private_t *priv; /* process private data */ apr_time_t atime; /* time template was last accessed */ apr_size_t count; /* number of threads using this */ }; struct rxv_spin_root{ rxv_spin_node_t *root; rxv_spin_root_t *next; }; /* * Data structures for the scanner */ struct rxv_spin_extra{ apr_pool_t *pool; /* pool for all memory allocations */ apr_off_t offset; /* from beginning of brigade */ apr_off_t pos; /* good chunk from beginning of brigade */ apr_off_t row; /* current row of the template */ apr_off_t col; /* current column of the template */ rxv_spin_tmpl_t *cache; /* cached template */ rxv_spin_root_t *current; /* cached root we should use */ apr_hash_t *refs; /* equivalent refs in the copy of the cache */ rxv_spin_node_t *root; /* root of the abstract syntax tree */ rxv_spin_for_t **loop; /* nesting loops */ unsigned char *nest; /* nesting type stack, #if or #for */ int depth; /* current nesting depth */ int ldepth; /* current loop nesting depth */ apr_size_t count; /* number of parsed TXT/REF tokens */ char *error; /* descriptive error */ apr_bucket_brigade *input; /* what we're scanning */ apr_bucket_brigade *split; /* split brigade that needs saving */ apr_bucket_brigade *output; /* where the result goes */ apr_bucket_brigade *metabb; /* metadata bucket brigade to send out */ apr_bucket *eof; /* brigade sentinel seen */ apr_bucket *eos; /* EOS bucket seen */ apr_bucket *scan; /* first bucket we're scanning */ apr_size_t soff; /* offset from start of the scan bucket */ apr_off_t erow; /* scan row where the error occurred */ apr_off_t ecol; /* scan column where the error occurred */ char *buf; /* flex buffer */ apr_size_t blen; /* flex buffer length */ apr_size_t bpos; /* where are we within the buffer now */ void *scanner; /* the scanner */ rxv_spin_ctx_t *ctx; /* the context - data, parameters etc. */ ap_filter_t *f; /* our filter, if any */ }; /* Function declarations */ apr_status_t rxv_spin_build(rxv_spin_extra_t *extra); apr_status_t rxv_spin_render(rxv_spin_node_t *node,rxv_spin_extra_t *extra); /* Missing parser and scanner stuff */ #define YYSTYPE rxv_spin_node_t* #define YY_EXTRA_TYPE rxv_spin_extra_t* int rxv_spin_yyparse(void *YYPARSE_PARAM); void rxv_spin_yyerror(char *s); int rxv_spin_yylex(rxv_spin_node_t **yyval_param,void *yyscanner); /* * Module configuration */ typedef enum{ RXV_SPIN_APPLICATION_SET=0x0001, RXV_SPIN_APPINIT_SET =0x0002, RXV_SPIN_APPFIXUP_SET =0x0004, RXV_SPIN_APPENTRY_SET =0x0008, RXV_SPIN_CFGFN_SET =0x0010, RXV_SPIN_STORE_SET =0x0020, RXV_SPIN_STORETBL_SET =0x0040, RXV_SPIN_CKNAME_SET =0x0080, RXV_SPIN_CKPATH_SET =0x0100, RXV_SPIN_CKDOMAIN_SET =0x0200, RXV_SPIN_SALT_SET =0x0400, RXV_SPIN_OSLT_SET =0x0800, RXV_SPIN_TIMEOUT_SET =0x1000, RXV_SPIN_CACHE_SET =0x2000, RXV_SPIN_CONNPOOL_SET =0x4000 } rxv_spin_cfg_e; struct rxv_spin_config{ char *application; /* path to the application shared library */ char *appinit; /* application init function name */ char *appfixup; /* application fixup function name */ char *appentry; /* application entry function name */ char *cfgfn; /* configuration file filename */ char *driver; /* store connect driver */ char *store; /* store connect string */ char *appfn; /* application store file name */ char *storetbl; /* store table name */ char *ckname; /* name of the cookie for session tracking */ char *ckpath; /* path of the cookie for session tracking */ char *ckdomain; /* domain of the cookie for session tracking */ char *salt; /* current crypto salt */ char *oslt; /* old crypto salt */ apr_time_t timeout; /* session timeout */ rxv_spin_bool_e cache:1; /* enable template caching */ rxv_spin_bool_e connpool:1; /* enable connection pooling */ rxv_spin_cfg_e set:15; /* what options were actually set */ }; /* * Request configuration */ struct rxv_spin_reqcf{ char *sesid; /* session id */ rxv_spin_ctx_t *ctx; /* context passed from fixup to handler */ apr_dso_handle_sym_t fix; /* fixup function handle */ apr_dso_handle_sym_t svc; /* service function handle */ rxv_spin_bool_e valid:1; /* session is valid: value 1, otherwise 0 */ }; /* * Filter configuration */ struct rxv_spin_fltcf{ rxv_spin_extra_t *extra; }; /* * Private process data */ struct rxv_spin_private{ apr_pool_t *pool; /* process specific pool */ apr_hash_t *dso; /* cache of DSOs so we don't keep opening */ apr_hash_t *tmpls; /* hash table of templates */ apr_hash_t *conns; /* hash table of connection pools */ int count; /* maximum number of connections in each pool */ APR_RING_HEAD(rxv_spin_tmpl_list,rxv_spin_tmpl) tmpl; /* LRU: tmpl list */ APR_RING_HEAD(rxv_spin_pool_list,rxv_spin_pool) conn; /* LRU: conn list */ #if APR_HAS_THREADS apr_thread_mutex_t *mutex; /* global thread mutex */ #endif }; #if APR_HAS_THREADS #define rxv_spin_lock(p) \ do { \ if((p)->mutex) apr_thread_mutex_lock((p)->mutex); \ } while(0) #define rxv_spin_trylock(p,rv) \ do { \ if((p)->mutex) (rv)=apr_thread_mutex_trylock((p)->mutex); \ else (rv)=APR_SUCCESS; \ } while(0) #define rxv_spin_unlock(p) \ do { \ if((p)->mutex) apr_thread_mutex_unlock((p)->mutex); \ } while(0) #else #define rxv_spin_lock(p) #define rxv_spin_trylock(p,rv) #define rxv_spin_unlock(p) #endif /* * Crypto lengths */ #define RXV_SPIN_SALT_MIN 30 #define RXV_SPIN_SALT_MAX 64 /* * Missing from APR 1.2.x */ #ifndef APR_INT64_MIN #ifdef INT64_MIN #define APR_INT64_MIN INT64_MIN #else #define APR_INT64_MIN (APR_INT64_C(-0x7fffffffffffffff) - 1) #endif #endif #endif