From 1ff1743a0ede7b96584291c50347e0388203de50 Mon Sep 17 00:00:00 2001 From: lazy dogs Date: Thu, 20 Feb 2014 10:50:13 +0100 Subject: [PATCH] init svn r49 --- LICENSE | 24 ++ README | 129 ++++++++ config | 6 + docs/sticky.pdf | Bin 0 -> 81907 bytes docs/sticky.vsd | Bin 0 -> 54272 bytes ngx_http_sticky_misc.c | 315 ++++++++++++++++++ ngx_http_sticky_misc.h | 28 ++ ngx_http_sticky_module.c | 691 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 1193 insertions(+) create mode 100644 LICENSE create mode 100644 README create mode 100644 config create mode 100644 docs/sticky.pdf create mode 100644 docs/sticky.vsd create mode 100644 ngx_http_sticky_misc.c create mode 100644 ngx_http_sticky_misc.h create mode 100644 ngx_http_sticky_module.c diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0654c57 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2010 Jerome Loyet (jerome at loyet dot net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ diff --git a/README b/README new file mode 100644 index 0000000..77bff37 --- /dev/null +++ b/README @@ -0,0 +1,129 @@ +Nginx Sticky Module +-- + +Description: + A nginx module to add a sticky cookie to be always forwarded the the same + upstream server. + + When dealing with several backend servers, it's sometimes useful that one + client (browser) is always served by the same backend server + (for session persistance for example). + + Using a persistance by IP (with the ip_hash upstream module) is maybe not + a good idea because there could be situations where a lot of different + browsers are coming with the same IP address (behind proxies)and the load + balancing system won't be fair. + + Using a cookie to track the upstream server makes each browser unique. + + When the sticky module can't apply, it switchs back to the classic Round Robin + Upstream or returns a "Bad Gateway" (depending on the no_fallback flag). + + Sticky module can't apply when cookies are not supported by the browser + + * Sticky module is based on a "best effort" algorithm. Its aim is not to handle + * security somehow. It's been made to ensure that normal users are always + * redirected to the same backend server: that's all! + +Installation + + You'll need to re-compile Nginx from source to include this module. + Modify your compile of Nginx by adding the following directive + (modified to suit your path of course): + + ./configure ... --add-module=/absolute/path/to/nginx-sticky-module + make + make install + +Usage + upstream { + sticky; + server 127.0.0.1:9000; + server 127.0.0.1:9001; + server 127.0.0.1:9002; + } + + sticky [name=route] [domain=.foo.bar] [path=/] [expires=1h] [hash=index|md5|sha1] [no_fallback]; + - name: the name of the cookies used to track the persistant upstream srv + default: route + + - domain: the domain in which the cookie will be valid + default: nothing. Let the browser handle this. + + - path: the path in which the cookie will be valid + default: nothing. Let the browser handle this. + + - expires: the validity duration of the cookie + default: nothing. It's a session cookie. + restriction: must be a duration greater than one second + + - hash: the hash mechanism to encode upstream server. It cant' be used + with hmac. + md5|sha1: well known hash + index: it's not hashed, an in-memory index is used instead + it's quicker and the overhead is shorter + Warning: the matching against upstream servers list + is inconsistent. So, at reload, if upstreams servers + has changed, index values are not guaranted to + correspond to the same server as before! + USE IT WITH CAUTION and only if you need to! + default: md5 + + - hmac: the HMAC hash mechanism to encode upstream server + It's like the hash mechanism but it uses hmac_key + to secure the hashing. It can't be used with hash. + md5|sha1: well known hash + default: none. see hash. + + -hmac_key: the key to use with hmac. It's mandatory when hmac is set + default: nothing. + + -no_fallback: when this flag is set, nginx will return a 502 (Bad Gateway or + Proxy Error) if a request comes with a cookie and the + corresponding backend is unavailable. + +Detail Mechanism + see docs/sticky.{vsd,pdf} + +Warnings: + - sticky module does not work with the "backup" option of the "server" configuration item. + - sticky module does not work with the nginx_http_upstream_check_module. + - sticky module may require to configure nginx with SSL support. + +Contributing + http://code.google.com/p/nginx-sticky-module/ + +TODO + Stress + Code review + +Author + Jerome Loyet + +Copyright & License + This module is licenced under the BSD license. + + Copyright (C) 2010 Jerome Loyet (jerome at loyet dot net) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. diff --git a/config b/config new file mode 100644 index 0000000..bf9bacc --- /dev/null +++ b/config @@ -0,0 +1,6 @@ +ngx_addon_name=ngx_http_sticky_module +HTTP_MODULES="$HTTP_MODULES ngx_http_sticky_module" +NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_sticky_module.c $ngx_addon_dir/ngx_http_sticky_misc.c" +NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/ngx_http_sticky_misc.h" +USE_MD5=YES +USE_SHA1=YES diff --git a/docs/sticky.pdf b/docs/sticky.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ae74c1d0127049ec83e0d9de2d87604d9e61b3da GIT binary patch literal 81907 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 z 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%0A*v~MH`4W0~*M9NyxSg}_oi?dd@ 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�?zToitwDfvx8(_lTMwiiY6$`9?t8?ZBcvFRAzhRs&Kw~(05YHp zNdY9I2NJPdNuCA7zN^eD`3bTJ5T`C=DwJslgxiJW6Q{|+%McpWg|x>WCMN=dN82c$ zW53EsAs}=>jH8oyMMehoKwgc{BIg0pEscCYk^t$ZOn1m4clIcAY*ZF`wnv#)*JNZN zAl+@9fwu1TK=RG9$cKP*kManYED};Jeu3Nto*`)93p#xQ&XT=*AY&A#$bNuy>(7p~ zQ{)stMs)T4ar!B8F(BM7Wk#IY}?Fcv4kx_6%q_W{!^mVO1o_J7Gf8%vS+f0~b zlVSQ^iNj$bA3h3K;aS)ajt|LU;%!laEzHfUku7ae+L!fUsqCx=S<|8J>i4+c5w-d# zl=x-{ien<4Jv>-?Y7iucK;hQN*%U>;9}To5*02UFJ2eD3k46$x#ABoAkJc#K15&$> zN8?5r!b5y7J4(VT50U?c`V@u>gLUIHNhlVt`O4UGB0=fMBj=Kc?;3!sjbRR(zz zICO{4Mh<%zsC)eJe@Bj9z}Z{i(joRsJ2-&<&s>>%_slT|bNIIDke$j4yCfYPhRBNYCFjl+h`#8Xzm zJcObK*mSrIV8c5Lmr$5&&>qrf=BF1 Pd$a}5xc|ET+Y +#include +#include +#include +#include +#include + +#include "ngx_http_sticky_misc.h" + +#ifndef ngx_str_set + #define ngx_str_set(str, text) (str)->len = sizeof(text) - 1; (str)->data = (u_char *) text +#endif + +ngx_int_t ngx_http_sticky_misc_set_cookie(ngx_http_request_t *r, ngx_str_t *name, ngx_str_t *value, ngx_str_t *domain, ngx_str_t *path, time_t expires) +{ + u_char *cookie, *p; + size_t len; + ngx_table_elt_t *set_cookie, *elt; + ngx_str_t remove; + ngx_list_part_t *part; + ngx_uint_t i; + + if (value == NULL) { + ngx_str_set(&remove, "_remove_"); + value = &remove; + } + + /* name = value */ + len = name->len + 1 + value->len; + + /*; Domain= */ + if (domain->len > 0) { + len += sizeof("; Domain=") - 1 + domain->len; + } + + /*; Max-Age= */ + if (expires != NGX_CONF_UNSET) { + len += sizeof("; Max-Age=") - 1 + NGX_TIME_T_LEN; + } + + /* ; Path= */ + if (path->len > 0) { + len += sizeof("; Path=") - 1 + path->len; + } + + cookie = ngx_pnalloc(r->pool, len); + if (cookie == NULL) { + return NGX_ERROR; + } + + p = ngx_copy(cookie, name->data, name->len); + *p++ = '='; + p = ngx_copy(p, value->data, value->len); + + if (domain->len > 0) { + p = ngx_copy(p, "; Domain=", sizeof("; Domain=") - 1); + p = ngx_copy(p, domain->data, domain->len); + } + + if (expires != NGX_CONF_UNSET) { + p = ngx_copy(p, "; Max-Age=", sizeof("; Max-Age=") - 1); + p = ngx_snprintf(p, NGX_TIME_T_LEN, "%T", expires); + } + + if (path->len > 0) { + p = ngx_copy(p, "; Path=", sizeof("; Path=") - 1); + p = ngx_copy(p, path->data, path->len); + } + + part = &r->headers_out.headers.part; + elt = part->elts; + set_cookie = NULL; + + for (i=0 ;; i++) { + if (part->nelts > 1 || i >= part->nelts) { + if (part->next == NULL) { + break; + } + part = part->next; + elt = part->elts; + i = 0; + } + /* ... */ + if (ngx_strncmp(elt->value.data, name->data, name->len) == 0) { + set_cookie = elt; + break; + } + } + + /* found a Set-Cookie header with the same name: replace it */ + if (set_cookie != NULL) { + set_cookie->value.len = p - cookie; + set_cookie->value.data = cookie; + return NGX_OK; + } + + set_cookie = ngx_list_push(&r->headers_out.headers); + if (set_cookie == NULL) { + return NGX_ERROR; + } + set_cookie->hash = 1; + ngx_str_set(&set_cookie->key, "Set-Cookie"); + set_cookie->value.len = p - cookie; + set_cookie->value.data = cookie; + + return NGX_OK; +} + +ngx_int_t ngx_http_sticky_misc_md5(ngx_pool_t *pool, void *in, size_t len, ngx_str_t *digest) +{ + ngx_md5_t md5; + u_char hash[MD5_DIGEST_LENGTH]; + + digest->data = ngx_pcalloc(pool, MD5_DIGEST_LENGTH * 2); + if (digest->data == NULL) { + return NGX_ERROR; + } + + digest->len = MD5_DIGEST_LENGTH * 2; + ngx_md5_init(&md5); + ngx_md5_update(&md5, in, len); + ngx_md5_final(hash, &md5); + + ngx_hex_dump(digest->data, hash, MD5_DIGEST_LENGTH); + return NGX_OK; +} + +ngx_int_t ngx_http_sticky_misc_sha1(ngx_pool_t *pool, void *in, size_t len, ngx_str_t *digest) +{ + ngx_sha1_t sha1; + u_char hash[SHA_DIGEST_LENGTH]; + + digest->data = ngx_pcalloc(pool, SHA_DIGEST_LENGTH * 2); + if (digest->data == NULL) { + return NGX_ERROR; + } + + digest->len = SHA_DIGEST_LENGTH * 2; + ngx_sha1_init(&sha1); + ngx_sha1_update(&sha1, in, len); + ngx_sha1_final(hash, &sha1); + + ngx_hex_dump(digest->data, hash, SHA_DIGEST_LENGTH); + return NGX_OK; +} + +ngx_int_t ngx_http_sticky_misc_hmac_md5(ngx_pool_t *pool, void *in, size_t len, ngx_str_t *key, ngx_str_t *digest) +{ + u_char hash[MD5_DIGEST_LENGTH]; + u_char k[MD5_CBLOCK]; + ngx_md5_t md5; + u_int i; + + digest->data = ngx_pcalloc(pool, MD5_DIGEST_LENGTH * 2); + if (digest->data == NULL) { + return NGX_ERROR; + } + digest->len = MD5_DIGEST_LENGTH * 2; + + ngx_memzero(k, sizeof(k)); + + if (key->len > MD5_CBLOCK) { + ngx_md5_init(&md5); + ngx_md5_update(&md5, key->data, key->len); + ngx_md5_final(k, &md5); + } else { + ngx_memcpy(k, key->data, key->len); + } + + /* XOR ipad */ + for (i=0; i < MD5_CBLOCK; i++) { + k[i] ^= 0x36; + } + + ngx_md5_init(&md5); + ngx_md5_update(&md5, k, MD5_CBLOCK); + ngx_md5_update(&md5, in, len); + ngx_md5_final(hash, &md5); + + /* Convert k to opad -- 0x6A = 0x36 ^ 0x5C */ + for (i=0; i < MD5_CBLOCK; i++) { + k[i] ^= 0x6a; + } + + ngx_md5_init(&md5); + ngx_md5_update(&md5, k, MD5_CBLOCK); + ngx_md5_update(&md5, hash, MD5_DIGEST_LENGTH); + ngx_md5_final(hash, &md5); + + ngx_hex_dump(digest->data, hash, MD5_DIGEST_LENGTH); + + return NGX_OK; +} + +ngx_int_t ngx_http_sticky_misc_hmac_sha1(ngx_pool_t *pool, void *in, size_t len, ngx_str_t *key, ngx_str_t *digest) +{ + u_char hash[SHA_DIGEST_LENGTH]; + u_char k[SHA_CBLOCK]; + ngx_sha1_t sha1; + u_int i; + + digest->data = ngx_pcalloc(pool, SHA_DIGEST_LENGTH * 2); + if (digest->data == NULL) { + return NGX_ERROR; + } + digest->len = SHA_DIGEST_LENGTH * 2; + + ngx_memzero(k, sizeof(k)); + + if (key->len > SHA_CBLOCK) { + ngx_sha1_init(&sha1); + ngx_sha1_update(&sha1, key->data, key->len); + ngx_sha1_final(k, &sha1); + } else { + ngx_memcpy(k, key->data, key->len); + } + + /* XOR ipad */ + for (i=0; i < SHA_CBLOCK; i++) { + k[i] ^= 0x36; + } + + ngx_sha1_init(&sha1); + ngx_sha1_update(&sha1, k, SHA_CBLOCK); + ngx_sha1_update(&sha1, in, len); + ngx_sha1_final(hash, &sha1); + + /* Convert k to opad -- 0x6A = 0x36 ^ 0x5C */ + for (i=0; i < SHA_CBLOCK; i++) { + k[i] ^= 0x6a; + } + + ngx_sha1_init(&sha1); + ngx_sha1_update(&sha1, k, SHA_CBLOCK); + ngx_sha1_update(&sha1, hash, SHA_DIGEST_LENGTH); + ngx_sha1_final(hash, &sha1); + + ngx_hex_dump(digest->data, hash, SHA_DIGEST_LENGTH); + + return NGX_OK; +} + +ngx_int_t ngx_http_sticky_misc_text_raw(ngx_pool_t *pool, struct sockaddr *in, ngx_str_t *digest) +{ + size_t len; + if (!in) { + return NGX_ERROR; + } + + switch (in->sa_family) { + case AF_INET: + len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; + break; + +#if (NGX_HAVE_INET6) + case AF_INET6: + len = NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1; + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + len = sizeof("unix:") - 1 + NGX_UNIX_ADDRSTRLEN; + break; +#endif + + default: + return NGX_ERROR; + } + + + digest->data = ngx_pnalloc(pool, len); + if (digest->data == NULL) { + return NGX_ERROR; + } + digest->len = ngx_sock_ntop(in, digest->data, len, 1); + return NGX_OK; + return NGX_OK; +} + +ngx_int_t ngx_http_sticky_misc_text_md5(ngx_pool_t *pool, struct sockaddr *in, ngx_str_t *digest) +{ + ngx_str_t str; + if (ngx_http_sticky_misc_text_raw(pool, in, &str) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_http_sticky_misc_md5(pool, (void *)str.data, str.len, digest) != NGX_OK) { + ngx_pfree(pool, &str); + return NGX_ERROR; + } + + return ngx_pfree(pool, &str); +} + +ngx_int_t ngx_http_sticky_misc_text_sha1(ngx_pool_t *pool, struct sockaddr *in, ngx_str_t *digest) +{ + ngx_str_t str; + if (ngx_http_sticky_misc_text_raw(pool, in, &str) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_http_sticky_misc_sha1(pool, (void *)str.data, str.len, digest) != NGX_OK) { + ngx_pfree(pool, &str); + return NGX_ERROR; + } + + return ngx_pfree(pool, &str); +} + diff --git a/ngx_http_sticky_misc.h b/ngx_http_sticky_misc.h new file mode 100644 index 0000000..fe8e859 --- /dev/null +++ b/ngx_http_sticky_misc.h @@ -0,0 +1,28 @@ + +/* + * Copyright (C) 2010 Jerome Loyet (jerome at loyet dot net) + */ + +#ifndef _NGX_HTTP_STICKY_MISC_H_INCLUDED_ +#define _NGX_HTTP_STICKY_MISC_H_INCLUDED_ + +#include +#include +#include +#include + +typedef ngx_int_t (*ngx_http_sticky_misc_hash_pt)(ngx_pool_t *pool, void *in, size_t len, ngx_str_t *digest); +typedef ngx_int_t (*ngx_http_sticky_misc_hmac_pt)(ngx_pool_t *pool, void *in, size_t len, ngx_str_t *key, ngx_str_t *digest); +typedef ngx_int_t (*ngx_http_sticky_misc_text_pt)(ngx_pool_t *pool, struct sockaddr *in, ngx_str_t *digest); + +ngx_int_t ngx_http_sticky_misc_set_cookie (ngx_http_request_t *r, ngx_str_t *name, ngx_str_t *value, ngx_str_t *domain, ngx_str_t *path, time_t expires); +ngx_int_t ngx_http_sticky_misc_md5(ngx_pool_t *pool, void *in, size_t len, ngx_str_t *digest); +ngx_int_t ngx_http_sticky_misc_sha1(ngx_pool_t *pool, void *in, size_t len, ngx_str_t *digest); +ngx_int_t ngx_http_sticky_misc_hmac_md5(ngx_pool_t *pool, void *in, size_t len, ngx_str_t *key, ngx_str_t *digest); +ngx_int_t ngx_http_sticky_misc_hmac_sha1(ngx_pool_t *pool, void *in, size_t len, ngx_str_t *key, ngx_str_t *digest); + +ngx_int_t ngx_http_sticky_misc_text_raw(ngx_pool_t *pool, struct sockaddr *in, ngx_str_t *digest); +ngx_int_t ngx_http_sticky_misc_text_md5(ngx_pool_t *pool, struct sockaddr *in, ngx_str_t *digest); +ngx_int_t ngx_http_sticky_misc_text_sha1(ngx_pool_t *pool, struct sockaddr *in, ngx_str_t *digest); + +#endif /* _NGX_HTTP_STICKY_MISC_H_INCLUDED_ */ diff --git a/ngx_http_sticky_module.c b/ngx_http_sticky_module.c new file mode 100644 index 0000000..82d8f5f --- /dev/null +++ b/ngx_http_sticky_module.c @@ -0,0 +1,691 @@ + +/* + * Copyright (C) Jerome Loyet + */ + + +#include +#include +#include + +#include "ngx_http_sticky_misc.h" + +/* define a peer */ +typedef struct { + ngx_http_upstream_rr_peer_t *rr_peer; + ngx_str_t digest; +} ngx_http_sticky_peer_t; + +/* the configuration structure */ +typedef struct { + ngx_http_upstream_srv_conf_t uscf; + ngx_str_t cookie_name; + ngx_str_t cookie_domain; + ngx_str_t cookie_path; + time_t cookie_expires; + ngx_str_t hmac_key; + ngx_http_sticky_misc_hash_pt hash; + ngx_http_sticky_misc_hmac_pt hmac; + ngx_http_sticky_misc_text_pt text; + ngx_uint_t no_fallback; + ngx_http_sticky_peer_t *peers; +} ngx_http_sticky_srv_conf_t; + + +/* the custom sticky struct used on each request */ +typedef struct { + /* the round robin data must be first */ + ngx_http_upstream_rr_peer_data_t rrp; + ngx_event_get_peer_pt get_rr_peer; + int selected_peer; + int no_fallback; + ngx_http_sticky_srv_conf_t *sticky_conf; + ngx_http_request_t *request; +} ngx_http_sticky_peer_data_t; + + +static ngx_int_t ngx_http_init_sticky_peer(ngx_http_request_t *r, ngx_http_upstream_srv_conf_t *us); +static ngx_int_t ngx_http_get_sticky_peer(ngx_peer_connection_t *pc, void *data); +static char *ngx_http_sticky_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static void *ngx_http_sticky_create_conf(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_sticky_commands[] = { + + { ngx_string("sticky"), + NGX_HTTP_UPS_CONF|NGX_CONF_ANY, + ngx_http_sticky_set, + 0, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_sticky_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_http_sticky_create_conf, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_sticky_module = { + NGX_MODULE_V1, + &ngx_http_sticky_module_ctx, /* module context */ + ngx_http_sticky_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 +}; + + +/* + * function called by the upstream module to init itself + * it's called once per instance + */ +ngx_int_t ngx_http_init_upstream_sticky(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) +{ + ngx_http_upstream_rr_peers_t *rr_peers; + ngx_http_sticky_srv_conf_t *conf; + ngx_uint_t i; + + /* call the rr module on wich the sticky module is based on */ + if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) { + return NGX_ERROR; + } + + /* calculate each peer digest once and save */ + rr_peers = us->peer.data; + + /* do nothing there's only one peer */ + if (rr_peers->number <= 1 || rr_peers->single) { + return NGX_OK; + } + + /* tell the upstream module to call ngx_http_init_sticky_peer when it inits peer */ + us->peer.init = ngx_http_init_sticky_peer; + + conf = ngx_http_conf_upstream_srv_conf(us, ngx_http_sticky_module); + + /* if 'index', no need to alloc and generate digest */ + if (!conf->hash && !conf->hmac && !conf->text) { + conf->peers = NULL; + return NGX_OK; + } + + /* create our own upstream indexes */ + conf->peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_sticky_peer_t) * rr_peers->number); + if (conf->peers == NULL) { + return NGX_ERROR; + } + + /* parse each peer and generate digest if necessary */ + for (i = 0; i < rr_peers->number; i++) { + conf->peers[i].rr_peer = &rr_peers->peer[i]; + + if (conf->hmac) { + /* generate hmac */ + conf->hmac(cf->pool, rr_peers->peer[i].sockaddr, rr_peers->peer[i].socklen, &conf->hmac_key, &conf->peers[i].digest); + + } else if (conf->text) { + /* generate text */ + conf->text(cf->pool, rr_peers->peer[i].sockaddr, &conf->peers[i].digest); + + } else { + /* generate hash */ + conf->hash(cf->pool, rr_peers->peer[i].sockaddr, rr_peers->peer[i].socklen, &conf->peers[i].digest); + } + +#if 0 +/* FIXME: is it possible to log to debug level when at configuration stage ? */ + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "[sticky/ngx_http_init_upstream_sticky] generated digest \"%V\" for upstream at index %d", &conf->peers[i].digest, i); +#endif + + } + + return NGX_OK; +} + +/* + * function called by the upstream module when it inits each peer + * it's called once per request + */ +static ngx_int_t ngx_http_init_sticky_peer(ngx_http_request_t *r, ngx_http_upstream_srv_conf_t *us) +{ + ngx_http_sticky_peer_data_t *iphp; + ngx_str_t route; + ngx_uint_t i; + ngx_int_t n; + + /* alloc custom sticky struct */ + iphp = ngx_palloc(r->pool, sizeof(ngx_http_sticky_peer_data_t)); + if (iphp == NULL) { + return NGX_ERROR; + } + + /* attach it to the request upstream data */ + r->upstream->peer.data = &iphp->rrp; + + /* call the rr module on which the sticky is based on */ + if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) { + return NGX_ERROR; + } + + /* set the callback to select the next peer to use */ + r->upstream->peer.get = ngx_http_get_sticky_peer; + + /* init the custom sticky struct */ + iphp->get_rr_peer = ngx_http_upstream_get_round_robin_peer; + iphp->selected_peer = -1; + iphp->no_fallback = 0; + iphp->sticky_conf = ngx_http_conf_upstream_srv_conf(us, ngx_http_sticky_module); + iphp->request = r; + + /* check weather a cookie is present or not and save it */ + if (ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &iphp->sticky_conf->cookie_name, &route) != NGX_DECLINED) { + /* a route cookie has been found. Let's give it a try */ + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[sticky/init_sticky_peer] got cookie route=%V, let's try to find a matching peer", &route); + + /* hash, hmac or text, just compare digest */ + if (iphp->sticky_conf->hash || iphp->sticky_conf->hmac || iphp->sticky_conf->text) { + + /* check internal struct has been set */ + if (!iphp->sticky_conf->peers) { + /* log a warning, as it will continue without the sticky */ + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "[sticky/init_sticky_peer] internal peers struct has not been set"); + return NGX_OK; /* return OK, in order to continue */ + } + + /* search the digest found in the cookie in the peer digest list */ + for (i = 0; i < iphp->rrp.peers->number; i++) { + + /* ensure the both len are equal and > 0 */ + if (iphp->sticky_conf->peers[i].digest.len != route.len || route.len <= 0) { + continue; + } + + if (!ngx_strncmp(iphp->sticky_conf->peers[i].digest.data, route.data, route.len)) { + /* we found a match */ + iphp->selected_peer = i; + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[sticky/init_sticky_peer] the route \"%V\" matches peer at index %ui", &route, i); + return NGX_OK; + } + } + + } else { + + /* switch back to index, just convert to integer and ensure it corresponds to a valid peer */ + n = ngx_atoi(route.data, route.len); + if (n == NGX_ERROR) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "[sticky/init_sticky_peer] unable to convert the route \"%V\" to an integer value", &route); + } else if (n >= 0 && n < (ngx_int_t)iphp->rrp.peers->number) { + /* found one */ + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[sticky/init_sticky_peer] the route \"%V\" matches peer at index %i", &route, n); + iphp->selected_peer = n; + return NGX_OK; + } + } + + /* nothing was found, just continue with rr */ + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[sticky/init_sticky_peer] the route \"%V\" does not match any peer. Just ignoring it ...", &route); + return NGX_OK; + } + + /* nothing found */ + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[sticky/init_sticky_peer] route cookie not found", &route); + return NGX_OK; /* return OK, in order to continue */ +} + +/* + * function called by the upstream module to choose the next peer to use + * called at least one time per request + */ +static ngx_int_t ngx_http_get_sticky_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_http_sticky_peer_data_t *iphp = data; + ngx_http_sticky_srv_conf_t *conf = iphp->sticky_conf; + ngx_int_t selected_peer = -1; + time_t now = ngx_time(); + uintptr_t m; + ngx_uint_t n, i; + ngx_http_upstream_rr_peer_t *peer = NULL; + + ngx_log_debug(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[sticky/get_sticky_peer] get sticky peer, try: %ui, n_peers: %ui, no_fallback: %ui/%ui", pc->tries, iphp->rrp.peers->number, conf->no_fallback, iphp->no_fallback); + + /* TODO: cached */ + + /* has the sticky module already choosen a peer to connect to and is it a valid peer */ + /* is there more than one peer (otherwise, no choices to make) */ + if (iphp->selected_peer >= 0 && iphp->selected_peer < (ngx_int_t)iphp->rrp.peers->number && !iphp->rrp.peers->single) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[sticky/get_sticky_peer] let's try the selected peer (%i)", iphp->selected_peer); + + n = iphp->selected_peer / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << iphp->selected_peer % (8 * sizeof(uintptr_t)); + + /* has the peer not already been tried ? */ + if (!(iphp->rrp.tried[n] & m)) { + peer = &iphp->rrp.peers->peer[iphp->selected_peer]; + + /* if the no_fallback flag is set */ + if (conf->no_fallback) { + + iphp->no_fallback = 1; + + /* if peer is down */ + if (peer->down) { + ngx_log_error(NGX_LOG_NOTICE, pc->log, 0, "[sticky/get_sticky_peer] the selected peer is down and no_fallback is flagged"); + return NGX_BUSY; + } + + /* if it's been ignored for long enought (fail_timeout), reset timeout */ + /* do this check before testing peer->fails ! :) */ + if (now - peer->accessed > peer->fail_timeout) { + peer->fails = 0; + } + + /* if peer is failed */ + if (peer->max_fails > 0 && peer->fails >= peer->max_fails) { + ngx_log_error(NGX_LOG_NOTICE, pc->log, 0, "[sticky/get_sticky_peer] the selected peer is maked as failed and no_fallback is flagged"); + return NGX_BUSY; + } + } + + /* ensure the peer is not marked as down */ + if (!peer->down) { + + /* if it's not failedi, use it */ + if (peer->max_fails == 0 || peer->fails < peer->max_fails) { + selected_peer = (ngx_int_t)n; + + /* if it's been ignored for long enought (fail_timeout), reset timeout and use it */ + } else if (now - peer->accessed > peer->fail_timeout) { + peer->fails = 0; + selected_peer = (ngx_int_t)n; + + /* it's failed or timeout did not expire yet */ + } else { + /* mark the peer as tried */ + iphp->rrp.tried[n] |= m; + } + } + } + } + + /* we have a valid peer, tell the upstream module to use it */ + if (peer && selected_peer >= 0) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[sticky/get_sticky_peer] peer found at index %i", selected_peer); + + iphp->rrp.current = iphp->selected_peer; + pc->cached = 0; + pc->connection = NULL; + pc->sockaddr = peer->sockaddr; + pc->socklen = peer->socklen; + pc->name = &peer->name; + + iphp->rrp.tried[n] |= m; + + } else { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[sticky/get_sticky_peer] no sticky peer selected, switch back to classic rr"); + + if (iphp->no_fallback) { + ngx_log_error(NGX_LOG_NOTICE, pc->log, 0, "[sticky/get_sticky_peer] No fallback in action !"); + return NGX_BUSY; + } + + ngx_int_t ret = iphp->get_rr_peer(pc, &iphp->rrp); + if (ret != NGX_OK) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[sticky/get_sticky_peer] ngx_http_upstream_get_round_robin_peer returned %i", ret); + return ret; + } + + /* search for the choosen peer in order to set the cookie */ + for (i = 0; i < iphp->rrp.peers->number; i++) { + + if (iphp->rrp.peers->peer[i].sockaddr == pc->sockaddr && iphp->rrp.peers->peer[i].socklen == pc->socklen) { + if (conf->hash || conf->hmac || conf->text) { + ngx_http_sticky_misc_set_cookie(iphp->request, &conf->cookie_name, &conf->peers[i].digest, &conf->cookie_domain, &conf->cookie_path, conf->cookie_expires); + ngx_log_debug(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[sticky/get_sticky_peer] set cookie \"%V\" value=\"%V\" index=%ui", &conf->cookie_name, &conf->peers[i].digest, i); + } else { + ngx_str_t route; + ngx_uint_t tmp = i; + route.len = 0; + do { + route.len++; + } while (tmp /= 10); + route.data = ngx_pcalloc(iphp->request->pool, sizeof(u_char) * (route.len + 1)); + if (route.data == NULL) { + break; + } + ngx_snprintf(route.data, route.len, "%d", i); + route.len = ngx_strlen(route.data); + ngx_http_sticky_misc_set_cookie(iphp->request, &conf->cookie_name, &route, &conf->cookie_domain, &conf->cookie_path, conf->cookie_expires); + ngx_log_debug(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[sticky/get_sticky_peer] set cookie \"%V\" value=\"%V\" index=%ui", &conf->cookie_name, &tmp, i); + } + break; /* found and hopefully the cookie have been set */ + } + } + } + + /* reset the selection in order to bypass the sticky module when the upstream module will try another peers if necessary */ + iphp->selected_peer = -1; + + return NGX_OK; +} + +/* + * Function called when the sticky command is parsed on the conf file + */ +static char *ngx_http_sticky_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_upstream_srv_conf_t *upstream_conf; + ngx_http_sticky_srv_conf_t *sticky_conf; + ngx_uint_t i; + ngx_str_t tmp; + ngx_str_t name = ngx_string("route"); + ngx_str_t domain = ngx_string(""); + ngx_str_t path = ngx_string(""); + ngx_str_t hmac_key = ngx_string(""); + time_t expires = NGX_CONF_UNSET; + ngx_http_sticky_misc_hash_pt hash = NGX_CONF_UNSET_PTR; + ngx_http_sticky_misc_hmac_pt hmac = NULL; + ngx_http_sticky_misc_text_pt text = NULL; + ngx_uint_t no_fallback = 0; + + /* parse all elements */ + for (i = 1; i < cf->args->nelts; i++) { + ngx_str_t *value = cf->args->elts; + + /* is "name=" is starting the argument ? */ + if ((u_char *)ngx_strstr(value[i].data, "name=") == value[i].data) { + + /* do we have at least on char after "name=" ? */ + if (value[i].len <= sizeof("name=") - 1) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"name=\""); + return NGX_CONF_ERROR; + } + + /* save what's after "name=" */ + name.len = value[i].len - ngx_strlen("name="); + name.data = (u_char *)(value[i].data + sizeof("name=") - 1); + continue; + } + + /* is "domain=" is starting the argument ? */ + if ((u_char *)ngx_strstr(value[i].data, "domain=") == value[i].data) { + + /* do we have at least on char after "domain=" ? */ + if (value[i].len <= ngx_strlen("domain=")) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"domain=\""); + return NGX_CONF_ERROR; + } + + /* save what's after "domain=" */ + domain.len = value[i].len - ngx_strlen("domain="); + domain.data = (u_char *)(value[i].data + sizeof("domain=") - 1); + continue; + } + + /* is "path=" is starting the argument ? */ + if ((u_char *)ngx_strstr(value[i].data, "path=") == value[i].data) { + + /* do we have at least on char after "path=" ? */ + if (value[i].len <= ngx_strlen("path=")) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"path=\""); + return NGX_CONF_ERROR; + } + + /* save what's after "domain=" */ + path.len = value[i].len - ngx_strlen("path="); + path.data = (u_char *)(value[i].data + sizeof("path=") - 1); + continue; + } + + /* is "expires=" is starting the argument ? */ + if ((u_char *)ngx_strstr(value[i].data, "expires=") == value[i].data) { + + /* do we have at least on char after "expires=" ? */ + if (value[i].len <= sizeof("expires=") - 1) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"expires=\""); + return NGX_CONF_ERROR; + } + + /* extract value */ + tmp.len = value[i].len - ngx_strlen("expires="); + tmp.data = (u_char *)(value[i].data + sizeof("expires=") - 1); + + /* convert to time, save and validate */ + expires = ngx_parse_time(&tmp, 1); + if (expires == NGX_ERROR || expires < 1) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid value for \"expires=\""); + return NGX_CONF_ERROR; + } + continue; + } + + /* is "text=" is starting the argument ? */ + if ((u_char *)ngx_strstr(value[i].data, "text=") == value[i].data) { + + /* only hash or hmac can be used, not both */ + if (hmac || hash != NGX_CONF_UNSET_PTR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "please choose between \"hash=\", \"hmac=\" and \"text\""); + return NGX_CONF_ERROR; + } + + /* do we have at least on char after "name=" ? */ + if (value[i].len <= sizeof("text=") - 1) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"text=\""); + return NGX_CONF_ERROR; + } + + /* extract value to temp */ + tmp.len = value[i].len - ngx_strlen("text="); + tmp.data = (u_char *)(value[i].data + sizeof("text=") - 1); + + /* is name=raw */ + if (ngx_strncmp(tmp.data, "raw", sizeof("raw") - 1) == 0 ) { + text = ngx_http_sticky_misc_text_raw; + continue; + } + + /* is name=md5 */ + if (ngx_strncmp(tmp.data, "md5", sizeof("md5") - 1) == 0 ) { + text = ngx_http_sticky_misc_text_md5; + continue; + } + + /* is name=sha1 */ + if (ngx_strncmp(tmp.data, "sha1", sizeof("sha1") - 1) == 0 ) { + text = ngx_http_sticky_misc_text_sha1; + continue; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "wrong value for \"text=\": raw, md5 or sha1"); + return NGX_CONF_ERROR; + } + + /* is "hash=" is starting the argument ? */ + if ((u_char *)ngx_strstr(value[i].data, "hash=") == value[i].data) { + + /* only hash or hmac can be used, not both */ + if (hmac || text) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "please choose between \"hash=\", \"hmac=\" and \"text=\""); + return NGX_CONF_ERROR; + } + + /* do we have at least on char after "hash=" ? */ + if (value[i].len <= sizeof("hash=") - 1) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"hash=\""); + return NGX_CONF_ERROR; + } + + /* extract value to temp */ + tmp.len = value[i].len - ngx_strlen("hash="); + tmp.data = (u_char *)(value[i].data + sizeof("hash=") - 1); + + /* is hash=index */ + if (ngx_strncmp(tmp.data, "index", sizeof("index") - 1) == 0 ) { + hash = NULL; + continue; + } + + /* is hash=md5 */ + if (ngx_strncmp(tmp.data, "md5", sizeof("md5") - 1) == 0 ) { + hash = ngx_http_sticky_misc_md5; + continue; + } + + /* is hash=sha1 */ + if (ngx_strncmp(tmp.data, "sha1", sizeof("sha1") - 1) == 0 ) { + hash = ngx_http_sticky_misc_sha1; + continue; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "wrong value for \"hash=\": index, md5 or sha1"); + return NGX_CONF_ERROR; + } + + /* is "hmac=" is starting the argument ? */ + if ((u_char *)ngx_strstr(value[i].data, "hmac=") == value[i].data) { + + /* only hash or hmac can be used, not both */ + if (hash != NGX_CONF_UNSET_PTR || text) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "please choose between \"hash=\", \"hmac=\" and \"text\""); + return NGX_CONF_ERROR; + } + + /* do we have at least on char after "hmac=" ? */ + if (value[i].len <= sizeof("hmac=") - 1) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"hmac=\""); + return NGX_CONF_ERROR; + } + + /* extract value */ + tmp.len = value[i].len - ngx_strlen("hmac="); + tmp.data = (u_char *)(value[i].data + sizeof("hmac=") - 1); + + /* is hmac=md5 ? */ + if (ngx_strncmp(tmp.data, "md5", sizeof("md5") - 1) == 0 ) { + hmac = ngx_http_sticky_misc_hmac_md5; + continue; + } + + /* is hmac=sha1 ? */ + if (ngx_strncmp(tmp.data, "sha1", sizeof("sha1") - 1) == 0 ) { + hmac = ngx_http_sticky_misc_hmac_sha1; + continue; + } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "wrong value for \"hmac=\": md5 or sha1"); + return NGX_CONF_ERROR; + } + + /* is "hmac_key=" is starting the argument ? */ + if ((u_char *)ngx_strstr(value[i].data, "hmac_key=") == value[i].data) { + + /* do we have at least on char after "hmac_key=" ? */ + if (value[i].len <= ngx_strlen("hmac_key=")) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "a value must be provided to \"hmac_key=\""); + return NGX_CONF_ERROR; + } + + /* save what's after "hmac_key=" */ + hmac_key.len = value[i].len - ngx_strlen("hmac_key="); + hmac_key.data = (u_char *)(value[i].data + sizeof("hmac_key=") - 1); + continue; + } + + /* is "no_fallback" flag present ? */ + if (ngx_strncmp(value[i].data, "no_fallback", sizeof("no_fallback") - 1) == 0 ) { + no_fallback = 1; + continue; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid arguement (%V)", &value[i]); + return NGX_CONF_ERROR; + } + + /* if has and hmac and name have not been set, default to md5 */ + if (hash == NGX_CONF_UNSET_PTR && hmac == NULL && text == NULL) { + hash = ngx_http_sticky_misc_md5; + } + + /* don't allow meaning less parameters */ + if (hmac_key.len > 0 && hash != NGX_CONF_UNSET_PTR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"hmac_key=\" is meaningless when \"hmac\" is used. Please remove it."); + return NGX_CONF_ERROR; + } + + /* ensure we have an hmac key if hmac's been set */ + if (hmac_key.len == 0 && hmac != NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "please specify \"hmac_key=\" when using \"hmac\""); + return NGX_CONF_ERROR; + } + + /* ensure hash is NULL to avoid conflicts later */ + if (hash == NGX_CONF_UNSET_PTR) { + hash = NULL; + } + + /* save the sticky parameters */ + sticky_conf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_sticky_module); + sticky_conf->cookie_name = name; + sticky_conf->cookie_domain = domain; + sticky_conf->cookie_path = path; + sticky_conf->cookie_expires = expires; + sticky_conf->hash = hash; + sticky_conf->hmac = hmac; + sticky_conf->text = text; + sticky_conf->hmac_key = hmac_key; + sticky_conf->no_fallback = no_fallback; + sticky_conf->peers = NULL; /* ensure it's null before running */ + + upstream_conf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); + + /* + * ensure another upstream module has not been already loaded + * peer.init_upstream is set to null and the upstream module use RR if not set + * But this check only works when the other module is declared before sticky + */ + if (upstream_conf->peer.init_upstream) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "You can't use sticky with another upstream module"); + return NGX_CONF_ERROR; + } + + /* configure the upstream to get back to this module */ + upstream_conf->peer.init_upstream = ngx_http_init_upstream_sticky; + + upstream_conf->flags = NGX_HTTP_UPSTREAM_CREATE + | NGX_HTTP_UPSTREAM_MAX_FAILS + | NGX_HTTP_UPSTREAM_FAIL_TIMEOUT + | NGX_HTTP_UPSTREAM_DOWN + | NGX_HTTP_UPSTREAM_WEIGHT; + + return NGX_CONF_OK; +} + +/* + * alloc stick configuration + */ +static void *ngx_http_sticky_create_conf(ngx_conf_t *cf) +{ + ngx_http_sticky_srv_conf_t *conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_sticky_srv_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + return conf; +}