static ngx_int_t
ngx_http_realip_handler(ngx_http_request_t *r)
{
    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;
    ngx_http_realip_ctx_t       *ctx;
    ngx_http_realip_loc_conf_t  *rlcf;
    ctx = ngx_http_get_module_ctx(r, ngx_http_realip_module);
    if (ctx)
    {
        return NGX_DECLINED;
    }
    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module);
    if (rlcf->from == NULL)
    {
        return NGX_DECLINED;
    }
    switch (rlcf->type)
    {
    case NGX_HTTP_REALIP_XREALIP:
        if (r->headers_in.x_real_ip == NULL)
        {
            return NGX_DECLINED;
        }
        value = &r->headers_in.x_real_ip->value;
        xfwd = NULL;
        break;
    case NGX_HTTP_REALIP_XFWD:
        xfwd = &r->headers_in.x_forwarded_for;
        if (xfwd->elts == NULL)
        {
            return NGX_DECLINED;
        }
        value = NULL;
        break;
    case NGX_HTTP_REALIP_PROXY:
        value = &r->connection->proxy_protocol_addr;
        if (value->len == 0)
        {
            return NGX_DECLINED;
        }
        xfwd = NULL;
        break;
    default: /* NGX_HTTP_REALIP_HEADER */
        part = &r->headers_in.headers.part;
        header = part->elts;
        hash = rlcf->hash;
        len = rlcf->header.len;
        p = rlcf->header.data;
        for (i = 0; /* void */ ; i++)
        {
            if (i >= part->nelts)
            {
                if (part->next == NULL)
                {
                    break;
                }
                part = part->next;
                header = part->elts;
                i = 0;
            }
            if (hash == header[i].hash
                    && len == header[i].key.len
                    && ngx_strncmp(p, header[i].lowcase_key, len) == 0)
            {
                value = &header[i].value;
                xfwd = NULL;
                goto found;
            }
        }
        return NGX_DECLINED;
    }
found:
    c = r->connection;
    addr.sockaddr = c->sockaddr;
    addr.socklen = c->socklen;
    /* addr.name = c->addr_text; */
    if (ngx_http_get_forwarded_addr(r, &addr, xfwd, value, rlcf->from,
                                    rlcf->recursive)
            != NGX_DECLINED)
    {
        return ngx_http_realip_set_addr(r, &addr);
    }
    return NGX_DECLINED;
}
static ngx_int_t
ngx_http_realip_handler(ngx_http_request_t *r)
{
    u_char                      *ip, *p;
    size_t                       len;
    ngx_uint_t                   i, hash;
    ngx_list_part_t             *part;
    ngx_table_elt_t             *header;
    struct sockaddr_in          *sin;
    ngx_connection_t            *c;
    ngx_http_realip_ctx_t       *ctx;
    ngx_http_realip_from_t      *from;
    ngx_http_realip_loc_conf_t  *rlcf;

    ctx = ngx_http_get_module_ctx(r, ngx_http_realip_module);

    if (ctx) {
        return NGX_DECLINED;
    }

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module);

    if (rlcf->from == NULL
#if (NGX_HAVE_UNIX_DOMAIN)
        && !rlcf->unixsock
#endif
       )
    {
        return NGX_DECLINED;
    }

    switch (rlcf->type) {

    case NGX_HTTP_REALIP_XREALIP:

        if (r->headers_in.x_real_ip == NULL) {
            return NGX_DECLINED;
        }

        len = r->headers_in.x_real_ip->value.len;
        ip = r->headers_in.x_real_ip->value.data;

        break;

    case NGX_HTTP_REALIP_XFWD:

        if (r->headers_in.x_forwarded_for == NULL) {
            return NGX_DECLINED;
        }

        len = r->headers_in.x_forwarded_for->value.len;
        ip = r->headers_in.x_forwarded_for->value.data;

        for (p = ip + len - 1; p > ip; p--) {
            if (*p == ' ' || *p == ',') {
                p++;
                len -= p - ip;
                ip = p;
                break;
            }
        }

        break;

    default: /* NGX_HTTP_REALIP_HEADER */

        part = &r->headers_in.headers.part;
        header = part->elts;

        hash = rlcf->hash;
        len = rlcf->header.len;
        p = rlcf->header.data;

        for (i = 0; /* void */ ; i++) {

            if (i >= part->nelts) {
                if (part->next == NULL) {
                    break;
                }

                part = part->next;
                header = part->elts;
                i = 0;
            }

            if (hash == header[i].hash
                && len == header[i].key.len
                && ngx_strncmp(p, header[i].lowcase_key, len) == 0)
            {
                len = header[i].value.len;
                ip = header[i].value.data;

                goto found;
            }
        }

        return NGX_DECLINED;
    }

found:

    c = r->connection;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "realip: \"%s\"", ip);

    /* AF_INET only */

    if (c->sockaddr->sa_family == AF_INET) {
        sin = (struct sockaddr_in *) c->sockaddr;

        from = rlcf->from->elts;
        for (i = 0; i < rlcf->from->nelts; i++) {

            ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
                           "realip: %08XD %08XD %08XD",
                           sin->sin_addr.s_addr, from[i].mask, from[i].addr);

            if ((sin->sin_addr.s_addr & from[i].mask) == from[i].addr) {
                return ngx_http_realip_set_addr(r, ip, len);
            }
        }
    }

#if (NGX_HAVE_UNIX_DOMAIN)

    if (c->sockaddr->sa_family == AF_UNIX && rlcf->unixsock) {
        return ngx_http_realip_set_addr(r, ip, len);
    }

#endif

    return NGX_DECLINED;
}