Correctly handle multiple X-Forwarded-For headers (ticket #106).
diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c
index a927ab7..725baa2 100644
--- a/src/http/modules/ngx_http_geo_module.c
+++ b/src/http/modules/ngx_http_geo_module.c
@@ -314,18 +314,17 @@
 ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx,
     ngx_addr_t *addr)
 {
-    ngx_table_elt_t  *xfwd;
+    ngx_array_t  *xfwd;
 
     if (ngx_http_geo_real_addr(r, ctx, addr) != NGX_OK) {
         return NGX_ERROR;
     }
 
-    xfwd = r->headers_in.x_forwarded_for;
+    xfwd = &r->headers_in.x_forwarded_for;
 
-    if (xfwd != NULL && ctx->proxies != NULL) {
-        (void) ngx_http_get_forwarded_addr(r, addr, xfwd->value.data,
-                                           xfwd->value.len, ctx->proxies,
-                                           ctx->proxy_recursive);
+    if (xfwd->nelts > 0 && ctx->proxies != NULL) {
+        (void) ngx_http_get_forwarded_addr(r, addr, xfwd, NULL,
+                                           ctx->proxies, ctx->proxy_recursive);
     }
 
     return NGX_OK;
diff --git a/src/http/modules/ngx_http_geoip_module.c b/src/http/modules/ngx_http_geoip_module.c
index 3641065..576fc5f 100644
--- a/src/http/modules/ngx_http_geoip_module.c
+++ b/src/http/modules/ngx_http_geoip_module.c
@@ -240,19 +240,18 @@
 ngx_http_geoip_addr(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
 {
     ngx_addr_t           addr;
-    ngx_table_elt_t     *xfwd;
+    ngx_array_t         *xfwd;
     struct sockaddr_in  *sin;
 
     addr.sockaddr = r->connection->sockaddr;
     addr.socklen = r->connection->socklen;
     /* addr.name = r->connection->addr_text; */
 
-    xfwd = r->headers_in.x_forwarded_for;
+    xfwd = &r->headers_in.x_forwarded_for;
 
-    if (xfwd != NULL && gcf->proxies != NULL) {
-        (void) ngx_http_get_forwarded_addr(r, &addr, xfwd->value.data,
-                                           xfwd->value.len, gcf->proxies,
-                                           gcf->proxy_recursive);
+    if (xfwd->nelts > 0 && gcf->proxies != NULL) {
+        (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL,
+                                           gcf->proxies, gcf->proxy_recursive);
     }
 
 #if (NGX_HAVE_INET6)
@@ -293,7 +292,7 @@
 ngx_http_geoip_addr_v6(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
 {
     ngx_addr_t            addr;
-    ngx_table_elt_t      *xfwd;
+    ngx_array_t          *xfwd;
     in_addr_t             addr4;
     struct in6_addr       addr6;
     struct sockaddr_in   *sin;
@@ -303,12 +302,11 @@
     addr.socklen = r->connection->socklen;
     /* addr.name = r->connection->addr_text; */
 
-    xfwd = r->headers_in.x_forwarded_for;
+    xfwd = &r->headers_in.x_forwarded_for;
 
-    if (xfwd != NULL && gcf->proxies != NULL) {
-        (void) ngx_http_get_forwarded_addr(r, &addr, xfwd->value.data,
-                                           xfwd->value.len, gcf->proxies,
-                                           gcf->proxy_recursive);
+    if (xfwd->nelts > 0 && gcf->proxies != NULL) {
+        (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL,
+                                           gcf->proxies, gcf->proxy_recursive);
     }
 
     switch (addr.sockaddr->sa_family) {
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index a623adc..eadc8c4 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -2014,32 +2014,44 @@
 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data)
 {
-    u_char  *p;
+    size_t             len;
+    u_char            *p;
+    ngx_uint_t         i, n;
+    ngx_table_elt_t  **h;
 
     v->valid = 1;
     v->no_cacheable = 0;
     v->not_found = 0;
 
-    if (r->headers_in.x_forwarded_for == NULL) {
+    n = r->headers_in.x_forwarded_for.nelts;
+    h = r->headers_in.x_forwarded_for.elts;
+
+    len = 0;
+
+    for (i = 0; i < n; i++) {
+        len += h[i]->value.len + sizeof(", ") - 1;
+    }
+
+    if (len == 0) {
         v->len = r->connection->addr_text.len;
         v->data = r->connection->addr_text.data;
         return NGX_OK;
     }
 
-    v->len = r->headers_in.x_forwarded_for->value.len
-             + sizeof(", ") - 1 + r->connection->addr_text.len;
+    len += r->connection->addr_text.len;
 
-    p = ngx_pnalloc(r->pool, v->len);
+    p = ngx_pnalloc(r->pool, len);
     if (p == NULL) {
         return NGX_ERROR;
     }
 
+    v->len = len;
     v->data = p;
 
-    p = ngx_copy(p, r->headers_in.x_forwarded_for->value.data,
-                 r->headers_in.x_forwarded_for->value.len);
-
-    *p++ = ','; *p++ = ' ';
+    for (i = 0; i < n; i++) {
+        p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
+        *p++ = ','; *p++ = ' ';
+    }
 
     ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len);
 
diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c
index 4531ea5..ed9c5f9 100644
--- a/src/http/modules/ngx_http_realip_module.c
+++ b/src/http/modules/ngx_http_realip_module.c
@@ -107,10 +107,12 @@
 static ngx_int_t
 ngx_http_realip_handler(ngx_http_request_t *r)
 {
-    u_char                      *ip, *p;
+    u_char                      *p;
     size_t                       len;
+    ngx_str_t                   *value;
     ngx_uint_t                   i, hash;
     ngx_addr_t                   addr;
+    ngx_array_t                 *xfwd;
     ngx_list_part_t             *part;
     ngx_table_elt_t             *header;
     ngx_connection_t            *c;
@@ -137,19 +139,20 @@
             return NGX_DECLINED;
         }
 
-        len = r->headers_in.x_real_ip->value.len;
-        ip = r->headers_in.x_real_ip->value.data;
+        value = &r->headers_in.x_real_ip->value;
+        xfwd = NULL;
 
         break;
 
     case NGX_HTTP_REALIP_XFWD:
 
-        if (r->headers_in.x_forwarded_for == NULL) {
+        xfwd = &r->headers_in.x_forwarded_for;
+
+        if (xfwd->elts == NULL) {
             return NGX_DECLINED;
         }
 
-        len = r->headers_in.x_forwarded_for->value.len;
-        ip = r->headers_in.x_forwarded_for->value.data;
+        value = NULL;
 
         break;
 
@@ -178,8 +181,8 @@
                 && len == header[i].key.len
                 && ngx_strncmp(p, header[i].lowcase_key, len) == 0)
             {
-                len = header[i].value.len;
-                ip = header[i].value.data;
+                value = &header[i].value;
+                xfwd = NULL;
 
                 goto found;
             }
@@ -192,15 +195,13 @@
 
     c = r->connection;
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "realip: \"%s\"", ip);
-
     addr.sockaddr = c->sockaddr;
     addr.socklen = c->socklen;
     /* addr.name = c->addr_text; */
 
-    if (ngx_http_get_forwarded_addr(r, &addr, ip, len, rlcf->from,
+    if (ngx_http_get_forwarded_addr(r, &addr, xfwd, value, rlcf->from,
                                     rlcf->recursive)
-        == NGX_OK)
+        != NGX_DECLINED)
     {
         return ngx_http_realip_set_addr(r, &addr);
     }