On Tuesday 24 of March 2009 11:07:12 Ratko Rudič wrote: > I'll be replying to this email with a sorce code, > > Ratko
Here it is,,, Ratko
/** * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * memcache apache module * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * This is a memcache module for apache web server. * It connects to memcache server and tries to fetch HTML content from it. * * Memcache key is based on the hostname and URI after it. * * If HTML is found, it is returned with an OK status. * If HTML is not found, module is skipped and apache does whatever it does next. * * Memcache module is enabled in the <Directory> or <Location> directive with: * SetHandler memcache_handler * * Memcache servers are added with (IP, port pairs): * MemCacheServerAdd 10.0.0.212 11211 * * You can set debugging with: * MemCacheDebug INT * where INT is one of the: * 0 - no debugging info * 1 - debugging is written into error log file * 2 - debugging is written to browser and error log file * 3 - debugging is written at the bottom of HTML * * To build this module use: * # apxs2 -a -c -l memcached -l mhash -i mod_memcache.c * * You will also need libmemcache from: * http://tangent.org/552/libmemcached.html * * and mhash library for generating md5() hash keys. * * * BSD License * * POP-ONLINE * Ratko Rudic * ratko.ru...@pop-tv.si * * Version: 1 at 2008-12-04 * Initial source code. * */ #include "httpd.h" #include "http_config.h" #include "http_protocol.h" #include "ap_config.h" #include <string.h> #include <libmemcached/memcached.h> #include "common.h" #include <mhash.h> #define DEBUG_NONE 0 #define DEBUG_LOG 1 #define DEBUG_COMMENT 2 #define DEBUG_HTML 3 #define URL_MAX_LEN 512 /** * Forward-declarations */ extern module AP_MODULE_DECLARE_DATA memcache_module; /** * Structure that holds pointer to memcache object and log level. * It is initialized at the server start. */ typedef struct { memcached_st *memc; int debug; } memcache_config; /** * Returns md5() of the given key. */ static void memcache_key( const char *key, char *md5_ascii ) { MHASH td; int bsize; unsigned char *md5; char c[10]; int i; bsize = mhash_get_block_size( MHASH_MD5 ); td = mhash_init( MHASH_MD5 ); mhash( td, key, strlen(key) ); md5 = mhash_end( td ); for (i = 0; i < bsize; i++) { snprintf(c, sizeof(c), "%02x", md5[i] ); strncat( md5_ascii, c, sizeof(md5_ascii) - 1 ); } return; } /** * Adds a new server to the pool of memcached servers. * It is called if user adds MemCacheServerAdd parameter */ static const char *memcache_server_add(cmd_parms *parms, void *mconfig, const char *arg1, const char *arg2) { memcache_config *cfg = ap_get_module_config(parms->server->module_config, &memcache_module); memcached_server_add( cfg->memc, (char *)arg1, atoi(arg2) ); return NULL; } /** * Returns basename of the URI */ char *memcache_basename( const char *name ) { const char *base; for ( base = name; *name; name++ ) { if ( (*name) == '/' ) base = name + 1; } return (char *)base; } /** * Function adds "/" to the end of given URL, if URL is a * folder (eg: "http://24ur.com/my-dir") */ void memcache_url_setup( request_rec *r, char *url ) { char *bname; char last_char = '\0'; if ( strlen(url) == 0 ) return; bname = memcache_basename( url ); last_char = url[ (int)strlen(url) - 1 ]; if ( (last_char != '/') && (strstr(bname,".")==NULL) ) strcat( url, "/index.html" ); if ( last_char == '/' ) strcat( url, "index.html" ); } /** * Returns current URL */ void memcache_url_get( request_rec *r, char *url ) { strncpy(url, r->hostname, URL_MAX_LEN); strncat(url, r->uri, URL_MAX_LEN - strlen(url) ); } /** * Main function * Tries to find HTML for the current URL in the memcache. * * Returns HTML to user and stops additional serving if URL is found in memcache. */ static int memcache_handler(request_rec *r) { // Return immediatelly if handler is not defined if (strcmp(r->handler, "memcache_handler")) { return DECLINED; } memcache_config *cfg = ap_get_module_config(r->server->module_config, &memcache_module); char url[URL_MAX_LEN]; char key[128]; uint32_t flags; size_t html_length = 0; memcached_return error; char *html; if (!r->header_only) { // Write some debug info for current page if ( cfg->debug == DEBUG_HTML ) { r->content_type = "text/html"; ap_rprintf(r, "<b>Debug from mod_memcache.c - disable it with MemCacheDebug 0, or delete MemCacheDebug statement from apache conf.</b><hr>\n"); ap_rprintf(r, "Hostname: %s <br>", r->hostname); ap_rprintf(r, "Unparsed URI: %s <br>", r->unparsed_uri); ap_rprintf(r, "URI: %s <br>", r->uri); ap_rprintf(r, "Filename: %s <br>", r->filename); ap_rprintf(r, "Path info: %s <br><hr>", r->path_info); } } // Get current URL and set it up properly memcache_url_get( r, url ); memcache_url_setup( r, url ); // Create key that we'll be looking for in memcache // key is a md5() of the hostname + URI memset(key, 0, sizeof(key)); memcache_key( url, key ); if ( cfg->debug == DEBUG_HTML ) ap_rprintf(r, "Looking for URL: '%s' that has KEY: %s <br>", url, key); // Get HTML for the current key html = memcached_get( cfg->memc, (char *)key, strlen((char *)key), &html_length, &flags, &error ); if ( cfg->debug == DEBUG_HTML ) ap_rprintf(r, "Memcache response: (%i) %s - %d in length<br>", error, memcached_strerror(cfg->memc, error), (html == NULL ? 0 : (int)html_length) ); if ( cfg->debug >= DEBUG_LOG ) fprintf(stderr,"MEMCACHE: key: %s for url: %s, got: (%i) %s, response is %d in length\n", (char *)key, url, error, memcached_strerror(cfg->memc, error), (html == NULL ? 0 : (int)html_length) ); // If HTML is found in memcache, Write it to user if ( html != NULL ) { r->content_type = "text/html"; ap_rprintf(r, "%s", html); if ( cfg->debug >= DEBUG_COMMENT ) ap_rprintf(r, "\n<!-- %s | %s | %d -->", memcached_strerror(cfg->memc, error), key, (int)strlen(html) ); return OK; } if ( cfg->debug == DEBUG_HTML ) return OK; return DECLINED; } /** * Creates config struct */ static void *memcache_create_config( apr_pool_t *p ) { memcache_config *conf; conf = (memcache_config *) apr_pcalloc(p, sizeof(memcache_config)); conf->memc = memcached_create(NULL); conf->debug = 0; return (void *)conf; } /** * Per server config */ static void *memcache_create_server_config(apr_pool_t *p, server_rec *s) { return memcache_create_config( p ); } /** * Per directory config */ static void *memcache_create_dir_config(apr_pool_t *p, char *dir) { return memcache_create_config( p ); } /** * Initialize debug level */ static const char *memcache_server_debug_set( cmd_parms *parms, void *mconfig, const char *arg1 ) { int debug_level = atoi( arg1 ); memcache_config *cfg = ap_get_module_config(parms->server->module_config, &memcache_module); if ( (debug_level < 0) || (debug_level > 3) ) { fprintf(stderr,"memcache: Wrong debug level (%s). must be 0, 1, 2 or 3. Setting it to 0 - no debug.\n",arg1); debug_level = 0; } fprintf(stderr,"memcache: Setting debug level to: %d.\n",debug_level); cfg->debug = debug_level; return NULL; } /** * Apache register hook so that our code will get called. */ static void memcache_register_hooks(apr_pool_t *p) { ap_hook_handler(memcache_handler, NULL, NULL, APR_HOOK_FIRST); } static const command_rec memcache_cmds[] = { AP_INIT_TAKE2( "MemCacheServerAdd", memcache_server_add, NULL, ACCESS_CONF, "IP & PORT of memcached server (ex: MemCacheServerAdd 192.168.1.100 11211 ) !" ), AP_INIT_TAKE1( "MemCacheDebug", memcache_server_debug_set, NULL, ACCESS_CONF, "Show DEBUG: 0: none, 1: log, 2: on top of html" ), {NULL} }; /* Dispatch list for API hooks */ module AP_MODULE_DECLARE_DATA memcache_module = { STANDARD20_MODULE_STUFF, memcache_create_dir_config, /* create per-dir config structures */ NULL, /* merge per-dir config structures */ memcache_create_server_config, /* create per-server config structures */ NULL, /* merge per-server config structures */ memcache_cmds, /* table of config file commands */ memcache_register_hooks /* register hooks */ };