/*
* rxv_spin.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_H__
#define __RXV_SPIN_H__
/**
* @file rxv_spin.h
* @brief mod_spin data structures and functions
*/
/**
* @mainpage
*
Copyright © 2003 - 2008 Bojan Smojver, Rexursive®
*
* @anchor Introduction
* Introduction
* @par See also:
* @ref Installation
* @ref News
* @ref Licence
*
* @verbinclude README
*
* @anchor Installation
* Installation and configuration
* @par See also:
* @ref Introduction
* @ref News
* @ref Licence
*
* @verbinclude INSTALL
*
* @anchor News
* News
* @par See also:
* @ref Introduction
* @ref Installation
* @ref Licence
* @verbinclude NEWS
*
* @anchor Licence
* Terms of copying, distribution and modification
* @par See also:
* @ref Introduction
* @ref News
* @ref Installation
* @verbinclude COPYING
*/
#define RXV_SPIN_STDC_HEADERS @RXV_SPIN_STDC_HEADERS@
#define RXV_SPIN_HAVE_UNISTD_H @RXV_SPIN_HAVE_UNISTD_H@
#define RXV_SPIN_HAVE_SYS_TYPES_H @RXV_SPIN_HAVE_SYS_TYPES_H@
#define RXV_SPIN_HAVE_APR_STRINGS_H @RXV_SPIN_HAVE_APR_STRINGS_H@
#define RXV_SPIN_HAVE_APR_POOLS_H @RXV_SPIN_HAVE_APR_POOLS_H@
#define RXV_SPIN_HAVE_APR_HASH_H @RXV_SPIN_HAVE_APR_HASH_H@
#define RXV_SPIN_HAVE_APR_TIME_H @RXV_SPIN_HAVE_APR_TIME_H@
#define RXV_SPIN_HAVE_APR_DSO_H @RXV_SPIN_HAVE_APR_DSO_H@
#define RXV_SPIN_HAVE_APR_BUCKETS_H @RXV_SPIN_HAVE_APR_BUCKETS_H@
#define RXV_SPIN_HAVE_APR_DBD_H @RXV_SPIN_HAVE_APR_DBD_H@
#define RXV_SPIN_HAVE_APREQ_PARAM_H @RXV_SPIN_HAVE_APREQ_PARAM_H@
#define RXV_SPIN_HAVE_APREQ_COOKIE_H @RXV_SPIN_HAVE_APREQ_COOKIE_H@
#define RXV_SPIN_HAVE_APREQ_MODULE_H @RXV_SPIN_HAVE_APREQ_MODULE_H@
#define RXV_SPIN_HAVE_HTTPD_H @RXV_SPIN_HAVE_HTTPD_H@
#define RXV_SPIN_HAVE_HTTP_REQUEST_H @RXV_SPIN_HAVE_HTTP_REQUEST_H@
#define RXV_SPIN_HAVE_AP_REGEX_H @RXV_SPIN_HAVE_AP_REGEX_H@
#include
#if RXV_SPIN_STDC_HEADERS
#include
#include
#include
#include
#endif
#if RXV_SPIN_HAVE_UNISTD_H
#include
#endif
#if RXV_SPIN_HAVE_SYS_TYPES_H
#include
#endif
#if RXV_SPIN_HAVE_APR_STRINGS_H
#include
#endif
#if RXV_SPIN_HAVE_APR_POOLS_H
#include
#endif
#if RXV_SPIN_HAVE_APR_HASH_H
#include
#endif
#if RXV_SPIN_HAVE_APR_TIME_H
#include
#endif
#if RXV_SPIN_HAVE_APR_DSO_H
#include
#endif
#if RXV_SPIN_HAVE_APR_BUCKETS_H
#include
#endif
#if RXV_SPIN_HAVE_APR_DBD_H
#include
#endif
#if RXV_SPIN_HAVE_APREQ_PARAM_H
#include
#endif
#if RXV_SPIN_HAVE_APREQ_COOKIE_H
#include
#endif
#if RXV_SPIN_HAVE_APREQ_MODULE_H
#include
#endif
/* remove some macros, Apache defines them as well */
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#undef PACKAGE_BUGREPORT
#undef PACKAGE_NAME
#undef PACKAGE_STRING
#undef PACKAGE_TARNAME
#undef PACKAGE_VERSION
#endif
#if RXV_SPIN_HAVE_HTTPD_H
#include
#endif
/* remove Apache macros, restore good definitions */
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#undef PACKAGE_BUGREPORT
#undef PACKAGE_NAME
#undef PACKAGE_STRING
#undef PACKAGE_TARNAME
#undef PACKAGE_VERSION
#define PACKAGE_BUGREPORT RXV_SPIN_PACKAGE_BUGREPORT
#define PACKAGE_NAME RXV_SPIN_PACKAGE_NAME
#define PACKAGE_STRING RXV_SPIN_PACKAGE_STRING
#define PACKAGE_TARNAME RXV_SPIN_PACKAGE_TARNAME
#define PACKAGE_VERSION RXV_SPIN_PACKAGE_VERSION
#endif
#if RXV_SPIN_HAVE_HTTP_REQUEST_H
#include
#endif
#if RXV_SPIN_HAVE_AP_REGEX_H
#include
#endif
/**
* Data functions (mod_spin API)
*
* @defgroup rxv_spin_data_functions Data functions
* @{
*/
typedef enum{
RXV_SPIN_TRIM_LEFT=1, /**< trim whitespace on the left */
RXV_SPIN_TRIM_RIGHT /**< trim whitespace on the right */
} rxv_spin_trim_e;
typedef struct rxv_spin_data rxv_spin_data_t; /**< data type */
typedef struct rxv_spin_curs rxv_spin_curs_t; /**< cursor type */
/** @} */
/**
* Context functions (mod_spin API)
*
* @defgroup rxv_spin_context_functions Context functions
* @{
*/
typedef struct rxv_spin_ctx rxv_spin_ctx_t; /**< context type */
/** @} */
/**
* @addtogroup rxv_spin_data_functions
* @{
*/
/* Data creation and manipulation functions */
/**
* Create single data from from a nul terminated string.
* String is not copied.
*
* @param pool Pool for allocation of data structure
* @param str String to create data from
* @param data Pointer to existing data or NULL to allocate anew
* @return rxv_spin_data_t pointer, structure allocated from
* the pool, NULL on error
* @par Example:
* @code
* rxv_spin_datum(pool,"some string",NULL);
* @endcode
* @remarks Pool can be NULL is data is not NULL.
*/
rxv_spin_data_t *rxv_spin_datum(apr_pool_t *pool,const char *str,
rxv_spin_data_t *data);
/**
* Create single data from from a counted string. Although the string is
* counted, it has to end with a nul character. This function will check for
* it and if it isn't there, it'll refuse to create the single. Keep in mind
* that the memory allocated for the counted string will be size + 1, meaning,
* if it isn't, the check for that nul character at the end may cause a
* segfault.
* String is not copied.
*
* @param pool Pool for allocation of data structure
* @param str String to create data from
* @param size Size of the string, not counting the ending nul character
* @param data Pointer to existing data or NULL to allocate anew
* @return rxv_spin_data_t pointer, structure allocated from
* the pool, NULL on error
* @par Example:
* @code
* rxv_spin_mdatum(pool,"1234567890",10,NULL);
* @endcode
* @remarks Pool can be NULL is data is not NULL.
*/
rxv_spin_data_t *rxv_spin_mdatum(apr_pool_t *pool,const char *str,
apr_size_t size,rxv_spin_data_t *data);
/**
* Get a nul terminated string from single data. String is not copied.
*
* @param single Single data
* @return nul terminated string, NULL on error
* @par Example:
* @code
* rxv_spin_string(data);
* @endcode
*/
char *rxv_spin_string(rxv_spin_data_t *single);
/**
* Get a hash table from rows data. Hash table is not copied.
*
* @param rows Rows data
* @return pointer to hash table NULL on error
* @par Example:
* @code
* rxv_spin_guts(data);
* @endcode
* @remarks Values in the hash table are apr_array_header_t pointers. The
* arrays contain rxv_spin_data_t (meaning: array->elts is
* rxv_spin_data_t pointer), so it is possible to use this mechanism
* to iterate through individual colums as well. If you do modify
* data this way, make sure all arrays contained in the hash have the
* same size, or you may get segfaults when you try to access the
* data. Keep in mind that although you can find out the size of the
* rxv_spin_data_t this way, it is still an opaque type that should
* be accessed through mod_spin API.
*/
apr_hash_t *rxv_spin_guts(rxv_spin_data_t *rows);
/**
* Get the size of data. This does not include terminating nul byte for
* single. Number of rows is returned for rows.
*
* @param data Data
* @return size of single or rows or 0 on error
* @par Example:
* @code
* rxv_spin_size(data);
* @endcode
*/
apr_size_t rxv_spin_size(rxv_spin_data_t *data);
#define rxv_spin_multi(d) (!rxv_spin_string(d) && rxv_spin_size(d)>0)
/**< check if data is of rows type */
#define rxv_spin_single(d) (!rxv_spin_multi(d))
/**< check if data is of single type */
/**
* Create a column of data from other data. The data returned is of type rows.
* Data is not copied.
*
* @param pool Pool for allocation of data structure
* @param name Name of the column
* @param data Pointer to existing data or NULL to allocate anew
* @param ... List of rxv_spin_data_t pointers, ending with NULL
* @return rxv_spin_data_t pointer, structures allocated from
* the pool, NULL on error
* @par Example:
* @code
* rxv_spin_column(pool,"column1",NULL,
* rxv_spin_rows(pool,NULL,x,y,z,NULL),
* rxv_spin_rows(pool,NULL,u,v,w,NULL),
* rxv_spin_single(pool,"some important data",NULL),
* NULL);
* @endcode
*/
rxv_spin_data_t *rxv_spin_column(apr_pool_t *pool,const char *name,
rxv_spin_data_t *data,...)
#if defined(__GNUC__) && __GNUC__ >= 4
__attribute__((sentinel))
#endif
;
/**
* Create a column of data by parsing a string. The data returned is of type
* rows.
* String to parse is NOT copied into pool storage before parsing, therefore,
* if you want to parse constant strings, you MUST copy them. This function
* actually chops up the string that is passed into it, so if the string is
* supposed to be used somewhere else, you may get a nasty surprise after
* calling this function. It is safer to make a copy.
*
* @param pool Pool for allocation of data structure
* @param name Name of the column
* @param str String to parse
* @param sep Separators to use when parsing
* @param data Pointer to existing data or NULL to allocate anew
* @return rxv_spin_data_t pointer, structures allocated from
* the pool, NULL on error
* @par Example:
* @code
* rxv_spin_parse(pool,"column1",
* apr_pstrdup(pool,"first str,second str/third str"),
* ",/",NULL);
* @endcode
*/
rxv_spin_data_t *rxv_spin_parse(apr_pool_t *pool,const char *name,
char *str,const char *sep,
rxv_spin_data_t *data);
/**
* Create a column of data from an array of nul terminated strings. The data
* returned is of type rows.
* Strings are not copied.
*
* @param pool Pool for allocation of data structure
* @param name Name of the column
* @param arr Array of pointers to nul terminated strings
* @param data Pointer to existing data or NULL to allocate anew
* @return rxv_spin_data_t pointer, structures allocated from
* the pool, NULL on error
* @par Example:
* @code
* rxv_spin_array(pool,"column1",arr,NULL);
* @endcode
*/
rxv_spin_data_t *rxv_spin_array(apr_pool_t *pool,const char *name,
apr_array_header_t *arr,rxv_spin_data_t *data);
/**
* Create a column of data by reading a bucket brigade. The data returned is
* of type rows.
* All read data is copied into the storage allocated from the pool.
*
* @param pool Pool for allocation of data structure
* @param name Name of the column
* @param bb Bucket brigade to read
* @param data Pointer to existing data or NULL to allocate anew
* @return rxv_spin_data_t pointer, structures allocated from
* the pool, NULL on error
* @par Example:
* @code
* rxv_spin_brigade(pool,"column1",bb,NULL);
* @endcode
*/
rxv_spin_data_t *rxv_spin_brigade(apr_pool_t *pool,const char *name,
apr_bucket_brigade *bb,
rxv_spin_data_t *data);
/**
* Create an empty column of data.
*
* @param pool Pool for allocation of data structures
* @param name Name of the column
* @param size Size (number of elements) of the column to create
* @param data Pointer to existing data or NULL to allocate anew
* @return rxv_spin_data_t pointer, structures allocated from
* the pool, NULL on error
* @par Example:
* @code
* rxv_spin_null(pool,"column1",rxv_spin_rws_len(r),NULL);
* @endcode
* @remarks This function is useful for creating boilerplate columns.
*/
rxv_spin_data_t *rxv_spin_null(apr_pool_t *pool,const char *name,
apr_size_t size,rxv_spin_data_t *data);
/**
* Merge rows of data.
* If rows contain different array lengths, the biggest size will be used.
* Data is not copied.
*
* @param pool Pool for allocation of data structure
* @param data Pointer to existing data or NULL to allocate anew
* @param ... List of rxv_spin_data_t pointers, ending with NULL
* @return rxv_spin_data_t pointer, structures allocated from
* the pool, NULL on error
* @par Example:
* @code
* rxv_spin_rows(pool,NULL,def,ghi,xyz,NULL);
* @endcode
* @remarks Rows that appear later in the argument list override columns of
* the same name from earlier arguments. If columns need to have
* their size adjusted, empty elements will be pushed to the end of
* the arrays that columns point to. Note that give that data isn't
* copied, this resizing affects original columns too.
*/
rxv_spin_data_t *rxv_spin_rows(apr_pool_t *pool,rxv_spin_data_t *data,...)
#if defined(__GNUC__) && __GNUC__ >= 4
__attribute__((sentinel))
#endif
;
/**
* Get first row of data.
*
* @param pool Pool for allocation of data structure
* @param rows Data to get the first row from
* @param ... List of column names (constant pointer to nul terminated
* string) and cursors (pointer to pointer of rxv_spin_curs_t),
* ending with NULL
* @return 1 if successful, or 0 if no rows available
* @par Example:
* @code
* rxv_spin_curs_t *c1=NULL,*c2=NULL;
*
* rxv_spin_first(pool,rows,"column1",&c1,"column2",&c2,NULL);
* @endcode
*/
apr_size_t rxv_spin_first(apr_pool_t *pool,rxv_spin_data_t *rows,...)
#if defined(__GNUC__) && __GNUC__ >= 4
__attribute__((sentinel))
#endif
;
/**
* Get next row of data.
*
* @param curs Pointer to the cursor
* @return current row number, counted from 1, or 0 if no more available
* @par Example:
* @code
* for(r=rxv_spin_first(p,rws,"c1",&c1,NULL);r;r=rxv_spin_next(c1)){
* ...
* }
* @endcode
* @remarks Note that it is sufficient to call rxv_spin_next() just once on
* any of the cursors that have been initialised through
* rxv_spin_first() to get the next row on all of them.
*/
apr_size_t rxv_spin_next(rxv_spin_curs_t *curs);
/**
* Get data from the cursor.
*
* @param curs Pointer to to the cursor
* @return rxv_spin_data_t pointer, NULL on error
* @par Example:
* @code
* data=rxv_spin_this(curs);
* @endcode
*/
rxv_spin_data_t *rxv_spin_this(rxv_spin_curs_t *curs);
/**
* Get an entry from rows of data.
*
* @param rows Rows data
* @param name Name of the column
* @param index Row number, starting at 1
* @return rxv_spin_data_t pointer, NULL on error
* @par Example:
* @code
* data=rxv_spin_entry(rows,"thiscolumn",3);
* @endcode
*/
rxv_spin_data_t *rxv_spin_entry(rxv_spin_data_t *rows,const char *name,
apr_size_t index);
/**
* Resize rows.
*
* @param pool Pool for all memory allocation
* @param data Data, rows or metadata type only
* @param size New size
* @return resized data, NULL on error
* @par Example:
* @code
* rxv_spin_resize(data,100);
* @endcode
* @remarks If the requested size is smaller than original size, only the size
* field will be adjusted. If the requested size is larger, the
* structures containing pointers to data will be copied to the newly
* allocated memory space. If you rely on the old data (i.e. before
* resizing) in any way, you might create big problems, even security
* related ones.
*/
rxv_spin_data_t *rxv_spin_resize(rxv_spin_data_t *data,apr_size_t size);
/**
* Make a copy of data. The result is a full, deep copy (i.e. there is not a
* single byte in common with the original).
*
* @param pool Pool for all memory allocation
* @param src Data to copy, any type
* @param data Pointer to existing data or NULL to allocate anew
* @return copy of the data, NULL on error
* @par Example:
* @code
* rxv_spin_copy(pool,data,NULL);
* @endcode
* @remarks If you're using this function on rows, the copying might take a
* while, as all memory is going to be allocated from the pool and
* all data and structures are going to be copied, down to the last
* string. In such a scenario, only use this function if you are
* planning on putting the result into context as a new item, or you
* need to keep the original data for some other reason.
*/
rxv_spin_data_t *rxv_spin_copy(apr_pool_t *pool,rxv_spin_data_t *src,
rxv_spin_data_t *data);
/**
* Convert a string to lowercase. String pushed into the function is modified,
* no copy is made.
*
* @param str String to convert, nul terminated
* @return the same string in lowercase, NULL on error
* @par Example:
* @code
* rxv_spin_slower(single);
* @endcode
*/
char *rxv_spin_slower(const char *str);
/**
* Convert a string to uppercase. String pushed into the function is modified,
* no copy is made.
*
* @param str String to convert, nul terminated
* @return the same string in uppercase, NULL on error
* @par Example:
* @code
* rxv_spin_supper(single);
* @endcode
*/
char *rxv_spin_supper(const char *str);
/**
* Trim whitespace from a string. No copy is made. You MUST copy the string
* if you're trimming constant strings.
*
* @param str String
* @param what Trim left: RXV_SPIN_TRIM_LEFT, trim right: RXV_SPIN_TRIM_RIGHT
* @return the same string trimmed, NULL on error
* @par Example:
* @code
* rxv_spin_strim(apr_strdup(pool," string with whitespace ",
* RXV_SPIN_TRIM_LEFT|RXV_SPIN_TRIM_RIGHT);
* @endcode
*/
char *rxv_spin_strim(const char *str,rxv_spin_trim_e what);
#define rxv_spin_strim2(s) \
rxv_spin_strim((s),(RXV_SPIN_TRIM_LEFT|RXV_SPIN_TRIM_RIGHT))
/**< trim string on both sides */
#define rxv_spin_striml(s) \
rxv_spin_strim((s),(RXV_SPIN_TRIM_LEFT))
/**< trim string on the left side */
#define rxv_spin_strimr(s) \
rxv_spin_strim((s),(RXV_SPIN_TRIM_RIGHT))
/**< trim string on the right side */
#define rxv_spin_lower(s) \
((s)?(rxv_spin_single(s) \
?rxv_spin_datum(NULL,rxv_spin_slower(rxv_spin_string(s)),(s)) \
:NULL) \
:NULL)
/**< convert single to lowercase */
#define rxv_spin_upper(s) \
((s)?(rxv_spin_single(s) \
?rxv_spin_datum(NULL,rxv_spin_supper(rxv_spin_string(s)),(s)) \
:NULL) \
:NULL)
/**< convert single to uppercase */
#define rxv_spin_trim(s,w) \
((s)?(rxv_spin_single(s) \
?rxv_spin_datum(NULL,rxv_spin_strim(rxv_spin_string(s),(w)),(s)) \
:NULL) \
:NULL)
/**< trim single */
#define rxv_spin_trim2(s) \
rxv_spin_trim((s),(RXV_SPIN_TRIM_LEFT|RXV_SPIN_TRIM_RIGHT))
/**< trim single on both sides */
#define rxv_spin_triml(s) \
rxv_spin_trim((s),(RXV_SPIN_TRIM_LEFT))
/**< trim single on the left side */
#define rxv_spin_trimr(s) \
rxv_spin_trim((s),(RXV_SPIN_TRIM_RIGHT))
/**< trim single on the right side */
/** @} */
/**
* @addtogroup rxv_spin_context_functions
* @{
*/
/* Context functions and macros */
/**
* Retrieve context specific pool.
*
* @param ctx Context
* @return pointer to context specific pool, NULL on error
* @par Example:
* @code
* rxv_spin_pool(ctx);
* @endcode
*/
apr_pool_t *rxv_spin_pool(rxv_spin_ctx_t *ctx);
/**
* Retrieve process specific pool.
*
* @param ctx Context
* @return pointer to process specific pool, NULL on error
* @par Example:
* @code
* rxv_spin_ppool(ctx);
* @endcode
*/
apr_pool_t *rxv_spin_ppool(rxv_spin_ctx_t *ctx);
/**
* Retrieve data from context.
*
* @param ctx Context
* @return pointer to data, NULL on error
* @par Example:
* @code
* rxv_spin_data(ctx);
* @endcode
*/
rxv_spin_data_t *rxv_spin_data(rxv_spin_ctx_t *ctx);
/**
* Retrieve Apache request from context.
*
* @param ctx Context
* @return pointer to Apache request, NULL on error
* @par Example:
* @code
* rxv_spin_r(ctx);
* @endcode
*/
request_rec *rxv_spin_r(rxv_spin_ctx_t *ctx);
/**
* Retrieve parsed request from context.
*
* @param ctx Context
* @return pointer to parsed request, NULL on error
* @par Example:
* @code
* rxv_spin_req(ctx);
* @endcode
*/
apreq_handle_t *rxv_spin_req(rxv_spin_ctx_t *ctx);
/**
* Retrieve extra data from the context.
*
* @param ctx Context
* @return pointer to extra data, NULL on error
* @par Example:
* @code
* rxv_spin_xget(ctx);
* @endcode
*/
void *rxv_spin_xget(rxv_spin_ctx_t *ctx);
/**
* Set extra data into the context.
*
* @param ctx Context
* @param extra Pointer to extra data to set into the context
* @return pointer to extra data, NULL on error
* @par Example:
* @code
* rxv_spin_xset(ctx,somedata);
* @endcode
*/
void *rxv_spin_xset(rxv_spin_ctx_t *ctx,void *extra);
/**
* Retrieve data from the context.
*
* @param ctx Context
* @param key Unique key by which this data is identified
* @return pointer to data, NULL if not found
* @par Example:
* @code
* rxv_spin_get(ctx,"result");
* @endcode
*/
rxv_spin_data_t *rxv_spin_get(rxv_spin_ctx_t *ctx,const char *key);
#define rxv_spin_sget(ctx,key) \
rxv_spin_string(rxv_spin_get((ctx),(key)))
/**< get a string from the context by converting from single */
/**
* Place data into the context.
*
* @param ctx Context
* @param key Unique key by which this data is identified
* @param value The actual data
* @return pointer to data, NULL on error
* @par Example:
* @code
* rxv_spin_set(ctx,"result",result);
* @endcode
* @remarks This function is also used for context data removal, through a
* macro. In such a case, NULL return value is not necessarily a
* failure.
* @warning
* The data set into the context has to have at least the lifetime of the
* request. Anything less and the pool used to hold the data may get cleaned
* before the bucket holding the value gets created. In most cases, this will
* result in a segfault.
* @warning
* Do not put data allocated from the heap (with malloc(), calloc() and
* friends) into the context unless you set up cleanup functions that will
* free the allocated space. Although the context itself and the bucket
* brigade passed to Apache will be cleaned automatically (because it is
* allocated from the pool and/or has relevant cleanup functions), the heap
* storage space has to be freed explicitly. The safest option is to always
* use data allocated from the request pool.
*/
rxv_spin_data_t *rxv_spin_set(rxv_spin_ctx_t *ctx,
const char *key,rxv_spin_data_t *value);
#define rxv_spin_sset(ctx,key,val) \
rxv_spin_set((ctx),(key),rxv_spin_datum(rxv_spin_pool(ctx),(val),NULL))
/**< set a string into context by converting to single */
#define rxv_spin_del(ctx,key) rxv_spin_set((ctx),(key),NULL)
/**< delete a value from context */
/** @} */
/* Application/session functions */
/**
* Application and session functions (mod_spin API)
*
* @defgroup rxv_spin_as_functions Application and session functions
* @{
*/
/**
* Retrieve a value from the application store.
*
* @param ctx Context
* @param key Unique key by which this value is identified
* @return pointer to the value, NULL on error
* @par Example:
* @code
* rxv_spin_app_get(ctx,"some application key");
* @endcode
*/
rxv_spin_data_t *rxv_spin_app_get(rxv_spin_ctx_t *ctx,const char *key);
#define rxv_spin_app_sget(ctx,key) \
rxv_spin_string(rxv_spin_app_get((ctx),(key)))
/**< get a string from application instead of single */
/**
* Put value in the application store.
*
* @param ctx Context
* @param key Unique key by which this value is identified
* @param val Value to be placed in the store (single)
* @return pointer to the value, NULL on error
* @par Example:
* @code
* rxv_spin_app_set(ctx,"some application key",
* rxv_spin_datum(pool,"some application value",NULL));
* @endcode
* @warning
* The data set into the application store has to have at least the lifetime
* of the request. Anything less and the pool used to hold the data may get
* cleaned before the bucket holding the value gets created. In most cases,
* this will result in a segfault.
*/
rxv_spin_data_t *rxv_spin_app_set(rxv_spin_ctx_t *ctx,
const char *key,rxv_spin_data_t *val);
#define rxv_spin_app_sset(ctx,key,val) \
rxv_spin_app_set((ctx),(key),rxv_spin_datum(rxv_spin_pool(ctx),(val),NULL))
/**< set string into application instead of single */
/**
* Delete a record in the application store.
*
* @param ctx Context
* @param key Unique key by which record is identified
* @return APR_SUCCESS on success, otherwise an error
* @par Example:
* @code
* rxv_spin_app_del(ctx,"some application key");
* @endcode
* @remarks It is not an error to delete and non-existent record.
*/
apr_status_t rxv_spin_app_del(rxv_spin_ctx_t *ctx,const char *key);
/**
* Retrieve a value from the session store.
*
* @param ctx Context
* @param key Unique key by which this value is identified
* @return pointer to the value, NULL on error
* @par Example:
* @code
* rxv_spin_ses_get(ctx,"some session key");
* @endcode
*/
rxv_spin_data_t *rxv_spin_ses_get(rxv_spin_ctx_t *ctx,const char *key);
#define rxv_spin_ses_sget(ctx,key) \
rxv_spin_string(rxv_spin_ses_get((ctx),(key)))
/**< get a string from session instead of single */
/**
* Put value in the session store.
*
* @param ctx Context
* @param key Unique key by which this value is identified
* @param val Value to be placed in the store (single)
* @return pointer to the value, NULL on error
* @par Example:
* @code
* rxv_spin_ses_set(ctx,"some session key",
* rxv_spin_datum(pool,"some session value",NULL));
* @endcode
* @warning
* The data set into the session store has to have at least the lifetime of
* the request. Anything less and the pool used to hold the data may get
* cleaned before the bucket holding the value gets created. In most cases,
* this will result in a segfault.
*/
rxv_spin_data_t *rxv_spin_ses_set(rxv_spin_ctx_t *ctx,
const char *key,rxv_spin_data_t *val);
#define rxv_spin_ses_sset(ctx,key,val) \
rxv_spin_ses_set((ctx),(key),rxv_spin_datum(rxv_spin_pool(ctx),(val),NULL))
/**< set string into application instead of single */
/**
* Delete a record in the session store.
*
* @param ctx Context
* @param key Unique key by which record is identified
* @return APR_SUCCESS on success, otherwise an error
* @par Example:
* @code
* rxv_spin_ses_del(ctx,"some session key");
* @endcode
* @remarks It is not an error to delete and non-existent record.
*/
apr_status_t rxv_spin_ses_del(rxv_spin_ctx_t *ctx,const char *key);
/**
* Kill the session
*
* @param ctx Context
* @par Example:
* @code
* rxv_spin_ses_kill(ctx);
* @endcode
* @remarks Destroys the session by marking session data for removal from the
* store. Note that session cookie will still get served. This function would
* usually be used to log users out of the system, as any session data would
* have to be reestablished once user logs back in.
*/
void rxv_spin_ses_kill(rxv_spin_ctx_t *ctx);
/**
* Get session id
*
* @param ctx Context
* @return Session id or NULL if no session support exists
* @par Example:
* @code
* rxv_spin_ses_id(ctx);
* @endcode
* @remarks This function fetches a string representation of the session id,
* which draws is origin from mod_unique_id. If mod_unique_id isn't present in
* Apache, this function returns NULL. Note that the fact that one can get a
* session id does not mean that there is a valid session in existence (that
* is to say, that the client accepted the session). Use rxv_spin_ses_valid()
* function to find that out.
*/
char *rxv_spin_ses_id(rxv_spin_ctx_t *ctx);
/**
* Find out if the session is valid.
*
* @param ctx Context
* @return 1 if valid, otherwise 0
* @par Example:
* @code
* rxv_spin_ses_valid(ctx);
* @endcode
* @remarks If the client accepted this session, this function returns 1. This
* will only be true if the client submitted a valid session id and its
* relevant hash to mod_spin. Also, the session will not be considered valid
* if there are path tricks in the session id (this is unlikely to happen, due
* to hash checking, but nevertheless).
*/
int rxv_spin_ses_valid(rxv_spin_ctx_t *ctx);
/**
* Last access time for the session.
*
* @param ctx Context
* @return Access time, 0 if session has been killed or on error
* @par Example:
* @code
* rxv_spin_ses_atime(ctx);
* @endcode
*/
apr_time_t rxv_spin_ses_atime(rxv_spin_ctx_t *ctx);
/** @} */
typedef struct rxv_spin_db rxv_spin_db_t; /**< database connection type */
typedef struct rxv_spin_db_txn rxv_spin_db_txn_t; /**< database transaction type */
/**
* Database functions (mod_spin API)
*
* @defgroup rxv_spin_database_functions Database functions
* @{
*/
/**
* Retrieve database specific pool.
*
* @param db Database connection
* @return pointer to database specific pool, NULL on error
* @par Example:
* @code
* rxv_spin_db_pool(db);
* @endcode
*/
apr_pool_t *rxv_spin_db_pool(rxv_spin_db_t *db);
/**
* Retrieve database connection information.
*
* @param db Database connection
* @return pointer to connection information, NULL on error
* @par Example:
* @code
* rxv_spin_db_cinfo(db);
* @endcode
*/
char *rxv_spin_db_cinfo(rxv_spin_db_t *db);
/**
* Retrieve database driver.
*
* @param db Database connection
* @return pointer to database driver, NULL on error
* @par Example:
* @code
* rxv_spin_db_driver(db);
* @endcode
*/
const apr_dbd_driver_t *rxv_spin_db_driver(rxv_spin_db_t *db);
/**
* Retrieve database handle.
*
* @param db Database connection
* @return pointer to database handle, NULL on error
* @par Example:
* @code
* rxv_spin_db_handle(db);
* @endcode
*/
apr_dbd_t *rxv_spin_db_handle(rxv_spin_db_t *db);
/**
* Retrieve database transaction.
*
* @param txn Database transaction
* @return pointer to database transaction, NULL on error
* @par Example:
* @code
* rxv_spin_db_txn(txn);
* @endcode
* @remarks This function returns underlying Apache Portable Runtime DBD
* transaction.
*/
apr_dbd_transaction_t *rxv_spin_db_txn(rxv_spin_db_txn_t *txn);
/**
* Connect to a database and optionally pool the connection.
*
* @param ctx Context
* @param conninfo Connection string
* @return pointer to a database connection, NULL on error
* @par Example:
* @code
* rxv_spin_db_open(ctx,"pgsql:dbname=spintest");
* @endcode
* @remarks Whether or not the connection will be pooled, depends on what has
* been set as connection pool value in the context. And this depends
* on the SpinConnPool configuration parameter (default is on).
* Valid database prefixes are pgsql, mysql, sqlite2, sqlite3,
* oracle, freetds etc., depending on the drivers that have been
* compiled and linked with Apache Portable Runtime Utilities Library
* (APU).
* @remarks Connections will be pooled by using connection string as a key
* into the hash. So, if a connection string differs in the amount of
* white space or case, this will open a new connection.
* @remarks Cleanup will be registered with the context pool.
*/
rxv_spin_db_t *rxv_spin_db_open(rxv_spin_ctx_t *ctx,const char *conninfo);
/**
* Close a database connection.
*
* @param ctx Context
* @param db Pointer to a database connection
* @return APR_SUCCESS on success, otherwise an error
* @par Example:
* @code
* rxv_spin_db_close(ctx,db);
* @endcode
*/
apr_status_t rxv_spin_db_close(rxv_spin_ctx_t *ctx,rxv_spin_db_t *db);
/**
* Get the status of the connection.
*
* @param ctx Context
* @param db Database connection
* @return APR_SUCCESS if OK, otherwise an error
* @par Example:
* @code
* if(rxv_spin_db_status(ctx,db)!=APR_SUCCESS){
* ...
* }
* @endcode
* @remarks If this function returns any code other than success (for valid
* ctx and db), the database connection should not be used again.
*/
apr_status_t rxv_spin_db_status(rxv_spin_ctx_t *ctx,rxv_spin_db_t *db);
/**
* Convert APR DBD SQL result set to mod_spin database result.
*
* @param pool Pool used for memory allocation
* @param db Database connection
* @param dbdres APR DBD results
* @return Valid rxv_spin_data_t pointer, NULL on error
* @par Example:
* @code
* rxv_spin_db_data(pool,conn,db,dbdres);
* @endcode
* @remarks Make sure the pool passed into this function is the same one used
* for select or you will have memory allocation problems.
*/
rxv_spin_data_t *rxv_spin_db_data(apr_pool_t *pool,rxv_spin_db_t *db,
apr_dbd_results_t *dbdres);
/**
* Execute a database query that returns a result set (i.e. SELECT).
*
* @param pool Pool used for memory allocation
* @param db Database connection
* @param query SQL query to be performed
* @return Valid rxv_spin_data_t pointer, NULL on error
* @par Example:
* @code
* result=rxv_spin_db_select(pool,db,"select * from spintest");
* @endcode
* @remarks If the query finished successfully, returned data will not be
* NULL, but a pointer to an empty data structure.
*/
rxv_spin_data_t *rxv_spin_db_select(apr_pool_t *pool,rxv_spin_db_t *db,
const char *query);
/**
* Execute a database query that doesn't return a result set.
*
* @param pool Pool used for memory allocation
* @param db Database connection
* @param query SQL query to be performed
* @return Number of rows affected, -1 on error
* @par Example:
* @code
* nrows=rxv_spin_db_query(pool,db,"delete from spintest");
* @endcode
*/
int rxv_spin_db_query(apr_pool_t *pool,rxv_spin_db_t *db,const char *query);
/**
* Prepare and execute database that returns a result set (i.e. SELECT)
*
* @param pool Pool used for memory allocation
* @param db Database connection
* @param query SQL query to be prepared and executed
* @param ... Parameters for prepared statement, (constant pointer to nul
* terminated string)
* @return Valid rxv_spin_data_t pointer, NULL on error
* @par Example:
* @code
* result=rxv_spin_db_pselect(pool,db,"select * from names where name = %s",
* "Dude",NULL);
* @endcode
* @remarks Prepared statements done using this function only accept string
* parameters. For anything more complicated, use native database API
* and then convert the data so it can be used within the context.
* Make sure the number of paramters passed is correct, or you may be
* in for a nasty surprise when your program segfaults.
* @warning
* Make sure you use \%s where the replaced parameter is supposed to go. This
* is the official Apache Portable Runtime DBD way :-).
* @warning
* The last parameter in the list should be NULL and it has to be specified
* even when there are no other parameters.
*/
rxv_spin_data_t *rxv_spin_db_pselect(apr_pool_t *pool,rxv_spin_db_t *db,
const char *query,...)
#if defined(__GNUC__) && __GNUC__ >= 4
__attribute__((sentinel))
#endif
;
/**
* Prepare and execute database that doesn't return a result set.
*
* @param pool Pool used for memory allocation
* @param db Database connection
* @param query SQL query to be prepared and executed
* @param ... Parameters for prepared statement, (constant pointer to nul
* terminated string)
* @return Number of rows affected, -1 on error
* @par Example:
* @code
* nrows=rxv_spin_db_pquery(pool,db,"delete from names where name = %s",
* "Dude",NULL);
* @endcode
* @remarks Prepared statements done using this function only accept string
* parameters. For anything more complicated, use native database API
* and then convert the data so it can be used within the context.
* Make sure the number of paramters passed is correct, or you may be
* in for a nasty surprise when your program segfaults.
* @warning
* Make sure you use \%s where the replaced parameter is supposed to go. This
* is the official Apache Portable Runtime DBD way :-).
* @warning
* The last parameter in the list should be NULL and it has to be specified
* even when there are no other parameters.
*/
int rxv_spin_db_pquery(apr_pool_t *pool,rxv_spin_db_t *db,
const char *query,...)
#if defined(__GNUC__) && __GNUC__ >= 4
__attribute__((sentinel))
#endif
;
/**
* Start a transaction.
*
* @param pool Pool used for memory allocation
* @param db Database connection
* @return Pointer to a valid transaction, NULL on error
* @par Example:
* @code
* txn=rxv_spin_db_start(pool,db);
* @endcode
* @remarks The pool is also used to register a cleanup function for the
* transaction. It makes little sense to have transactions more
* permanent than one request, so this should always be the request
* pool, which can be obtained from the context.
*/
rxv_spin_db_txn_t *rxv_spin_db_start(apr_pool_t *pool,rxv_spin_db_t *db);
/**
* End a transaction.
*
* @param txn Database transaction
* @return APR_SUCCESS on success, otherwise an error
* @par Example:
* @code
* rxv_spin_db_end(txn);
* @endcode
*/
apr_status_t rxv_spin_db_end(rxv_spin_db_txn_t *txn);
/** @} */
/**
* Connection functions (mod_spin API)
*
* @defgroup rxv_spin_connection_functions Connection functions
* @{
*/
/**
* Get a registered connection from the connection pool.
*
* @param ctx Context
* @param conninfo Connection string for this connection
* @return Pointer to the connection or NULL if not found
* @par Example:
* @code
* rxv_spin_conn_get(ctx,"openldap:ldap://ldap.example.com/dc=example,dc=com");
* @endcode
*/
void *rxv_spin_conn_get(rxv_spin_ctx_t *ctx,const char *conninfo);
/**
* Register a connection with the connection pool.
*
* @param ctx Context
* @param conninfo Connection string for this connection
* @param conn Connection pointer
* @param cleanup Cleanup function to call on pool destruction
* @return Pointer to the connection, NULL on error
* @par Example:
* @code
* rxv_spin_conn_set(ctx,"openldap:ldap://host.domain/dc=example,dc=com",
* ldapconn,ldap_cleanup);
* @endcode
* @remarks This function will register the connection even if the connection
* with the same key already exists. This may lead to multiple
* cleanup functions being registered for the same connection and
* eventually segfaults. Use rxv_spin_conn_get() function to verify
* if the connection was registered before.
* @warning
* If you decide to close the connection by hand, you must remove the cleanup
* function from the thread specific pool (you can find out what that is by
* calling rxv_spin_tpool()).
* @warning
* The lifetime of the connection and all other variables passed into this
* function has to be at least the lifetime of the connection pool you are
* registering the connection with. Normally, connection pools have thread
* lifetime, so if you have shorter lifetime for your connection (e.g.
* request, connection) or the connect string, you are setting yourself up for
* segfaults. Also, if the lifetime of the connection is longer than the one
* of the connection pool, for instance, if it has the lifetime of the process
* and you are registering it with the regular thread based connection pool,
* you may experience segfaults if you rely on that connection once the thread
* exited.
*/
void *rxv_spin_conn_set(rxv_spin_ctx_t *ctx,
const char *conninfo,void *conn,
apr_status_t (*cleanup)(void *data));
/** @} */
/**
* Application entry functions (mod_spin API)
*
* @defgroup rxv_spin_entry_functions Application entry functions
* @{
*/
typedef void (*rxv_spin_init_t)(rxv_spin_ctx_t *ctx);
/**< init function */
typedef int (*rxv_spin_prepare_t)(rxv_spin_ctx_t *ctx);
/**< prepare function */
typedef int (*rxv_spin_service_t)(rxv_spin_ctx_t *ctx);
/**< service function */
/** @} */
/* DSO loading functions */
/**
* DSO loading functions (mod_spin API)
*
* @defgroup rxv_spin_dso_functions DSO loading functions
* @{
*/
/**
* Load a DSO into the cache.
*
* @param ctx Context
* @param path Full path of the DSO to load
* @param handle DSO handle
* @return APR_SUCCESS on successful load, otherwise an error
* @par Example:
* @code
* rxv_spin_dso_load(ctx,"/path/to/dso/object.so",&handle);
* @endcode
* @remarks To preserve pool sanity, this function copies path into the
* memory allocated from the private pool.
*/
apr_status_t rxv_spin_dso_load(rxv_spin_ctx_t *ctx,const char *path,
apr_dso_handle_t **handle);
/** @} */
/**
* Crypto functions (mod_spin API)
*
* @defgroup rxv_spin_crypto_functions Crypto functions
* @{
*/
/**
* Create MD5 hash, using ASCII letters only
*
* @param pool Pool for allocation the hash
* @param uniq String to hash
* @return MD5 hash of the string, 32 bytes long, encoded [a-p]
* @par Example:
* @code
* rxv_spin_hash(pool,"some string");
* @endcode
*/
char *rxv_spin_hash(apr_pool_t *pool,const char *uniq);
/**
* Create MD5 HMAC, using ASCII letters only
*
* @param pool Pool for allocation the hash
* @param uniq String to hash
* @param salt Key used for HMAC, must be 64 bytes long
* @return MD5 HMAC of the string, 32 bytes long, encoded [a-p]
* @par Example:
* @code
* rxv_spin_hmac(pool,"some string",verysecretkey);
* @endcode
*/
char *rxv_spin_hmac(apr_pool_t *pool,const char *uniq,const char *salt);
/** @} */
#endif /* __RXV_SPIN_H__ */