{"action":"created","comment":{"url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/pulls/comments/36710616","id":36710616,"diff_hunk":"@@ -98,10 +84,854 @@ ngx_http_lua_upstream_create_module(lua_State * L)\n     lua_pushcfunction(L, ngx_http_lua_upstream_set_peer_down);\n     lua_setfield(L, -2, \"set_peer_down\");\n \n+    lua_pushcfunction(L, ngx_http_lua_upstream_add_server);\n+    lua_setfield(L, -2, \"add_server\");\n+\n+    lua_pushcfunction(L, ngx_http_lua_upstream_add_peer);\n+    lua_setfield(L, -2, \"add_peer\");\n+\n+    lua_pushcfunction(L, ngx_http_lua_upstream_remove_server);\n+    lua_setfield(L, -2, \"remove_server\");\n+\n+    lua_pushcfunction(L, ngx_http_lua_upstream_remove_peer);\n+    lua_setfield(L, -2, \"remove_peer\");\n+\n+    return 1;\n+}\n+\n+\n+/*\n+ * The function is compare server as upstream server \n+ * if exists and return upstream_server_t else return \n+ * NULL\n+ * \n+*/\n+static ngx_http_upstream_server_t*\n+ngx_http_lua_upstream_compare_server(ngx_http_upstream_srv_conf_t * us , ngx_url_t u )\n+{\n+    ngx_uint_t                       i,j;\n+    size_t                           len;\n+    ngx_http_upstream_server_t      *server = NULL;\n+\n+    if (us->servers == NULL || us->servers->nelts == 0) {\n+        return NULL;\n+    }\n+\n+    server = us->servers->elts;\n+\n+    for (i = 0; i < us->servers->nelts; ++i) {\n+        for(j = 0; j < server[i].naddrs; ++j) {\n+\n+            len = server[i].addrs[j].name.len;\n+            if ( len == u.url.len \n+                 && ngx_memcmp( u.url.data ,server[i].addrs[j].name.data , u.url.len) == 0 ) {\n+\n+                 return  &server[i];\n+            } \n+         }\n+        \n+    }\n+\n+    return NULL;\n+\n+}\n+\n+\n+/*\n+ * The function is dynamically add a server to upstream \n+ * server ,but not added it to the back-end peer\n+ * \n+*/\n+static int\n+ngx_http_lua_upstream_add_server(lua_State * L)\n+{\n+\n+    ngx_str_t                         host;\n+    ngx_http_upstream_server_t       *us;\n+    ngx_http_upstream_srv_conf_t     *uscf;\n+    ngx_url_t                         u;\n+    ngx_http_request_t               *r;\n+    ngx_int_t                         weight, max_fails;\n+    time_t                            fail_timeout;\n+    u_char                           *p;\n+\n+    if (lua_gettop(L) != 5) {\n+        // five param is :\"upstream name\", \"ip:port\" , \"weight\" , \"max_fails\", \n+        //\"fail_time\"\n+        // for lua code , you must pass this five param, is none ,you should \n+        // consider pass default value.\n+        return luaL_error(L, \"exactly five argument expected\");\n+    }\n+\n+    r = ngx_http_lua_get_request(L);\n+    if (NULL == r) {\n+        lua_pushnil(L);\n+        lua_pushliteral(L, \"get request error \\n\");\n+        return 2;\n+    }\n+\n+    host.data = (u_char *) luaL_checklstring(L, 1, &host.len);\n+\n+    ngx_memzero(&u, sizeof (ngx_url_t));\n+    p = (u_char *) luaL_checklstring(L, 2, &u.url.len);\n+    u.default_port = 80;\n+\n+    weight = (ngx_int_t) luaL_checkint(L, 3);\n+    max_fails = (ngx_int_t) luaL_checkint(L, 4);\n+    fail_timeout = (time_t) luaL_checklong(L, 5);\n+#if (NGX_DEBUG)\n+    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, \"%s %s params: %s,%s,%d,%d,%d\\n\", __FILE__,__FUNCTION__, host.data, p, weight, max_fails, fail_timeout);\n+#endif\n+    uscf = ngx_http_lua_upstream_find_upstream(L, &host);\n+    if (NULL == uscf) {\n+        lua_pushnil(L);\n+        lua_pushliteral(L, \"upstream not found\\n\");\n+        return 2;\n+    }\n+ \n+     \n+    // lua virtual machine memory is stack,so dup a memory \n+    u.url.data = ngx_pcalloc(uscf->servers->pool,u.url.len+1);\n+    ngx_memcpy(u.url.data ,p ,u.url.len);\n+\n+    if ( NULL != ngx_http_lua_upstream_compare_server(uscf,u) ) {\n+        lua_pushnil(L);\n+        lua_pushliteral(L,\"this server is exist\\n\");\n+        return 2;\n+    }    \n+\n+    if (uscf->servers == NULL || uscf->servers->nelts == 0) {\n+        //TODO: 对于 默认的空upstream来讲，nginx当前会不允许其启动，可以考虑调整策略，允许此种情况下nginx启动\n+        lua_pushliteral(L, \"upstream has no server before!\\n\");\n+        lua_newtable(L);\n+        return 2;\n+    } else {\n+        if (ngx_parse_url(uscf->servers->pool, &u) != NGX_OK) {\n+            if (u.err) {\n+                lua_pushnil(L);\n+                lua_pushliteral(L, \"url parser error\");\n+                return 2;\n+            }\n+        }\n+\n+        us = ngx_array_push(uscf->servers);\n+        if (us == NULL) {\n+            lua_pushliteral(L, \"us push uscf->servers failed\\n\");\n+            return 3;\n+        }\n+       \n+        ngx_memzero(us, sizeof (ngx_http_upstream_server_t));\n+\n+        us->name = u.url;\n+        us->addrs = u.addrs;\n+        us->naddrs = u.naddrs;\n+        us->weight = weight;\n+        us->max_fails = max_fails;\n+        us->fail_timeout = fail_timeout;\n+\n+    }\n+\n+    return 1;\n+}\n+\n+\n+/*\n+ * The function is remove a server from ngx_http_upstream_srv_conf_t servers  \n+ * \n+*/\n+static int\n+ngx_http_lua_upstream_remove_server(lua_State * L)\n+{\n+    ngx_uint_t                           i,j,k;\n+    size_t                               len;\n+    ngx_str_t                            host;\n+    ngx_array_t                         *servers;\n+    ngx_http_upstream_server_t          *us,*server;\n+    ngx_http_upstream_srv_conf_t        *uscf;\n+    ngx_http_request_t                  *r;\n+    ngx_url_t                            u;\n+    size_t                               old_size,new_size;\n+    \n+    if (lua_gettop(L) != 2) {\n+        // two param is :  \"bar\",\"ip:port\" \n+        // for lua code , you must pass this two param, is none ,you should \n+        // consider pass default value.\n+        lua_pushnil(L);\n+        lua_pushliteral(L, \"exactly two argument expected\\n\");\n+        return 2;\n+    }\n+\n+    r = ngx_http_lua_get_request(L);\n+    if (NULL == r) {\n+        lua_pushnil(L);\n+        lua_pushliteral(L, \"get request error \\n\");\n+        return 2;\n+    }\n+\n+    host.data = (u_char *) luaL_checklstring(L, 1, &host.len);\n+\n+    ngx_memzero(&u, sizeof (ngx_url_t));\n+    u.url.data = (u_char *) luaL_checklstring(L, 2, &u.url.len);\n+    u.default_port = 80;\n+\n+#if (NGX_DEBUG)\n+    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, \"%s %s params: %s\\n\", __FILE__,__FUNCTION__ , u.url.data );\n+#endif\n+\n+    uscf = ngx_http_lua_upstream_find_upstream(L, &host);\n+    if (NULL == uscf) {\n+        lua_pushnil(L);\n+        lua_pushliteral(L, \"upstream not found\\n\");\n+        return 2;\n+    }\n+    \n+    if ( NULL == ngx_http_lua_upstream_compare_server(uscf,u) ) {\n+        lua_pushnil(L);\n+        lua_pushliteral(L,\"not found this server\\n\");\n+        return 2;\n+    }    \n+\n+    server = uscf->servers->elts;\n+\n+    servers = ngx_array_create(ngx_cycle->pool,uscf->servers->nelts,sizeof(ngx_http_upstream_server_t));    \n+    if (NULL == servers) {\n+        lua_pushnil(L);\n+        lua_pushliteral(L, \"servers create fail\\n\");\n+        return 2;\n+    }\n+    \n+    for (i = 0; i<uscf->servers->nelts; i++) {\n+        if ( server[i].naddrs == 1 ) {\n+\n+             len = server[i].addrs->name.len;\n+\t     if ( len == u.url.len \n+                  && ngx_memcmp( u.url.data ,server[i].addrs->name.data , u.url.len) == 0 ) {\n+                  continue;\n+             }\n+         } else {\n+             for(j = 0; j < server[i].naddrs; ++j) {\n+\n+                 len = server[i].addrs[j].name.len;\n+\t         if ( len == u.url.len \n+                      && ngx_memcmp( u.url.data ,server[i].addrs[j].name.data , u.url.len) == 0 ) {\n+                      for(k = j; k < server[i].naddrs -1; ++k) {\n+                           server[i].addrs[k] = server[i].addrs[k+1];\n+                      }\n+\n+                      old_size = server[i].naddrs * sizeof(ngx_addr_t);\n+                      new_size = (server[i].naddrs - 1) * sizeof(ngx_addr_t);\n+\n+                      server[i].addrs = ngx_prealloc(ngx_cycle->pool, server[i].addrs, old_size, new_size );\n+                      server[i].naddrs -= 1;\n+                      break;\n+                  }\n+            }\n+         }\n+              \n+\n+       us = ngx_array_push(servers);\n+       ngx_memzero(us,sizeof(ngx_http_upstream_server_t));\n+       us->name = server[i].name;\n+       us->addrs = server[i].addrs;\n+       us->naddrs = server[i].naddrs;\n+       us->weight = server[i].weight;\n+       us->max_fails = server[i].max_fails;\n+       us->fail_timeout = server[i].fail_timeout;\n+   }\n+   \n+   ngx_array_destroy(uscf->servers);\n+   uscf->servers = servers;\n+   \n+\n+    return 1;\n+\n+}\n+\n+\n+/*\n+ * The function is remove server from back-end peers. if \n+ * the server is not find and return error and notes the \n+ * server is not find. now suitable for round_robin or\n+ * ip_hash \n+*/\n+static int\n+ngx_http_lua_upstream_remove_peer(lua_State * L)\n+{\n+    ngx_uint_t                               i,j;\n+    ngx_uint_t                               n;\n+    size_t                                   len;\n+    ngx_str_t                                host;\n+    ngx_http_upstream_rr_peers_t            *peers; \n+    ngx_http_upstream_srv_conf_t            *uscf;\n+    ngx_http_request_t                      *r;\n+    ngx_url_t                                u;\n+    size_t                                   old_size,new_size;\n+    \n+    if (lua_gettop(L) != 2) {\n+        // two param is :  \"bar\",\"ip:port\" \n+        // for lua code , you must pass this two param, is none ,you should \n+        // consider pass default value.\n+        lua_pushnil(L);\n+        lua_pushliteral(L, \"exactly two argument expected\\n\");\n+        return 2;\n+    }\n+\n+    r = ngx_http_lua_get_request(L);\n+    if (NULL == r) {\n+        lua_pushnil(L);\n+        lua_pushliteral(L, \"get request error \\n\");\n+        return 2;\n+    }\n+\n+    host.data = (u_char *) luaL_checklstring(L, 1, &host.len);\n+\n+    ngx_memzero(&u, sizeof (ngx_url_t));\n+    u.url.data = (u_char *) luaL_checklstring(L, 2, &u.url.len);\n+    u.default_port = 80;\n+\n+#if (NGX_DEBUG)\n+    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, \"%s %s params: %s\\n\", __FILE__,__FUNCTION__ , u.url.data );\n+#endif\n+\n+    uscf = ngx_http_lua_upstream_find_upstream(L, &host);\n+    if (NULL == uscf) {\n+        lua_pushnil(L);\n+        lua_pushliteral(L, \"upstream not found\\n\");\n+        return 2;\n+    }\n+    \n+    peers = uscf->peer.data;    \n+\n+    if ( 0 == ngx_http_lua_upstream_exist_peer(peers,u) ) {\n+        lua_pushnil(L);\n+        lua_pushliteral(L, \"not found this peer\\n\");\n+        return 2;\n+    }\n+\n+    peers = uscf->peer.data;\n+    if (NULL == peers ) {\n+        lua_pushnil(L);\n+        lua_pushliteral(L, \"peers is null\\n\");\n+        return 2;\n+    }\n+    \n+    for (i = 0; i < peers->number; i++) {\n+        len = ( peers->peer[i].name.data == NULL ? 0 : ngx_strlen(peers->peer[i].name.data));\n+\tif ( len == u.url.len\n+             && ngx_memcmp( u.url.data ,peers->peer[i].name.data , u.url.len) == 0 ) {\n+#if (NGX_HTTP_UPSTREAM_CHECH)\n+             if (!peers->peer[i].down) {\n+                 ngx_http_lua_upstream_check_remove_peer(uscf, u);\n+             } \n+#endif\n+             for ( j = i; j < peers->number-1; j++) {\n+                peers->peer[j] = peers->peer[j+1];\n+             }\n+\n+             n = peers->number -1 ;\n+             n += peers->next != NULL ? peers->next->number : 0;\n+             old_size = n*sizeof(ngx_http_upstream_rr_peer_t) \n+\t\t\t  + sizeof(ngx_http_upstream_rr_peers_t)*(peers->next != NULL ? 2:1);\n+             new_size = old_size - sizeof(ngx_http_upstream_rr_peer_t);\n+\n+             peers  = ngx_prealloc(ngx_cycle->pool, peers, old_size, new_size );\n+             peers->number -= 1;\n+\n+             break;\n+        }\n+    }\n+\n+\n+    return 1;\n+\n+}\n+\n+\n+\n+\n+/*\n+ * The function is check upstream whether there is  \n+ * such a u.url.data,if exist return srv_conf_t structure \n+ * else return NULL\n+*/\n+static ngx_http_upstream_srv_conf_t *\n+ngx_http_lua_upstream_check_peers(lua_State * L,ngx_url_t u,ngx_http_upstream_server_t ** srv)\n+{\n+    ngx_http_upstream_srv_conf_t               *uscf;\n+    ngx_str_t                                   host;\n+\n+    if (lua_gettop(L) != 2) {\n+        lua_pushnil(L);\n+        lua_pushliteral(L, \"no argument expected\\n\");\n+        return NULL;\n+    }\n+    \n+\n+    ngx_memzero(&host, sizeof(ngx_str_t));\n+    host.data = (u_char *) luaL_checklstring(L, 1, &host.len);\n+\n+    uscf = ngx_http_lua_upstream_find_upstream(L, &host);\n+    if (NULL == uscf) {\n+        lua_pushnil(L);\n+        lua_pushliteral(L, \"upstream not found\\n\");\n+        return NULL;\n+    }\n+\n+\n+   *srv = ngx_http_lua_upstream_compare_server(uscf,u);\n+   if (NULL == *srv) {    \n+        lua_pushnil(L);\n+        lua_pushliteral(L,\"not find this peer\\n\");\n+        return NULL;\n+    }\n+\n+    \n+    return uscf;\n+\n+}\n+\n+\n+/*\n+ * The function is check current peers whether exists \n+ * a peer  such a u.url.data if exists and return 1,\n+ * else return 0\n+*/\n+static int\n+ngx_http_lua_upstream_exist_peer(ngx_http_upstream_rr_peers_t * peers , ngx_url_t u)\n+{\n+    ngx_uint_t                          i;\n+    size_t                              len;\n+    ngx_http_upstream_rr_peer_t         peer;\n+\n+    for (i = 0; (NULL != peers) && (i < peers->number) ; i++) {\n+        peer = peers->peer[i];\n+        len = ( peer.name.data == NULL ? 0:ngx_strlen(peer.name.data) );\n+        if (len == u.url.len\n+            && ngx_memcmp(u.url.data , peer.name.data , u.url.len) == 0) {\n+            return 1;\n+        }\n+    }\n+    \n+    return 0;\n+\n+}\n+\n+\n+#if (NGX_HTTP_UPSTREAM_CHECK)\n+\n+/*\n+ * This function copy from ngx_http_upstream_check_module.c in older to \n+ * support ngx_http_upstream_check_module \n+ *\n+*/\n+static ngx_int_t\n+ngx_http_upstream_check_addr_change_port(ngx_pool_t *pool, ngx_addr_t *dst,\n+                                         ngx_addr_t *src, ngx_uint_t port)\n+{\n+    size_t                len;\n+    u_char               *p;\n+    struct sockaddr_in   *sin;\n+#if (NGX_HAVE_INET6)\n+    struct sockaddr_in6  *sin6;\n+#endif\n+\n+    dst->socklen = src->socklen;\n+    dst->sockaddr = ngx_palloc(pool, dst->socklen);\n+    if (dst->sockaddr == NULL) {\n+        return NGX_ERROR;\n+    }\n+\n+    ngx_memcpy(dst->sockaddr, src->sockaddr, dst->socklen);\n+\n+    switch (dst->sockaddr->sa_family) {\n+\n+    case AF_INET:\n+\n+        len = NGX_INET_ADDRSTRLEN + sizeof(\":65535\") - 1;\n+        sin = (struct sockaddr_in *) dst->sockaddr;\n+        sin->sin_port = htons(port);\n+\n+        break;\n+\n+#if (NGX_HAVE_INET6)\n+    case AF_INET6:\n+\n+        len = NGX_INET6_ADDRSTRLEN + sizeof(\":65535\") - 1;\n+        sin6 = (struct sockaddr_in6 *) dst->sockaddr;\n+        sin6->sin6_port = htons(port);\n+\n+        break;\n+#endif\n+\n+    default:\n+        return NGX_ERROR;\n+    }\n+\n+    p = ngx_pnalloc(pool, len);\n+    if (p == NULL) {\n+        return NGX_ERROR;\n+    }\n+\n+    len = ngx_sock_ntop(dst->sockaddr, dst->socklen, p, len, 1);\n+\n+    dst->name.len = len;\n+    dst->name.data = p;\n+\n+    return NGX_OK;\n+}\n+\n+\n+/*\n+ * The function is add a peer to upstream check\n+ * module\n+*/\n+ngx_uint_t \n+ngx_http_lua_upstream_add_check_peer(ngx_http_upstream_srv_conf_t *us , \n+                                     ngx_addr_t *peer_addr)\n+{\n+    ngx_http_upstream_check_peer_t          *peer;\n+    ngx_http_upstream_check_peers_t         *peers;\n+    ngx_http_upstream_check_srv_conf_t      *ucscf;\n+    ngx_http_upstream_check_main_conf_t     *ucmcf;\n+\n+    \n+   if (us->srv_conf == NULL) {\n+        return NGX_ERROR;\n+    }\n+\n+    ucscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_check_module);\n+\n+    if(ucscf->check_interval == 0) {\n+        return NGX_ERROR;\n+    }\n+\n+    ucmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,ngx_http_upstream_check_module);\n+    peers = ucmcf->peers;\n+\n+    peer = ngx_array_push(&peers->peers);\n+    if (peer == NULL) {\n+    }\n+\n+    ngx_memzero(peer, sizeof(ngx_http_upstream_check_peer_t));\n+    \n+    peer->index = peers->peers.nelts - 1;\n+    peer->conf = ucscf;\n+    peer->upstream_name = &us->host;\n+    peer->peer_addr = peer_addr;\n+\n+    if (ucscf->port) {\n+        peer->check_peer_addr = ngx_pcalloc(ngx_cycle->pool, sizeof(ngx_addr_t));\n+        if (peer->check_peer_addr == NULL) {\n+            return NGX_ERROR;\n+        }\n+\n+        if (ngx_http_upstream_check_addr_change_port(ngx_cycle->pool,\n+                peer->check_peer_addr, peer_addr, ucscf->port)\n+            != NGX_OK) {\n+\n+            return NGX_ERROR;\n+        }\n+\n+    } else {\n+        peer->check_peer_addr = peer->peer_addr;\n+    }\n+\n+    peers->checksum +=\n+        ngx_murmur_hash2(peer_addr->name.data, peer_addr->name.len);\n+\n+    return peer->index;\n+\n+}\n+\n+\n+/*\n+ * The function is remove a peer to upstream check\n+ * module\n+*/\n+\n+ngx_uint_t \n+ngx_http_lua_upstream_remove_check_peer(ngx_http_upstream_srv_conf_t *us , \n+                                        ngx_url_t u)\n+{\n+    ngx_uint_t                             i;\n+    size_t                                 len;\n+    ngx_array_t                           *servers;\n+    ngx_http_upstream_check_peer_t        *cpeer,*peer;\n+    ngx_http_upstream_check_peers_t       *peers;\n+    ngx_http_upstream_check_srv_conf_t    *ucscf;\n+    ngx_http_upstream_check_main_conf_t   *ucmcf;\n+\n+    \n+   if (us->srv_conf == NULL) {\n+        return 0;\n+    }\n+\n+    ucscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_check_module);\n+\n+    if(ucscf->check_interval == 0) {\n+        return 0;\n+    }\n+\n+    ucmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,ngx_http_upstream_check_module);\n+    peers = ucmcf->peers;\n+\n+\n+    peer = peers->peers.elts;\n+\n+    servers = ngx_array_create(ngx_cycle->pool,peers->peers.nelts,\n+                                               sizeof(ngx_http_upstream_check_peer_t));    \n+    if (NULL == servers) {\n+\n+        return 0;\n+    }\n+    \n+    for (i = 0; i < peers->peers.nelts; i++) {\n+        len = ( peer[i].peer_addr == NULL ? 0 : ngx_strlen(peer[i].peer_addr));\n+\tif ( len == u.url.len\n+             && ngx_memcmp( u.url.data ,peer[i].peer_addr, u.url.len) == 0 ) {\n+             continue;\n+        }\n+\n+        cpeer = ngx_array_push(servers);\n+        ngx_memzero(cpeer,sizeof(ngx_http_upstream_check_peer_t));\n+        cpeer->index = i;\n+        cpeer->conf = ucscf;\n+        cpeer->upstream_name = peer[i].upstream_name;\n+        cpeer->peer_addr = peer[i].peer_addr;\n+       \n+        if (ucscf->port) {\n+           ngx_pfree(ngx_cycle->pool,peer[i].check_peer_addr);\n+           peer[i].check_peer_addr = NULL;\n+                 \n+           ngx_pfree(ngx_cycle->pool,peer[i].check_peer_addr->sockaddr);\n+           peer[i].check_peer_addr->sockaddr = NULL;\n+        }\n+   }\n+ \n+  \n+   ngx_array_destroy(&ucmcf->peers->peers);\n+   ucmcf->peers->peers = *servers;\n+\n+ \n+   return 1;\n+\n+}\n+\n+\n+#endif\n+\n+\n+/*\n+ * The function is add a server to back-end peers \n+ * it's suitable for ip_hash or round_robin,the \n+ * peer's weight ip port ... depends on\n+ * nginx.conf   \n+*/\n+static int\n+ngx_http_lua_upstream_add_peer(lua_State * L)\n+{\n+    ngx_uint_t                            n;\n+    ngx_http_upstream_server_t           *us;\n+    ngx_http_upstream_srv_conf_t         *uscf;\n+    ngx_http_upstream_rr_peer_t           peer; \n+    ngx_http_upstream_rr_peers_t         *peers; \n+    ngx_http_upstream_rr_peers_t         *backup; \n+    ngx_http_request_t                   *r;\n+    ngx_url_t                             u;\n+    size_t                                old_size,new_size;\n+    \n+    if (lua_gettop(L) != 2) {\n+        // two param is :  \"upstream\" \"ip:port\" \n+        // for lua code , you must pass this one param, is none ,you should \n+        // consider pass default value.\n+        lua_pushnil(L);\n+        lua_pushliteral(L, \"exactly two argument expected\\n\");\n+        return 2;\n+    }\n+\n+    r = ngx_http_lua_get_request(L);\n+    if (NULL == r) {\n+        lua_pushnil(L);\n+        lua_pushliteral(L, \"get request error \\n\");\n+        return 2;\n+    }\n+\n+\n+    ngx_memzero(&u, sizeof (ngx_url_t));\n+    u.url.data = (u_char *) luaL_checklstring(L, 2, &u.url.len);\n+    u.default_port = 80;\n+\n+#if (NGX_DEBUG)\n+    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, \"%s %s params: %s\\n\", __FILE__,__FUNCTION__ , u.url.data );\n+#endif\n+\n+    uscf = ngx_http_lua_upstream_check_peers(L,u,&us);\n+    if ( NULL == uscf || NULL == us) {\n+       return 2;\n+    }\n+    \n+    peers = uscf->peer.data;\n+\n+    ngx_memzero(&peer, sizeof (ngx_http_upstream_rr_peer_t));\n+\n+#if (NGX_HTTP_UPSTREAM_CHECH)\n+    if (!us->down) {\n+        peer.check_index = ngx_http_lua_upstream_check_add_peer(uscf, us->addrs);\n+    } else {\n+        peer.check_index = (nxg_uint_t) NGX_ERROR;\n+    }\n+#endif\n+\n+    if ( !us->backup ) {\n+        if ( 1 == ngx_http_lua_upstream_exist_peer(peers,u) ) {\n+            lua_pushnil(L);\n+            lua_pushliteral(L, \"the peer is exist\\n\");\n+            return 2;\n+        }\n+\n+        n = peers->number -1 ;\n+        n += peers->next != NULL ? peers->next->number : 0;\n+        old_size = n*sizeof(ngx_http_upstream_rr_peer_t) \n+\t\t\t+ sizeof(ngx_http_upstream_rr_peers_t)*(peers->next != NULL ? 2:1);\n+        new_size = sizeof(ngx_http_upstream_rr_peer_t) + old_size;\n+    \n+        peers  = ngx_prealloc(ngx_cycle->pool, uscf->peer.data, old_size, new_size );\n+        if (NULL == peers ) {\n+            lua_pushnil(L);\n+            lua_pushliteral(L, \"peers pcalloc fail\\n\");\n+            return 2;\n+        }\n+\n+\n+        peer.weight = us->weight; \n+        peer.effective_weight = us->weight;\n+        peer.current_weight= 0;\n+        peer.max_fails = us->max_fails;\n+        peer.fail_timeout = us->fail_timeout;\n+        peer.sockaddr = us->addrs->sockaddr;\n+        peer.socklen = us->addrs->socklen;\n+        peer.name = us->addrs->name;\n+        peer.down = us->down;\n+        peer.fails = 0;\n+\n+        peer.server = us->name;\n+\n+        peers->peer[peers->number++] = peer;\n+        peers->total_weight += peer.weight;\n+        peers->single = (peers->number == 1);\n+        peers->weighted = (peers->total_weight != peers->number);\n+\n+        uscf->peer.data = peers;\n+    } else {\n+\n+        backup = peers->next;\n+        if ( 1 == ngx_http_lua_upstream_exist_peer(backup,u) ) {\n+            lua_pushnil(L);\n+            lua_pushliteral(L, \"the backup peer is exist\\n\");\n+            return 2;\n+        }\n+\n+        n = backup != NULL ? (backup->number - 1) : 0 ;\n+\n+        old_size = n*sizeof(ngx_http_upstream_rr_peer_t) \n+\t\t\t       + sizeof(ngx_http_upstream_rr_peers_t);\n+        new_size = sizeof(ngx_http_upstream_rr_peer_t) + old_size;\n+    \n+        backup  = ngx_prealloc(ngx_cycle->pool, peers->next, old_size, new_size );\n+        if (NULL == backup ) {\n+            lua_pushnil(L);\n+            lua_pushliteral(L, \"backup pcalloc fail\\n\");\n+            return 2;\n+        }\n+\n+        peers->single = 0;\n+        backup->single = 0;\n+        if ( n == 0 ) {\n+           backup->number = 0;\n+           backup->total_weight = 0;\n+        }\n+        peer.weight = us->weight; \n+        peer.effective_weight = us->weight;\n+        peer.current_weight= 0;\n+        peer.max_fails = us->max_fails;\n+        peer.fail_timeout = us->fail_timeout;\n+        peer.server = us->name;\n+\n+        peer.sockaddr = us->addrs->sockaddr;\n+        peer.socklen = us->addrs->socklen;\n+        peer.name = us->addrs->name;\n+        peer.down = us->down;\n+        peer.fails = 0;\n+   \n+\n+        backup->peer[backup->number++] = peer;\n+        backup->total_weight += peer.weight;\n+        backup->single = (backup->number == 1);\n+        backup->weighted = (backup->total_weight != backup->number);\n+\n+        peers->next = backup;\n+}","path":"src/ngx_http_lua_upstream_module.c","position":819,"original_position":819,"commit_id":"d9197a12e7e1f2a6538145367bdfeecd415bf6e3","original_commit_id":"d9197a12e7e1f2a6538145367bdfeecd415bf6e3","user":{"login":"agentzh","id":56241,"avatar_url":"https://avatars.githubusercontent.com/u/56241?v=3","gravatar_id":"","url":"https://api.github.com/users/agentzh","html_url":"https://github.com/agentzh","followers_url":"https://api.github.com/users/agentzh/followers","following_url":"https://api.github.com/users/agentzh/following{/other_user}","gists_url":"https://api.github.com/users/agentzh/gists{/gist_id}","starred_url":"https://api.github.com/users/agentzh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/agentzh/subscriptions","organizations_url":"https://api.github.com/users/agentzh/orgs","repos_url":"https://api.github.com/users/agentzh/repos","events_url":"https://api.github.com/users/agentzh/events{/privacy}","received_events_url":"https://api.github.com/users/agentzh/received_events","type":"User","site_admin":false},"body":"Style: indentation.","created_at":"2015-08-11T04:19:36Z","updated_at":"2015-08-11T04:19:36Z","html_url":"https://github.com/openresty/lua-upstream-nginx-module/pull/13#discussion_r36710616","pull_request_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/pulls/13","_links":{"self":{"href":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/pulls/comments/36710616"},"html":{"href":"https://github.com/openresty/lua-upstream-nginx-module/pull/13#discussion_r36710616"},"pull_request":{"href":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/pulls/13"}}},"pull_request":{"url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/pulls/13","id":42014528,"html_url":"https://github.com/openresty/lua-upstream-nginx-module/pull/13","diff_url":"https://github.com/openresty/lua-upstream-nginx-module/pull/13.diff","patch_url":"https://github.com/openresty/lua-upstream-nginx-module/pull/13.patch","issue_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/issues/13","number":13,"state":"open","locked":false,"title":"Add some functions: add_server(),add_peer(),remove_server(),remove_peer() and it's support round_robin or ip_hash.","user":{"login":"wangfakang","id":8215757,"avatar_url":"https://avatars.githubusercontent.com/u/8215757?v=3","gravatar_id":"","url":"https://api.github.com/users/wangfakang","html_url":"https://github.com/wangfakang","followers_url":"https://api.github.com/users/wangfakang/followers","following_url":"https://api.github.com/users/wangfakang/following{/other_user}","gists_url":"https://api.github.com/users/wangfakang/gists{/gist_id}","starred_url":"https://api.github.com/users/wangfakang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wangfakang/subscriptions","organizations_url":"https://api.github.com/users/wangfakang/orgs","repos_url":"https://api.github.com/users/wangfakang/repos","events_url":"https://api.github.com/users/wangfakang/events{/privacy}","received_events_url":"https://api.github.com/users/wangfakang/received_events","type":"User","site_admin":false},"body":"Hi, agentzh : \r\nI did the following there points Pls review the code, and thx.\r\nFirst: Add functions: add_server(), add_peer(), remove_server() and remove_peer() and they support load balance algorithm: ip_hash or round_robin. \r\nSecond: In order to support UPSTREAM_CHECK_MODULE, I add  the ngx_http_lua_upstream_module.h head file. In this file, there are save some structs/variables which are used in health check module.  \r\nThird: Update README.md and add some test for add_server() / add_peer() / remove_server() /  remove_peer().","created_at":"2015-08-10T12:28:06Z","updated_at":"2015-08-11T04:19:36Z","closed_at":null,"merged_at":null,"merge_commit_sha":"60d2898fca03cd304410b29c1e57eec795226c09","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/pulls/13/commits","review_comments_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/pulls/13/comments","review_comment_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/pulls/comments{/number}","comments_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/issues/13/comments","statuses_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/statuses/d9197a12e7e1f2a6538145367bdfeecd415bf6e3","head":{"label":"SinaMSRE:master","ref":"master","sha":"d9197a12e7e1f2a6538145367bdfeecd415bf6e3","user":{"login":"SinaMSRE","id":10557169,"avatar_url":"https://avatars.githubusercontent.com/u/10557169?v=3","gravatar_id":"","url":"https://api.github.com/users/SinaMSRE","html_url":"https://github.com/SinaMSRE","followers_url":"https://api.github.com/users/SinaMSRE/followers","following_url":"https://api.github.com/users/SinaMSRE/following{/other_user}","gists_url":"https://api.github.com/users/SinaMSRE/gists{/gist_id}","starred_url":"https://api.github.com/users/SinaMSRE/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SinaMSRE/subscriptions","organizations_url":"https://api.github.com/users/SinaMSRE/orgs","repos_url":"https://api.github.com/users/SinaMSRE/repos","events_url":"https://api.github.com/users/SinaMSRE/events{/privacy}","received_events_url":"https://api.github.com/users/SinaMSRE/received_events","type":"Organization","site_admin":false},"repo":{"id":31710541,"name":"lua-upstream-nginx-module","full_name":"SinaMSRE/lua-upstream-nginx-module","owner":{"login":"SinaMSRE","id":10557169,"avatar_url":"https://avatars.githubusercontent.com/u/10557169?v=3","gravatar_id":"","url":"https://api.github.com/users/SinaMSRE","html_url":"https://github.com/SinaMSRE","followers_url":"https://api.github.com/users/SinaMSRE/followers","following_url":"https://api.github.com/users/SinaMSRE/following{/other_user}","gists_url":"https://api.github.com/users/SinaMSRE/gists{/gist_id}","starred_url":"https://api.github.com/users/SinaMSRE/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SinaMSRE/subscriptions","organizations_url":"https://api.github.com/users/SinaMSRE/orgs","repos_url":"https://api.github.com/users/SinaMSRE/repos","events_url":"https://api.github.com/users/SinaMSRE/events{/privacy}","received_events_url":"https://api.github.com/users/SinaMSRE/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/SinaMSRE/lua-upstream-nginx-module","description":"Nginx C module to expose Lua API to ngx_lua for Nginx upstreams","fork":true,"url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module","forks_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/forks","keys_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/keys{/key_id}","collaborators_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/teams","hooks_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/hooks","issue_events_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/issues/events{/number}","events_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/events","assignees_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/assignees{/user}","branches_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/branches{/branch}","tags_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/tags","blobs_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/git/refs{/sha}","trees_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/git/trees{/sha}","statuses_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/statuses/{sha}","languages_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/languages","stargazers_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/stargazers","contributors_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/contributors","subscribers_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/subscribers","subscription_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/subscription","commits_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/commits{/sha}","git_commits_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/git/commits{/sha}","comments_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/comments{/number}","issue_comment_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/issues/comments{/number}","contents_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/contents/{+path}","compare_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/compare/{base}...{head}","merges_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/merges","archive_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/downloads","issues_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/issues{/number}","pulls_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/pulls{/number}","milestones_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/milestones{/number}","notifications_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/labels{/name}","releases_url":"https://api.github.com/repos/SinaMSRE/lua-upstream-nginx-module/releases{/id}","created_at":"2015-03-05T11:20:41Z","updated_at":"2015-07-26T12:43:00Z","pushed_at":"2015-08-10T09:52:37Z","git_url":"git://github.com/SinaMSRE/lua-upstream-nginx-module.git","ssh_url":"git@github.com:SinaMSRE/lua-upstream-nginx-module.git","clone_url":"https://github.com/SinaMSRE/lua-upstream-nginx-module.git","svn_url":"https://github.com/SinaMSRE/lua-upstream-nginx-module","homepage":null,"size":138,"stargazers_count":2,"watchers_count":2,"language":"C","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":0,"forks":2,"open_issues":0,"watchers":2,"default_branch":"master"}},"base":{"label":"openresty:master","ref":"master","sha":"db32ca8f829b009b71e0e113f0771e18d424bb23","user":{"login":"openresty","id":7390180,"avatar_url":"https://avatars.githubusercontent.com/u/7390180?v=3","gravatar_id":"","url":"https://api.github.com/users/openresty","html_url":"https://github.com/openresty","followers_url":"https://api.github.com/users/openresty/followers","following_url":"https://api.github.com/users/openresty/following{/other_user}","gists_url":"https://api.github.com/users/openresty/gists{/gist_id}","starred_url":"https://api.github.com/users/openresty/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openresty/subscriptions","organizations_url":"https://api.github.com/users/openresty/orgs","repos_url":"https://api.github.com/users/openresty/repos","events_url":"https://api.github.com/users/openresty/events{/privacy}","received_events_url":"https://api.github.com/users/openresty/received_events","type":"Organization","site_admin":false},"repo":{"id":15853845,"name":"lua-upstream-nginx-module","full_name":"openresty/lua-upstream-nginx-module","owner":{"login":"openresty","id":7390180,"avatar_url":"https://avatars.githubusercontent.com/u/7390180?v=3","gravatar_id":"","url":"https://api.github.com/users/openresty","html_url":"https://github.com/openresty","followers_url":"https://api.github.com/users/openresty/followers","following_url":"https://api.github.com/users/openresty/following{/other_user}","gists_url":"https://api.github.com/users/openresty/gists{/gist_id}","starred_url":"https://api.github.com/users/openresty/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openresty/subscriptions","organizations_url":"https://api.github.com/users/openresty/orgs","repos_url":"https://api.github.com/users/openresty/repos","events_url":"https://api.github.com/users/openresty/events{/privacy}","received_events_url":"https://api.github.com/users/openresty/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/openresty/lua-upstream-nginx-module","description":"Nginx C module to expose Lua API to ngx_lua for Nginx upstreams","fork":false,"url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module","forks_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/forks","keys_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/keys{/key_id}","collaborators_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/teams","hooks_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/hooks","issue_events_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/issues/events{/number}","events_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/events","assignees_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/assignees{/user}","branches_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/branches{/branch}","tags_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/tags","blobs_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/git/refs{/sha}","trees_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/git/trees{/sha}","statuses_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/statuses/{sha}","languages_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/languages","stargazers_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/stargazers","contributors_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/contributors","subscribers_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/subscribers","subscription_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/subscription","commits_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/commits{/sha}","git_commits_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/git/commits{/sha}","comments_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/comments{/number}","issue_comment_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/issues/comments{/number}","contents_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/contents/{+path}","compare_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/compare/{base}...{head}","merges_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/merges","archive_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/downloads","issues_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/issues{/number}","pulls_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/pulls{/number}","milestones_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/milestones{/number}","notifications_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/labels{/name}","releases_url":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/releases{/id}","created_at":"2014-01-13T00:14:19Z","updated_at":"2015-08-06T19:01:54Z","pushed_at":"2015-08-10T12:28:07Z","git_url":"git://github.com/openresty/lua-upstream-nginx-module.git","ssh_url":"git@github.com:openresty/lua-upstream-nginx-module.git","clone_url":"https://github.com/openresty/lua-upstream-nginx-module.git","svn_url":"https://github.com/openresty/lua-upstream-nginx-module","homepage":null,"size":474,"stargazers_count":91,"watchers_count":91,"language":"Perl","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":32,"mirror_url":null,"open_issues_count":7,"forks":32,"open_issues":7,"watchers":91,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/pulls/13"},"html":{"href":"https://github.com/openresty/lua-upstream-nginx-module/pull/13"},"issue":{"href":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/issues/13"},"comments":{"href":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/issues/13/comments"},"review_comments":{"href":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/pulls/13/comments"},"review_comment":{"href":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/pulls/13/commits"},"statuses":{"href":"https://api.github.com/repos/openresty/lua-upstream-nginx-module/statuses/d9197a12e7e1f2a6538145367bdfeecd415bf6e3"}}}}