Tarek Ziadé avatar Tarek Ziadé committed 581cfb5

initial commit

Comments (0)

Files changed (3)

+ngx_addon_name=ngx_http_sstatus_module
+HTTP_MODULES="$HTTP_MODULES ngx_http_sstatus_module"
+NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_sstatus_module.c"
+CORE_LIBS="$CORE_LIBS -lmemcached"

ngx_http_sstatus_module.c

+/*
+ * nginx (c) Igor Sysoev
+ * this module (C) Mykola Grechukh <gns@altlinux.org>
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+#include "ngx_utils.c"
+
+
+typedef struct {
+    ngx_flag_t    enable;
+    ngx_str_t     services;
+    ngx_str_t    memcached;
+} ngx_http_sstatus_loc_conf_t;
+
+static ngx_int_t ngx_http_sstatus_handler(ngx_http_request_t *r);
+static void *ngx_http_sstatus_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_sstatus_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child);
+static ngx_int_t ngx_http_sstatus_init(ngx_conf_t *cf);
+
+
+static ngx_command_t  ngx_http_sstatus_commands[] = {
+    { ngx_string("sstatus"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_sstatus_loc_conf_t, enable),
+      NULL },
+
+    { ngx_string("sstatus_memcached"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_sstatus_loc_conf_t, memcached),
+      NULL },
+
+    { ngx_string("sstatus_services"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_sstatus_loc_conf_t, services),
+      NULL },
+
+     ngx_null_command
+};
+
+
+static ngx_http_module_t  ngx_http_sstatus_module_ctx = {
+    NULL,                                  /* preconfiguration */
+    ngx_http_sstatus_init,                  /* postconfiguration */
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+    ngx_http_sstatus_create_loc_conf,       /* create location configuration */
+    ngx_http_sstatus_merge_loc_conf         /* merge location configuration */
+};
+
+
+ngx_module_t  ngx_http_sstatus_module = {
+    NGX_MODULE_V1,
+    &ngx_http_sstatus_module_ctx,           /* module context */
+    ngx_http_sstatus_commands,              /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    NULL,                                  /* init master */
+    NULL,                                  /* init module */
+    NULL,                                  /* init process */
+    NULL,                                  /* init thread */
+    NULL,                                  /* exit thread */
+    NULL,                                  /* exit process */
+    NULL,                                  /* exit master */
+    NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_int_t
+ngx_http_sstatus_handler(ngx_http_request_t *r)
+{
+    ngx_http_sstatus_loc_conf_t  *alcf;
+    alcf = ngx_http_get_module_loc_conf(r, ngx_http_sstatus_module);
+
+    if (!alcf->enable) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+            "disabled");
+
+
+        return NGX_OK;
+    }
+
+    // reading the headers
+    ngx_str_t service = ngx_string("X-Target-Service");
+
+    ngx_table_elt_t* header = search_headers_in(r, service.data, service.len);
+
+    if (!header)
+    {
+        // no header specified
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+            "no header specified");
+
+        return NGX_OK;
+    }
+    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+            "reading memcached");
+
+
+    // let's get the status
+    char* enabled = get_status(r, (char*)header->value.data);
+
+    if (!enabled)
+    {
+        // could not get the status
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+            "could not get the status");
+
+        return NGX_OK;
+    }
+
+    char* is_enabled = "1";
+
+    if (strcmp(enabled, is_enabled) == 0)
+    {
+        // enabled, good !
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+            "enabled");
+
+
+        return NGX_OK;
+    }
+
+    // disabled
+    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+            "disabled");
+
+    return NGX_HTTP_SERVICE_UNAVAILABLE;
+
+
+}
+
+static void *
+ngx_http_sstatus_create_loc_conf(ngx_conf_t *cf)
+{
+    ngx_http_sstatus_loc_conf_t  *conf;
+
+    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_sstatus_loc_conf_t));
+    if (conf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+    conf->enable = NGX_CONF_UNSET;
+    return conf;
+}
+
+
+static char *
+ngx_http_sstatus_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_sstatus_loc_conf_t  *prev = parent;
+    ngx_http_sstatus_loc_conf_t  *conf = child;
+    ngx_conf_merge_value(conf->enable, prev->enable, 0);
+    ngx_conf_merge_str_value(conf->memcached, prev->memcached, "127.0.0.1:11211");
+    ngx_conf_merge_str_value(conf->services, prev->services, "google");
+    return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_sstatus_init(ngx_conf_t *cf)
+{
+    ngx_http_handler_pt        *h;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+
+    h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    *h = ngx_http_sstatus_handler;
+
+    return NGX_OK;
+}
+/*
+ * nginx (c) Igor Sysoev
+ * this module (C) Tarek Ziade <tarek@mozilla.com>
+ */
+#include <stdio.h>
+#include <string.h>
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+#include <libmemcached/memcached.h>
+
+#define SERVER_NAME "127.0.0.1"
+#define SERVER_PORT 11211
+
+
+static ngx_table_elt_t *
+search_headers_in(ngx_http_request_t *r, u_char *name, size_t len);
+char* get_status(ngx_http_request_t *r, char* service);
+
+static ngx_table_elt_t *
+search_headers_in(ngx_http_request_t *r, u_char *name, size_t len) {
+    ngx_list_part_t            *part;
+    ngx_table_elt_t            *h;
+    ngx_uint_t                  i;
+    /*
+    Get the first part of the list. There is usual only one part.
+    */
+    part = &r->headers_in.headers.part;
+    h = part->elts;
+    /*
+    Headers list array may consist of more than one part,
+    so loop through all of it
+    */
+    for (i = 0; /* void */ ; i++) {
+        if (i >= part->nelts) {
+            if (part->next == NULL) {
+                /* The last part, search is done. */
+                break;
+            }
+            part = part->next;
+            h = part->elts;
+            i = 0;
+        }
+        /*
+        Just compare the lengths and then the names case insensitively.
+        */
+        if (len != h[i].key.len || ngx_strcasecmp(name, h[i].key.data) != 0) {
+            /* This header doesn't match. */
+            continue;
+        }
+        /*
+        Ta-da, we got one!
+        Note, we'v stop the search at the first matched header
+        while more then one header may fit.
+        */
+        return &h[i];
+    }
+    /*
+    No headers was found
+    */
+    return NULL;
+}
+
+char *
+get_status(ngx_http_request_t *r, char* service)
+{
+    /* the keys are:
+
+        service:google:on = True or False
+        service:google:succ = Number of successes
+        service:google:fail = Number of failures
+    */
+    char enabled_key[8 + strlen(service) + 3];
+    sprintf(enabled_key, "service:%s:on", service);
+
+    /*
+    char succ_key[8 + strlen(service) + 5];
+    sprintf(succ_key, "service:%s:succ", service);
+
+    char fail_key[8 + strlen(service) + 5];
+    sprintf(fail_key, "service:%s:fail", service);
+    */
+
+    memcached_return rc;
+    memcached_st *memc;
+
+    size_t enabled_length = 0;
+    uint32_t flags;
+
+    // creating a connection to the memcached server
+    memc = memcached_create(NULL);
+    rc = memcached_server_add(memc, SERVER_NAME, SERVER_PORT);
+
+    // now getting the values for the service
+    char *enabled = memcached_get(memc, enabled_key, strlen(enabled_key), &enabled_length, &flags, &rc);
+
+    memcached_free(memc);
+    return enabled;
+}
+
+
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.