LCOV - code coverage report
Current view: top level - home/build/openresty-1.13.6.1/build/ngx_lua-0.10.11/src - ngx_http_lua_socket_tcp.c (source / functions) Hit Total Coverage
Test: coverage ngix Lines: 477 2252 21.2 %
Date: 2020-03-03 04:25:50 Functions: 24 75 32.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : 
       2             : /*
       3             :  * Copyright (C) Yichun Zhang (agentzh)
       4             :  */
       5             : 
       6             : 
       7             : #ifndef DDEBUG
       8             : #define DDEBUG 0
       9             : #endif
      10             : #include "ddebug.h"
      11             : 
      12             : 
      13             : #include "ngx_http_lua_socket_tcp.h"
      14             : #include "ngx_http_lua_util.h"
      15             : #include "ngx_http_lua_uthread.h"
      16             : #include "ngx_http_lua_output.h"
      17             : #include "ngx_http_lua_contentby.h"
      18             : #include "ngx_http_lua_probe.h"
      19             : 
      20             : 
      21             : static int ngx_http_lua_socket_tcp(lua_State *L);
      22             : static int ngx_http_lua_socket_tcp_connect(lua_State *L);
      23             : #if (NGX_HTTP_SSL)
      24             : static int ngx_http_lua_socket_tcp_sslhandshake(lua_State *L);
      25             : #endif
      26             : static int ngx_http_lua_socket_tcp_receive(lua_State *L);
      27             : static int ngx_http_lua_socket_tcp_send(lua_State *L);
      28             : static int ngx_http_lua_socket_tcp_close(lua_State *L);
      29             : static int ngx_http_lua_socket_tcp_setoption(lua_State *L);
      30             : static int ngx_http_lua_socket_tcp_settimeout(lua_State *L);
      31             : static int ngx_http_lua_socket_tcp_settimeouts(lua_State *L);
      32             : static void ngx_http_lua_socket_tcp_handler(ngx_event_t *ev);
      33             : static ngx_int_t ngx_http_lua_socket_tcp_get_peer(ngx_peer_connection_t *pc,
      34             :     void *data);
      35             : static void ngx_http_lua_socket_read_handler(ngx_http_request_t *r,
      36             :     ngx_http_lua_socket_tcp_upstream_t *u);
      37             : static void ngx_http_lua_socket_send_handler(ngx_http_request_t *r,
      38             :     ngx_http_lua_socket_tcp_upstream_t *u);
      39             : static void ngx_http_lua_socket_connected_handler(ngx_http_request_t *r,
      40             :     ngx_http_lua_socket_tcp_upstream_t *u);
      41             : static void ngx_http_lua_socket_tcp_cleanup(void *data);
      42             : static void ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r,
      43             :     ngx_http_lua_socket_tcp_upstream_t *u);
      44             : static void ngx_http_lua_socket_tcp_finalize_read_part(ngx_http_request_t *r,
      45             :     ngx_http_lua_socket_tcp_upstream_t *u);
      46             : static void ngx_http_lua_socket_tcp_finalize_write_part(ngx_http_request_t *r,
      47             :     ngx_http_lua_socket_tcp_upstream_t *u);
      48             : static ngx_int_t ngx_http_lua_socket_send(ngx_http_request_t *r,
      49             :     ngx_http_lua_socket_tcp_upstream_t *u);
      50             : static ngx_int_t ngx_http_lua_socket_test_connect(ngx_http_request_t *r,
      51             :     ngx_connection_t *c);
      52             : static void ngx_http_lua_socket_handle_conn_error(ngx_http_request_t *r,
      53             :     ngx_http_lua_socket_tcp_upstream_t *u, ngx_uint_t ft_type);
      54             : static void ngx_http_lua_socket_handle_read_error(ngx_http_request_t *r,
      55             :     ngx_http_lua_socket_tcp_upstream_t *u, ngx_uint_t ft_type);
      56             : static void ngx_http_lua_socket_handle_write_error(ngx_http_request_t *r,
      57             :     ngx_http_lua_socket_tcp_upstream_t *u, ngx_uint_t ft_type);
      58             : static void ngx_http_lua_socket_handle_conn_success(ngx_http_request_t *r,
      59             :     ngx_http_lua_socket_tcp_upstream_t *u);
      60             : static void ngx_http_lua_socket_handle_read_success(ngx_http_request_t *r,
      61             :     ngx_http_lua_socket_tcp_upstream_t *u);
      62             : static void ngx_http_lua_socket_handle_write_success(ngx_http_request_t *r,
      63             :     ngx_http_lua_socket_tcp_upstream_t *u);
      64             : static int ngx_http_lua_socket_tcp_send_retval_handler(ngx_http_request_t *r,
      65             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L);
      66             : static int ngx_http_lua_socket_tcp_conn_retval_handler(ngx_http_request_t *r,
      67             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L);
      68             : static void ngx_http_lua_socket_dummy_handler(ngx_http_request_t *r,
      69             :     ngx_http_lua_socket_tcp_upstream_t *u);
      70             : static ngx_int_t ngx_http_lua_socket_tcp_read(ngx_http_request_t *r,
      71             :     ngx_http_lua_socket_tcp_upstream_t *u);
      72             : static int ngx_http_lua_socket_tcp_receive_retval_handler(ngx_http_request_t *r,
      73             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L);
      74             : static ngx_int_t ngx_http_lua_socket_read_line(void *data, ssize_t bytes);
      75             : static void ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx);
      76             : static int ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r,
      77             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L);
      78             : static int ngx_http_lua_socket_conn_error_retval_handler(ngx_http_request_t *r,
      79             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L);
      80             : static int ngx_http_lua_socket_read_error_retval_handler(ngx_http_request_t *r,
      81             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L);
      82             : static int ngx_http_lua_socket_write_error_retval_handler(ngx_http_request_t *r,
      83             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L);
      84             : static ngx_int_t ngx_http_lua_socket_read_all(void *data, ssize_t bytes);
      85             : static ngx_int_t ngx_http_lua_socket_read_until(void *data, ssize_t bytes);
      86             : static ngx_int_t ngx_http_lua_socket_read_chunk(void *data, ssize_t bytes);
      87             : static int ngx_http_lua_socket_tcp_receiveuntil(lua_State *L);
      88             : static int ngx_http_lua_socket_receiveuntil_iterator(lua_State *L);
      89             : static ngx_int_t ngx_http_lua_socket_compile_pattern(u_char *data, size_t len,
      90             :     ngx_http_lua_socket_compiled_pattern_t *cp, ngx_log_t *log);
      91             : static int ngx_http_lua_socket_cleanup_compiled_pattern(lua_State *L);
      92             : static int ngx_http_lua_req_socket(lua_State *L);
      93             : static void ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r);
      94             : static int ngx_http_lua_socket_tcp_getreusedtimes(lua_State *L);
      95             : static int ngx_http_lua_socket_tcp_setkeepalive(lua_State *L);
      96             : static ngx_int_t ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r,
      97             :     lua_State *L, int key_index,
      98             :     ngx_http_lua_socket_tcp_upstream_t *u);
      99             : static void ngx_http_lua_socket_keepalive_dummy_handler(ngx_event_t *ev);
     100             : static ngx_int_t ngx_http_lua_socket_keepalive_close_handler(ngx_event_t *ev);
     101             : static void ngx_http_lua_socket_keepalive_rev_handler(ngx_event_t *ev);
     102             : static void ngx_http_lua_socket_free_pool(ngx_log_t *log,
     103             :     ngx_http_lua_socket_pool_t *spool);
     104             : static int ngx_http_lua_socket_tcp_upstream_destroy(lua_State *L);
     105             : static int ngx_http_lua_socket_downstream_destroy(lua_State *L);
     106             : static ngx_int_t ngx_http_lua_socket_push_input_data(ngx_http_request_t *r,
     107             :     ngx_http_lua_ctx_t *ctx, ngx_http_lua_socket_tcp_upstream_t *u,
     108             :     lua_State *L);
     109             : static ngx_int_t ngx_http_lua_socket_add_pending_data(ngx_http_request_t *r,
     110             :     ngx_http_lua_socket_tcp_upstream_t *u, u_char *pos, size_t len, u_char *pat,
     111             :     int prefix, int old_state);
     112             : static ngx_int_t ngx_http_lua_socket_add_input_buffer(ngx_http_request_t *r,
     113             :     ngx_http_lua_socket_tcp_upstream_t *u);
     114             : static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r,
     115             :     ngx_http_lua_socket_tcp_upstream_t *u, u_char *pat, size_t prefix);
     116             : static ngx_int_t ngx_http_lua_socket_tcp_conn_resume(ngx_http_request_t *r);
     117             : static ngx_int_t ngx_http_lua_socket_tcp_read_resume(ngx_http_request_t *r);
     118             : static ngx_int_t ngx_http_lua_socket_tcp_write_resume(ngx_http_request_t *r);
     119             : static ngx_int_t ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r,
     120             :     int socket_op);
     121             : static void ngx_http_lua_tcp_resolve_cleanup(void *data);
     122             : static void ngx_http_lua_coctx_cleanup(void *data);
     123             : static int ngx_http_lua_socket_shutdown_pool(lua_State *L);
     124             : static void
     125             :     ngx_http_lua_socket_empty_resolve_handler(ngx_resolver_ctx_t *ctx);
     126             : static int ngx_http_lua_socket_prepare_error_retvals(ngx_http_request_t *r,
     127             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L, ngx_uint_t ft_type);
     128             : #if (NGX_HTTP_SSL)
     129             : static int ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r,
     130             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L);
     131             : static void ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c);
     132             : static int ngx_http_lua_ssl_free_session(lua_State *L);
     133             : #endif
     134             : static void ngx_http_lua_socket_tcp_close_connection(ngx_connection_t *c);
     135             : 
     136             : 
     137             : enum {
     138             :     SOCKET_CTX_INDEX = 1,
     139             :     SOCKET_KEY_INDEX = 3,
     140             :     SOCKET_CONNECT_TIMEOUT_INDEX = 2,
     141             :     SOCKET_SEND_TIMEOUT_INDEX = 4,
     142             :     SOCKET_READ_TIMEOUT_INDEX = 5,
     143             : };
     144             : 
     145             : 
     146             : enum {
     147             :     SOCKET_OP_CONNECT,
     148             :     SOCKET_OP_READ,
     149             :     SOCKET_OP_WRITE
     150             : };
     151             : 
     152             : 
     153             : #define ngx_http_lua_socket_check_busy_connecting(r, u, L)                   \
     154             :     if ((u)->conn_waiting) {                                                 \
     155             :         lua_pushnil(L);                                                      \
     156             :         lua_pushliteral(L, "socket busy connecting");                        \
     157             :         return 2;                                                            \
     158             :     }
     159             : 
     160             : 
     161             : #define ngx_http_lua_socket_check_busy_reading(r, u, L)                      \
     162             :     if ((u)->read_waiting) {                                                 \
     163             :         lua_pushnil(L);                                                      \
     164             :         lua_pushliteral(L, "socket busy reading");                           \
     165             :         return 2;                                                            \
     166             :     }
     167             : 
     168             : 
     169             : #define ngx_http_lua_socket_check_busy_writing(r, u, L)                      \
     170             :     if ((u)->write_waiting) {                                                \
     171             :         lua_pushnil(L);                                                      \
     172             :         lua_pushliteral(L, "socket busy writing");                           \
     173             :         return 2;                                                            \
     174             :     }                                                                        \
     175             :     if ((u)->raw_downstream                                                  \
     176             :         && ((r)->connection->buffered & NGX_HTTP_LOWLEVEL_BUFFERED))         \
     177             :     {                                                                        \
     178             :         lua_pushnil(L);                                                      \
     179             :         lua_pushliteral(L, "socket busy writing");                           \
     180             :         return 2;                                                            \
     181             :     }
     182             : 
     183             : 
     184             : static char ngx_http_lua_req_socket_metatable_key;
     185             : static char ngx_http_lua_raw_req_socket_metatable_key;
     186             : static char ngx_http_lua_tcp_socket_metatable_key;
     187             : static char ngx_http_lua_upstream_udata_metatable_key;
     188             : static char ngx_http_lua_downstream_udata_metatable_key;
     189             : static char ngx_http_lua_pool_udata_metatable_key;
     190             : static char ngx_http_lua_pattern_udata_metatable_key;
     191             : #if (NGX_HTTP_SSL)
     192             : static char ngx_http_lua_ssl_session_metatable_key;
     193             : #endif
     194             : 
     195             : 
     196             : void
     197          18 : ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L)
     198             : {
     199             :     ngx_int_t         rc;
     200             : 
     201          18 :     lua_createtable(L, 0, 4 /* nrec */);    /* ngx.socket */
     202             : 
     203          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp);
     204          18 :     lua_pushvalue(L, -1);
     205          18 :     lua_setfield(L, -3, "tcp");
     206          18 :     lua_setfield(L, -2, "stream");
     207             : 
     208             :     {
     209          18 :         const char  buf[] = "local sock = ngx.socket.tcp()"
     210             :                             " local ok, err = sock:connect(...)"
     211             :                             " if ok then return sock else return nil, err end";
     212             : 
     213          18 :         rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "=ngx.socket.connect");
     214             :     }
     215             : 
     216          18 :     if (rc != NGX_OK) {
     217           0 :         ngx_log_error(NGX_LOG_CRIT, log, 0,
     218             :                       "failed to load Lua code for ngx.socket.connect(): %i",
     219             :                       rc);
     220             : 
     221             :     } else {
     222          18 :         lua_setfield(L, -2, "connect");
     223             :     }
     224             : 
     225          18 :     lua_setfield(L, -2, "socket");
     226             : 
     227             :     /* {{{req socket object metatable */
     228          18 :     lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key);
     229          18 :     lua_createtable(L, 0 /* narr */, 5 /* nrec */);
     230             : 
     231          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive);
     232          18 :     lua_setfield(L, -2, "receive");
     233             : 
     234          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveuntil);
     235          18 :     lua_setfield(L, -2, "receiveuntil");
     236             : 
     237          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_settimeout);
     238          18 :     lua_setfield(L, -2, "settimeout"); /* ngx socket mt */
     239             : 
     240          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_settimeouts);
     241          18 :     lua_setfield(L, -2, "settimeouts"); /* ngx socket mt */
     242             : 
     243          18 :     lua_pushvalue(L, -1);
     244          18 :     lua_setfield(L, -2, "__index");
     245             : 
     246          18 :     lua_rawset(L, LUA_REGISTRYINDEX);
     247             :     /* }}} */
     248             : 
     249             :     /* {{{raw req socket object metatable */
     250          18 :     lua_pushlightuserdata(L, &ngx_http_lua_raw_req_socket_metatable_key);
     251          18 :     lua_createtable(L, 0 /* narr */, 6 /* nrec */);
     252             : 
     253          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive);
     254          18 :     lua_setfield(L, -2, "receive");
     255             : 
     256          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveuntil);
     257          18 :     lua_setfield(L, -2, "receiveuntil");
     258             : 
     259          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_send);
     260          18 :     lua_setfield(L, -2, "send");
     261             : 
     262          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_settimeout);
     263          18 :     lua_setfield(L, -2, "settimeout"); /* ngx socket mt */
     264             : 
     265          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_settimeouts);
     266          18 :     lua_setfield(L, -2, "settimeouts"); /* ngx socket mt */
     267             : 
     268          18 :     lua_pushvalue(L, -1);
     269          18 :     lua_setfield(L, -2, "__index");
     270             : 
     271          18 :     lua_rawset(L, LUA_REGISTRYINDEX);
     272             :     /* }}} */
     273             : 
     274             :     /* {{{tcp object metatable */
     275          18 :     lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key);
     276          18 :     lua_createtable(L, 0 /* narr */, 12 /* nrec */);
     277             : 
     278          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_connect);
     279          18 :     lua_setfield(L, -2, "connect");
     280             : 
     281             : #if (NGX_HTTP_SSL)
     282             : 
     283          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_sslhandshake);
     284          18 :     lua_setfield(L, -2, "sslhandshake");
     285             : 
     286             : #endif
     287             : 
     288          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive);
     289          18 :     lua_setfield(L, -2, "receive");
     290             : 
     291          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveuntil);
     292          18 :     lua_setfield(L, -2, "receiveuntil");
     293             : 
     294          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_send);
     295          18 :     lua_setfield(L, -2, "send");
     296             : 
     297          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_close);
     298          18 :     lua_setfield(L, -2, "close");
     299             : 
     300          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_setoption);
     301          18 :     lua_setfield(L, -2, "setoption");
     302             : 
     303          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_settimeout);
     304          18 :     lua_setfield(L, -2, "settimeout"); /* ngx socket mt */
     305             : 
     306          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_settimeouts);
     307          18 :     lua_setfield(L, -2, "settimeouts"); /* ngx socket mt */
     308             : 
     309          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_getreusedtimes);
     310          18 :     lua_setfield(L, -2, "getreusedtimes");
     311             : 
     312          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_setkeepalive);
     313          18 :     lua_setfield(L, -2, "setkeepalive");
     314             : 
     315          18 :     lua_pushvalue(L, -1);
     316          18 :     lua_setfield(L, -2, "__index");
     317          18 :     lua_rawset(L, LUA_REGISTRYINDEX);
     318             :     /* }}} */
     319             : 
     320             :     /* {{{upstream userdata metatable */
     321          18 :     lua_pushlightuserdata(L, &ngx_http_lua_upstream_udata_metatable_key);
     322          18 :     lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */
     323          18 :     lua_pushcfunction(L, ngx_http_lua_socket_tcp_upstream_destroy);
     324          18 :     lua_setfield(L, -2, "__gc");
     325          18 :     lua_rawset(L, LUA_REGISTRYINDEX);
     326             :     /* }}} */
     327             : 
     328             :     /* {{{downstream userdata metatable */
     329          18 :     lua_pushlightuserdata(L, &ngx_http_lua_downstream_udata_metatable_key);
     330          18 :     lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */
     331          18 :     lua_pushcfunction(L, ngx_http_lua_socket_downstream_destroy);
     332          18 :     lua_setfield(L, -2, "__gc");
     333          18 :     lua_rawset(L, LUA_REGISTRYINDEX);
     334             :     /* }}} */
     335             : 
     336             :     /* {{{socket pool userdata metatable */
     337          18 :     lua_pushlightuserdata(L, &ngx_http_lua_pool_udata_metatable_key);
     338          18 :     lua_createtable(L, 0, 1); /* metatable */
     339          18 :     lua_pushcfunction(L, ngx_http_lua_socket_shutdown_pool);
     340          18 :     lua_setfield(L, -2, "__gc");
     341          18 :     lua_rawset(L, LUA_REGISTRYINDEX);
     342             :     /* }}} */
     343             : 
     344             :     /* {{{socket compiled pattern userdata metatable */
     345          18 :     lua_pushlightuserdata(L, &ngx_http_lua_pattern_udata_metatable_key);
     346          18 :     lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */
     347          18 :     lua_pushcfunction(L, ngx_http_lua_socket_cleanup_compiled_pattern);
     348          18 :     lua_setfield(L, -2, "__gc");
     349          18 :     lua_rawset(L, LUA_REGISTRYINDEX);
     350             :     /* }}} */
     351             : 
     352             : #if (NGX_HTTP_SSL)
     353             : 
     354             :     /* {{{ssl session userdata metatable */
     355          18 :     lua_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key);
     356          18 :     lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */
     357          18 :     lua_pushcfunction(L, ngx_http_lua_ssl_free_session);
     358          18 :     lua_setfield(L, -2, "__gc");
     359          18 :     lua_rawset(L, LUA_REGISTRYINDEX);
     360             :     /* }}} */
     361             : 
     362             : #endif
     363          18 : }
     364             : 
     365             : 
     366             : void
     367          18 : ngx_http_lua_inject_req_socket_api(lua_State *L)
     368             : {
     369          18 :     lua_pushcfunction(L, ngx_http_lua_req_socket);
     370          18 :     lua_setfield(L, -2, "socket");
     371          18 : }
     372             : 
     373             : 
     374             : static int
     375           1 : ngx_http_lua_socket_tcp(lua_State *L)
     376             : {
     377             :     ngx_http_request_t      *r;
     378             :     ngx_http_lua_ctx_t      *ctx;
     379             : 
     380           1 :     if (lua_gettop(L) != 0) {
     381           0 :         return luaL_error(L, "expecting zero arguments, but got %d",
     382             :                           lua_gettop(L));
     383             :     }
     384             : 
     385           1 :     r = ngx_http_lua_get_req(L);
     386           1 :     if (r == NULL) {
     387           0 :         return luaL_error(L, "no request found");
     388             :     }
     389             : 
     390           1 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
     391           1 :     if (ctx == NULL) {
     392           0 :         return luaL_error(L, "no ctx found");
     393             :     }
     394             : 
     395           1 :     ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
     396             :                                | NGX_HTTP_LUA_CONTEXT_ACCESS
     397             :                                | NGX_HTTP_LUA_CONTEXT_CONTENT
     398             :                                | NGX_HTTP_LUA_CONTEXT_TIMER
     399             :                                | NGX_HTTP_LUA_CONTEXT_SSL_CERT
     400             :                                | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH);
     401             : 
     402           1 :     lua_createtable(L, 5 /* narr */, 1 /* nrec */);
     403           1 :     lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key);
     404           1 :     lua_rawget(L, LUA_REGISTRYINDEX);
     405           1 :     lua_setmetatable(L, -2);
     406             : 
     407             :     dd("top: %d", lua_gettop(L));
     408             : 
     409           1 :     return 1;
     410             : }
     411             : 
     412             : 
     413             : static int
     414           1 : ngx_http_lua_socket_tcp_connect(lua_State *L)
     415             : {
     416             :     ngx_http_request_t          *r;
     417             :     ngx_http_lua_ctx_t          *ctx;
     418             :     ngx_str_t                    host;
     419             :     int                          port;
     420             :     ngx_resolver_ctx_t          *rctx, temp;
     421             :     ngx_http_core_loc_conf_t    *clcf;
     422             :     int                          saved_top;
     423             :     int                          n;
     424             :     u_char                      *p;
     425             :     size_t                       len;
     426             :     ngx_url_t                    url;
     427             :     ngx_int_t                    rc;
     428             :     ngx_http_lua_loc_conf_t     *llcf;
     429             :     ngx_peer_connection_t       *pc;
     430             :     int                          connect_timeout, send_timeout, read_timeout;
     431             :     unsigned                     custom_pool;
     432             :     int                          key_index;
     433             :     const char                  *msg;
     434             :     ngx_http_lua_co_ctx_t       *coctx;
     435             : 
     436             :     ngx_http_lua_socket_tcp_upstream_t      *u;
     437             : 
     438           1 :     n = lua_gettop(L);
     439           1 :     if (n != 2 && n != 3 && n != 4) {
     440           0 :         return luaL_error(L, "ngx.socket connect: expecting 2, 3, or 4 "
     441             :                           "arguments (including the object), but seen %d", n);
     442             :     }
     443             : 
     444           1 :     r = ngx_http_lua_get_req(L);
     445           1 :     if (r == NULL) {
     446           0 :         return luaL_error(L, "no request found");
     447             :     }
     448             : 
     449           1 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
     450           1 :     if (ctx == NULL) {
     451           0 :         return luaL_error(L, "no ctx found");
     452             :     }
     453             : 
     454           1 :     ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
     455             :                                | NGX_HTTP_LUA_CONTEXT_ACCESS
     456             :                                | NGX_HTTP_LUA_CONTEXT_CONTENT
     457             :                                | NGX_HTTP_LUA_CONTEXT_TIMER
     458             :                                | NGX_HTTP_LUA_CONTEXT_SSL_CERT
     459             :                                | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH);
     460             : 
     461           1 :     luaL_checktype(L, 1, LUA_TTABLE);
     462             : 
     463           1 :     p = (u_char *) luaL_checklstring(L, 2, &len);
     464             : 
     465           1 :     key_index = 2;
     466           1 :     custom_pool = 0;
     467             : 
     468           1 :     if (lua_type(L, n) == LUA_TTABLE) {
     469             : 
     470             :         /* found the last optional option table */
     471             : 
     472           0 :         lua_getfield(L, n, "pool");
     473             : 
     474           0 :         switch (lua_type(L, -1)) {
     475           0 :         case LUA_TNUMBER:
     476           0 :             lua_tostring(L, -1);
     477             :             /* FALLTHROUGH */
     478             : 
     479           0 :         case LUA_TSTRING:
     480           0 :             custom_pool = 1;
     481             : 
     482           0 :             lua_pushvalue(L, -1);
     483           0 :             lua_rawseti(L, 1, SOCKET_KEY_INDEX);
     484             : 
     485           0 :             key_index = n + 1;
     486             : 
     487           0 :             break;
     488             : 
     489           0 :         case LUA_TNIL:
     490           0 :             lua_pop(L, 2);
     491           0 :             break;
     492             : 
     493           0 :         default:
     494           0 :             msg = lua_pushfstring(L, "bad \"pool\" option type: %s",
     495             :                                   luaL_typename(L, -1));
     496           0 :             luaL_argerror(L, n, msg);
     497           0 :             break;
     498             :         }
     499             : 
     500           0 :         n--;
     501             :     }
     502             : 
     503             :     /* the fourth argument is not a table */
     504           1 :     if (n == 4) {
     505           0 :         lua_pop(L, 1);
     506           0 :         n--;
     507             :     }
     508             : 
     509           1 :     if (n == 3) {
     510           1 :         port = luaL_checkinteger(L, 3);
     511             : 
     512           1 :         if (port < 0 || port > 65536) {
     513           0 :             lua_pushnil(L);
     514           0 :             lua_pushfstring(L, "bad port number: %d", port);
     515           0 :             return 2;
     516             :         }
     517             : 
     518           1 :         if (!custom_pool) {
     519           1 :             lua_pushliteral(L, ":");
     520           1 :             lua_insert(L, 3);
     521           1 :             lua_concat(L, 3);
     522             :         }
     523             : 
     524             :         dd("socket key: %s", lua_tostring(L, -1));
     525             : 
     526             :     } else { /* n == 2 */
     527           0 :         port = 0;
     528             :     }
     529             : 
     530           1 :     if (!custom_pool) {
     531             :         /* the key's index is 2 */
     532             : 
     533           1 :         lua_pushvalue(L, 2);
     534           1 :         lua_rawseti(L, 1, SOCKET_KEY_INDEX);
     535             :     }
     536             : 
     537           1 :     lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
     538           1 :     u = lua_touserdata(L, -1);
     539           1 :     lua_pop(L, 1);
     540             : 
     541           1 :     if (u) {
     542           0 :         if (u->request && u->request != r) {
     543           0 :             return luaL_error(L, "bad request");
     544             :         }
     545             : 
     546           0 :         ngx_http_lua_socket_check_busy_connecting(r, u, L);
     547           0 :         ngx_http_lua_socket_check_busy_reading(r, u, L);
     548           0 :         ngx_http_lua_socket_check_busy_writing(r, u, L);
     549             : 
     550           0 :         if (u->body_downstream || u->raw_downstream) {
     551           0 :             return luaL_error(L, "attempt to re-connect a request socket");
     552             :         }
     553             : 
     554           0 :         if (u->peer.connection) {
     555           0 :             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     556             :                            "lua tcp socket reconnect without shutting down");
     557             : 
     558           0 :             ngx_http_lua_socket_tcp_finalize(r, u);
     559             :         }
     560             : 
     561           0 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     562             :                        "lua reuse socket upstream ctx");
     563             : 
     564             :     } else {
     565           1 :         u = lua_newuserdata(L, sizeof(ngx_http_lua_socket_tcp_upstream_t));
     566           1 :         if (u == NULL) {
     567           0 :             return luaL_error(L, "no memory");
     568             :         }
     569             : 
     570             : #if 1
     571           1 :         lua_pushlightuserdata(L, &ngx_http_lua_upstream_udata_metatable_key);
     572           1 :         lua_rawget(L, LUA_REGISTRYINDEX);
     573           1 :         lua_setmetatable(L, -2);
     574             : #endif
     575             : 
     576           1 :         lua_rawseti(L, 1, SOCKET_CTX_INDEX);
     577             :     }
     578             : 
     579           1 :     ngx_memzero(u, sizeof(ngx_http_lua_socket_tcp_upstream_t));
     580             : 
     581           1 :     coctx = ctx->cur_co_ctx;
     582             : 
     583           1 :     u->request = r; /* set the controlling request */
     584             : 
     585           1 :     llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
     586             : 
     587           1 :     u->conf = llcf;
     588             : 
     589           1 :     pc = &u->peer;
     590             : 
     591           1 :     pc->log = r->connection->log;
     592           1 :     pc->log_error = NGX_ERROR_ERR;
     593             : 
     594             :     dd("lua peer connection log: %p", pc->log);
     595             : 
     596           1 :     lua_rawgeti(L, 1, SOCKET_CONNECT_TIMEOUT_INDEX);
     597           1 :     lua_rawgeti(L, 1, SOCKET_SEND_TIMEOUT_INDEX);
     598           1 :     lua_rawgeti(L, 1, SOCKET_READ_TIMEOUT_INDEX);
     599             : 
     600           1 :     read_timeout = (ngx_int_t) lua_tointeger(L, -1);
     601           1 :     send_timeout = (ngx_int_t) lua_tointeger(L, -2);
     602           1 :     connect_timeout = (ngx_int_t) lua_tointeger(L, -3);
     603             : 
     604           1 :     lua_pop(L, 3);
     605             : 
     606           1 :     if (connect_timeout > 0) {
     607           0 :         u->connect_timeout = (ngx_msec_t) connect_timeout;
     608             : 
     609             :     } else {
     610           1 :         u->connect_timeout = u->conf->connect_timeout;
     611             :     }
     612             : 
     613           1 :     if (send_timeout > 0) {
     614           0 :         u->send_timeout = (ngx_msec_t) send_timeout;
     615             : 
     616             :     } else {
     617           1 :         u->send_timeout = u->conf->send_timeout;
     618             :     }
     619             : 
     620           1 :     if (read_timeout > 0) {
     621           0 :         u->read_timeout = (ngx_msec_t) read_timeout;
     622             : 
     623             :     } else {
     624           1 :         u->read_timeout = u->conf->read_timeout;
     625             :     }
     626             : 
     627           1 :     rc = ngx_http_lua_get_keepalive_peer(r, L, key_index, u);
     628             : 
     629           1 :     if (rc == NGX_OK) {
     630           0 :         lua_pushinteger(L, 1);
     631           0 :         return 1;
     632             :     }
     633             : 
     634           1 :     if (rc == NGX_ERROR) {
     635           0 :         lua_pushnil(L);
     636           0 :         lua_pushliteral(L, "error in get keepalive peer");
     637           0 :         return 2;
     638             :     }
     639             : 
     640             :     /* rc == NGX_DECLINED */
     641             : 
     642             :     /* TODO: we should avoid this in-pool allocation */
     643             : 
     644           1 :     host.data = ngx_palloc(r->pool, len + 1);
     645           1 :     if (host.data == NULL) {
     646           0 :         return luaL_error(L, "no memory");
     647             :     }
     648             : 
     649           1 :     host.len = len;
     650             : 
     651           1 :     ngx_memcpy(host.data, p, len);
     652           1 :     host.data[len] = '\0';
     653             : 
     654           1 :     ngx_memzero(&url, sizeof(ngx_url_t));
     655             : 
     656           1 :     url.url.len = host.len;
     657           1 :     url.url.data = host.data;
     658           1 :     url.default_port = (in_port_t) port;
     659           1 :     url.no_resolve = 1;
     660             : 
     661           1 :     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
     662           0 :         lua_pushnil(L);
     663             : 
     664           0 :         if (url.err) {
     665           0 :             lua_pushfstring(L, "failed to parse host name \"%s\": %s",
     666             :                             host.data, url.err);
     667             : 
     668             :         } else {
     669           0 :             lua_pushfstring(L, "failed to parse host name \"%s\"", host.data);
     670             :         }
     671             : 
     672           0 :         return 2;
     673             :     }
     674             : 
     675           1 :     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     676             :                    "lua tcp socket connect timeout: %M", u->connect_timeout);
     677             : 
     678           1 :     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
     679           1 :     if (u->resolved == NULL) {
     680           0 :         return luaL_error(L, "no memory");
     681             :     }
     682             : 
     683           1 :     if (url.addrs && url.addrs[0].sockaddr) {
     684           1 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     685             :                        "lua tcp socket network address given directly");
     686             : 
     687           1 :         u->resolved->sockaddr = url.addrs[0].sockaddr;
     688           1 :         u->resolved->socklen = url.addrs[0].socklen;
     689           1 :         u->resolved->naddrs = 1;
     690           1 :         u->resolved->host = url.addrs[0].name;
     691             : 
     692             :     } else {
     693           0 :         u->resolved->host = host;
     694           0 :         u->resolved->port = (in_port_t) port;
     695             :     }
     696             : 
     697           1 :     if (u->resolved->sockaddr) {
     698           1 :         rc = ngx_http_lua_socket_resolve_retval_handler(r, u, L);
     699           1 :         if (rc == NGX_AGAIN) {
     700           1 :             return lua_yield(L, 0);
     701             :         }
     702             : 
     703           0 :         return rc;
     704             :     }
     705             : 
     706           0 :     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
     707             : 
     708           0 :     temp.name = host;
     709           0 :     rctx = ngx_resolve_start(clcf->resolver, &temp);
     710           0 :     if (rctx == NULL) {
     711           0 :         u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER;
     712           0 :         lua_pushnil(L);
     713           0 :         lua_pushliteral(L, "failed to start the resolver");
     714           0 :         return 2;
     715             :     }
     716             : 
     717           0 :     if (rctx == NGX_NO_RESOLVER) {
     718           0 :         u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER;
     719           0 :         lua_pushnil(L);
     720           0 :         lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data);
     721           0 :         return 2;
     722             :     }
     723             : 
     724           0 :     rctx->name = host;
     725             : #if !defined(nginx_version) || nginx_version < 1005008
     726             :     rctx->type = NGX_RESOLVE_A;
     727             : #endif
     728           0 :     rctx->handler = ngx_http_lua_socket_resolve_handler;
     729           0 :     rctx->data = u;
     730           0 :     rctx->timeout = clcf->resolver_timeout;
     731             : 
     732           0 :     u->resolved->ctx = rctx;
     733           0 :     u->write_co_ctx = ctx->cur_co_ctx;
     734             : 
     735           0 :     ngx_http_lua_cleanup_pending_operation(coctx);
     736           0 :     coctx->cleanup = ngx_http_lua_tcp_resolve_cleanup;
     737           0 :     coctx->data = u;
     738             : 
     739           0 :     saved_top = lua_gettop(L);
     740             : 
     741           0 :     if (ngx_resolve_name(rctx) != NGX_OK) {
     742           0 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     743             :                        "lua tcp socket fail to run resolver immediately");
     744             : 
     745           0 :         u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER;
     746             : 
     747           0 :         coctx->cleanup = NULL;
     748           0 :         coctx->data = NULL;
     749             : 
     750           0 :         u->resolved->ctx = NULL;
     751           0 :         lua_pushnil(L);
     752           0 :         lua_pushfstring(L, "%s could not be resolved", host.data);
     753             : 
     754           0 :         return 2;
     755             :     }
     756             : 
     757           0 :     if (u->conn_waiting) {
     758             :         dd("resolved and already connecting");
     759           0 :         return lua_yield(L, 0);
     760             :     }
     761             : 
     762           0 :     n = lua_gettop(L) - saved_top;
     763           0 :     if (n) {
     764             :         dd("errors occurred during resolving or connecting"
     765             :            "or already connected");
     766           0 :         return n;
     767             :     }
     768             : 
     769             :     /* still resolving */
     770             : 
     771           0 :     u->conn_waiting = 1;
     772           0 :     u->write_prepare_retvals = ngx_http_lua_socket_resolve_retval_handler;
     773             : 
     774             :     dd("setting data to %p", u);
     775             : 
     776           0 :     if (ctx->entered_content_phase) {
     777           0 :         r->write_event_handler = ngx_http_lua_content_wev_handler;
     778             : 
     779             :     } else {
     780           0 :         r->write_event_handler = ngx_http_core_run_phases;
     781             :     }
     782             : 
     783           0 :     return lua_yield(L, 0);
     784             : }
     785             : 
     786             : 
     787             : static void
     788           0 : ngx_http_lua_socket_empty_resolve_handler(ngx_resolver_ctx_t *ctx)
     789             : {
     790             :     /* do nothing */
     791           0 : }
     792             : 
     793             : 
     794             : static void
     795           0 : ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx)
     796             : {
     797             :     ngx_http_request_t                  *r;
     798             :     ngx_connection_t                    *c;
     799             :     ngx_http_upstream_resolved_t        *ur;
     800             :     ngx_http_lua_ctx_t                  *lctx;
     801             :     lua_State                           *L;
     802             :     ngx_http_lua_socket_tcp_upstream_t  *u;
     803             :     u_char                              *p;
     804             :     size_t                               len;
     805             : #if defined(nginx_version) && nginx_version >= 1005008
     806             :     socklen_t                            socklen;
     807             :     struct sockaddr                     *sockaddr;
     808             : #else
     809             :     struct sockaddr_in                  *sin;
     810             : #endif
     811             :     ngx_uint_t                           i;
     812             :     unsigned                             waiting;
     813             : 
     814           0 :     u = ctx->data;
     815           0 :     r = u->request;
     816           0 :     c = r->connection;
     817           0 :     ur = u->resolved;
     818             : 
     819           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
     820             :                    "lua tcp socket resolve handler");
     821             : 
     822           0 :     lctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
     823           0 :     if (lctx == NULL) {
     824           0 :         return;
     825             :     }
     826             : 
     827           0 :     lctx->cur_co_ctx = u->write_co_ctx;
     828             : 
     829           0 :     u->write_co_ctx->cleanup = NULL;
     830             : 
     831           0 :     L = lctx->cur_co_ctx->co;
     832             : 
     833           0 :     waiting = u->conn_waiting;
     834             : 
     835           0 :     if (ctx->state) {
     836           0 :         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
     837             :                        "lua tcp socket resolver error: %s "
     838             :                        "(connect waiting: %d)",
     839             :                        ngx_resolver_strerror(ctx->state), (int) waiting);
     840             : 
     841           0 :         lua_pushnil(L);
     842           0 :         lua_pushlstring(L, (char *) ctx->name.data, ctx->name.len);
     843           0 :         lua_pushfstring(L, " could not be resolved (%d: %s)",
     844           0 :                         (int) ctx->state,
     845             :                         ngx_resolver_strerror(ctx->state));
     846           0 :         lua_concat(L, 2);
     847             : 
     848           0 :         u->write_prepare_retvals =
     849             :                                 ngx_http_lua_socket_conn_error_retval_handler;
     850           0 :         ngx_http_lua_socket_handle_conn_error(r, u,
     851             :                                               NGX_HTTP_LUA_SOCKET_FT_RESOLVER);
     852             : 
     853           0 :         if (waiting) {
     854           0 :             ngx_http_run_posted_requests(c);
     855             :         }
     856             : 
     857           0 :         return;
     858             :     }
     859             : 
     860           0 :     ur->naddrs = ctx->naddrs;
     861           0 :     ur->addrs = ctx->addrs;
     862             : 
     863             : #if (NGX_DEBUG)
     864             :     {
     865             : #   if defined(nginx_version) && nginx_version >= 1005008
     866             :     u_char      text[NGX_SOCKADDR_STRLEN];
     867             :     ngx_str_t   addr;
     868             : #   else
     869             :     in_addr_t   addr;
     870             : #   endif
     871             :     ngx_uint_t  i;
     872             : 
     873             : #   if defined(nginx_version) && nginx_version >= 1005008
     874           0 :     addr.data = text;
     875             : 
     876           0 :     for (i = 0; i < ctx->naddrs; i++) {
     877           0 :         addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen,
     878             :                                  text, NGX_SOCKADDR_STRLEN, 0);
     879             : 
     880           0 :         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
     881             :                        "name was resolved to %V", &addr);
     882             :     }
     883             : #   else
     884             :     for (i = 0; i < ctx->naddrs; i++) {
     885             :         dd("addr i: %d %p", (int) i,  &ctx->addrs[i]);
     886             : 
     887             :         addr = ntohl(ctx->addrs[i]);
     888             : 
     889             :         ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
     890             :                        "name was resolved to %ud.%ud.%ud.%ud",
     891             :                        (addr >> 24) & 0xff, (addr >> 16) & 0xff,
     892             :                        (addr >> 8) & 0xff, addr & 0xff);
     893             :     }
     894             : #   endif
     895             :     }
     896             : #endif
     897             : 
     898           0 :     ngx_http_lua_assert(ur->naddrs > 0);
     899             : 
     900           0 :     if (ur->naddrs == 1) {
     901           0 :         i = 0;
     902             : 
     903             :     } else {
     904           0 :         i = ngx_random() % ur->naddrs;
     905             :     }
     906             : 
     907             :     dd("selected addr index: %d", (int) i);
     908             : 
     909             : #if defined(nginx_version) && nginx_version >= 1005008
     910           0 :     socklen = ur->addrs[i].socklen;
     911             : 
     912           0 :     sockaddr = ngx_palloc(r->pool, socklen);
     913           0 :     if (sockaddr == NULL) {
     914           0 :         goto nomem;
     915             :     }
     916             : 
     917           0 :     ngx_memcpy(sockaddr, ur->addrs[i].sockaddr, socklen);
     918             : 
     919           0 :     switch (sockaddr->sa_family) {
     920             : #if (NGX_HAVE_INET6)
     921           0 :     case AF_INET6:
     922           0 :         ((struct sockaddr_in6 *) sockaddr)->sin6_port = htons(ur->port);
     923           0 :         break;
     924             : #endif
     925           0 :     default: /* AF_INET */
     926           0 :         ((struct sockaddr_in *) sockaddr)->sin_port = htons(ur->port);
     927             :     }
     928             : 
     929           0 :     p = ngx_pnalloc(r->pool, NGX_SOCKADDR_STRLEN);
     930           0 :     if (p == NULL) {
     931           0 :         goto nomem;
     932             :     }
     933             : 
     934           0 :     len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1);
     935           0 :     ur->sockaddr = sockaddr;
     936           0 :     ur->socklen = socklen;
     937             : 
     938             : #else
     939             :     /* for nginx older than 1.5.8 */
     940             : 
     941             :     len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;
     942             : 
     943             :     p = ngx_pnalloc(r->pool, len + sizeof(struct sockaddr_in));
     944             :     if (p == NULL) {
     945             :         goto nomem;
     946             :     }
     947             : 
     948             :     sin = (struct sockaddr_in *) &p[len];
     949             :     ngx_memzero(sin, sizeof(struct sockaddr_in));
     950             : 
     951             :     len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, NGX_INET_ADDRSTRLEN);
     952             :     len = ngx_sprintf(&p[len], ":%d", ur->port) - p;
     953             : 
     954             :     sin->sin_family = AF_INET;
     955             :     sin->sin_port = htons(ur->port);
     956             :     sin->sin_addr.s_addr = ur->addrs[i];
     957             : 
     958             :     ur->sockaddr = (struct sockaddr *) sin;
     959             :     ur->socklen = sizeof(struct sockaddr_in);
     960             : #endif
     961             : 
     962           0 :     ur->host.data = p;
     963           0 :     ur->host.len = len;
     964           0 :     ur->naddrs = 1;
     965             : 
     966           0 :     ngx_resolve_name_done(ctx);
     967           0 :     ur->ctx = NULL;
     968             : 
     969           0 :     u->conn_waiting = 0;
     970           0 :     u->write_co_ctx = NULL;
     971             : 
     972           0 :     if (waiting) {
     973           0 :         lctx->resume_handler = ngx_http_lua_socket_tcp_conn_resume;
     974           0 :         r->write_event_handler(r);
     975           0 :         ngx_http_run_posted_requests(c);
     976             : 
     977             :     } else {
     978           0 :         (void) ngx_http_lua_socket_resolve_retval_handler(r, u, L);
     979             :     }
     980             : 
     981           0 :     return;
     982             : 
     983           0 : nomem:
     984             : 
     985           0 :     if (ur->ctx) {
     986           0 :         ngx_resolve_name_done(ctx);
     987           0 :         ur->ctx = NULL;
     988             :     }
     989             : 
     990           0 :     u->write_prepare_retvals = ngx_http_lua_socket_conn_error_retval_handler;
     991           0 :     ngx_http_lua_socket_handle_conn_error(r, u,
     992             :                                           NGX_HTTP_LUA_SOCKET_FT_NOMEM);
     993             : 
     994           0 :     if (waiting) {
     995             :         dd("run posted requests");
     996           0 :         ngx_http_run_posted_requests(c);
     997             : 
     998             :     } else {
     999           0 :         lua_pushnil(L);
    1000           0 :         lua_pushliteral(L, "no memory");
    1001             :     }
    1002             : }
    1003             : 
    1004             : 
    1005             : static int
    1006           1 : ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r,
    1007             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L)
    1008             : {
    1009             :     ngx_http_lua_ctx_t              *ctx;
    1010             :     ngx_peer_connection_t           *pc;
    1011             :     ngx_connection_t                *c;
    1012             :     ngx_http_cleanup_t              *cln;
    1013             :     ngx_http_upstream_resolved_t    *ur;
    1014             :     ngx_int_t                        rc;
    1015             :     ngx_http_lua_co_ctx_t           *coctx;
    1016             : 
    1017           1 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1018             :                    "lua tcp socket resolve retval handler");
    1019             : 
    1020           1 :     if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_RESOLVER) {
    1021           0 :         return 2;
    1022             :     }
    1023             : 
    1024           1 :     pc = &u->peer;
    1025             : 
    1026           1 :     ur = u->resolved;
    1027             : 
    1028           1 :     if (ur->sockaddr) {
    1029           1 :         pc->sockaddr = ur->sockaddr;
    1030           1 :         pc->socklen = ur->socklen;
    1031           1 :         pc->name = &ur->host;
    1032             : 
    1033             :     } else {
    1034           0 :         lua_pushnil(L);
    1035           0 :         lua_pushliteral(L, "resolver not working");
    1036           0 :         return 2;
    1037             :     }
    1038             : 
    1039           1 :     pc->get = ngx_http_lua_socket_tcp_get_peer;
    1040             : 
    1041           1 :     rc = ngx_event_connect_peer(pc);
    1042             : 
    1043           1 :     if (rc == NGX_ERROR) {
    1044           0 :         u->socket_errno = ngx_socket_errno;
    1045             :     }
    1046             : 
    1047           1 :     if (u->cleanup == NULL) {
    1048           1 :         cln = ngx_http_lua_cleanup_add(r, 0);
    1049           1 :         if (cln == NULL) {
    1050           0 :             u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR;
    1051           0 :             lua_pushnil(L);
    1052           0 :             lua_pushliteral(L, "no memory");
    1053           0 :             return 2;
    1054             :         }
    1055             : 
    1056           1 :         cln->handler = ngx_http_lua_socket_tcp_cleanup;
    1057           1 :         cln->data = u;
    1058           1 :         u->cleanup = &cln->handler;
    1059             :     }
    1060             : 
    1061           1 :     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1062             :                    "lua tcp socket connect: %i", rc);
    1063             : 
    1064           1 :     if (rc == NGX_ERROR) {
    1065           0 :         return ngx_http_lua_socket_conn_error_retval_handler(r, u, L);
    1066             :     }
    1067             : 
    1068           1 :     if (rc == NGX_BUSY) {
    1069           0 :         u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR;
    1070           0 :         lua_pushnil(L);
    1071           0 :         lua_pushliteral(L, "no live connection");
    1072           0 :         return 2;
    1073             :     }
    1074             : 
    1075           1 :     if (rc == NGX_DECLINED) {
    1076             :         dd("socket errno: %d", (int) ngx_socket_errno);
    1077           0 :         u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR;
    1078           0 :         u->socket_errno = ngx_socket_errno;
    1079           0 :         return ngx_http_lua_socket_conn_error_retval_handler(r, u, L);
    1080             :     }
    1081             : 
    1082             :     /* rc == NGX_OK || rc == NGX_AGAIN */
    1083             : 
    1084           1 :     c = pc->connection;
    1085             : 
    1086           1 :     c->data = u;
    1087             : 
    1088           1 :     c->write->handler = ngx_http_lua_socket_tcp_handler;
    1089           1 :     c->read->handler = ngx_http_lua_socket_tcp_handler;
    1090             : 
    1091           1 :     u->write_event_handler = ngx_http_lua_socket_connected_handler;
    1092           1 :     u->read_event_handler = ngx_http_lua_socket_connected_handler;
    1093             : 
    1094           1 :     c->sendfile &= r->connection->sendfile;
    1095             : 
    1096           1 :     if (c->pool == NULL) {
    1097             : 
    1098             :         /* we need separate pool here to be able to cache SSL connections */
    1099             : 
    1100           1 :         c->pool = ngx_create_pool(128, r->connection->log);
    1101           1 :         if (c->pool == NULL) {
    1102           0 :             return ngx_http_lua_socket_prepare_error_retvals(r, u, L,
    1103             :                                                 NGX_HTTP_LUA_SOCKET_FT_NOMEM);
    1104             :         }
    1105             :     }
    1106             : 
    1107           1 :     c->log = r->connection->log;
    1108           1 :     c->pool->log = c->log;
    1109           1 :     c->read->log = c->log;
    1110           1 :     c->write->log = c->log;
    1111             : 
    1112             :     /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */
    1113             : 
    1114             : #if 0
    1115             :     u->writer.out = NULL;
    1116             :     u->writer.last = &u->writer.out;
    1117             : #endif
    1118             : 
    1119           1 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    1120             : 
    1121           1 :     coctx = ctx->cur_co_ctx;
    1122             : 
    1123             :     dd("setting data to %p", u);
    1124             : 
    1125           1 :     if (rc == NGX_OK) {
    1126           0 :         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1127             :                        "lua tcp socket connected: fd:%d", (int) c->fd);
    1128             : 
    1129             :         /* We should delete the current write/read event
    1130             :          * here because the socket object may not be used immediately
    1131             :          * on the Lua land, thus causing hot spin around level triggered
    1132             :          * event poll and wasting CPU cycles. */
    1133             : 
    1134           0 :         if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
    1135           0 :             ngx_http_lua_socket_handle_conn_error(r, u,
    1136             :                                                   NGX_HTTP_LUA_SOCKET_FT_ERROR);
    1137           0 :             lua_pushnil(L);
    1138           0 :             lua_pushliteral(L, "failed to handle write event");
    1139           0 :             return 2;
    1140             :         }
    1141             : 
    1142           0 :         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
    1143           0 :             ngx_http_lua_socket_handle_conn_error(r, u,
    1144             :                                                   NGX_HTTP_LUA_SOCKET_FT_ERROR);
    1145           0 :             lua_pushnil(L);
    1146           0 :             lua_pushliteral(L, "failed to handle read event");
    1147           0 :             return 2;
    1148             :         }
    1149             : 
    1150           0 :         u->read_event_handler = ngx_http_lua_socket_dummy_handler;
    1151           0 :         u->write_event_handler = ngx_http_lua_socket_dummy_handler;
    1152             : 
    1153           0 :         lua_pushinteger(L, 1);
    1154           0 :         return 1;
    1155             :     }
    1156             : 
    1157             :     /* rc == NGX_AGAIN */
    1158             : 
    1159           1 :     ngx_http_lua_cleanup_pending_operation(coctx);
    1160           1 :     coctx->cleanup = ngx_http_lua_coctx_cleanup;
    1161           1 :     coctx->data = u;
    1162             : 
    1163           1 :     ngx_add_timer(c->write, u->connect_timeout);
    1164             : 
    1165           1 :     u->write_co_ctx = ctx->cur_co_ctx;
    1166           1 :     u->conn_waiting = 1;
    1167           1 :     u->write_prepare_retvals = ngx_http_lua_socket_tcp_conn_retval_handler;
    1168             : 
    1169             :     dd("setting data to %p", u);
    1170             : 
    1171           1 :     if (ctx->entered_content_phase) {
    1172           1 :         r->write_event_handler = ngx_http_lua_content_wev_handler;
    1173             : 
    1174             :     } else {
    1175           0 :         r->write_event_handler = ngx_http_core_run_phases;
    1176             :     }
    1177             : 
    1178           1 :     return NGX_AGAIN;
    1179             : }
    1180             : 
    1181             : 
    1182             : static int
    1183           0 : ngx_http_lua_socket_conn_error_retval_handler(ngx_http_request_t *r,
    1184             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L)
    1185             : {
    1186             :     ngx_uint_t      ft_type;
    1187             : 
    1188           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1189             :                    "lua tcp socket error retval handler");
    1190             : 
    1191           0 :     if (u->write_co_ctx) {
    1192           0 :         u->write_co_ctx->cleanup = NULL;
    1193             :     }
    1194             : 
    1195           0 :     ngx_http_lua_socket_tcp_finalize(r, u);
    1196             : 
    1197           0 :     ft_type = u->ft_type;
    1198           0 :     u->ft_type = 0;
    1199           0 :     return ngx_http_lua_socket_prepare_error_retvals(r, u, L, ft_type);
    1200             : }
    1201             : 
    1202             : 
    1203             : #if (NGX_HTTP_SSL)
    1204             : 
    1205             : static int
    1206           0 : ngx_http_lua_socket_tcp_sslhandshake(lua_State *L)
    1207             : {
    1208             :     int                      n, top;
    1209             :     ngx_int_t                rc;
    1210           0 :     ngx_str_t                name = ngx_null_string;
    1211             :     ngx_connection_t        *c;
    1212             :     ngx_ssl_session_t      **psession;
    1213             :     ngx_http_request_t      *r;
    1214             :     ngx_http_lua_ctx_t      *ctx;
    1215             :     ngx_http_lua_co_ctx_t   *coctx;
    1216             : 
    1217             :     ngx_http_lua_socket_tcp_upstream_t  *u;
    1218             : 
    1219             :     /* Lua function arguments: self [,session] [,host] [,verify]
    1220             :        [,send_status_req] */
    1221             : 
    1222           0 :     n = lua_gettop(L);
    1223           0 :     if (n < 1 || n > 5) {
    1224           0 :         return luaL_error(L, "ngx.socket sslhandshake: expecting 1 ~ 5 "
    1225             :                           "arguments (including the object), but seen %d", n);
    1226             :     }
    1227             : 
    1228           0 :     r = ngx_http_lua_get_req(L);
    1229           0 :     if (r == NULL) {
    1230           0 :         return luaL_error(L, "no request found");
    1231             :     }
    1232             : 
    1233           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1234             :                    "lua tcp socket ssl handshake");
    1235             : 
    1236           0 :     luaL_checktype(L, 1, LUA_TTABLE);
    1237             : 
    1238           0 :     lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
    1239           0 :     u = lua_touserdata(L, -1);
    1240             : 
    1241           0 :     if (u == NULL
    1242           0 :         || u->peer.connection == NULL
    1243           0 :         || u->read_closed
    1244           0 :         || u->write_closed)
    1245             :     {
    1246           0 :         lua_pushnil(L);
    1247           0 :         lua_pushliteral(L, "closed");
    1248           0 :         return 2;
    1249             :     }
    1250             : 
    1251           0 :     if (u->request != r) {
    1252           0 :         return luaL_error(L, "bad request");
    1253             :     }
    1254             : 
    1255           0 :     ngx_http_lua_socket_check_busy_connecting(r, u, L);
    1256           0 :     ngx_http_lua_socket_check_busy_reading(r, u, L);
    1257           0 :     ngx_http_lua_socket_check_busy_writing(r, u, L);
    1258             : 
    1259           0 :     if (u->raw_downstream || u->body_downstream) {
    1260           0 :         lua_pushnil(L);
    1261           0 :         lua_pushliteral(L, "not supported for downstream");
    1262           0 :         return 2;
    1263             :     }
    1264             : 
    1265           0 :     c = u->peer.connection;
    1266             : 
    1267           0 :     u->ssl_session_reuse = 1;
    1268             : 
    1269           0 :     if (c->ssl && c->ssl->handshaked) {
    1270           0 :         switch (lua_type(L, 2)) {
    1271           0 :         case LUA_TUSERDATA:
    1272           0 :             lua_pushvalue(L, 2);
    1273           0 :             break;
    1274             : 
    1275           0 :         case LUA_TBOOLEAN:
    1276           0 :             if (!lua_toboolean(L, 2)) {
    1277             :                 /* avoid generating the ssl session */
    1278           0 :                 lua_pushboolean(L, 1);
    1279           0 :                 break;
    1280             :             }
    1281             :             /* fall through */
    1282             : 
    1283             :         default:
    1284           0 :             ngx_http_lua_ssl_handshake_retval_handler(r, u, L);
    1285           0 :             break;
    1286             :         }
    1287             : 
    1288           0 :         return 1;
    1289             :     }
    1290             : 
    1291           0 :     if (ngx_ssl_create_connection(u->conf->ssl, c,
    1292             :                                   NGX_SSL_BUFFER|NGX_SSL_CLIENT)
    1293             :         != NGX_OK)
    1294             :     {
    1295           0 :         lua_pushnil(L);
    1296           0 :         lua_pushliteral(L, "failed to create ssl connection");
    1297           0 :         return 2;
    1298             :     }
    1299             : 
    1300           0 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    1301           0 :     if (ctx == NULL) {
    1302           0 :         return luaL_error(L, "no ctx found");
    1303             :     }
    1304             : 
    1305           0 :     coctx = ctx->cur_co_ctx;
    1306             : 
    1307           0 :     c->sendfile = 0;
    1308             : 
    1309           0 :     if (n >= 2) {
    1310           0 :         if (lua_type(L, 2) == LUA_TBOOLEAN) {
    1311           0 :             u->ssl_session_reuse = lua_toboolean(L, 2);
    1312             : 
    1313             :         } else {
    1314           0 :             psession = lua_touserdata(L, 2);
    1315             : 
    1316           0 :             if (psession != NULL && *psession != NULL) {
    1317           0 :                 if (ngx_ssl_set_session(c, *psession) != NGX_OK) {
    1318           0 :                     lua_pushnil(L);
    1319           0 :                     lua_pushliteral(L, "lua ssl set session failed");
    1320           0 :                     return 2;
    1321             :                 }
    1322             : 
    1323           0 :                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
    1324             :                                "lua ssl set session: %p:%d",
    1325             :                                *psession, (*psession)->references);
    1326             :             }
    1327             :         }
    1328             : 
    1329           0 :         if (n >= 3) {
    1330           0 :             name.data = (u_char *) lua_tolstring(L, 3, &name.len);
    1331             : 
    1332           0 :             if (name.data) {
    1333           0 :                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1334             :                                "lua ssl server name: \"%*s\"", name.len,
    1335             :                                name.data);
    1336             : 
    1337             : #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
    1338             : 
    1339           0 :                 if (SSL_set_tlsext_host_name(c->ssl->connection,
    1340             :                                              (char *) name.data)
    1341             :                     == 0)
    1342             :                 {
    1343           0 :                     lua_pushnil(L);
    1344           0 :                     lua_pushliteral(L, "SSL_set_tlsext_host_name failed");
    1345           0 :                     return 2;
    1346             :                 }
    1347             : 
    1348             : #else
    1349             : 
    1350             :                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
    1351             :                               "lua socket SNI disabled because the current "
    1352             :                               "version of OpenSSL lacks the support");
    1353             : 
    1354             : #endif
    1355             :             }
    1356             : 
    1357           0 :             if (n >= 4) {
    1358           0 :                 u->ssl_verify = lua_toboolean(L, 4);
    1359             : 
    1360           0 :                 if (n >= 5) {
    1361           0 :                     if (lua_toboolean(L, 5)) {
    1362             : #ifdef NGX_HTTP_LUA_USE_OCSP
    1363           0 :                         SSL_set_tlsext_status_type(c->ssl->connection,
    1364             :                                                    TLSEXT_STATUSTYPE_ocsp);
    1365             : #else
    1366             :                         return luaL_error(L, "no OCSP support");
    1367             : #endif
    1368             :                     }
    1369             :                 }
    1370             :             }
    1371             :         }
    1372             :     }
    1373             : 
    1374             :     dd("found sni name: %.*s %p", (int) name.len, name.data, name.data);
    1375             : 
    1376           0 :     if (name.len == 0) {
    1377           0 :         u->ssl_name.len = 0;
    1378             : 
    1379             :     } else {
    1380           0 :         if (u->ssl_name.data) {
    1381             :             /* buffer already allocated */
    1382             : 
    1383           0 :             if (u->ssl_name.len >= name.len) {
    1384             :                 /* reuse it */
    1385           0 :                 ngx_memcpy(u->ssl_name.data, name.data, name.len);
    1386           0 :                 u->ssl_name.len = name.len;
    1387             : 
    1388             :             } else {
    1389           0 :                 ngx_free(u->ssl_name.data);
    1390           0 :                 goto new_ssl_name;
    1391             :             }
    1392             : 
    1393             :         } else {
    1394             : 
    1395           0 : new_ssl_name:
    1396             : 
    1397           0 :             u->ssl_name.data = ngx_alloc(name.len, ngx_cycle->log);
    1398           0 :             if (u->ssl_name.data == NULL) {
    1399           0 :                 u->ssl_name.len = 0;
    1400             : 
    1401           0 :                 lua_pushnil(L);
    1402           0 :                 lua_pushliteral(L, "no memory");
    1403           0 :                 return 2;
    1404             :             }
    1405             : 
    1406           0 :             ngx_memcpy(u->ssl_name.data, name.data, name.len);
    1407           0 :             u->ssl_name.len = name.len;
    1408             :         }
    1409             :     }
    1410             : 
    1411           0 :     u->write_co_ctx = coctx;
    1412             : 
    1413             : #if 0
    1414             : #ifdef NGX_HTTP_LUA_USE_OCSP
    1415             :     SSL_set_tlsext_status_type(c->ssl->connection, TLSEXT_STATUSTYPE_ocsp);
    1416             : #endif
    1417             : #endif
    1418             : 
    1419           0 :     rc = ngx_ssl_handshake(c);
    1420             : 
    1421             :     dd("ngx_ssl_handshake returned %d", (int) rc);
    1422             : 
    1423           0 :     if (rc == NGX_AGAIN) {
    1424           0 :         if (c->write->timer_set) {
    1425           0 :             ngx_del_timer(c->write);
    1426             :         }
    1427             : 
    1428           0 :         ngx_add_timer(c->read, u->connect_timeout);
    1429             : 
    1430           0 :         u->conn_waiting = 1;
    1431           0 :         u->write_prepare_retvals = ngx_http_lua_ssl_handshake_retval_handler;
    1432             : 
    1433           0 :         ngx_http_lua_cleanup_pending_operation(coctx);
    1434           0 :         coctx->cleanup = ngx_http_lua_coctx_cleanup;
    1435           0 :         coctx->data = u;
    1436             : 
    1437           0 :         c->ssl->handler = ngx_http_lua_ssl_handshake_handler;
    1438             : 
    1439           0 :         if (ctx->entered_content_phase) {
    1440           0 :             r->write_event_handler = ngx_http_lua_content_wev_handler;
    1441             : 
    1442             :         } else {
    1443           0 :             r->write_event_handler = ngx_http_core_run_phases;
    1444             :         }
    1445             : 
    1446           0 :         return lua_yield(L, 0);
    1447             :     }
    1448             : 
    1449           0 :     top = lua_gettop(L);
    1450           0 :     ngx_http_lua_ssl_handshake_handler(c);
    1451           0 :     return lua_gettop(L) - top;
    1452             : }
    1453             : 
    1454             : 
    1455             : static void
    1456           0 : ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c)
    1457             : {
    1458             :     const char                  *err;
    1459             :     int                          waiting;
    1460             :     lua_State                   *L;
    1461             :     ngx_int_t                    rc;
    1462             :     ngx_connection_t            *dc;  /* downstream connection */
    1463             :     ngx_http_request_t          *r;
    1464             :     ngx_http_lua_ctx_t          *ctx;
    1465             :     ngx_http_lua_loc_conf_t     *llcf;
    1466             : 
    1467             :     ngx_http_lua_socket_tcp_upstream_t  *u;
    1468             : 
    1469           0 :     u = c->data;
    1470           0 :     r = u->request;
    1471             : 
    1472           0 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    1473           0 :     if (ctx == NULL) {
    1474           0 :         return;
    1475             :     }
    1476             : 
    1477           0 :     c->write->handler = ngx_http_lua_socket_tcp_handler;
    1478           0 :     c->read->handler = ngx_http_lua_socket_tcp_handler;
    1479             : 
    1480           0 :     waiting = u->conn_waiting;
    1481             : 
    1482           0 :     dc = r->connection;
    1483           0 :     L = u->write_co_ctx->co;
    1484             : 
    1485           0 :     if (c->read->timedout) {
    1486           0 :         lua_pushnil(L);
    1487           0 :         lua_pushliteral(L, "timeout");
    1488           0 :         goto failed;
    1489             :     }
    1490             : 
    1491           0 :     if (c->read->timer_set) {
    1492           0 :         ngx_del_timer(c->read);
    1493             :     }
    1494             : 
    1495           0 :     if (c->ssl->handshaked) {
    1496             : 
    1497           0 :         if (u->ssl_verify) {
    1498           0 :             rc = SSL_get_verify_result(c->ssl->connection);
    1499             : 
    1500           0 :             if (rc != X509_V_OK) {
    1501           0 :                 lua_pushnil(L);
    1502           0 :                 err = lua_pushfstring(L, "%d: %s", (int) rc,
    1503             :                                       X509_verify_cert_error_string(rc));
    1504             : 
    1505           0 :                 llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
    1506           0 :                 if (llcf->log_socket_errors) {
    1507           0 :                     ngx_log_error(NGX_LOG_ERR, dc->log, 0, "lua ssl "
    1508             :                                   "certificate verify error: (%s)", err);
    1509             :                 }
    1510             : 
    1511           0 :                 goto failed;
    1512             :             }
    1513             : 
    1514             : #if defined(nginx_version) && nginx_version >= 1007000
    1515             : 
    1516           0 :             if (u->ssl_name.len
    1517           0 :                 && ngx_ssl_check_host(c, &u->ssl_name) != NGX_OK)
    1518             :             {
    1519           0 :                 lua_pushnil(L);
    1520           0 :                 lua_pushliteral(L, "certificate host mismatch");
    1521             : 
    1522           0 :                 llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
    1523           0 :                 if (llcf->log_socket_errors) {
    1524           0 :                     ngx_log_error(NGX_LOG_ERR, dc->log, 0, "lua ssl "
    1525             :                                   "certificate does not match host \"%V\"",
    1526             :                                   &u->ssl_name);
    1527             :                 }
    1528             : 
    1529           0 :                 goto failed;
    1530             :             }
    1531             : 
    1532             : #endif
    1533             :         }
    1534             : 
    1535           0 :         if (waiting) {
    1536           0 :             ngx_http_lua_socket_handle_conn_success(r, u);
    1537             : 
    1538             :         } else {
    1539           0 :             (void) ngx_http_lua_ssl_handshake_retval_handler(r, u, L);
    1540             :         }
    1541             : 
    1542           0 :         if (waiting) {
    1543           0 :             ngx_http_run_posted_requests(dc);
    1544             :         }
    1545             : 
    1546           0 :         return;
    1547             :     }
    1548             : 
    1549           0 :     lua_pushnil(L);
    1550           0 :     lua_pushliteral(L, "handshake failed");
    1551             : 
    1552           0 : failed:
    1553             : 
    1554           0 :     if (waiting) {
    1555           0 :         u->write_prepare_retvals =
    1556             :                                 ngx_http_lua_socket_conn_error_retval_handler;
    1557           0 :         ngx_http_lua_socket_handle_conn_error(r, u,
    1558             :                                               NGX_HTTP_LUA_SOCKET_FT_SSL);
    1559           0 :         ngx_http_run_posted_requests(dc);
    1560             : 
    1561             :     } else {
    1562           0 :         (void) ngx_http_lua_socket_conn_error_retval_handler(r, u, L);
    1563             :     }
    1564             : }
    1565             : 
    1566             : 
    1567             : static int
    1568           0 : ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r,
    1569             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L)
    1570             : {
    1571             :     ngx_connection_t            *c;
    1572             :     ngx_ssl_session_t           *ssl_session, **ud;
    1573             : 
    1574           0 :     if (!u->ssl_session_reuse) {
    1575           0 :         lua_pushboolean(L, 1);
    1576           0 :         return 1;
    1577             :     }
    1578             : 
    1579           0 :     ud = lua_newuserdata(L, sizeof(ngx_ssl_session_t *));
    1580             : 
    1581           0 :     c = u->peer.connection;
    1582             : 
    1583           0 :     ssl_session = ngx_ssl_get_session(c);
    1584           0 :     if (ssl_session == NULL) {
    1585           0 :         *ud = NULL;
    1586             : 
    1587             :     } else {
    1588           0 :         *ud = ssl_session;
    1589             : 
    1590           0 :        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
    1591             :                       "lua ssl save session: %p:%d", ssl_session,
    1592             :                       ssl_session->references);
    1593             : 
    1594             :         /* set up the __gc metamethod */
    1595           0 :         lua_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key);
    1596           0 :         lua_rawget(L, LUA_REGISTRYINDEX);
    1597           0 :         lua_setmetatable(L, -2);
    1598             :     }
    1599             : 
    1600           0 :     return 1;
    1601             : }
    1602             : 
    1603             : #endif  /* NGX_HTTP_SSL */
    1604             : 
    1605             : 
    1606             : static int
    1607           0 : ngx_http_lua_socket_read_error_retval_handler(ngx_http_request_t *r,
    1608             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L)
    1609             : {
    1610             :     ngx_uint_t          ft_type;
    1611             : 
    1612           0 :     if (u->read_co_ctx) {
    1613           0 :         u->read_co_ctx->cleanup = NULL;
    1614             :     }
    1615             : 
    1616           0 :     ft_type = u->ft_type;
    1617           0 :     u->ft_type = 0;
    1618             : 
    1619           0 :     if (u->no_close) {
    1620           0 :         u->no_close = 0;
    1621             : 
    1622             :     } else {
    1623           0 :         ngx_http_lua_socket_tcp_finalize_read_part(r, u);
    1624             :     }
    1625             : 
    1626           0 :     return ngx_http_lua_socket_prepare_error_retvals(r, u, L, ft_type);
    1627             : }
    1628             : 
    1629             : 
    1630             : static int
    1631           0 : ngx_http_lua_socket_write_error_retval_handler(ngx_http_request_t *r,
    1632             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L)
    1633             : {
    1634             :     ngx_uint_t          ft_type;
    1635             : 
    1636           0 :     if (u->write_co_ctx) {
    1637           0 :         u->write_co_ctx->cleanup = NULL;
    1638             :     }
    1639             : 
    1640           0 :     ngx_http_lua_socket_tcp_finalize_write_part(r, u);
    1641             : 
    1642           0 :     ft_type = u->ft_type;
    1643           0 :     u->ft_type = 0;
    1644           0 :     return ngx_http_lua_socket_prepare_error_retvals(r, u, L, ft_type);
    1645             : }
    1646             : 
    1647             : 
    1648             : static int
    1649           0 : ngx_http_lua_socket_prepare_error_retvals(ngx_http_request_t *r,
    1650             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L, ngx_uint_t ft_type)
    1651             : {
    1652             :     u_char           errstr[NGX_MAX_ERROR_STR];
    1653             :     u_char          *p;
    1654             : 
    1655           0 :     if (ft_type & (NGX_HTTP_LUA_SOCKET_FT_RESOLVER
    1656             :                    | NGX_HTTP_LUA_SOCKET_FT_SSL))
    1657             :     {
    1658           0 :         return 2;
    1659             :     }
    1660             : 
    1661           0 :     lua_pushnil(L);
    1662             : 
    1663           0 :     if (ft_type & NGX_HTTP_LUA_SOCKET_FT_TIMEOUT) {
    1664           0 :         lua_pushliteral(L, "timeout");
    1665             : 
    1666           0 :     } else if (ft_type & NGX_HTTP_LUA_SOCKET_FT_CLOSED) {
    1667           0 :         lua_pushliteral(L, "closed");
    1668             : 
    1669           0 :     } else if (ft_type & NGX_HTTP_LUA_SOCKET_FT_BUFTOOSMALL) {
    1670           0 :         lua_pushliteral(L, "buffer too small");
    1671             : 
    1672           0 :     } else if (ft_type & NGX_HTTP_LUA_SOCKET_FT_NOMEM) {
    1673           0 :         lua_pushliteral(L, "no memory");
    1674             : 
    1675           0 :     } else if (ft_type & NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT) {
    1676           0 :         lua_pushliteral(L, "client aborted");
    1677             : 
    1678             :     } else {
    1679             : 
    1680           0 :         if (u->socket_errno) {
    1681             : #if defined(nginx_version) && nginx_version >= 9000
    1682           0 :             p = ngx_strerror(u->socket_errno, errstr, sizeof(errstr));
    1683             : #else
    1684             :             p = ngx_strerror_r(u->socket_errno, errstr, sizeof(errstr));
    1685             : #endif
    1686             :             /* for compatibility with LuaSocket */
    1687           0 :             ngx_strlow(errstr, errstr, p - errstr);
    1688           0 :             lua_pushlstring(L, (char *) errstr, p - errstr);
    1689             : 
    1690             :         } else {
    1691           0 :             lua_pushliteral(L, "error");
    1692             :         }
    1693             :     }
    1694             : 
    1695           0 :     return 2;
    1696             : }
    1697             : 
    1698             : 
    1699             : static int
    1700           1 : ngx_http_lua_socket_tcp_conn_retval_handler(ngx_http_request_t *r,
    1701             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L)
    1702             : {
    1703           1 :     if (u->ft_type) {
    1704           0 :         return ngx_http_lua_socket_conn_error_retval_handler(r, u, L);
    1705             :     }
    1706             : 
    1707           1 :     lua_pushinteger(L, 1);
    1708           1 :     return 1;
    1709             : }
    1710             : 
    1711             : 
    1712             : static int
    1713           0 : ngx_http_lua_socket_tcp_receive(lua_State *L)
    1714             : {
    1715             :     ngx_http_request_t                  *r;
    1716             :     ngx_http_lua_socket_tcp_upstream_t  *u;
    1717             :     ngx_int_t                            rc;
    1718             :     ngx_http_lua_ctx_t                  *ctx;
    1719             :     int                                  n;
    1720             :     ngx_str_t                            pat;
    1721             :     lua_Integer                          bytes;
    1722             :     char                                *p;
    1723             :     int                                  typ;
    1724             :     ngx_http_lua_loc_conf_t             *llcf;
    1725             :     ngx_http_lua_co_ctx_t               *coctx;
    1726             : 
    1727           0 :     n = lua_gettop(L);
    1728           0 :     if (n != 1 && n != 2) {
    1729           0 :         return luaL_error(L, "expecting 1 or 2 arguments "
    1730             :                           "(including the object), but got %d", n);
    1731             :     }
    1732             : 
    1733           0 :     r = ngx_http_lua_get_req(L);
    1734           0 :     if (r == NULL) {
    1735           0 :         return luaL_error(L, "no request found");
    1736             :     }
    1737             : 
    1738           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1739             :                    "lua tcp socket calling receive() method");
    1740             : 
    1741           0 :     luaL_checktype(L, 1, LUA_TTABLE);
    1742             : 
    1743           0 :     lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
    1744           0 :     u = lua_touserdata(L, -1);
    1745             : 
    1746           0 :     if (u == NULL || u->peer.connection == NULL || u->read_closed) {
    1747             : 
    1748           0 :         llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
    1749             : 
    1750           0 :         if (llcf->log_socket_errors) {
    1751           0 :             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
    1752             :                           "attempt to receive data on a closed socket: u:%p, "
    1753             :                           "c:%p, ft:%d eof:%d",
    1754             :                           u, u ? u->peer.connection : NULL,
    1755             :                           u ? (int) u->ft_type : 0, u ? (int) u->eof : 0);
    1756             :         }
    1757             : 
    1758           0 :         lua_pushnil(L);
    1759           0 :         lua_pushliteral(L, "closed");
    1760           0 :         return 2;
    1761             :     }
    1762             : 
    1763           0 :     if (u->request != r) {
    1764           0 :         return luaL_error(L, "bad request");
    1765             :     }
    1766             : 
    1767           0 :     ngx_http_lua_socket_check_busy_connecting(r, u, L);
    1768           0 :     ngx_http_lua_socket_check_busy_reading(r, u, L);
    1769             : 
    1770           0 :     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1771             :                    "lua tcp socket read timeout: %M", u->read_timeout);
    1772             : 
    1773           0 :     if (n > 1) {
    1774           0 :         if (lua_isnumber(L, 2)) {
    1775           0 :             typ = LUA_TNUMBER;
    1776             : 
    1777             :         } else {
    1778           0 :             typ = lua_type(L, 2);
    1779             :         }
    1780             : 
    1781           0 :         switch (typ) {
    1782           0 :         case LUA_TSTRING:
    1783           0 :             pat.data = (u_char *) luaL_checklstring(L, 2, &pat.len);
    1784           0 :             if (pat.len != 2 || pat.data[0] != '*') {
    1785           0 :                 p = (char *) lua_pushfstring(L, "bad pattern argument: %s",
    1786           0 :                                              (char *) pat.data);
    1787             : 
    1788           0 :                 return luaL_argerror(L, 2, p);
    1789             :             }
    1790             : 
    1791           0 :             switch (pat.data[1]) {
    1792           0 :             case 'l':
    1793           0 :                 u->input_filter = ngx_http_lua_socket_read_line;
    1794           0 :                 break;
    1795             : 
    1796           0 :             case 'a':
    1797           0 :                 u->input_filter = ngx_http_lua_socket_read_all;
    1798           0 :                 break;
    1799             : 
    1800           0 :             default:
    1801           0 :                 return luaL_argerror(L, 2, "bad pattern argument");
    1802             :                 break;
    1803             :             }
    1804             : 
    1805           0 :             u->length = 0;
    1806           0 :             u->rest = 0;
    1807             : 
    1808           0 :             break;
    1809             : 
    1810           0 :         case LUA_TNUMBER:
    1811           0 :             bytes = lua_tointeger(L, 2);
    1812           0 :             if (bytes < 0) {
    1813           0 :                 return luaL_argerror(L, 2, "bad pattern argument");
    1814             :             }
    1815             : 
    1816             : #if 1
    1817           0 :             if (bytes == 0) {
    1818           0 :                 lua_pushliteral(L, "");
    1819           0 :                 return 1;
    1820             :             }
    1821             : #endif
    1822             : 
    1823           0 :             u->input_filter = ngx_http_lua_socket_read_chunk;
    1824           0 :             u->length = (size_t) bytes;
    1825           0 :             u->rest = u->length;
    1826             : 
    1827           0 :             break;
    1828             : 
    1829           0 :         default:
    1830           0 :             return luaL_argerror(L, 2, "bad pattern argument");
    1831             :             break;
    1832             :         }
    1833             : 
    1834             :     } else {
    1835           0 :         u->input_filter = ngx_http_lua_socket_read_line;
    1836           0 :         u->length = 0;
    1837           0 :         u->rest = 0;
    1838             :     }
    1839             : 
    1840           0 :     u->input_filter_ctx = u;
    1841             : 
    1842           0 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    1843             : 
    1844           0 :     if (u->bufs_in == NULL) {
    1845           0 :         u->bufs_in =
    1846           0 :             ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool,
    1847             :                                             &ctx->free_recv_bufs,
    1848           0 :                                             u->conf->buffer_size);
    1849             : 
    1850           0 :         if (u->bufs_in == NULL) {
    1851           0 :             return luaL_error(L, "no memory");
    1852             :         }
    1853             : 
    1854           0 :         u->buf_in = u->bufs_in;
    1855           0 :         u->buffer = *u->buf_in->buf;
    1856             :     }
    1857             : 
    1858             :     dd("tcp receive: buf_in: %p, bufs_in: %p", u->buf_in, u->bufs_in);
    1859             : 
    1860           0 :     if (u->raw_downstream || u->body_downstream) {
    1861           0 :         r->read_event_handler = ngx_http_lua_req_socket_rev_handler;
    1862             :     }
    1863             : 
    1864           0 :     u->read_waiting = 0;
    1865           0 :     u->read_co_ctx = NULL;
    1866             : 
    1867           0 :     rc = ngx_http_lua_socket_tcp_read(r, u);
    1868             : 
    1869           0 :     if (rc == NGX_ERROR) {
    1870             :         dd("read failed: %d", (int) u->ft_type);
    1871           0 :         rc = ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L);
    1872             :         dd("tcp receive retval returned: %d", (int) rc);
    1873           0 :         return rc;
    1874             :     }
    1875             : 
    1876           0 :     if (rc == NGX_OK) {
    1877             : 
    1878           0 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1879             :                        "lua tcp socket receive done in a single run");
    1880             : 
    1881           0 :         return ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L);
    1882             :     }
    1883             : 
    1884             :     /* rc == NGX_AGAIN */
    1885             : 
    1886           0 :     u->read_event_handler = ngx_http_lua_socket_read_handler;
    1887             : 
    1888           0 :     coctx = ctx->cur_co_ctx;
    1889             : 
    1890           0 :     ngx_http_lua_cleanup_pending_operation(coctx);
    1891           0 :     coctx->cleanup = ngx_http_lua_coctx_cleanup;
    1892           0 :     coctx->data = u;
    1893             : 
    1894           0 :     if (ctx->entered_content_phase) {
    1895           0 :         r->write_event_handler = ngx_http_lua_content_wev_handler;
    1896             : 
    1897             :     } else {
    1898           0 :         r->write_event_handler = ngx_http_core_run_phases;
    1899             :     }
    1900             : 
    1901           0 :     u->read_co_ctx = coctx;
    1902           0 :     u->read_waiting = 1;
    1903           0 :     u->read_prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler;
    1904             : 
    1905             :     dd("setting data to %p, coctx:%p", u, coctx);
    1906             : 
    1907           0 :     if (u->raw_downstream || u->body_downstream) {
    1908           0 :         ctx->downstream = u;
    1909             :     }
    1910             : 
    1911           0 :     return lua_yield(L, 0);
    1912             : }
    1913             : 
    1914             : 
    1915             : static ngx_int_t
    1916           0 : ngx_http_lua_socket_read_chunk(void *data, ssize_t bytes)
    1917             : {
    1918           0 :     ngx_http_lua_socket_tcp_upstream_t      *u = data;
    1919             : 
    1920             :     ngx_buf_t                   *b;
    1921             : #if (NGX_DEBUG)
    1922             :     ngx_http_request_t          *r;
    1923             : 
    1924           0 :     r = u->request;
    1925             : #endif
    1926             : 
    1927           0 :     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1928             :                    "lua tcp socket read chunk %z", bytes);
    1929             : 
    1930           0 :     if (bytes == 0) {
    1931           0 :         u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED;
    1932           0 :         return NGX_ERROR;
    1933             :     }
    1934             : 
    1935           0 :     b = &u->buffer;
    1936             : 
    1937           0 :     if (bytes >= (ssize_t) u->rest) {
    1938             : 
    1939           0 :         u->buf_in->buf->last += u->rest;
    1940           0 :         b->pos += u->rest;
    1941           0 :         u->rest = 0;
    1942             : 
    1943           0 :         return NGX_OK;
    1944             :     }
    1945             : 
    1946             :     /* bytes < u->rest */
    1947             : 
    1948           0 :     u->buf_in->buf->last += bytes;
    1949           0 :     b->pos += bytes;
    1950           0 :     u->rest -= bytes;
    1951             : 
    1952           0 :     return NGX_AGAIN;
    1953             : }
    1954             : 
    1955             : 
    1956             : static ngx_int_t
    1957           0 : ngx_http_lua_socket_read_all(void *data, ssize_t bytes)
    1958             : {
    1959           0 :     ngx_http_lua_socket_tcp_upstream_t      *u = data;
    1960             : 
    1961             :     ngx_buf_t                   *b;
    1962             : #if (NGX_DEBUG)
    1963             :     ngx_http_request_t          *r;
    1964             : 
    1965           0 :     r = u->request;
    1966             : #endif
    1967             : 
    1968           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    1969             :                    "lua tcp socket read all");
    1970             : 
    1971           0 :     if (bytes == 0) {
    1972           0 :         return NGX_OK;
    1973             :     }
    1974             : 
    1975           0 :     b = &u->buffer;
    1976             : 
    1977           0 :     u->buf_in->buf->last += bytes;
    1978           0 :     b->pos += bytes;
    1979             : 
    1980           0 :     return NGX_AGAIN;
    1981             : }
    1982             : 
    1983             : 
    1984             : static ngx_int_t
    1985           0 : ngx_http_lua_socket_read_line(void *data, ssize_t bytes)
    1986             : {
    1987           0 :     ngx_http_lua_socket_tcp_upstream_t      *u = data;
    1988             : 
    1989             :     ngx_buf_t                   *b;
    1990             :     u_char                      *dst;
    1991             :     u_char                       c;
    1992             : #if (NGX_DEBUG)
    1993             :     u_char                      *begin;
    1994             : #endif
    1995             : 
    1996           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0,
    1997             :                    "lua tcp socket read line");
    1998             : 
    1999           0 :     if (bytes == 0) {
    2000           0 :         u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED;
    2001           0 :         return NGX_ERROR;
    2002             :     }
    2003             : 
    2004           0 :     b = &u->buffer;
    2005             : 
    2006             : #if (NGX_DEBUG)
    2007           0 :     begin = b->pos;
    2008             : #endif
    2009             : 
    2010             :     dd("already read: %p: %.*s", u->buf_in,
    2011             :        (int) (u->buf_in->buf->last - u->buf_in->buf->pos),
    2012             :        u->buf_in->buf->pos);
    2013             : 
    2014             :     dd("data read: %.*s", (int) bytes, b->pos);
    2015             : 
    2016           0 :     dst = u->buf_in->buf->last;
    2017             : 
    2018           0 :     while (bytes--) {
    2019             : 
    2020           0 :         c = *b->pos++;
    2021             : 
    2022           0 :         switch (c) {
    2023           0 :         case '\n':
    2024           0 :             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0,
    2025             :                            "lua tcp socket read the final line part: \"%*s\"",
    2026             :                            b->pos - 1 - begin, begin);
    2027             : 
    2028           0 :             u->buf_in->buf->last = dst;
    2029             : 
    2030             :             dd("read a line: %p: %.*s", u->buf_in,
    2031             :                (int) (u->buf_in->buf->last - u->buf_in->buf->pos),
    2032             :                u->buf_in->buf->pos);
    2033             : 
    2034           0 :             return NGX_OK;
    2035             : 
    2036           0 :         case '\r':
    2037             :             /* ignore it */
    2038           0 :             break;
    2039             : 
    2040           0 :         default:
    2041           0 :             *dst++ = c;
    2042           0 :             break;
    2043             :         }
    2044             :     }
    2045             : 
    2046             : #if (NGX_DEBUG)
    2047           0 :     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0,
    2048             :                    "lua tcp socket read partial line data: %*s",
    2049             :                    dst - begin, begin);
    2050             : #endif
    2051             : 
    2052           0 :     u->buf_in->buf->last = dst;
    2053             : 
    2054           0 :     return NGX_AGAIN;
    2055             : }
    2056             : 
    2057             : 
    2058             : static ngx_int_t
    2059           0 : ngx_http_lua_socket_tcp_read(ngx_http_request_t *r,
    2060             :     ngx_http_lua_socket_tcp_upstream_t *u)
    2061             : {
    2062             :     ngx_int_t                    rc;
    2063             :     ngx_connection_t            *c;
    2064             :     ngx_buf_t                   *b;
    2065             :     ngx_event_t                 *rev;
    2066             :     size_t                       size;
    2067             :     ssize_t                      n;
    2068             :     unsigned                     read;
    2069           0 :     off_t                        preread = 0;
    2070             :     ngx_http_lua_loc_conf_t     *llcf;
    2071             : 
    2072           0 :     c = u->peer.connection;
    2073           0 :     rev = c->read;
    2074             : 
    2075           0 :     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
    2076             :                    "lua tcp socket read data: wait:%d",
    2077             :                    (int) u->read_waiting);
    2078             : 
    2079           0 :     b = &u->buffer;
    2080           0 :     read = 0;
    2081             : 
    2082             :     for ( ;; ) {
    2083             : 
    2084           0 :         size = b->last - b->pos;
    2085             : 
    2086           0 :         if (size || u->eof) {
    2087             : 
    2088           0 :             rc = u->input_filter(u->input_filter_ctx, size);
    2089             : 
    2090           0 :             if (rc == NGX_OK) {
    2091             : 
    2092           0 :                 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    2093             :                                "lua tcp socket receive done: wait:%d, eof:%d, "
    2094             :                                "uri:\"%V?%V\"", (int) u->read_waiting,
    2095             :                                (int) u->eof, &r->uri, &r->args);
    2096             : 
    2097           0 :                 if (u->body_downstream
    2098           0 :                     && b->last == b->pos
    2099           0 :                     && r->request_body->rest == 0)
    2100             :                 {
    2101             : 
    2102           0 :                     llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
    2103             : 
    2104           0 :                     if (llcf->check_client_abort) {
    2105           0 :                         rc = ngx_http_lua_check_broken_connection(r, rev);
    2106             : 
    2107           0 :                         if (rc == NGX_OK) {
    2108           0 :                             goto success;
    2109             :                         }
    2110             : 
    2111           0 :                         if (rc == NGX_HTTP_CLIENT_CLOSED_REQUEST) {
    2112           0 :                             ngx_http_lua_socket_handle_read_error(r, u,
    2113             :                                           NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT);
    2114             : 
    2115             :                         } else {
    2116           0 :                             ngx_http_lua_socket_handle_read_error(r, u,
    2117             :                                              NGX_HTTP_LUA_SOCKET_FT_ERROR);
    2118             :                         }
    2119             : 
    2120           0 :                         return NGX_ERROR;
    2121             :                     }
    2122             :                 }
    2123             : 
    2124             : #if 1
    2125           0 :                 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
    2126           0 :                     ngx_http_lua_socket_handle_read_error(r, u,
    2127             :                                      NGX_HTTP_LUA_SOCKET_FT_ERROR);
    2128           0 :                     return NGX_ERROR;
    2129             :                 }
    2130             : #endif
    2131             : 
    2132           0 : success:
    2133             : 
    2134           0 :                 ngx_http_lua_socket_handle_read_success(r, u);
    2135           0 :                 return NGX_OK;
    2136             :             }
    2137             : 
    2138           0 :             if (rc == NGX_ERROR) {
    2139             :                 dd("input filter error: ft_type:%d wait:%d",
    2140             :                    (int) u->ft_type, (int) u->read_waiting);
    2141             : 
    2142           0 :                 ngx_http_lua_socket_handle_read_error(r, u,
    2143             :                                                 NGX_HTTP_LUA_SOCKET_FT_ERROR);
    2144           0 :                 return NGX_ERROR;
    2145             :             }
    2146             : 
    2147             :             /* rc == NGX_AGAIN */
    2148             : 
    2149           0 :             if (u->body_downstream && r->request_body->rest == 0) {
    2150           0 :                 u->eof = 1;
    2151             :             }
    2152             : 
    2153           0 :             continue;
    2154             :         }
    2155             : 
    2156           0 :         if (read && !rev->ready) {
    2157           0 :             rc = NGX_AGAIN;
    2158           0 :             break;
    2159             :         }
    2160             : 
    2161           0 :         size = b->end - b->last;
    2162             : 
    2163           0 :         if (size == 0) {
    2164           0 :             rc = ngx_http_lua_socket_add_input_buffer(r, u);
    2165           0 :             if (rc == NGX_ERROR) {
    2166           0 :                 ngx_http_lua_socket_handle_read_error(r, u,
    2167             :                                                 NGX_HTTP_LUA_SOCKET_FT_NOMEM);
    2168             : 
    2169           0 :                 return NGX_ERROR;
    2170             :             }
    2171             : 
    2172           0 :             b = &u->buffer;
    2173           0 :             size = (size_t) (b->end - b->last);
    2174             :         }
    2175             : 
    2176           0 :         if (u->raw_downstream) {
    2177           0 :             preread = r->header_in->last - r->header_in->pos;
    2178             : 
    2179           0 :             if (preread) {
    2180             : 
    2181           0 :                 if ((off_t) size > preread) {
    2182           0 :                     size = (size_t) preread;
    2183             :                 }
    2184             : 
    2185             :                 ngx_http_lua_probe_req_socket_consume_preread(r,
    2186             :                                                               r->header_in->pos,
    2187             :                                                               size);
    2188             : 
    2189           0 :                 b->last = ngx_copy(b->last, r->header_in->pos, size);
    2190           0 :                 r->header_in->pos += size;
    2191           0 :                 continue;
    2192             :             }
    2193             : 
    2194           0 :         } else if (u->body_downstream) {
    2195             : 
    2196           0 :             if (r->request_body->rest == 0) {
    2197             : 
    2198             :                 dd("request body rest is zero");
    2199             : 
    2200           0 :                 u->eof = 1;
    2201             : 
    2202           0 :                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    2203             :                                "lua request body exhausted");
    2204             : 
    2205           0 :                 continue;
    2206             :             }
    2207             : 
    2208             :             /* try to process the preread body */
    2209             : 
    2210           0 :             preread = r->header_in->last - r->header_in->pos;
    2211             : 
    2212           0 :             if (preread) {
    2213             : 
    2214             :                 /* there is the pre-read part of the request body */
    2215             : 
    2216           0 :                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    2217             :                                "http client request body preread %O", preread);
    2218             : 
    2219           0 :                 if (preread >= r->request_body->rest) {
    2220           0 :                     preread = r->request_body->rest;
    2221             :                 }
    2222             : 
    2223           0 :                 if ((off_t) size > preread) {
    2224           0 :                     size = (size_t) preread;
    2225             :                 }
    2226             : 
    2227             :                 ngx_http_lua_probe_req_socket_consume_preread(r,
    2228             :                                                               r->header_in->pos,
    2229             :                                                               size);
    2230             : 
    2231           0 :                 b->last = ngx_copy(b->last, r->header_in->pos, size);
    2232             : 
    2233           0 :                 r->header_in->pos += size;
    2234           0 :                 r->request_length += size;
    2235             : 
    2236           0 :                 if (r->request_body->rest) {
    2237           0 :                     r->request_body->rest -= size;
    2238             :                 }
    2239             : 
    2240           0 :                 continue;
    2241             :             }
    2242             : 
    2243           0 :             if (size > (size_t) r->request_body->rest) {
    2244           0 :                 size = (size_t) r->request_body->rest;
    2245             :             }
    2246             :         }
    2247             : 
    2248             : #if 1
    2249           0 :         if (rev->active && !rev->ready) {
    2250           0 :             rc = NGX_AGAIN;
    2251           0 :             break;
    2252             :         }
    2253             : #endif
    2254             : 
    2255           0 :         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    2256             :                        "lua tcp socket try to recv data %uz: \"%V?%V\"",
    2257             :                        size, &r->uri, &r->args);
    2258             : 
    2259           0 :         n = c->recv(c, b->last, size);
    2260             : 
    2261             :         dd("read event ready: %d", (int) c->read->ready);
    2262             : 
    2263           0 :         read = 1;
    2264             : 
    2265           0 :         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    2266             :                        "lua tcp socket recv returned %d: \"%V?%V\"",
    2267             :                        (int) n, &r->uri, &r->args);
    2268             : 
    2269           0 :         if (n == NGX_AGAIN) {
    2270           0 :             rc = NGX_AGAIN;
    2271             :             dd("socket recv busy");
    2272           0 :             break;
    2273             :         }
    2274             : 
    2275           0 :         if (n == 0) {
    2276             : 
    2277           0 :             if (u->raw_downstream || u->body_downstream) {
    2278             : 
    2279           0 :                 llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
    2280             : 
    2281           0 :                 if (llcf->check_client_abort) {
    2282             : 
    2283           0 :                     ngx_http_lua_socket_handle_read_error(r, u,
    2284             :                                           NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT);
    2285           0 :                     return NGX_ERROR;
    2286             :                 }
    2287             : 
    2288             :                 /* llcf->check_client_abort == 0 */
    2289             : 
    2290           0 :                 if (u->body_downstream && r->request_body->rest) {
    2291           0 :                     ngx_http_lua_socket_handle_read_error(r, u,
    2292             :                                           NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT);
    2293           0 :                     return NGX_ERROR;
    2294             :                 }
    2295             :             }
    2296             : 
    2297           0 :             u->eof = 1;
    2298             : 
    2299           0 :             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    2300             :                            "lua tcp socket closed");
    2301             : 
    2302           0 :             continue;
    2303             :         }
    2304             : 
    2305           0 :         if (n == NGX_ERROR) {
    2306           0 :             u->socket_errno = ngx_socket_errno;
    2307           0 :             ngx_http_lua_socket_handle_read_error(r, u,
    2308             :                                                   NGX_HTTP_LUA_SOCKET_FT_ERROR);
    2309           0 :             return NGX_ERROR;
    2310             :         }
    2311             : 
    2312           0 :         b->last += n;
    2313             : 
    2314           0 :         if (u->body_downstream) {
    2315           0 :             r->request_length += n;
    2316           0 :             r->request_body->rest -= n;
    2317             :         }
    2318             :     }
    2319             : 
    2320             : #if 1
    2321           0 :     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
    2322           0 :         ngx_http_lua_socket_handle_read_error(r, u,
    2323             :                                               NGX_HTTP_LUA_SOCKET_FT_ERROR);
    2324           0 :         return NGX_ERROR;
    2325             :     }
    2326             : #endif
    2327             : 
    2328           0 :     if (rev->active) {
    2329           0 :         ngx_add_timer(rev, u->read_timeout);
    2330             : 
    2331           0 :     } else if (rev->timer_set) {
    2332           0 :         ngx_del_timer(rev);
    2333             :     }
    2334             : 
    2335           0 :     return rc;
    2336             : }
    2337             : 
    2338             : 
    2339             : static int
    2340           1 : ngx_http_lua_socket_tcp_send(lua_State *L)
    2341             : {
    2342             :     ngx_int_t                            rc;
    2343             :     ngx_http_request_t                  *r;
    2344             :     u_char                              *p;
    2345             :     size_t                               len;
    2346             :     ngx_chain_t                         *cl;
    2347             :     ngx_http_lua_ctx_t                  *ctx;
    2348             :     ngx_http_lua_socket_tcp_upstream_t  *u;
    2349             :     int                                  type;
    2350             :     int                                  tcp_nodelay;
    2351             :     const char                          *msg;
    2352             :     ngx_buf_t                           *b;
    2353             :     ngx_connection_t                    *c;
    2354             :     ngx_http_lua_loc_conf_t             *llcf;
    2355             :     ngx_http_core_loc_conf_t            *clcf;
    2356             :     ngx_http_lua_co_ctx_t               *coctx;
    2357             : 
    2358             :     /* TODO: add support for the optional "i" and "j" arguments */
    2359             : 
    2360           1 :     if (lua_gettop(L) != 2) {
    2361           0 :         return luaL_error(L, "expecting 2 arguments (including the object), "
    2362             :                           "but got %d", lua_gettop(L));
    2363             :     }
    2364             : 
    2365           1 :     r = ngx_http_lua_get_req(L);
    2366           1 :     if (r == NULL) {
    2367           0 :         return luaL_error(L, "no request found");
    2368             :     }
    2369             : 
    2370           1 :     luaL_checktype(L, 1, LUA_TTABLE);
    2371             : 
    2372           1 :     lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
    2373           1 :     u = lua_touserdata(L, -1);
    2374           1 :     lua_pop(L, 1);
    2375             : 
    2376             :     dd("tcp send: u=%p, u->write_closed=%d", u, (unsigned) u->write_closed);
    2377             : 
    2378           1 :     if (u == NULL || u->peer.connection == NULL || u->write_closed) {
    2379           0 :         llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
    2380             : 
    2381           0 :         if (llcf->log_socket_errors) {
    2382           0 :             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
    2383             :                           "attempt to send data on a closed socket: u:%p, "
    2384             :                           "c:%p, ft:%d eof:%d",
    2385             :                           u, u ? u->peer.connection : NULL,
    2386             :                           u ? (int) u->ft_type : 0, u ? (int) u->eof : 0);
    2387             :         }
    2388             : 
    2389           0 :         lua_pushnil(L);
    2390           0 :         lua_pushliteral(L, "closed");
    2391           0 :         return 2;
    2392             :     }
    2393             : 
    2394           1 :     if (u->request != r) {
    2395           0 :         return luaL_error(L, "bad request");
    2396             :     }
    2397             : 
    2398           1 :     ngx_http_lua_socket_check_busy_connecting(r, u, L);
    2399           1 :     ngx_http_lua_socket_check_busy_writing(r, u, L);
    2400             : 
    2401           1 :     if (u->body_downstream) {
    2402           0 :         return luaL_error(L, "attempt to write to request sockets");
    2403             :     }
    2404             : 
    2405           1 :     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    2406             :                    "lua tcp socket send timeout: %M", u->send_timeout);
    2407             : 
    2408           1 :     type = lua_type(L, 2);
    2409           1 :     switch (type) {
    2410           1 :         case LUA_TNUMBER:
    2411             :         case LUA_TSTRING:
    2412           1 :             lua_tolstring(L, 2, &len);
    2413           1 :             break;
    2414             : 
    2415           0 :         case LUA_TTABLE:
    2416           0 :             len = ngx_http_lua_calc_strlen_in_table(L, 2, 2, 1 /* strict */);
    2417           0 :             break;
    2418             : 
    2419           0 :         default:
    2420           0 :             msg = lua_pushfstring(L, "string, number, boolean, nil, "
    2421             :                                   "or array table expected, got %s",
    2422             :                                   lua_typename(L, type));
    2423             : 
    2424           0 :             return luaL_argerror(L, 2, msg);
    2425             :     }
    2426             : 
    2427           1 :     if (len == 0) {
    2428           0 :         lua_pushinteger(L, 0);
    2429           0 :         return 1;
    2430             :     }
    2431             : 
    2432           1 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    2433             : 
    2434           1 :     cl = ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool,
    2435             :                                          &ctx->free_bufs, len);
    2436             : 
    2437           1 :     if (cl == NULL) {
    2438           0 :         return luaL_error(L, "no memory");
    2439             :     }
    2440             : 
    2441           1 :     b = cl->buf;
    2442             : 
    2443           1 :     switch (type) {
    2444           1 :         case LUA_TNUMBER:
    2445             :         case LUA_TSTRING:
    2446           1 :             p = (u_char *) lua_tolstring(L, -1, &len);
    2447           1 :             b->last = ngx_copy(b->last, (u_char *) p, len);
    2448           1 :             break;
    2449             : 
    2450           0 :         case LUA_TTABLE:
    2451           0 :             b->last = ngx_http_lua_copy_str_in_table(L, -1, b->last);
    2452           0 :             break;
    2453             : 
    2454           0 :         default:
    2455           0 :             return luaL_error(L, "impossible to reach here");
    2456             :     }
    2457             : 
    2458           1 :     u->request_bufs = cl;
    2459             : 
    2460           1 :     u->request_len = len;
    2461             : 
    2462             :     /* mimic ngx_http_upstream_init_request here */
    2463             : 
    2464           1 :     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
    2465           1 :     c = u->peer.connection;
    2466             : 
    2467           1 :     if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
    2468           1 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
    2469             :                        "lua socket tcp_nodelay");
    2470             : 
    2471           1 :         tcp_nodelay = 1;
    2472             : 
    2473           1 :         if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
    2474             :                        (const void *) &tcp_nodelay, sizeof(int))
    2475             :             == -1)
    2476             :         {
    2477           0 :             llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
    2478           0 :             if (llcf->log_socket_errors) {
    2479           0 :                 ngx_connection_error(c, ngx_socket_errno,
    2480             :                                      "setsockopt(TCP_NODELAY) "
    2481             :                                      "failed");
    2482             :             }
    2483             : 
    2484           0 :             lua_pushnil(L);
    2485           0 :             lua_pushliteral(L, "setsocketopt tcp_nodelay failed");
    2486           0 :             return 2;
    2487             :         }
    2488             : 
    2489           1 :         c->tcp_nodelay = NGX_TCP_NODELAY_SET;
    2490             :     }
    2491             : 
    2492             : #if 1
    2493           1 :     u->write_waiting = 0;
    2494           1 :     u->write_co_ctx = NULL;
    2495             : #endif
    2496             : 
    2497             :     ngx_http_lua_probe_socket_tcp_send_start(r, u, b->pos, len);
    2498             : 
    2499           1 :     rc = ngx_http_lua_socket_send(r, u);
    2500             : 
    2501             :     dd("socket send returned %d", (int) rc);
    2502             : 
    2503           1 :     if (rc == NGX_ERROR) {
    2504           0 :         return ngx_http_lua_socket_write_error_retval_handler(r, u, L);
    2505             :     }
    2506             : 
    2507           1 :     if (rc == NGX_OK) {
    2508           1 :         lua_pushinteger(L, len);
    2509           1 :         return 1;
    2510             :     }
    2511             : 
    2512             :     /* rc == NGX_AGAIN */
    2513             : 
    2514           0 :     coctx = ctx->cur_co_ctx;
    2515             : 
    2516           0 :     ngx_http_lua_cleanup_pending_operation(coctx);
    2517           0 :     coctx->cleanup = ngx_http_lua_coctx_cleanup;
    2518           0 :     coctx->data = u;
    2519             : 
    2520           0 :     if (u->raw_downstream) {
    2521           0 :         ctx->writing_raw_req_socket = 1;
    2522             :     }
    2523             : 
    2524           0 :     if (ctx->entered_content_phase) {
    2525           0 :         r->write_event_handler = ngx_http_lua_content_wev_handler;
    2526             : 
    2527             :     } else {
    2528           0 :         r->write_event_handler = ngx_http_core_run_phases;
    2529             :     }
    2530             : 
    2531           0 :     u->write_co_ctx = coctx;
    2532           0 :     u->write_waiting = 1;
    2533           0 :     u->write_prepare_retvals = ngx_http_lua_socket_tcp_send_retval_handler;
    2534             : 
    2535             :     dd("setting data to %p", u);
    2536             : 
    2537           0 :     return lua_yield(L, 0);
    2538             : }
    2539             : 
    2540             : 
    2541             : static int
    2542           0 : ngx_http_lua_socket_tcp_send_retval_handler(ngx_http_request_t *r,
    2543             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L)
    2544             : {
    2545           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    2546             :                    "lua tcp socket send return value handler");
    2547             : 
    2548           0 :     if (u->ft_type) {
    2549           0 :         return ngx_http_lua_socket_write_error_retval_handler(r, u, L);
    2550             :     }
    2551             : 
    2552           0 :     lua_pushinteger(L, u->request_len);
    2553           0 :     return 1;
    2554             : }
    2555             : 
    2556             : 
    2557             : static int
    2558           0 : ngx_http_lua_socket_tcp_receive_retval_handler(ngx_http_request_t *r,
    2559             :     ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L)
    2560             : {
    2561             :     int                          n;
    2562             :     ngx_int_t                    rc;
    2563             :     ngx_http_lua_ctx_t          *ctx;
    2564             :     ngx_event_t                 *ev;
    2565             : 
    2566             :     ngx_http_lua_loc_conf_t             *llcf;
    2567             : 
    2568           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    2569             :                    "lua tcp socket receive return value handler");
    2570             : 
    2571           0 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    2572             : 
    2573             : #if 1
    2574           0 :     if (u->raw_downstream || u->body_downstream) {
    2575           0 :         llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
    2576             : 
    2577           0 :         if (llcf->check_client_abort) {
    2578             : 
    2579           0 :             r->read_event_handler = ngx_http_lua_rd_check_broken_connection;
    2580             : 
    2581           0 :             ev = r->connection->read;
    2582             : 
    2583             :             dd("rev active: %d", ev->active);
    2584             : 
    2585           0 :             if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && !ev->active) {
    2586           0 :                 if (ngx_add_event(ev, NGX_READ_EVENT, 0) != NGX_OK) {
    2587           0 :                     lua_pushnil(L);
    2588           0 :                     lua_pushliteral(L, "failed to add event");
    2589           0 :                     return 2;
    2590             :                 }
    2591             :             }
    2592             : 
    2593             :         } else {
    2594             :             /* llcf->check_client_abort == 0 */
    2595           0 :             r->read_event_handler = ngx_http_block_reading;
    2596             :         }
    2597             :     }
    2598             : #endif
    2599             : 
    2600           0 :     if (u->ft_type) {
    2601             : 
    2602           0 :         if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_TIMEOUT) {
    2603           0 :             u->no_close = 1;
    2604             :         }
    2605             : 
    2606             :         dd("u->bufs_in: %p", u->bufs_in);
    2607             : 
    2608           0 :         if (u->bufs_in) {
    2609           0 :             rc = ngx_http_lua_socket_push_input_data(r, ctx, u, L);
    2610           0 :             if (rc == NGX_ERROR) {
    2611           0 :                 lua_pushnil(L);
    2612           0 :                 lua_pushliteral(L, "no memory");
    2613           0 :                 return 2;
    2614             :             }
    2615             : 
    2616           0 :             (void) ngx_http_lua_socket_read_error_retval_handler(r, u, L);
    2617             : 
    2618           0 :             lua_pushvalue(L, -3);
    2619           0 :             lua_remove(L, -4);
    2620           0 :             return 3;
    2621             :         }
    2622             : 
    2623           0 :         n = ngx_http_lua_socket_read_error_retval_handler(r, u, L);
    2624           0 :         lua_pushliteral(L, "");
    2625           0 :         return n + 1;
    2626             :     }
    2627             : 
    2628           0 :     rc = ngx_http_lua_socket_push_input_data(r, ctx, u, L);
    2629           0 :     if (rc == NGX_ERROR) {
    2630           0 :         lua_pushnil(L);
    2631           0 :         lua_pushliteral(L, "no memory");
    2632           0 :         return 2;
    2633             :     }
    2634             : 
    2635           0 :     return 1;
    2636             : }
    2637             : 
    2638             : 
    2639             : static int
    2640           1 : ngx_http_lua_socket_tcp_close(lua_State *L)
    2641             : {
    2642             :     ngx_http_request_t                  *r;
    2643             :     ngx_http_lua_socket_tcp_upstream_t  *u;
    2644             : 
    2645           1 :     if (lua_gettop(L) != 1) {
    2646           0 :         return luaL_error(L, "expecting 1 argument "
    2647             :                           "(including the object) but seen %d", lua_gettop(L));
    2648             :     }
    2649             : 
    2650           1 :     r = ngx_http_lua_get_req(L);
    2651           1 :     if (r == NULL) {
    2652           0 :         return luaL_error(L, "no request found");
    2653             :     }
    2654             : 
    2655           1 :     luaL_checktype(L, 1, LUA_TTABLE);
    2656             : 
    2657           1 :     lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
    2658           1 :     u = lua_touserdata(L, -1);
    2659           1 :     lua_pop(L, 1);
    2660             : 
    2661           1 :     if (u == NULL
    2662           1 :         || u->peer.connection == NULL
    2663           1 :         || (u->read_closed && u->write_closed))
    2664             :     {
    2665           0 :         lua_pushnil(L);
    2666           0 :         lua_pushliteral(L, "closed");
    2667           0 :         return 2;
    2668             :     }
    2669             : 
    2670           1 :     if (u->request != r) {
    2671           0 :         return luaL_error(L, "bad request");
    2672             :     }
    2673             : 
    2674           1 :     ngx_http_lua_socket_check_busy_connecting(r, u, L);
    2675           1 :     ngx_http_lua_socket_check_busy_reading(r, u, L);
    2676           1 :     ngx_http_lua_socket_check_busy_writing(r, u, L);
    2677             : 
    2678           1 :     if (u->raw_downstream || u->body_downstream) {
    2679           0 :         lua_pushnil(L);
    2680           0 :         lua_pushliteral(L, "attempt to close a request socket");
    2681           0 :         return 2;
    2682             :     }
    2683             : 
    2684           1 :     ngx_http_lua_socket_tcp_finalize(r, u);
    2685             : 
    2686           1 :     lua_pushinteger(L, 1);
    2687           1 :     return 1;
    2688             : }
    2689             : 
    2690             : 
    2691             : static int
    2692           0 : ngx_http_lua_socket_tcp_setoption(lua_State *L)
    2693             : {
    2694             :     /* TODO */
    2695           0 :     return 0;
    2696             : }
    2697             : 
    2698             : 
    2699             : static int
    2700           0 : ngx_http_lua_socket_tcp_settimeout(lua_State *L)
    2701             : {
    2702             :     int                     n;
    2703             :     ngx_int_t               timeout;
    2704             : 
    2705             :     ngx_http_lua_socket_tcp_upstream_t  *u;
    2706             : 
    2707           0 :     n = lua_gettop(L);
    2708             : 
    2709           0 :     if (n != 2) {
    2710           0 :         return luaL_error(L, "ngx.socket settimout: expecting 2 arguments "
    2711             :                           "(including the object) but seen %d", lua_gettop(L));
    2712             :     }
    2713             : 
    2714           0 :     timeout = (ngx_int_t) lua_tonumber(L, 2);
    2715           0 :     if (timeout >> 31) {
    2716           0 :         return luaL_error(L, "bad timeout value");
    2717             :     }
    2718             : 
    2719           0 :     lua_pushinteger(L, timeout);
    2720           0 :     lua_pushinteger(L, timeout);
    2721             : 
    2722           0 :     lua_rawseti(L, 1, SOCKET_CONNECT_TIMEOUT_INDEX);
    2723           0 :     lua_rawseti(L, 1, SOCKET_SEND_TIMEOUT_INDEX);
    2724           0 :     lua_rawseti(L, 1, SOCKET_READ_TIMEOUT_INDEX);
    2725             : 
    2726           0 :     lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
    2727           0 :     u = lua_touserdata(L, -1);
    2728             : 
    2729           0 :     if (u) {
    2730           0 :         if (timeout > 0) {
    2731           0 :             u->read_timeout = (ngx_msec_t) timeout;
    2732           0 :             u->send_timeout = (ngx_msec_t) timeout;
    2733           0 :             u->connect_timeout = (ngx_msec_t) timeout;
    2734             : 
    2735             :         } else {
    2736           0 :             u->read_timeout = u->conf->read_timeout;
    2737           0 :             u->send_timeout = u->conf->send_timeout;
    2738           0 :             u->connect_timeout = u->conf->connect_timeout;
    2739             :         }
    2740             :     }
    2741             : 
    2742           0 :     return 0;
    2743             : }
    2744             : 
    2745             : 
    2746             : static int
    2747           0 : ngx_http_lua_socket_tcp_settimeouts(lua_State *L)
    2748             : {
    2749             :     int                     n;
    2750             :     ngx_int_t               connect_timeout, send_timeout, read_timeout;
    2751             : 
    2752             :     ngx_http_lua_socket_tcp_upstream_t  *u;
    2753             : 
    2754           0 :     n = lua_gettop(L);
    2755             : 
    2756           0 :     if (n != 4) {
    2757           0 :         return luaL_error(L, "ngx.socket settimout: expecting 4 arguments "
    2758             :                           "(including the object) but seen %d", lua_gettop(L));
    2759             :     }
    2760             : 
    2761           0 :     connect_timeout = (ngx_int_t) lua_tonumber(L, 2);
    2762           0 :     if (connect_timeout >> 31) {
    2763           0 :         return luaL_error(L, "bad timeout value");
    2764             :     }
    2765             : 
    2766           0 :     send_timeout = (ngx_int_t) lua_tonumber(L, 3);
    2767           0 :     if (send_timeout >> 31) {
    2768           0 :         return luaL_error(L, "bad timeout value");
    2769             :     }
    2770             : 
    2771           0 :     read_timeout = (ngx_int_t) lua_tonumber(L, 4);
    2772           0 :     if (read_timeout >> 31) {
    2773           0 :         return luaL_error(L, "bad timeout value");
    2774             :     }
    2775             : 
    2776           0 :     lua_rawseti(L, 1, SOCKET_READ_TIMEOUT_INDEX);
    2777           0 :     lua_rawseti(L, 1, SOCKET_SEND_TIMEOUT_INDEX);
    2778           0 :     lua_rawseti(L, 1, SOCKET_CONNECT_TIMEOUT_INDEX);
    2779             : 
    2780           0 :     lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
    2781           0 :     u = lua_touserdata(L, -1);
    2782             : 
    2783           0 :     if (u) {
    2784           0 :         if (connect_timeout > 0) {
    2785           0 :             u->connect_timeout = (ngx_msec_t) connect_timeout;
    2786             : 
    2787             :         } else {
    2788           0 :             u->connect_timeout = u->conf->connect_timeout;
    2789             :         }
    2790             : 
    2791           0 :         if (send_timeout > 0) {
    2792           0 :             u->send_timeout = (ngx_msec_t) send_timeout;
    2793             : 
    2794             :         } else {
    2795           0 :             u->send_timeout = u->conf->send_timeout;
    2796             :         }
    2797             : 
    2798           0 :         if (read_timeout > 0) {
    2799           0 :             u->read_timeout = (ngx_msec_t) read_timeout;
    2800             : 
    2801             :         } else {
    2802           0 :             u->read_timeout = u->conf->read_timeout;
    2803             :         }
    2804             :     }
    2805             : 
    2806           0 :     return 0;
    2807             : }
    2808             : 
    2809             : 
    2810             : static void
    2811           1 : ngx_http_lua_socket_tcp_handler(ngx_event_t *ev)
    2812             : {
    2813             :     ngx_connection_t                *c;
    2814             :     ngx_http_request_t              *r;
    2815             :     ngx_http_log_ctx_t              *ctx;
    2816             : 
    2817             :     ngx_http_lua_socket_tcp_upstream_t  *u;
    2818             : 
    2819           1 :     c = ev->data;
    2820           1 :     u = c->data;
    2821           1 :     r = u->request;
    2822           1 :     c = r->connection;
    2823             : 
    2824           1 :     if (c->fd != (ngx_socket_t) -1) {  /* not a fake connection */
    2825           1 :         ctx = c->log->data;
    2826           1 :         ctx->current_request = r;
    2827             :     }
    2828             : 
    2829           1 :     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
    2830             :                    "lua tcp socket handler for \"%V?%V\", wev %d", &r->uri,
    2831             :                    &r->args, (int) ev->write);
    2832             : 
    2833           1 :     if (ev->write) {
    2834           1 :         u->write_event_handler(r, u);
    2835             : 
    2836             :     } else {
    2837           0 :         u->read_event_handler(r, u);
    2838             :     }
    2839             : 
    2840           1 :     ngx_http_run_posted_requests(c);
    2841           1 : }
    2842             : 
    2843             : 
    2844             : static ngx_int_t
    2845           1 : ngx_http_lua_socket_tcp_get_peer(ngx_peer_connection_t *pc, void *data)
    2846             : {
    2847             :     /* empty */
    2848           1 :     return NGX_OK;
    2849             : }
    2850             : 
    2851             : 
    2852             : static void
    2853           0 : ngx_http_lua_socket_read_handler(ngx_http_request_t *r,
    2854             :     ngx_http_lua_socket_tcp_upstream_t *u)
    2855             : {
    2856             :     ngx_connection_t            *c;
    2857             :     ngx_http_lua_loc_conf_t     *llcf;
    2858             : 
    2859           0 :     c = u->peer.connection;
    2860             : 
    2861           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    2862             :                    "lua tcp socket read handler");
    2863             : 
    2864           0 :     if (c->read->timedout) {
    2865           0 :         c->read->timedout = 0;
    2866             : 
    2867           0 :         llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
    2868             : 
    2869           0 :         if (llcf->log_socket_errors) {
    2870           0 :             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
    2871             :                           "lua tcp socket read timed out");
    2872             :         }
    2873             : 
    2874           0 :         ngx_http_lua_socket_handle_read_error(r, u,
    2875             :                                               NGX_HTTP_LUA_SOCKET_FT_TIMEOUT);
    2876           0 :         return;
    2877             :     }
    2878             : 
    2879             : #if 1
    2880           0 :     if (c->read->timer_set) {
    2881           0 :         ngx_del_timer(c->read);
    2882             :     }
    2883             : #endif
    2884             : 
    2885           0 :     if (u->buffer.start != NULL) {
    2886           0 :         (void) ngx_http_lua_socket_tcp_read(r, u);
    2887             :     }
    2888             : }
    2889             : 
    2890             : 
    2891             : static void
    2892           0 : ngx_http_lua_socket_send_handler(ngx_http_request_t *r,
    2893             :     ngx_http_lua_socket_tcp_upstream_t *u)
    2894             : {
    2895             :     ngx_connection_t            *c;
    2896             :     ngx_http_lua_loc_conf_t     *llcf;
    2897             : 
    2898           0 :     c = u->peer.connection;
    2899             : 
    2900           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    2901             :                    "lua tcp socket send handler");
    2902             : 
    2903           0 :     if (c->write->timedout) {
    2904           0 :         llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
    2905             : 
    2906           0 :         if (llcf->log_socket_errors) {
    2907           0 :             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
    2908             :                           "lua tcp socket write timed out");
    2909             :         }
    2910             : 
    2911           0 :         ngx_http_lua_socket_handle_write_error(r, u,
    2912             :                                                NGX_HTTP_LUA_SOCKET_FT_TIMEOUT);
    2913           0 :         return;
    2914             :     }
    2915             : 
    2916           0 :     if (u->request_bufs) {
    2917           0 :         (void) ngx_http_lua_socket_send(r, u);
    2918             :     }
    2919             : }
    2920             : 
    2921             : 
    2922             : static ngx_int_t
    2923           1 : ngx_http_lua_socket_send(ngx_http_request_t *r,
    2924             :     ngx_http_lua_socket_tcp_upstream_t *u)
    2925             : {
    2926             :     ngx_int_t                    n;
    2927             :     ngx_connection_t            *c;
    2928             :     ngx_http_lua_ctx_t          *ctx;
    2929             :     ngx_buf_t                   *b;
    2930             : 
    2931           1 :     c = u->peer.connection;
    2932             : 
    2933           1 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    2934             :                    "lua tcp socket send data");
    2935             : 
    2936           1 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    2937           1 :     if (ctx == NULL) {
    2938           0 :         ngx_http_lua_socket_handle_write_error(r, u,
    2939             :                                                NGX_HTTP_LUA_SOCKET_FT_ERROR);
    2940           0 :         return NGX_ERROR;
    2941             :     }
    2942             : 
    2943           1 :     b = u->request_bufs->buf;
    2944             : 
    2945             :     for (;;) {
    2946           1 :         n = c->send(c, b->pos, b->last - b->pos);
    2947             : 
    2948           1 :         if (n >= 0) {
    2949           1 :             b->pos += n;
    2950             : 
    2951           1 :             if (b->pos == b->last) {
    2952           1 :                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
    2953             :                                "lua tcp socket sent all the data");
    2954             : 
    2955           1 :                 if (c->write->timer_set) {
    2956           0 :                     ngx_del_timer(c->write);
    2957             :                 }
    2958             : 
    2959             : 
    2960             : #if defined(nginx_version) && nginx_version >= 1001004
    2961           1 :                 ngx_chain_update_chains(r->pool,
    2962             : #else
    2963             :                 ngx_chain_update_chains(
    2964             : #endif
    2965             :                                         &ctx->free_bufs, &ctx->busy_bufs,
    2966             :                                         &u->request_bufs,
    2967             :                                         (ngx_buf_tag_t) &ngx_http_lua_module);
    2968             : 
    2969           1 :                 u->write_event_handler = ngx_http_lua_socket_dummy_handler;
    2970             : 
    2971           1 :                 if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
    2972           0 :                     ngx_http_lua_socket_handle_write_error(r, u,
    2973             :                                                 NGX_HTTP_LUA_SOCKET_FT_ERROR);
    2974           0 :                     return NGX_ERROR;
    2975             :                 }
    2976             : 
    2977           1 :                 ngx_http_lua_socket_handle_write_success(r, u);
    2978           1 :                 return NGX_OK;
    2979             :             }
    2980             : 
    2981             :             /* keep sending more data */
    2982           0 :             continue;
    2983             :         }
    2984             : 
    2985             :         /* NGX_ERROR || NGX_AGAIN */
    2986           0 :         break;
    2987             :     }
    2988             : 
    2989           0 :     if (n == NGX_ERROR) {
    2990           0 :         c->error = 1;
    2991           0 :         u->socket_errno = ngx_socket_errno;
    2992           0 :         ngx_http_lua_socket_handle_write_error(r, u,
    2993             :                                                NGX_HTTP_LUA_SOCKET_FT_ERROR);
    2994           0 :         return NGX_ERROR;
    2995             :     }
    2996             : 
    2997             :     /* n == NGX_AGAIN */
    2998             : 
    2999           0 :     if (u->raw_downstream) {
    3000           0 :         ctx->writing_raw_req_socket = 1;
    3001             :     }
    3002             : 
    3003           0 :     u->write_event_handler = ngx_http_lua_socket_send_handler;
    3004             : 
    3005           0 :     ngx_add_timer(c->write, u->send_timeout);
    3006             : 
    3007           0 :     if (ngx_handle_write_event(c->write, u->conf->send_lowat) != NGX_OK) {
    3008           0 :         ngx_http_lua_socket_handle_write_error(r, u,
    3009             :                                                NGX_HTTP_LUA_SOCKET_FT_ERROR);
    3010           0 :         return NGX_ERROR;
    3011             :     }
    3012             : 
    3013           0 :     return NGX_AGAIN;
    3014             : }
    3015             : 
    3016             : 
    3017             : static void
    3018           1 : ngx_http_lua_socket_handle_conn_success(ngx_http_request_t *r,
    3019             :     ngx_http_lua_socket_tcp_upstream_t *u)
    3020             : {
    3021             :     ngx_http_lua_ctx_t          *ctx;
    3022             :     ngx_http_lua_co_ctx_t       *coctx;
    3023             : 
    3024             : #if 1
    3025           1 :     u->read_event_handler = ngx_http_lua_socket_dummy_handler;
    3026           1 :     u->write_event_handler = ngx_http_lua_socket_dummy_handler;
    3027             : #endif
    3028             : 
    3029           1 :     if (u->conn_waiting) {
    3030           1 :         u->conn_waiting = 0;
    3031             : 
    3032           1 :         coctx = u->write_co_ctx;
    3033           1 :         coctx->cleanup = NULL;
    3034           1 :         u->write_co_ctx = NULL;
    3035             : 
    3036           1 :         ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    3037           1 :         if (ctx == NULL) {
    3038           0 :             return;
    3039             :         }
    3040             : 
    3041           1 :         ctx->resume_handler = ngx_http_lua_socket_tcp_conn_resume;
    3042           1 :         ctx->cur_co_ctx = coctx;
    3043             : 
    3044           1 :         ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx)
    3045             :                             || coctx->co_ref >= 0));
    3046             : 
    3047           1 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3048             :                        "lua tcp socket waking up the current request (conn)");
    3049             : 
    3050           1 :         r->write_event_handler(r);
    3051             :     }
    3052             : }
    3053             : 
    3054             : 
    3055             : static void
    3056           0 : ngx_http_lua_socket_handle_read_success(ngx_http_request_t *r,
    3057             :     ngx_http_lua_socket_tcp_upstream_t *u)
    3058             : {
    3059             :     ngx_http_lua_ctx_t          *ctx;
    3060             :     ngx_http_lua_co_ctx_t       *coctx;
    3061             : 
    3062             : #if 1
    3063           0 :     u->read_event_handler = ngx_http_lua_socket_dummy_handler;
    3064             : #endif
    3065             : 
    3066           0 :     if (u->read_waiting) {
    3067           0 :         u->read_waiting = 0;
    3068             : 
    3069           0 :         coctx = u->read_co_ctx;
    3070           0 :         coctx->cleanup = NULL;
    3071           0 :         u->read_co_ctx = NULL;
    3072             : 
    3073           0 :         ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    3074           0 :         if (ctx == NULL) {
    3075           0 :             return;
    3076             :         }
    3077             : 
    3078           0 :         ctx->resume_handler = ngx_http_lua_socket_tcp_read_resume;
    3079           0 :         ctx->cur_co_ctx = coctx;
    3080             : 
    3081           0 :         ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx)
    3082             :                             || coctx->co_ref >= 0));
    3083             : 
    3084           0 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3085             :                        "lua tcp socket waking up the current request (read)");
    3086             : 
    3087           0 :         r->write_event_handler(r);
    3088             :     }
    3089             : }
    3090             : 
    3091             : 
    3092             : static void
    3093           1 : ngx_http_lua_socket_handle_write_success(ngx_http_request_t *r,
    3094             :     ngx_http_lua_socket_tcp_upstream_t *u)
    3095             : {
    3096             :     ngx_http_lua_ctx_t          *ctx;
    3097             :     ngx_http_lua_co_ctx_t       *coctx;
    3098             : 
    3099             : #if 1
    3100           1 :     u->write_event_handler = ngx_http_lua_socket_dummy_handler;
    3101             : #endif
    3102             : 
    3103           1 :     if (u->write_waiting) {
    3104           0 :         u->write_waiting = 0;
    3105             : 
    3106           0 :         coctx = u->write_co_ctx;
    3107           0 :         coctx->cleanup = NULL;
    3108           0 :         u->write_co_ctx = NULL;
    3109             : 
    3110           0 :         ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    3111           0 :         if (ctx == NULL) {
    3112           0 :             return;
    3113             :         }
    3114             : 
    3115           0 :         ctx->resume_handler = ngx_http_lua_socket_tcp_write_resume;
    3116           0 :         ctx->cur_co_ctx = coctx;
    3117             : 
    3118           0 :         ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx)
    3119             :                             || coctx->co_ref >= 0));
    3120             : 
    3121           0 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3122             :                        "lua tcp socket waking up the current request (read)");
    3123             : 
    3124           0 :         r->write_event_handler(r);
    3125             :     }
    3126             : }
    3127             : 
    3128             : 
    3129             : static void
    3130           0 : ngx_http_lua_socket_handle_conn_error(ngx_http_request_t *r,
    3131             :     ngx_http_lua_socket_tcp_upstream_t *u, ngx_uint_t ft_type)
    3132             : {
    3133             :     ngx_http_lua_ctx_t          *ctx;
    3134             :     ngx_http_lua_co_ctx_t       *coctx;
    3135             : 
    3136           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3137             :                    "lua tcp socket handle connect error");
    3138             : 
    3139           0 :     u->ft_type |= ft_type;
    3140             : 
    3141             : #if 1
    3142           0 :     ngx_http_lua_socket_tcp_finalize(r, u);
    3143             : #endif
    3144             : 
    3145           0 :     u->read_event_handler = ngx_http_lua_socket_dummy_handler;
    3146           0 :     u->write_event_handler = ngx_http_lua_socket_dummy_handler;
    3147             : 
    3148             :     dd("connection waiting: %d", (int) u->conn_waiting);
    3149             : 
    3150           0 :     coctx = u->write_co_ctx;
    3151             : 
    3152           0 :     if (u->conn_waiting) {
    3153           0 :         u->conn_waiting = 0;
    3154             : 
    3155           0 :         coctx->cleanup = NULL;
    3156           0 :         u->write_co_ctx = NULL;
    3157             : 
    3158           0 :         ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    3159             : 
    3160           0 :         ctx->resume_handler = ngx_http_lua_socket_tcp_conn_resume;
    3161           0 :         ctx->cur_co_ctx = coctx;
    3162             : 
    3163           0 :         ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx)
    3164             :                             || coctx->co_ref >= 0));
    3165             : 
    3166           0 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3167             :                        "lua tcp socket waking up the current request");
    3168             : 
    3169           0 :         r->write_event_handler(r);
    3170             :     }
    3171           0 : }
    3172             : 
    3173             : 
    3174             : static void
    3175           0 : ngx_http_lua_socket_handle_read_error(ngx_http_request_t *r,
    3176             :     ngx_http_lua_socket_tcp_upstream_t *u, ngx_uint_t ft_type)
    3177             : {
    3178             :     ngx_http_lua_ctx_t          *ctx;
    3179             :     ngx_http_lua_co_ctx_t       *coctx;
    3180             : 
    3181           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3182             :                    "lua tcp socket handle read error");
    3183             : 
    3184           0 :     u->ft_type |= ft_type;
    3185             : 
    3186             : #if 0
    3187             :     ngx_http_lua_socket_tcp_finalize(r, u);
    3188             : #endif
    3189             : 
    3190           0 :     u->read_event_handler = ngx_http_lua_socket_dummy_handler;
    3191             : 
    3192           0 :     if (u->read_waiting) {
    3193           0 :         u->read_waiting = 0;
    3194             : 
    3195           0 :         coctx = u->read_co_ctx;
    3196           0 :         coctx->cleanup = NULL;
    3197           0 :         u->read_co_ctx = NULL;
    3198             : 
    3199           0 :         ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    3200             : 
    3201           0 :         ctx->resume_handler = ngx_http_lua_socket_tcp_read_resume;
    3202           0 :         ctx->cur_co_ctx = coctx;
    3203             : 
    3204           0 :         ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx)
    3205             :                             || coctx->co_ref >= 0));
    3206             : 
    3207           0 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3208             :                        "lua tcp socket waking up the current request");
    3209             : 
    3210           0 :         r->write_event_handler(r);
    3211             :     }
    3212           0 : }
    3213             : 
    3214             : 
    3215             : static void
    3216           0 : ngx_http_lua_socket_handle_write_error(ngx_http_request_t *r,
    3217             :     ngx_http_lua_socket_tcp_upstream_t *u, ngx_uint_t ft_type)
    3218             : {
    3219             :     ngx_http_lua_ctx_t          *ctx;
    3220             :     ngx_http_lua_co_ctx_t       *coctx;
    3221             : 
    3222           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3223             :                    "lua tcp socket handle write error");
    3224             : 
    3225           0 :     u->ft_type |= ft_type;
    3226             : 
    3227             : #if 0
    3228             :     ngx_http_lua_socket_tcp_finalize(r, u);
    3229             : #endif
    3230             : 
    3231           0 :     u->write_event_handler = ngx_http_lua_socket_dummy_handler;
    3232             : 
    3233           0 :     if (u->write_waiting) {
    3234           0 :         u->write_waiting = 0;
    3235             : 
    3236           0 :         coctx = u->write_co_ctx;
    3237           0 :         coctx->cleanup = NULL;
    3238           0 :         u->write_co_ctx = NULL;
    3239             : 
    3240           0 :         ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    3241             : 
    3242           0 :         ctx->resume_handler = ngx_http_lua_socket_tcp_write_resume;
    3243           0 :         ctx->cur_co_ctx = coctx;
    3244             : 
    3245           0 :         ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx)
    3246             :                             || coctx->co_ref >= 0));
    3247             : 
    3248           0 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3249             :                        "lua tcp socket waking up the current request");
    3250             : 
    3251           0 :         r->write_event_handler(r);
    3252             :     }
    3253           0 : }
    3254             : 
    3255             : 
    3256             : static void
    3257           1 : ngx_http_lua_socket_connected_handler(ngx_http_request_t *r,
    3258             :     ngx_http_lua_socket_tcp_upstream_t *u)
    3259             : {
    3260             :     ngx_int_t                    rc;
    3261             :     ngx_connection_t            *c;
    3262             :     ngx_http_lua_loc_conf_t     *llcf;
    3263             : 
    3264           1 :     c = u->peer.connection;
    3265             : 
    3266           1 :     if (c->write->timedout) {
    3267             : 
    3268           0 :         llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
    3269             : 
    3270           0 :         if (llcf->log_socket_errors) {
    3271           0 :             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
    3272             :                           "lua tcp socket connect timed out");
    3273             :         }
    3274             : 
    3275           0 :         ngx_http_lua_socket_handle_conn_error(r, u,
    3276             :                                               NGX_HTTP_LUA_SOCKET_FT_TIMEOUT);
    3277           0 :         return;
    3278             :     }
    3279             : 
    3280           1 :     if (c->write->timer_set) {
    3281           1 :         ngx_del_timer(c->write);
    3282             :     }
    3283             : 
    3284           1 :     rc = ngx_http_lua_socket_test_connect(r, c);
    3285           1 :     if (rc != NGX_OK) {
    3286           0 :         if (rc > 0) {
    3287           0 :             u->socket_errno = (ngx_err_t) rc;
    3288             :         }
    3289             : 
    3290           0 :         ngx_http_lua_socket_handle_conn_error(r, u,
    3291             :                                               NGX_HTTP_LUA_SOCKET_FT_ERROR);
    3292           0 :         return;
    3293             :     }
    3294             : 
    3295           1 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3296             :                    "lua tcp socket connected");
    3297             : 
    3298             :     /* We should delete the current write/read event
    3299             :      * here because the socket object may not be used immediately
    3300             :      * on the Lua land, thus causing hot spin around level triggered
    3301             :      * event poll and wasting CPU cycles. */
    3302             : 
    3303           1 :     if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
    3304           0 :         ngx_http_lua_socket_handle_conn_error(r, u,
    3305             :                                               NGX_HTTP_LUA_SOCKET_FT_ERROR);
    3306           0 :         return;
    3307             :     }
    3308             : 
    3309           1 :     if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
    3310           0 :         ngx_http_lua_socket_handle_conn_error(r, u,
    3311             :                                               NGX_HTTP_LUA_SOCKET_FT_ERROR);
    3312           0 :         return;
    3313             :     }
    3314             : 
    3315           1 :     ngx_http_lua_socket_handle_conn_success(r, u);
    3316             : }
    3317             : 
    3318             : 
    3319             : static void
    3320           0 : ngx_http_lua_socket_tcp_cleanup(void *data)
    3321             : {
    3322           0 :     ngx_http_lua_socket_tcp_upstream_t  *u = data;
    3323             : 
    3324             :     ngx_http_request_t  *r;
    3325             : 
    3326           0 :     r = u->request;
    3327             : 
    3328           0 :     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3329             :                    "cleanup lua tcp socket request: \"%V\"", &r->uri);
    3330             : 
    3331           0 :     ngx_http_lua_socket_tcp_finalize(r, u);
    3332           0 : }
    3333             : 
    3334             : 
    3335             : static void
    3336           1 : ngx_http_lua_socket_tcp_finalize_read_part(ngx_http_request_t *r,
    3337             :     ngx_http_lua_socket_tcp_upstream_t *u)
    3338             : {
    3339             :     ngx_chain_t                         *cl;
    3340             :     ngx_chain_t                        **ll;
    3341             :     ngx_connection_t                    *c;
    3342             :     ngx_http_lua_ctx_t                  *ctx;
    3343             : 
    3344           1 :     if (u->read_closed) {
    3345           0 :         return;
    3346             :     }
    3347             : 
    3348           1 :     u->read_closed = 1;
    3349             : 
    3350           1 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    3351             : 
    3352           1 :     if (ctx && u->bufs_in) {
    3353             : 
    3354           0 :         ll = &u->bufs_in;
    3355           0 :         for (cl = u->bufs_in; cl; cl = cl->next) {
    3356             :             dd("bufs_in chain: %p, next %p", cl, cl->next);
    3357           0 :             cl->buf->pos = cl->buf->last;
    3358           0 :             ll = &cl->next;
    3359             :         }
    3360             : 
    3361             :         dd("ctx: %p", ctx);
    3362             :         dd("free recv bufs: %p", ctx->free_recv_bufs);
    3363           0 :         *ll = ctx->free_recv_bufs;
    3364           0 :         ctx->free_recv_bufs = u->bufs_in;
    3365           0 :         u->bufs_in = NULL;
    3366           0 :         u->buf_in = NULL;
    3367           0 :         ngx_memzero(&u->buffer, sizeof(ngx_buf_t));
    3368             :     }
    3369             : 
    3370           1 :     if (u->raw_downstream || u->body_downstream) {
    3371           0 :         if (r->connection->read->timer_set) {
    3372           0 :             ngx_del_timer(r->connection->read);
    3373             :         }
    3374           0 :         return;
    3375             :     }
    3376             : 
    3377           1 :     c = u->peer.connection;
    3378             : 
    3379           1 :     if (c) {
    3380           1 :         if (c->read->timer_set) {
    3381           0 :             ngx_del_timer(c->read);
    3382             :         }
    3383             : 
    3384           1 :         if (c->read->active || c->read->disabled) {
    3385           1 :             ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
    3386             :         }
    3387             : 
    3388             : #if defined(nginx_version) && nginx_version >= 1007005
    3389           1 :         if (c->read->posted) {
    3390             : #else
    3391             :         if (c->read->prev) {
    3392             : #endif
    3393           0 :             ngx_delete_posted_event(c->read);
    3394             :         }
    3395             : 
    3396           1 :         c->read->closed = 1;
    3397             : 
    3398             :         /* TODO: shutdown the reading part of the connection */
    3399             :     }
    3400             : }
    3401             : 
    3402             : 
    3403             : static void
    3404           1 : ngx_http_lua_socket_tcp_finalize_write_part(ngx_http_request_t *r,
    3405             :     ngx_http_lua_socket_tcp_upstream_t *u)
    3406             : {
    3407             :     ngx_connection_t                    *c;
    3408             :     ngx_http_lua_ctx_t                  *ctx;
    3409             : 
    3410           1 :     if (u->write_closed) {
    3411           0 :         return;
    3412             :     }
    3413             : 
    3414           1 :     u->write_closed = 1;
    3415             : 
    3416           1 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    3417             : 
    3418           1 :     if (u->raw_downstream || u->body_downstream) {
    3419           0 :         if (ctx && ctx->writing_raw_req_socket) {
    3420           0 :             ctx->writing_raw_req_socket = 0;
    3421           0 :             if (r->connection->write->timer_set) {
    3422           0 :                 ngx_del_timer(r->connection->write);
    3423             :             }
    3424             : 
    3425           0 :             r->connection->write->error = 1;
    3426             :         }
    3427           0 :         return;
    3428             :     }
    3429             : 
    3430           1 :     c = u->peer.connection;
    3431             : 
    3432           1 :     if (c) {
    3433           1 :         if (c->write->timer_set) {
    3434           0 :             ngx_del_timer(c->write);
    3435             :         }
    3436             : 
    3437           1 :         if (c->write->active || c->write->disabled) {
    3438           1 :             ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT);
    3439             :         }
    3440             : 
    3441             : #if defined(nginx_version) && nginx_version >= 1007005
    3442           1 :         if (c->write->posted) {
    3443             : #else
    3444             :         if (c->write->prev) {
    3445             : #endif
    3446           0 :             ngx_delete_posted_event(c->write);
    3447             :         }
    3448             : 
    3449           1 :         c->write->closed = 1;
    3450             : 
    3451             :         /* TODO: shutdown the writing part of the connection */
    3452             :     }
    3453             : }
    3454             : 
    3455             : 
    3456             : static void
    3457           1 : ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r,
    3458             :     ngx_http_lua_socket_tcp_upstream_t *u)
    3459             : {
    3460             :     ngx_connection_t               *c;
    3461             :     ngx_http_lua_socket_pool_t     *spool;
    3462             : 
    3463             :     dd("request: %p, u: %p, u->cleanup: %p", r, u, u->cleanup);
    3464             : 
    3465           1 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3466             :                    "lua finalize socket");
    3467             : 
    3468           1 :     if (u->cleanup) {
    3469           1 :         *u->cleanup = NULL;
    3470           1 :         ngx_http_lua_cleanup_free(r, u->cleanup);
    3471           1 :         u->cleanup = NULL;
    3472             :     }
    3473             : 
    3474           1 :     ngx_http_lua_socket_tcp_finalize_read_part(r, u);
    3475           1 :     ngx_http_lua_socket_tcp_finalize_write_part(r, u);
    3476             : 
    3477           1 :     if (u->raw_downstream || u->body_downstream) {
    3478           0 :         u->peer.connection = NULL;
    3479           0 :         return;
    3480             :     }
    3481             : 
    3482           1 :     if (u->resolved && u->resolved->ctx) {
    3483           0 :         ngx_resolve_name_done(u->resolved->ctx);
    3484           0 :         u->resolved->ctx = NULL;
    3485             :     }
    3486             : 
    3487           1 :     if (u->peer.free) {
    3488           0 :         u->peer.free(&u->peer, u->peer.data, 0);
    3489             :     }
    3490             : 
    3491             : #if (NGX_HTTP_SSL)
    3492           1 :     if (u->ssl_name.data) {
    3493           0 :         ngx_free(u->ssl_name.data);
    3494           0 :         u->ssl_name.data = NULL;
    3495           0 :         u->ssl_name.len = 0;
    3496             :     }
    3497             : #endif
    3498             : 
    3499           1 :     c = u->peer.connection;
    3500           1 :     if (c) {
    3501           1 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3502             :                        "lua close socket connection");
    3503             : 
    3504           1 :         ngx_http_lua_socket_tcp_close_connection(c);
    3505           1 :         u->peer.connection = NULL;
    3506             : 
    3507           1 :         if (!u->reused) {
    3508           1 :             return;
    3509             :         }
    3510             : 
    3511           0 :         spool = u->socket_pool;
    3512           0 :         if (spool == NULL) {
    3513           0 :             return;
    3514             :         }
    3515             : 
    3516           0 :         spool->active_connections--;
    3517             : 
    3518           0 :         if (spool->active_connections == 0) {
    3519           0 :             ngx_http_lua_socket_free_pool(r->connection->log, spool);
    3520             :         }
    3521             :     }
    3522             : }
    3523             : 
    3524             : 
    3525             : static void
    3526           1 : ngx_http_lua_socket_tcp_close_connection(ngx_connection_t *c)
    3527             : {
    3528             : #if (NGX_HTTP_SSL)
    3529             : 
    3530           1 :     if (c->ssl) {
    3531           0 :         c->ssl->no_wait_shutdown = 1;
    3532           0 :         c->ssl->no_send_shutdown = 1;
    3533             : 
    3534           0 :         (void) ngx_ssl_shutdown(c);
    3535             :     }
    3536             : 
    3537             : #endif
    3538             : 
    3539           1 :     if (c->pool) {
    3540           1 :         ngx_destroy_pool(c->pool);
    3541           1 :         c->pool = NULL;
    3542             :     }
    3543             : 
    3544           1 :     ngx_close_connection(c);
    3545           1 : }
    3546             : 
    3547             : 
    3548             : static ngx_int_t
    3549           1 : ngx_http_lua_socket_test_connect(ngx_http_request_t *r, ngx_connection_t *c)
    3550             : {
    3551             :     int              err;
    3552             :     socklen_t        len;
    3553             : 
    3554             :     ngx_http_lua_loc_conf_t     *llcf;
    3555             : 
    3556             : #if (NGX_HAVE_KQUEUE)
    3557             : 
    3558             :     ngx_event_t     *ev;
    3559             : 
    3560             :     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT)  {
    3561             :         dd("pending eof: (%p)%d (%p)%d", c->write, c->write->pending_eof,
    3562             :            c->read, c->read->pending_eof);
    3563             : 
    3564             :         if (c->write->pending_eof) {
    3565             :             ev = c->write;
    3566             : 
    3567             :         } else if (c->read->pending_eof) {
    3568             :             ev = c->read;
    3569             : 
    3570             :         } else {
    3571             :             ev = NULL;
    3572             :         }
    3573             : 
    3574             :         if (ev) {
    3575             :             llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
    3576             :             if (llcf->log_socket_errors) {
    3577             :                 (void) ngx_connection_error(c, ev->kq_errno,
    3578             :                                             "kevent() reported that "
    3579             :                                             "connect() failed");
    3580             :             }
    3581             :             return ev->kq_errno;
    3582             :         }
    3583             : 
    3584             :     } else
    3585             : #endif
    3586             :     {
    3587           1 :         err = 0;
    3588           1 :         len = sizeof(int);
    3589             : 
    3590             :         /*
    3591             :          * BSDs and Linux return 0 and set a pending error in err
    3592             :          * Solaris returns -1 and sets errno
    3593             :          */
    3594             : 
    3595           1 :         if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len)
    3596             :             == -1)
    3597             :         {
    3598           0 :             err = ngx_errno;
    3599             :         }
    3600             : 
    3601           1 :         if (err) {
    3602           0 :             llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
    3603           0 :             if (llcf->log_socket_errors) {
    3604           0 :                 (void) ngx_connection_error(c, err, "connect() failed");
    3605             :             }
    3606           0 :             return err;
    3607             :         }
    3608             :     }
    3609             : 
    3610           1 :     return NGX_OK;
    3611             : }
    3612             : 
    3613             : 
    3614             : static void
    3615           0 : ngx_http_lua_socket_dummy_handler(ngx_http_request_t *r,
    3616             :     ngx_http_lua_socket_tcp_upstream_t *u)
    3617             : {
    3618           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3619             :                    "lua tcp socket dummy handler");
    3620           0 : }
    3621             : 
    3622             : 
    3623             : static int
    3624           0 : ngx_http_lua_socket_tcp_receiveuntil(lua_State *L)
    3625             : {
    3626             :     ngx_http_request_t                  *r;
    3627             :     int                                  n;
    3628             :     ngx_str_t                            pat;
    3629             :     ngx_int_t                            rc;
    3630             :     size_t                               size;
    3631           0 :     unsigned                             inclusive = 0;
    3632             : 
    3633             :     ngx_http_lua_socket_compiled_pattern_t     *cp;
    3634             : 
    3635           0 :     n = lua_gettop(L);
    3636           0 :     if (n != 2 && n != 3) {
    3637           0 :         return luaL_error(L, "expecting 2 or 3 arguments "
    3638             :                           "(including the object), but got %d", n);
    3639             :     }
    3640             : 
    3641           0 :     if (n == 3) {
    3642             :         /* check out the options table */
    3643             : 
    3644           0 :         luaL_checktype(L, 3, LUA_TTABLE);
    3645             : 
    3646           0 :         lua_getfield(L, 3, "inclusive");
    3647             : 
    3648           0 :         switch (lua_type(L, -1)) {
    3649           0 :             case LUA_TNIL:
    3650             :                 /* do nothing */
    3651           0 :                 break;
    3652             : 
    3653           0 :             case LUA_TBOOLEAN:
    3654           0 :                 if (lua_toboolean(L, -1)) {
    3655           0 :                     inclusive = 1;
    3656             :                 }
    3657           0 :                 break;
    3658             : 
    3659           0 :             default:
    3660           0 :                 return luaL_error(L, "bad \"inclusive\" option value type: %s",
    3661             :                                   luaL_typename(L, -1));
    3662             : 
    3663             :         }
    3664             : 
    3665           0 :         lua_pop(L, 2);
    3666             :     }
    3667             : 
    3668           0 :     r = ngx_http_lua_get_req(L);
    3669           0 :     if (r == NULL) {
    3670           0 :         return luaL_error(L, "no request found");
    3671             :     }
    3672             : 
    3673           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3674             :                    "lua tcp socket calling receiveuntil() method");
    3675             : 
    3676           0 :     luaL_checktype(L, 1, LUA_TTABLE);
    3677             : 
    3678           0 :     pat.data = (u_char *) luaL_checklstring(L, 2, &pat.len);
    3679           0 :     if (pat.len == 0) {
    3680           0 :         lua_pushnil(L);
    3681           0 :         lua_pushliteral(L, "pattern is empty");
    3682           0 :         return 2;
    3683             :     }
    3684             : 
    3685           0 :     size = sizeof(ngx_http_lua_socket_compiled_pattern_t);
    3686             : 
    3687           0 :     cp = lua_newuserdata(L, size);
    3688           0 :     if (cp == NULL) {
    3689           0 :         return luaL_error(L, "no memory");
    3690             :     }
    3691             : 
    3692           0 :     lua_pushlightuserdata(L, &ngx_http_lua_pattern_udata_metatable_key);
    3693           0 :     lua_rawget(L, LUA_REGISTRYINDEX);
    3694           0 :     lua_setmetatable(L, -2);
    3695             : 
    3696           0 :     ngx_memzero(cp, size);
    3697             : 
    3698           0 :     cp->inclusive = inclusive;
    3699             : 
    3700           0 :     rc = ngx_http_lua_socket_compile_pattern(pat.data, pat.len, cp,
    3701           0 :                                              r->connection->log);
    3702             : 
    3703           0 :     if (rc != NGX_OK) {
    3704           0 :         lua_pushnil(L);
    3705           0 :         lua_pushliteral(L, "failed to compile pattern");
    3706           0 :         return 2;
    3707             :     }
    3708             : 
    3709           0 :     lua_pushcclosure(L, ngx_http_lua_socket_receiveuntil_iterator, 3);
    3710           0 :     return 1;
    3711             : }
    3712             : 
    3713             : 
    3714             : static int
    3715           0 : ngx_http_lua_socket_receiveuntil_iterator(lua_State *L)
    3716             : {
    3717             :     ngx_http_request_t                  *r;
    3718             :     ngx_http_lua_socket_tcp_upstream_t  *u;
    3719             :     ngx_int_t                            rc;
    3720             :     ngx_http_lua_ctx_t                  *ctx;
    3721             :     lua_Integer                          bytes;
    3722             :     int                                  n;
    3723             :     ngx_http_lua_co_ctx_t               *coctx;
    3724             : 
    3725             :     ngx_http_lua_socket_compiled_pattern_t     *cp;
    3726             : 
    3727           0 :     n = lua_gettop(L);
    3728           0 :     if (n > 1) {
    3729           0 :         return luaL_error(L, "expecting 0 or 1 arguments, "
    3730             :                           "but seen %d", n);
    3731             :     }
    3732             : 
    3733           0 :     if (n >= 1) {
    3734           0 :         bytes = luaL_checkinteger(L, 1);
    3735           0 :         if (bytes < 0) {
    3736           0 :             bytes = 0;
    3737             :         }
    3738             : 
    3739             :     } else {
    3740           0 :         bytes = 0;
    3741             :     }
    3742             : 
    3743           0 :     lua_rawgeti(L, lua_upvalueindex(1), SOCKET_CTX_INDEX);
    3744           0 :     u = lua_touserdata(L, -1);
    3745           0 :     lua_pop(L, 1);
    3746             : 
    3747           0 :     if (u == NULL || u->peer.connection == NULL || u->read_closed) {
    3748           0 :         lua_pushnil(L);
    3749           0 :         lua_pushliteral(L, "closed");
    3750           0 :         return 2;
    3751             :     }
    3752             : 
    3753           0 :     r = ngx_http_lua_get_req(L);
    3754           0 :     if (r == NULL) {
    3755           0 :         return luaL_error(L, "no request found");
    3756             :     }
    3757             : 
    3758           0 :     if (u->request != r) {
    3759           0 :         return luaL_error(L, "bad request");
    3760             :     }
    3761             : 
    3762           0 :     ngx_http_lua_socket_check_busy_connecting(r, u, L);
    3763           0 :     ngx_http_lua_socket_check_busy_reading(r, u, L);
    3764             : 
    3765           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3766             :                    "lua tcp socket receiveuntil iterator");
    3767             : 
    3768           0 :     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3769             :                    "lua tcp socket read timeout: %M", u->read_timeout);
    3770             : 
    3771           0 :     u->input_filter = ngx_http_lua_socket_read_until;
    3772             : 
    3773           0 :     cp = lua_touserdata(L, lua_upvalueindex(3));
    3774             : 
    3775             :     dd("checking existing state: %d", cp->state);
    3776             : 
    3777           0 :     if (cp->state == -1) {
    3778           0 :         cp->state = 0;
    3779             : 
    3780           0 :         lua_pushnil(L);
    3781           0 :         lua_pushnil(L);
    3782           0 :         lua_pushnil(L);
    3783           0 :         return 3;
    3784             :     }
    3785             : 
    3786           0 :     cp->upstream = u;
    3787             : 
    3788           0 :     cp->pattern.data =
    3789           0 :         (u_char *) lua_tolstring(L, lua_upvalueindex(2),
    3790             :                                  &cp->pattern.len);
    3791             : 
    3792           0 :     u->input_filter_ctx = cp;
    3793             : 
    3794           0 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    3795             : 
    3796           0 :     if (u->bufs_in == NULL) {
    3797           0 :         u->bufs_in =
    3798           0 :             ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool,
    3799             :                                             &ctx->free_recv_bufs,
    3800           0 :                                             u->conf->buffer_size);
    3801             : 
    3802           0 :         if (u->bufs_in == NULL) {
    3803           0 :             return luaL_error(L, "no memory");
    3804             :         }
    3805             : 
    3806           0 :         u->buf_in = u->bufs_in;
    3807           0 :         u->buffer = *u->buf_in->buf;
    3808             :     }
    3809             : 
    3810           0 :     u->length = (size_t) bytes;
    3811           0 :     u->rest = u->length;
    3812             : 
    3813           0 :     if (u->raw_downstream || u->body_downstream) {
    3814           0 :         r->read_event_handler = ngx_http_lua_req_socket_rev_handler;
    3815             :     }
    3816             : 
    3817           0 :     u->read_waiting = 0;
    3818           0 :     u->read_co_ctx = NULL;
    3819             : 
    3820           0 :     rc = ngx_http_lua_socket_tcp_read(r, u);
    3821             : 
    3822           0 :     if (rc == NGX_ERROR) {
    3823             :         dd("read failed: %d", (int) u->ft_type);
    3824           0 :         rc = ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L);
    3825             :         dd("tcp receive retval returned: %d", (int) rc);
    3826           0 :         return rc;
    3827             :     }
    3828             : 
    3829           0 :     if (rc == NGX_OK) {
    3830             : 
    3831           0 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3832             :                        "lua tcp socket receive done in a single run");
    3833             : 
    3834           0 :         return ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L);
    3835             :     }
    3836             : 
    3837             :     /* rc == NGX_AGAIN */
    3838             : 
    3839           0 :     coctx = ctx->cur_co_ctx;
    3840             : 
    3841           0 :     u->read_event_handler = ngx_http_lua_socket_read_handler;
    3842             : 
    3843           0 :     ngx_http_lua_cleanup_pending_operation(coctx);
    3844           0 :     coctx->cleanup = ngx_http_lua_coctx_cleanup;
    3845           0 :     coctx->data = u;
    3846             : 
    3847           0 :     if (ctx->entered_content_phase) {
    3848           0 :         r->write_event_handler = ngx_http_lua_content_wev_handler;
    3849             : 
    3850             :     } else {
    3851           0 :         r->write_event_handler = ngx_http_core_run_phases;
    3852             :     }
    3853             : 
    3854           0 :     u->read_co_ctx = coctx;
    3855           0 :     u->read_waiting = 1;
    3856           0 :     u->read_prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler;
    3857             : 
    3858             :     dd("setting data to %p", u);
    3859             : 
    3860           0 :     if (u->raw_downstream || u->body_downstream) {
    3861           0 :         ctx->downstream = u;
    3862             :     }
    3863             : 
    3864           0 :     return lua_yield(L, 0);
    3865             : }
    3866             : 
    3867             : 
    3868             : static ngx_int_t
    3869           0 : ngx_http_lua_socket_compile_pattern(u_char *data, size_t len,
    3870             :     ngx_http_lua_socket_compiled_pattern_t *cp, ngx_log_t *log)
    3871             : {
    3872             :     size_t              i;
    3873             :     size_t              prefix_len;
    3874             :     size_t              size;
    3875             :     unsigned            found;
    3876             :     int                 cur_state, new_state;
    3877             : 
    3878             :     ngx_http_lua_dfa_edge_t         *edge;
    3879           0 :     ngx_http_lua_dfa_edge_t        **last = NULL;
    3880             : 
    3881           0 :     cp->pattern.len = len;
    3882             : 
    3883           0 :     if (len <= 2) {
    3884           0 :         return NGX_OK;
    3885             :     }
    3886             : 
    3887           0 :     for (i = 1; i < len; i++) {
    3888           0 :         prefix_len = 1;
    3889             : 
    3890           0 :         while (prefix_len <= len - i - 1) {
    3891             : 
    3892           0 :             if (ngx_memcmp(data, &data[i], prefix_len) == 0) {
    3893           0 :                 if (data[prefix_len] == data[i + prefix_len]) {
    3894           0 :                     prefix_len++;
    3895           0 :                     continue;
    3896             :                 }
    3897             : 
    3898           0 :                 cur_state = i + prefix_len;
    3899           0 :                 new_state = prefix_len + 1;
    3900             : 
    3901           0 :                 if (cp->recovering == NULL) {
    3902           0 :                     size = sizeof(void *) * (len - 2);
    3903           0 :                     cp->recovering = ngx_alloc(size, log);
    3904           0 :                     if (cp->recovering == NULL) {
    3905           0 :                         return NGX_ERROR;
    3906             :                     }
    3907             : 
    3908           0 :                     ngx_memzero(cp->recovering, size);
    3909             :                 }
    3910             : 
    3911           0 :                 edge = cp->recovering[cur_state - 2];
    3912             : 
    3913           0 :                 found = 0;
    3914             : 
    3915           0 :                 if (edge == NULL) {
    3916           0 :                     last = &cp->recovering[cur_state - 2];
    3917             : 
    3918             :                 } else {
    3919             : 
    3920           0 :                     for (; edge; edge = edge->next) {
    3921           0 :                         last = &edge->next;
    3922             : 
    3923           0 :                         if (edge->chr == data[prefix_len]) {
    3924           0 :                             found = 1;
    3925             : 
    3926           0 :                             if (edge->new_state < new_state) {
    3927           0 :                                 edge->new_state = new_state;
    3928             :                             }
    3929             : 
    3930           0 :                             break;
    3931             :                         }
    3932             :                     }
    3933             :                 }
    3934             : 
    3935           0 :                 if (!found) {
    3936           0 :                     ngx_log_debug7(NGX_LOG_DEBUG_HTTP, log, 0,
    3937             :                                    "lua tcp socket read until recovering point:"
    3938             :                                    " on state %d (%*s), if next is '%c', then "
    3939             :                                    "recover to state %d (%*s)", cur_state,
    3940             :                                    (size_t) cur_state, data, data[prefix_len],
    3941             :                                    new_state, (size_t) new_state, data);
    3942             : 
    3943           0 :                     edge = ngx_alloc(sizeof(ngx_http_lua_dfa_edge_t), log);
    3944           0 :                     if (edge == NULL) {
    3945           0 :                         return NGX_ERROR;
    3946             :                     }
    3947             : 
    3948           0 :                     edge->chr = data[prefix_len];
    3949           0 :                     edge->new_state = new_state;
    3950           0 :                     edge->next = NULL;
    3951             : 
    3952           0 :                     *last = edge;
    3953             :                 }
    3954             : 
    3955           0 :                 break;
    3956             :             }
    3957             : 
    3958           0 :             break;
    3959             :         }
    3960             :     }
    3961             : 
    3962           0 :     return NGX_OK;
    3963             : }
    3964             : 
    3965             : 
    3966             : static ngx_int_t
    3967           0 : ngx_http_lua_socket_read_until(void *data, ssize_t bytes)
    3968             : {
    3969           0 :     ngx_http_lua_socket_compiled_pattern_t     *cp = data;
    3970             : 
    3971             :     ngx_http_lua_socket_tcp_upstream_t      *u;
    3972             :     ngx_http_request_t                      *r;
    3973             :     ngx_buf_t                               *b;
    3974             :     u_char                                   c;
    3975             :     u_char                                  *pat;
    3976             :     size_t                                   pat_len;
    3977             :     int                                      i;
    3978             :     int                                      state;
    3979           0 :     int                                      old_state = 0; /* just to make old
    3980             :                                                                gcc happy */
    3981             :     ngx_http_lua_dfa_edge_t                 *edge;
    3982             :     unsigned                                 matched;
    3983             :     ngx_int_t                                rc;
    3984             : 
    3985           0 :     u = cp->upstream;
    3986           0 :     r = u->request;
    3987             : 
    3988           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3989             :                    "lua tcp socket read until");
    3990             : 
    3991           0 :     if (bytes == 0) {
    3992           0 :         u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED;
    3993           0 :         return NGX_ERROR;
    3994             :     }
    3995             : 
    3996           0 :     b = &u->buffer;
    3997             : 
    3998           0 :     pat = cp->pattern.data;
    3999           0 :     pat_len = cp->pattern.len;
    4000           0 :     state = cp->state;
    4001             : 
    4002           0 :     i = 0;
    4003           0 :     while (i < bytes) {
    4004           0 :         c = b->pos[i];
    4005             : 
    4006             :         dd("%d: read char %d, state: %d", i, c, state);
    4007             : 
    4008           0 :         if (c == pat[state]) {
    4009           0 :             i++;
    4010           0 :             state++;
    4011             : 
    4012           0 :             if (state == (int) pat_len) {
    4013             :                 /* already matched the whole pattern */
    4014             :                 dd("pat len: %d", (int) pat_len);
    4015             : 
    4016           0 :                 b->pos += i;
    4017             : 
    4018           0 :                 if (u->length) {
    4019           0 :                     cp->state = -1;
    4020             : 
    4021             :                 } else {
    4022           0 :                     cp->state = 0;
    4023             :                 }
    4024             : 
    4025           0 :                 if (cp->inclusive) {
    4026           0 :                     rc = ngx_http_lua_socket_add_pending_data(r, u, b->pos, 0,
    4027             :                                                               pat, state,
    4028             :                                                               state);
    4029             : 
    4030           0 :                     if (rc != NGX_OK) {
    4031           0 :                         u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR;
    4032           0 :                         return NGX_ERROR;
    4033             :                     }
    4034             :                 }
    4035             : 
    4036           0 :                 return NGX_OK;
    4037             :             }
    4038             : 
    4039           0 :             continue;
    4040             :         }
    4041             : 
    4042           0 :         if (state == 0) {
    4043           0 :             u->buf_in->buf->last++;
    4044             : 
    4045           0 :             i++;
    4046             : 
    4047           0 :             if (u->length && --u->rest == 0) {
    4048           0 :                 cp->state = state;
    4049           0 :                 b->pos += i;
    4050           0 :                 return NGX_OK;
    4051             :             }
    4052             : 
    4053           0 :             continue;
    4054             :         }
    4055             : 
    4056           0 :         matched = 0;
    4057             : 
    4058           0 :         if (cp->recovering && state >= 2) {
    4059             :             dd("accessing state: %d, index: %d", state, state - 2);
    4060           0 :             for (edge = cp->recovering[state - 2]; edge; edge = edge->next) {
    4061             : 
    4062           0 :                 if (edge->chr == c) {
    4063             :                     dd("matched '%c' and jumping to state %d", c,
    4064             :                        edge->new_state);
    4065             : 
    4066           0 :                     old_state = state;
    4067           0 :                     state = edge->new_state;
    4068           0 :                     matched = 1;
    4069           0 :                     break;
    4070             :                 }
    4071             :             }
    4072             :         }
    4073             : 
    4074           0 :         if (!matched) {
    4075             : #if 1
    4076             :             dd("adding pending data: %.*s", state, pat);
    4077           0 :             rc = ngx_http_lua_socket_add_pending_data(r, u, b->pos, i, pat,
    4078             :                                                       state, state);
    4079             : 
    4080           0 :             if (rc != NGX_OK) {
    4081           0 :                 u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR;
    4082           0 :                 return NGX_ERROR;
    4083             :             }
    4084             : 
    4085             : #endif
    4086             : 
    4087           0 :             if (u->length) {
    4088           0 :                 if (u->rest <= (size_t) state) {
    4089           0 :                     u->rest = 0;
    4090           0 :                     cp->state = 0;
    4091           0 :                     b->pos += i;
    4092           0 :                     return NGX_OK;
    4093             : 
    4094             :                 } else {
    4095           0 :                     u->rest -= state;
    4096             :                 }
    4097             :             }
    4098             : 
    4099           0 :             state = 0;
    4100           0 :             continue;
    4101             :         }
    4102             : 
    4103             :         /* matched */
    4104             : 
    4105             :         dd("adding pending data: %.*s", (int) (old_state + 1 - state),
    4106             :            (char *) pat);
    4107             : 
    4108           0 :         rc = ngx_http_lua_socket_add_pending_data(r, u, b->pos, i, pat,
    4109           0 :                                                   old_state + 1 - state,
    4110             :                                                   old_state);
    4111             : 
    4112           0 :         if (rc != NGX_OK) {
    4113           0 :             u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR;
    4114           0 :             return NGX_ERROR;
    4115             :         }
    4116             : 
    4117           0 :         i++;
    4118             : 
    4119           0 :         if (u->length) {
    4120           0 :             if (u->rest <= (size_t) state) {
    4121           0 :                 u->rest = 0;
    4122           0 :                 cp->state = state;
    4123           0 :                 b->pos += i;
    4124           0 :                 return NGX_OK;
    4125             : 
    4126             :             } else {
    4127           0 :                 u->rest -= state;
    4128             :             }
    4129             :         }
    4130             : 
    4131           0 :         continue;
    4132             :     }
    4133             : 
    4134           0 :     b->pos += i;
    4135           0 :     cp->state = state;
    4136             : 
    4137           0 :     return NGX_AGAIN;
    4138             : }
    4139             : 
    4140             : 
    4141             : static int
    4142           0 : ngx_http_lua_socket_cleanup_compiled_pattern(lua_State *L)
    4143             : {
    4144             :     ngx_http_lua_socket_compiled_pattern_t      *cp;
    4145             : 
    4146             :     ngx_http_lua_dfa_edge_t         *edge, *p;
    4147             :     unsigned                         i;
    4148             : 
    4149             :     dd("cleanup compiled pattern");
    4150             : 
    4151           0 :     cp = lua_touserdata(L, 1);
    4152           0 :     if (cp == NULL || cp->recovering == NULL) {
    4153           0 :         return 0;
    4154             :     }
    4155             : 
    4156             :     dd("pattern len: %d", (int) cp->pattern.len);
    4157             : 
    4158           0 :     for (i = 0; i < cp->pattern.len - 2; i++) {
    4159           0 :         edge = cp->recovering[i];
    4160             : 
    4161           0 :         while (edge) {
    4162           0 :             p = edge;
    4163           0 :             edge = edge->next;
    4164             : 
    4165             :             dd("freeing edge %p", p);
    4166             : 
    4167           0 :             ngx_free(p);
    4168             : 
    4169             :             dd("edge: %p", edge);
    4170             :         }
    4171             :     }
    4172             : 
    4173             : #if 1
    4174           0 :     ngx_free(cp->recovering);
    4175           0 :     cp->recovering = NULL;
    4176             : #endif
    4177             : 
    4178           0 :     return 0;
    4179             : }
    4180             : 
    4181             : 
    4182             : static int
    4183           0 : ngx_http_lua_req_socket(lua_State *L)
    4184             : {
    4185             :     int                              n, raw;
    4186             :     ngx_peer_connection_t           *pc;
    4187             :     ngx_http_lua_loc_conf_t         *llcf;
    4188             :     ngx_connection_t                *c;
    4189             :     ngx_http_request_t              *r;
    4190             :     ngx_http_lua_ctx_t              *ctx;
    4191             :     ngx_http_request_body_t         *rb;
    4192             :     ngx_http_cleanup_t              *cln;
    4193             :     ngx_http_lua_co_ctx_t           *coctx;
    4194             : 
    4195             :     ngx_http_lua_socket_tcp_upstream_t  *u;
    4196             : 
    4197           0 :     n = lua_gettop(L);
    4198           0 :     if (n == 0) {
    4199           0 :         raw = 0;
    4200             : 
    4201           0 :     } else if (n == 1) {
    4202           0 :         raw = lua_toboolean(L, 1);
    4203           0 :         lua_pop(L, 1);
    4204             : 
    4205             :     } else {
    4206           0 :         return luaL_error(L, "expecting zero arguments, but got %d",
    4207             :                           lua_gettop(L));
    4208             :     }
    4209             : 
    4210           0 :     r = ngx_http_lua_get_req(L);
    4211             : 
    4212           0 :     if (r != r->main) {
    4213           0 :         return luaL_error(L, "attempt to read the request body in a "
    4214             :                           "subrequest");
    4215             :     }
    4216             : 
    4217             : #if (NGX_HTTP_SPDY)
    4218             :     if (r->spdy_stream) {
    4219             :         return luaL_error(L, "spdy not supported yet");
    4220             :     }
    4221             : #endif
    4222             : 
    4223             : #if (NGX_HTTP_V2)
    4224           0 :     if (r->stream) {
    4225           0 :         return luaL_error(L, "http v2 not supported yet");
    4226             :     }
    4227             : #endif
    4228             : 
    4229             : #if nginx_version >= 1003009
    4230           0 :     if (!raw && r->headers_in.chunked) {
    4231           0 :         lua_pushnil(L);
    4232           0 :         lua_pushliteral(L, "chunked request bodies not supported yet");
    4233           0 :         return 2;
    4234             :     }
    4235             : #endif
    4236             : 
    4237           0 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    4238           0 :     if (ctx == NULL) {
    4239           0 :         return luaL_error(L, "no ctx found");
    4240             :     }
    4241             : 
    4242           0 :     ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
    4243             :                                | NGX_HTTP_LUA_CONTEXT_ACCESS
    4244             :                                | NGX_HTTP_LUA_CONTEXT_CONTENT);
    4245             : 
    4246           0 :     c = r->connection;
    4247             : 
    4248           0 :     if (raw) {
    4249             : #if !defined(nginx_version) || nginx_version < 1003013
    4250             :         lua_pushnil(L);
    4251             :         lua_pushliteral(L, "nginx version too old");
    4252             :         return 2;
    4253             : #else
    4254           0 :         if (r->request_body) {
    4255           0 :             if (r->request_body->rest > 0) {
    4256           0 :                 lua_pushnil(L);
    4257           0 :                 lua_pushliteral(L, "pending request body reading in some "
    4258             :                                 "other thread");
    4259           0 :                 return 2;
    4260             :             }
    4261             : 
    4262             :         } else {
    4263           0 :             rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
    4264           0 :             if (rb == NULL) {
    4265           0 :                 return luaL_error(L, "no memory");
    4266             :             }
    4267           0 :             r->request_body = rb;
    4268             :         }
    4269             : 
    4270           0 :         if (c->buffered & NGX_HTTP_LOWLEVEL_BUFFERED) {
    4271           0 :             lua_pushnil(L);
    4272           0 :             lua_pushliteral(L, "pending data to write");
    4273           0 :             return 2;
    4274             :         }
    4275             : 
    4276           0 :         if (ctx->buffering) {
    4277           0 :             lua_pushnil(L);
    4278           0 :             lua_pushliteral(L, "http 1.0 buffering");
    4279           0 :             return 2;
    4280             :         }
    4281             : 
    4282           0 :         if (!r->header_sent) {
    4283             :             /* prevent other parts of nginx from sending out
    4284             :              * the response header */
    4285           0 :             r->header_sent = 1;
    4286             :         }
    4287             : 
    4288           0 :         ctx->header_sent = 1;
    4289             : 
    4290             :         dd("ctx acquired raw req socket: %d", ctx->acquired_raw_req_socket);
    4291             : 
    4292           0 :         if (ctx->acquired_raw_req_socket) {
    4293           0 :             lua_pushnil(L);
    4294           0 :             lua_pushliteral(L, "duplicate call");
    4295           0 :             return 2;
    4296             :         }
    4297             : 
    4298           0 :         ctx->acquired_raw_req_socket = 1;
    4299           0 :         r->keepalive = 0;
    4300           0 :         r->lingering_close = 1;
    4301             : #endif
    4302             : 
    4303             :     } else {
    4304             :         /* request body reader */
    4305             : 
    4306           0 :         if (r->request_body) {
    4307           0 :             lua_pushnil(L);
    4308           0 :             lua_pushliteral(L, "request body already exists");
    4309           0 :             return 2;
    4310             :         }
    4311             : 
    4312           0 :         if (r->discard_body) {
    4313           0 :             lua_pushnil(L);
    4314           0 :             lua_pushliteral(L, "request body discarded");
    4315           0 :             return 2;
    4316             :         }
    4317             : 
    4318             :         dd("req content length: %d", (int) r->headers_in.content_length_n);
    4319             : 
    4320           0 :         if (r->headers_in.content_length_n <= 0) {
    4321           0 :             lua_pushnil(L);
    4322           0 :             lua_pushliteral(L, "no body");
    4323           0 :             return 2;
    4324             :         }
    4325             : 
    4326           0 :         if (ngx_http_lua_test_expect(r) != NGX_OK) {
    4327           0 :             lua_pushnil(L);
    4328           0 :             lua_pushliteral(L, "test expect failed");
    4329           0 :             return 2;
    4330             :         }
    4331             : 
    4332             :         /* prevent other request body reader from running */
    4333             : 
    4334           0 :         rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
    4335           0 :         if (rb == NULL) {
    4336           0 :             return luaL_error(L, "no memory");
    4337             :         }
    4338             : 
    4339           0 :         rb->rest = r->headers_in.content_length_n;
    4340             : 
    4341           0 :         r->request_body = rb;
    4342             :     }
    4343             : 
    4344           0 :     lua_createtable(L, 3 /* narr */, 1 /* nrec */); /* the object */
    4345             : 
    4346           0 :     if (raw) {
    4347           0 :         lua_pushlightuserdata(L, &ngx_http_lua_raw_req_socket_metatable_key);
    4348             : 
    4349             :     } else {
    4350           0 :         lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key);
    4351             :     }
    4352             : 
    4353           0 :     lua_rawget(L, LUA_REGISTRYINDEX);
    4354           0 :     lua_setmetatable(L, -2);
    4355             : 
    4356           0 :     u = lua_newuserdata(L, sizeof(ngx_http_lua_socket_tcp_upstream_t));
    4357           0 :     if (u == NULL) {
    4358           0 :         return luaL_error(L, "no memory");
    4359             :     }
    4360             : 
    4361             : #if 1
    4362           0 :     lua_pushlightuserdata(L, &ngx_http_lua_downstream_udata_metatable_key);
    4363           0 :     lua_rawget(L, LUA_REGISTRYINDEX);
    4364           0 :     lua_setmetatable(L, -2);
    4365             : #endif
    4366             : 
    4367           0 :     lua_rawseti(L, 1, SOCKET_CTX_INDEX);
    4368             : 
    4369           0 :     ngx_memzero(u, sizeof(ngx_http_lua_socket_tcp_upstream_t));
    4370             : 
    4371           0 :     if (raw) {
    4372           0 :         u->raw_downstream = 1;
    4373             : 
    4374             :     } else {
    4375           0 :         u->body_downstream = 1;
    4376             :     }
    4377             : 
    4378           0 :     coctx = ctx->cur_co_ctx;
    4379             : 
    4380           0 :     u->request = r;
    4381             : 
    4382           0 :     llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
    4383             : 
    4384           0 :     u->conf = llcf;
    4385             : 
    4386           0 :     u->read_timeout = u->conf->read_timeout;
    4387           0 :     u->connect_timeout = u->conf->connect_timeout;
    4388           0 :     u->send_timeout = u->conf->send_timeout;
    4389             : 
    4390           0 :     cln = ngx_http_lua_cleanup_add(r, 0);
    4391           0 :     if (cln == NULL) {
    4392           0 :         u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR;
    4393           0 :         lua_pushnil(L);
    4394           0 :         lua_pushliteral(L, "no memory");
    4395           0 :         return 2;
    4396             :     }
    4397             : 
    4398           0 :     cln->handler = ngx_http_lua_socket_tcp_cleanup;
    4399           0 :     cln->data = u;
    4400           0 :     u->cleanup = &cln->handler;
    4401             : 
    4402           0 :     pc = &u->peer;
    4403             : 
    4404           0 :     pc->log = c->log;
    4405           0 :     pc->log_error = NGX_ERROR_ERR;
    4406             : 
    4407           0 :     pc->connection = c;
    4408             : 
    4409             :     dd("setting data to %p", u);
    4410             : 
    4411           0 :     coctx->data = u;
    4412           0 :     ctx->downstream = u;
    4413             : 
    4414           0 :     if (c->read->timer_set) {
    4415           0 :         ngx_del_timer(c->read);
    4416             :     }
    4417             : 
    4418           0 :     if (raw) {
    4419           0 :         if (c->write->timer_set) {
    4420           0 :             ngx_del_timer(c->write);
    4421             :         }
    4422             :     }
    4423             : 
    4424           0 :     lua_settop(L, 1);
    4425           0 :     return 1;
    4426             : }
    4427             : 
    4428             : 
    4429             : static void
    4430           0 : ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r)
    4431             : {
    4432             :     ngx_http_lua_ctx_t                  *ctx;
    4433             :     ngx_http_lua_socket_tcp_upstream_t  *u;
    4434             : 
    4435           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    4436             :                    "lua request socket read event handler");
    4437             : 
    4438           0 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    4439           0 :     if (ctx == NULL) {
    4440           0 :         r->read_event_handler = ngx_http_block_reading;
    4441           0 :         return;
    4442             :     }
    4443             : 
    4444           0 :     u = ctx->downstream;
    4445           0 :     if (u == NULL || u->peer.connection == NULL) {
    4446           0 :         r->read_event_handler = ngx_http_block_reading;
    4447           0 :         return;
    4448             :     }
    4449             : 
    4450           0 :     u->read_event_handler(r, u);
    4451             : }
    4452             : 
    4453             : static int
    4454           0 : ngx_http_lua_socket_tcp_getreusedtimes(lua_State *L)
    4455             : {
    4456             :     ngx_http_lua_socket_tcp_upstream_t    *u;
    4457             : 
    4458           0 :     if (lua_gettop(L) != 1) {
    4459           0 :         return luaL_error(L, "expecting 1 argument "
    4460             :                           "(including the object), but got %d", lua_gettop(L));
    4461             :     }
    4462             : 
    4463           0 :     luaL_checktype(L, 1, LUA_TTABLE);
    4464             : 
    4465           0 :     lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
    4466           0 :     u = lua_touserdata(L, -1);
    4467             : 
    4468           0 :     if (u == NULL
    4469           0 :         || u->peer.connection == NULL
    4470           0 :         || (u->read_closed && u->write_closed))
    4471             :     {
    4472           0 :         lua_pushnil(L);
    4473           0 :         lua_pushliteral(L, "closed");
    4474           0 :         return 2;
    4475             :     }
    4476             : 
    4477           0 :     lua_pushinteger(L, u->reused);
    4478           0 :     return 1;
    4479             : }
    4480             : 
    4481             : 
    4482             : static int
    4483           0 : ngx_http_lua_socket_tcp_setkeepalive(lua_State *L)
    4484             : {
    4485             :     ngx_http_lua_loc_conf_t             *llcf;
    4486             :     ngx_http_lua_socket_tcp_upstream_t  *u;
    4487             :     ngx_connection_t                    *c;
    4488             :     ngx_http_lua_socket_pool_t          *spool;
    4489             :     size_t                               size, key_len;
    4490             :     ngx_str_t                            key;
    4491             :     ngx_uint_t                           i;
    4492             :     ngx_queue_t                         *q;
    4493             :     ngx_peer_connection_t               *pc;
    4494             :     u_char                              *p;
    4495             :     ngx_http_request_t                  *r;
    4496             :     ngx_msec_t                           timeout;
    4497             :     ngx_uint_t                           pool_size;
    4498             :     int                                  n;
    4499             :     ngx_int_t                            rc;
    4500             :     ngx_buf_t                           *b;
    4501             : 
    4502             :     ngx_http_lua_socket_pool_item_t     *items, *item;
    4503             : 
    4504           0 :     n = lua_gettop(L);
    4505             : 
    4506           0 :     if (n < 1 || n > 3) {
    4507           0 :         return luaL_error(L, "expecting 1 to 3 arguments "
    4508             :                           "(including the object), but got %d", n);
    4509             :     }
    4510             : 
    4511           0 :     luaL_checktype(L, 1, LUA_TTABLE);
    4512             : 
    4513           0 :     lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key);
    4514           0 :     lua_rawget(L, LUA_REGISTRYINDEX);
    4515             : 
    4516           0 :     lua_rawgeti(L, 1, SOCKET_KEY_INDEX);
    4517           0 :     key.data = (u_char *) lua_tolstring(L, -1, &key.len);
    4518           0 :     if (key.data == NULL) {
    4519           0 :         lua_pushnil(L);
    4520           0 :         lua_pushliteral(L, "key not found");
    4521           0 :         return 2;
    4522             :     }
    4523             : 
    4524           0 :     lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
    4525           0 :     u = lua_touserdata(L, -1);
    4526           0 :     lua_pop(L, 1);
    4527             : 
    4528           0 :     if (u == NULL) {
    4529           0 :         lua_pushnil(L);
    4530           0 :         lua_pushliteral(L, "closed");
    4531           0 :         return 2;
    4532             :     }
    4533             : 
    4534             :     /* stack: obj cache key */
    4535             : 
    4536           0 :     pc = &u->peer;
    4537           0 :     c = pc->connection;
    4538             : 
    4539           0 :     if (c == NULL || u->read_closed || u->write_closed) {
    4540           0 :         lua_pushnil(L);
    4541           0 :         lua_pushliteral(L, "closed");
    4542           0 :         return 2;
    4543             :     }
    4544             : 
    4545           0 :     r = ngx_http_lua_get_req(L);
    4546           0 :     if (r == NULL) {
    4547           0 :         return luaL_error(L, "no request found");
    4548             :     }
    4549             : 
    4550           0 :     if (u->request != r) {
    4551           0 :         return luaL_error(L, "bad request");
    4552             :     }
    4553             : 
    4554           0 :     ngx_http_lua_socket_check_busy_connecting(r, u, L);
    4555           0 :     ngx_http_lua_socket_check_busy_reading(r, u, L);
    4556           0 :     ngx_http_lua_socket_check_busy_writing(r, u, L);
    4557             : 
    4558           0 :     b = &u->buffer;
    4559             : 
    4560           0 :     if (b->start && ngx_buf_size(b)) {
    4561             :         ngx_http_lua_probe_socket_tcp_setkeepalive_buf_unread(r, u, b->pos,
    4562             :                                                               b->last - b->pos);
    4563             : 
    4564           0 :         lua_pushnil(L);
    4565           0 :         lua_pushliteral(L, "unread data in buffer");
    4566           0 :         return 2;
    4567             :     }
    4568             : 
    4569           0 :     if (c->read->eof
    4570           0 :         || c->read->error
    4571           0 :         || c->read->timedout
    4572           0 :         || c->write->error
    4573           0 :         || c->write->timedout)
    4574             :     {
    4575           0 :         lua_pushnil(L);
    4576           0 :         lua_pushliteral(L, "invalid connection");
    4577           0 :         return 2;
    4578             :     }
    4579             : 
    4580           0 :     if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
    4581           0 :         lua_pushnil(L);
    4582           0 :         lua_pushliteral(L, "failed to handle read event");
    4583           0 :         return 2;
    4584             :     }
    4585             : 
    4586           0 :     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
    4587             :                    "lua tcp socket set keepalive: saving connection %p", c);
    4588             : 
    4589             :     dd("saving connection to key %s", lua_tostring(L, -1));
    4590             : 
    4591           0 :     lua_pushvalue(L, -1);
    4592           0 :     lua_rawget(L, -3);
    4593           0 :     spool = lua_touserdata(L, -1);
    4594           0 :     lua_pop(L, 1);
    4595             : 
    4596             :     /* stack: obj timeout? size? cache key */
    4597             : 
    4598           0 :     llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
    4599             : 
    4600           0 :     if (spool == NULL) {
    4601             :         /* create a new socket pool for the current peer key */
    4602             : 
    4603           0 :         if (n >= 3 && !lua_isnil(L, 3)) {
    4604           0 :             pool_size = luaL_checkinteger(L, 3);
    4605             : 
    4606             :         } else {
    4607           0 :             pool_size = llcf->pool_size;
    4608             :         }
    4609             : 
    4610           0 :         if (pool_size == 0) {
    4611           0 :             lua_pushnil(L);
    4612           0 :             lua_pushliteral(L, "zero pool size");
    4613           0 :             return 2;
    4614             :         }
    4615             : 
    4616           0 :         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    4617             :                        "lua tcp socket connection pool size: %ui", pool_size);
    4618             : 
    4619           0 :         key_len = ngx_align(key.len + 1, sizeof(void *));
    4620             : 
    4621           0 :         size = sizeof(ngx_http_lua_socket_pool_t) + key_len - 1
    4622           0 :                + sizeof(ngx_http_lua_socket_pool_item_t)
    4623           0 :                * pool_size;
    4624             : 
    4625           0 :         spool = lua_newuserdata(L, size);
    4626           0 :         if (spool == NULL) {
    4627           0 :             return luaL_error(L, "no memory");
    4628             :         }
    4629             : 
    4630           0 :         lua_pushlightuserdata(L, &ngx_http_lua_pool_udata_metatable_key);
    4631           0 :         lua_rawget(L, LUA_REGISTRYINDEX);
    4632           0 :         lua_setmetatable(L, -2);
    4633             : 
    4634           0 :         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
    4635             :                        "lua tcp socket keepalive create connection pool for key"
    4636             :                        " \"%s\"", lua_tostring(L, -2));
    4637             : 
    4638           0 :         lua_rawset(L, -3);
    4639             : 
    4640           0 :         spool->active_connections = 0;
    4641           0 :         spool->lua_vm = ngx_http_lua_get_lua_vm(r, NULL);
    4642             : 
    4643           0 :         ngx_queue_init(&spool->cache);
    4644           0 :         ngx_queue_init(&spool->free);
    4645             : 
    4646           0 :         p = ngx_copy(spool->key, key.data, key.len);
    4647           0 :         *p++ = '\0';
    4648             : 
    4649           0 :         items = (ngx_http_lua_socket_pool_item_t *) (spool->key + key_len);
    4650             : 
    4651             :         dd("items: %p", items);
    4652             : 
    4653           0 :         ngx_http_lua_assert((void *) items == ngx_align_ptr(items,
    4654             :                                                             sizeof(void *)));
    4655             : 
    4656           0 :         for (i = 0; i < pool_size; i++) {
    4657           0 :             ngx_queue_insert_head(&spool->free, &items[i].queue);
    4658           0 :             items[i].socket_pool = spool;
    4659             :         }
    4660             :     }
    4661             : 
    4662           0 :     if (ngx_queue_empty(&spool->free)) {
    4663             : 
    4664           0 :         q = ngx_queue_last(&spool->cache);
    4665           0 :         ngx_queue_remove(q);
    4666           0 :         spool->active_connections--;
    4667             : 
    4668           0 :         item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue);
    4669             : 
    4670           0 :         ngx_http_lua_socket_tcp_close_connection(item->connection);
    4671             : 
    4672             :     } else {
    4673           0 :         q = ngx_queue_head(&spool->free);
    4674           0 :         ngx_queue_remove(q);
    4675             : 
    4676           0 :         item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue);
    4677             :     }
    4678             : 
    4679           0 :     item->connection = c;
    4680           0 :     ngx_queue_insert_head(&spool->cache, q);
    4681             : 
    4682           0 :     if (!u->reused) {
    4683           0 :         spool->active_connections++;
    4684             :     }
    4685             : 
    4686           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
    4687             :                    "lua tcp socket clear current socket connection");
    4688             : 
    4689           0 :     pc->connection = NULL;
    4690             : 
    4691             : #if 0
    4692             :     if (u->cleanup) {
    4693             :         *u->cleanup = NULL;
    4694             :         u->cleanup = NULL;
    4695             :     }
    4696             : #endif
    4697             : 
    4698           0 :     if (c->read->timer_set) {
    4699           0 :         ngx_del_timer(c->read);
    4700             :     }
    4701             : 
    4702           0 :     if (c->write->timer_set) {
    4703           0 :         ngx_del_timer(c->write);
    4704             :     }
    4705             : 
    4706           0 :     if (n >= 2 && !lua_isnil(L, 2)) {
    4707           0 :         timeout = (ngx_msec_t) luaL_checkinteger(L, 2);
    4708             : 
    4709             :     } else {
    4710           0 :         timeout = llcf->keepalive_timeout;
    4711             :     }
    4712             : 
    4713             : #if (NGX_DEBUG)
    4714           0 :     if (timeout == 0) {
    4715           0 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    4716             :                        "lua tcp socket keepalive timeout: unlimited");
    4717             :     }
    4718             : #endif
    4719             : 
    4720           0 :     if (timeout) {
    4721           0 :         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    4722             :                        "lua tcp socket keepalive timeout: %M ms", timeout);
    4723             : 
    4724           0 :         ngx_add_timer(c->read, timeout);
    4725             :     }
    4726             : 
    4727           0 :     c->write->handler = ngx_http_lua_socket_keepalive_dummy_handler;
    4728           0 :     c->read->handler = ngx_http_lua_socket_keepalive_rev_handler;
    4729             : 
    4730           0 :     c->data = item;
    4731           0 :     c->idle = 1;
    4732           0 :     c->log = ngx_cycle->log;
    4733           0 :     c->pool->log = ngx_cycle->log;
    4734           0 :     c->read->log = ngx_cycle->log;
    4735           0 :     c->write->log = ngx_cycle->log;
    4736             : 
    4737           0 :     item->socklen = pc->socklen;
    4738           0 :     ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen);
    4739           0 :     item->reused = u->reused;
    4740             : 
    4741           0 :     if (c->read->ready) {
    4742           0 :         rc = ngx_http_lua_socket_keepalive_close_handler(c->read);
    4743           0 :         if (rc != NGX_OK) {
    4744           0 :             lua_pushnil(L);
    4745           0 :             lua_pushliteral(L, "connection in dubious state");
    4746           0 :             return 2;
    4747             :         }
    4748             :     }
    4749             : 
    4750             : #if 1
    4751           0 :     ngx_http_lua_socket_tcp_finalize(r, u);
    4752             : #endif
    4753             : 
    4754           0 :     lua_pushinteger(L, 1);
    4755           0 :     return 1;
    4756             : }
    4757             : 
    4758             : 
    4759             : static ngx_int_t
    4760           1 : ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, lua_State *L,
    4761             :     int key_index, ngx_http_lua_socket_tcp_upstream_t *u)
    4762             : {
    4763             :     ngx_http_lua_socket_pool_item_t     *item;
    4764             :     ngx_http_lua_socket_pool_t          *spool;
    4765             :     ngx_http_cleanup_t                  *cln;
    4766             :     ngx_queue_t                         *q;
    4767             :     int                                  top;
    4768             :     ngx_peer_connection_t               *pc;
    4769             :     ngx_connection_t                    *c;
    4770             : 
    4771           1 :     top = lua_gettop(L);
    4772             : 
    4773           1 :     if (key_index < 0) {
    4774           0 :         key_index = top + key_index + 1;
    4775             :     }
    4776             : 
    4777           1 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    4778             :                    "lua tcp socket pool get keepalive peer");
    4779             : 
    4780           1 :     pc = &u->peer;
    4781             : 
    4782           1 :     lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key);
    4783           1 :     lua_rawget(L, LUA_REGISTRYINDEX); /* table */
    4784           1 :     lua_pushvalue(L, key_index); /* key */
    4785           1 :     lua_rawget(L, -2);
    4786             : 
    4787           1 :     spool = lua_touserdata(L, -1);
    4788           1 :     if (spool == NULL) {
    4789           1 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
    4790             :                        "lua tcp socket keepalive connection pool not found");
    4791           1 :         lua_settop(L, top);
    4792           1 :         return NGX_DECLINED;
    4793             :     }
    4794             : 
    4795           0 :     u->socket_pool = spool;
    4796             : 
    4797           0 :     if (!ngx_queue_empty(&spool->cache)) {
    4798           0 :         q = ngx_queue_head(&spool->cache);
    4799             : 
    4800           0 :         item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue);
    4801           0 :         c = item->connection;
    4802             : 
    4803           0 :         ngx_queue_remove(q);
    4804           0 :         ngx_queue_insert_head(&spool->free, q);
    4805             : 
    4806           0 :         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
    4807             :                        "lua tcp socket get keepalive peer: using connection %p,"
    4808             :                        " fd:%d", c, c->fd);
    4809             : 
    4810           0 :         c->idle = 0;
    4811           0 :         c->log = pc->log;
    4812           0 :         c->pool->log = pc->log;
    4813           0 :         c->read->log = pc->log;
    4814           0 :         c->write->log = pc->log;
    4815           0 :         c->data = u;
    4816             : 
    4817             : #if 1
    4818           0 :         c->write->handler = ngx_http_lua_socket_tcp_handler;
    4819           0 :         c->read->handler = ngx_http_lua_socket_tcp_handler;
    4820             : #endif
    4821             : 
    4822           0 :         if (c->read->timer_set) {
    4823           0 :             ngx_del_timer(c->read);
    4824             :         }
    4825             : 
    4826           0 :         pc->connection = c;
    4827           0 :         pc->cached = 1;
    4828             : 
    4829           0 :         u->reused = item->reused + 1;
    4830             : 
    4831             : #if 1
    4832           0 :         u->write_event_handler = ngx_http_lua_socket_dummy_handler;
    4833           0 :         u->read_event_handler = ngx_http_lua_socket_dummy_handler;
    4834             : #endif
    4835             : 
    4836           0 :         if (u->cleanup == NULL) {
    4837           0 :             cln = ngx_http_lua_cleanup_add(r, 0);
    4838           0 :             if (cln == NULL) {
    4839           0 :                 u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR;
    4840           0 :                 lua_settop(L, top);
    4841           0 :                 return NGX_ERROR;
    4842             :             }
    4843             : 
    4844           0 :             cln->handler = ngx_http_lua_socket_tcp_cleanup;
    4845           0 :             cln->data = u;
    4846           0 :             u->cleanup = &cln->handler;
    4847             :         }
    4848             : 
    4849           0 :         lua_settop(L, top);
    4850             : 
    4851           0 :         return NGX_OK;
    4852             :     }
    4853             : 
    4854           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
    4855             :                    "lua tcp socket keepalive: connection pool empty");
    4856             : 
    4857           0 :     lua_settop(L, top);
    4858             : 
    4859           0 :     return NGX_DECLINED;
    4860             : }
    4861             : 
    4862             : 
    4863             : static void
    4864           0 : ngx_http_lua_socket_keepalive_dummy_handler(ngx_event_t *ev)
    4865             : {
    4866           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
    4867             :                    "keepalive dummy handler");
    4868           0 : }
    4869             : 
    4870             : 
    4871             : static void
    4872           0 : ngx_http_lua_socket_keepalive_rev_handler(ngx_event_t *ev)
    4873             : {
    4874           0 :     (void) ngx_http_lua_socket_keepalive_close_handler(ev);
    4875           0 : }
    4876             : 
    4877             : 
    4878             : static ngx_int_t
    4879           0 : ngx_http_lua_socket_keepalive_close_handler(ngx_event_t *ev)
    4880             : {
    4881             :     ngx_http_lua_socket_pool_item_t     *item;
    4882             :     ngx_http_lua_socket_pool_t          *spool;
    4883             : 
    4884             :     int                n;
    4885             :     char               buf[1];
    4886             :     ngx_connection_t  *c;
    4887             : 
    4888           0 :     c = ev->data;
    4889             : 
    4890           0 :     if (c->close) {
    4891           0 :         goto close;
    4892             :     }
    4893             : 
    4894           0 :     if (c->read->timedout) {
    4895           0 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
    4896             :                        "lua tcp socket keepalive max idle timeout");
    4897             : 
    4898           0 :         goto close;
    4899             :     }
    4900             : 
    4901             :     dd("read event ready: %d", (int) c->read->ready);
    4902             : 
    4903           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
    4904             :                    "lua tcp socket keepalive close handler check stale events");
    4905             : 
    4906           0 :     n = recv(c->fd, buf, 1, MSG_PEEK);
    4907             : 
    4908           0 :     if (n == -1 && ngx_socket_errno == NGX_EAGAIN) {
    4909             :         /* stale event */
    4910             : 
    4911           0 :         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
    4912           0 :             goto close;
    4913             :         }
    4914             : 
    4915           0 :         return NGX_OK;
    4916             :     }
    4917             : 
    4918           0 : close:
    4919             : 
    4920           0 :     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
    4921             :                    "lua tcp socket keepalive close handler: fd:%d", c->fd);
    4922             : 
    4923           0 :     item = c->data;
    4924           0 :     spool = item->socket_pool;
    4925             : 
    4926           0 :     ngx_http_lua_socket_tcp_close_connection(c);
    4927             : 
    4928           0 :     ngx_queue_remove(&item->queue);
    4929           0 :     ngx_queue_insert_head(&spool->free, &item->queue);
    4930           0 :     spool->active_connections--;
    4931             : 
    4932             :     dd("keepalive: active connections: %u",
    4933             :        (unsigned) spool->active_connections);
    4934             : 
    4935           0 :     if (spool->active_connections == 0) {
    4936           0 :         ngx_http_lua_socket_free_pool(ev->log, spool);
    4937             :     }
    4938             : 
    4939           0 :     return NGX_DECLINED;
    4940             : }
    4941             : 
    4942             : 
    4943             : static void
    4944           0 : ngx_http_lua_socket_free_pool(ngx_log_t *log, ngx_http_lua_socket_pool_t *spool)
    4945             : {
    4946             :     lua_State                           *L;
    4947             : 
    4948           0 :     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
    4949             :                    "lua tcp socket keepalive: free connection pool for \"%s\"",
    4950             :                    spool->key);
    4951             : 
    4952           0 :     L = spool->lua_vm;
    4953             : 
    4954           0 :     lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key);
    4955           0 :     lua_rawget(L, LUA_REGISTRYINDEX);
    4956           0 :     lua_pushstring(L, (char *) spool->key);
    4957           0 :     lua_pushnil(L);
    4958           0 :     lua_rawset(L, -3);
    4959           0 :     lua_pop(L, 1);
    4960           0 : }
    4961             : 
    4962             : 
    4963             : static int
    4964           0 : ngx_http_lua_socket_shutdown_pool(lua_State *L)
    4965             : {
    4966             :     ngx_queue_t                         *q;
    4967             :     ngx_connection_t                    *c;
    4968             :     ngx_http_lua_socket_pool_t          *spool;
    4969             :     ngx_http_lua_socket_pool_item_t     *item;
    4970             : 
    4971           0 :     spool = lua_touserdata(L, 1);
    4972           0 :     if (spool == NULL) {
    4973           0 :         return 0;
    4974             :     }
    4975             : 
    4976           0 :     while (!ngx_queue_empty(&spool->cache)) {
    4977           0 :         q = ngx_queue_head(&spool->cache);
    4978             : 
    4979           0 :         item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue);
    4980           0 :         c = item->connection;
    4981             : 
    4982           0 :         ngx_http_lua_socket_tcp_close_connection(c);
    4983             : 
    4984           0 :         ngx_queue_remove(q);
    4985           0 :         ngx_queue_insert_head(&spool->free, q);
    4986             :     }
    4987             : 
    4988           0 :     spool->active_connections = 0;
    4989             : 
    4990           0 :     return 0;
    4991             : }
    4992             : 
    4993             : 
    4994             : static int
    4995           1 : ngx_http_lua_socket_tcp_upstream_destroy(lua_State *L)
    4996             : {
    4997             :     ngx_http_lua_socket_tcp_upstream_t      *u;
    4998             : 
    4999             :     dd("upstream destroy triggered by Lua GC");
    5000             : 
    5001           1 :     u = lua_touserdata(L, 1);
    5002           1 :     if (u == NULL) {
    5003           0 :         return 0;
    5004             :     }
    5005             : 
    5006           1 :     if (u->cleanup) {
    5007           0 :         ngx_http_lua_socket_tcp_cleanup(u); /* it will clear u->cleanup */
    5008             :     }
    5009             : 
    5010           1 :     return 0;
    5011             : }
    5012             : 
    5013             : 
    5014             : static int
    5015           0 : ngx_http_lua_socket_downstream_destroy(lua_State *L)
    5016             : {
    5017             :     ngx_http_lua_socket_tcp_upstream_t     *u;
    5018             : 
    5019             :     dd("downstream destroy");
    5020             : 
    5021           0 :     u = lua_touserdata(L, 1);
    5022           0 :     if (u == NULL) {
    5023             :         dd("u is NULL");
    5024           0 :         return 0;
    5025             :     }
    5026             : 
    5027           0 :     if (u->cleanup) {
    5028           0 :         ngx_http_lua_socket_tcp_cleanup(u); /* it will clear u->cleanup */
    5029             :     }
    5030             : 
    5031           0 :     return 0;
    5032             : }
    5033             : 
    5034             : 
    5035             : static ngx_int_t
    5036           0 : ngx_http_lua_socket_push_input_data(ngx_http_request_t *r,
    5037             :     ngx_http_lua_ctx_t *ctx, ngx_http_lua_socket_tcp_upstream_t *u,
    5038             :     lua_State *L)
    5039             : {
    5040             :     ngx_chain_t             *cl;
    5041             :     ngx_chain_t            **ll;
    5042             : #if (DDEBUG) || (NGX_DTRACE)
    5043             :     size_t                   size = 0;
    5044             : #endif
    5045             :     size_t                   chunk_size;
    5046             :     ngx_buf_t               *b;
    5047             :     size_t                   nbufs;
    5048             :     luaL_Buffer              luabuf;
    5049             : 
    5050             :     dd("bufs_in: %p, buf_in: %p", u->bufs_in, u->buf_in);
    5051             : 
    5052           0 :     nbufs = 0;
    5053           0 :     ll = NULL;
    5054             : 
    5055           0 :     luaL_buffinit(L, &luabuf);
    5056             : 
    5057           0 :     for (cl = u->bufs_in; cl; cl = cl->next) {
    5058           0 :         b = cl->buf;
    5059           0 :         chunk_size = b->last - b->pos;
    5060             : 
    5061             :         dd("copying input data chunk from %p: \"%.*s\"", cl,
    5062             :            (int) chunk_size, b->pos);
    5063             : 
    5064           0 :         luaL_addlstring(&luabuf, (char *) b->pos, chunk_size);
    5065             : 
    5066           0 :         if (cl->next) {
    5067           0 :             ll = &cl->next;
    5068             :         }
    5069             : 
    5070             : #if (DDEBUG) || (NGX_DTRACE)
    5071             :         size += chunk_size;
    5072             : #endif
    5073             : 
    5074           0 :         nbufs++;
    5075             :     }
    5076             : 
    5077           0 :     luaL_pushresult(&luabuf);
    5078             : 
    5079             : #if (DDEBUG)
    5080             :     dd("size: %d, nbufs: %d", (int) size, (int) nbufs);
    5081             : #endif
    5082             : 
    5083             : #if (NGX_DTRACE)
    5084             :     ngx_http_lua_probe_socket_tcp_receive_done(r, u,
    5085             :                                                (u_char *) lua_tostring(L, -1),
    5086             :                                                size);
    5087             : #endif
    5088             : 
    5089           0 :     if (nbufs > 1 && ll) {
    5090             :         dd("recycle buffers: %d", (int) (nbufs - 1));
    5091             : 
    5092           0 :         *ll = ctx->free_recv_bufs;
    5093           0 :         ctx->free_recv_bufs = u->bufs_in;
    5094           0 :         u->bufs_in = u->buf_in;
    5095             :     }
    5096             : 
    5097           0 :     if (u->buffer.pos == u->buffer.last) {
    5098             :         dd("resetting u->buffer pos & last");
    5099           0 :         u->buffer.pos = u->buffer.start;
    5100           0 :         u->buffer.last = u->buffer.start;
    5101             :     }
    5102             : 
    5103           0 :     if (u->bufs_in) {
    5104           0 :         u->buf_in->buf->last = u->buffer.pos;
    5105           0 :         u->buf_in->buf->pos = u->buffer.pos;
    5106             :     }
    5107             : 
    5108           0 :     return NGX_OK;
    5109             : }
    5110             : 
    5111             : 
    5112             : static ngx_int_t
    5113           0 : ngx_http_lua_socket_add_input_buffer(ngx_http_request_t *r,
    5114             :     ngx_http_lua_socket_tcp_upstream_t *u)
    5115             : {
    5116             :     ngx_chain_t             *cl;
    5117             :     ngx_http_lua_ctx_t      *ctx;
    5118             : 
    5119           0 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    5120             : 
    5121           0 :     cl = ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool,
    5122             :                                          &ctx->free_recv_bufs,
    5123           0 :                                          u->conf->buffer_size);
    5124             : 
    5125           0 :     if (cl == NULL) {
    5126           0 :         return NGX_ERROR;
    5127             :     }
    5128             : 
    5129           0 :     u->buf_in->next = cl;
    5130           0 :     u->buf_in = cl;
    5131           0 :     u->buffer = *cl->buf;
    5132             : 
    5133           0 :     return NGX_OK;
    5134             : }
    5135             : 
    5136             : 
    5137             : static ngx_int_t
    5138           0 : ngx_http_lua_socket_add_pending_data(ngx_http_request_t *r,
    5139             :     ngx_http_lua_socket_tcp_upstream_t *u, u_char *pos, size_t len, u_char *pat,
    5140             :     int prefix, int old_state)
    5141             : {
    5142             :     u_char          *last;
    5143             :     ngx_buf_t       *b;
    5144             : 
    5145             :     dd("resuming data: %d: [%.*s]", prefix, prefix, pat);
    5146             : 
    5147           0 :     last = &pos[len];
    5148             : 
    5149           0 :     b = u->buf_in->buf;
    5150             : 
    5151           0 :     if (last - b->last == old_state) {
    5152           0 :         b->last += prefix;
    5153           0 :         return NGX_OK;
    5154             :     }
    5155             : 
    5156             :     dd("need more buffers because %d != %d", (int) (last - b->last),
    5157             :        (int) old_state);
    5158             : 
    5159           0 :     if (ngx_http_lua_socket_insert_buffer(r, u, pat, prefix) != NGX_OK) {
    5160           0 :         return NGX_ERROR;
    5161             :     }
    5162             : 
    5163           0 :     b->pos = last;
    5164           0 :     b->last = last;
    5165             : 
    5166           0 :     return NGX_OK;
    5167             : }
    5168             : 
    5169             : 
    5170           0 : static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r,
    5171             :     ngx_http_lua_socket_tcp_upstream_t *u, u_char *pat, size_t prefix)
    5172             : {
    5173             :     ngx_chain_t             *cl, *new_cl, **ll;
    5174             :     ngx_http_lua_ctx_t      *ctx;
    5175             :     size_t                   size;
    5176             :     ngx_buf_t               *b;
    5177             : 
    5178           0 :     if (prefix <= u->conf->buffer_size) {
    5179           0 :         size = u->conf->buffer_size;
    5180             : 
    5181             :     } else {
    5182           0 :         size = prefix;
    5183             :     }
    5184             : 
    5185           0 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    5186             : 
    5187           0 :     new_cl = ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool,
    5188             :                                              &ctx->free_recv_bufs,
    5189             :                                              size);
    5190             : 
    5191           0 :     if (new_cl == NULL) {
    5192           0 :         return NGX_ERROR;
    5193             :     }
    5194             : 
    5195           0 :     b = new_cl->buf;
    5196             : 
    5197           0 :     b->last = ngx_copy(b->last, pat, prefix);
    5198             : 
    5199             :     dd("copy resumed data to %p: %d: \"%.*s\"",
    5200             :        new_cl, (int) (b->last - b->pos), (int) (b->last - b->pos), b->pos);
    5201             : 
    5202             :     dd("before resuming data: bufs_in %p, buf_in %p, buf_in next %p",
    5203             :        u->bufs_in, u->buf_in, u->buf_in->next);
    5204             : 
    5205           0 :     ll = &u->bufs_in;
    5206           0 :     for (cl = u->bufs_in; cl->next; cl = cl->next) {
    5207           0 :         ll = &cl->next;
    5208             :     }
    5209             : 
    5210           0 :     *ll = new_cl;
    5211           0 :     new_cl->next = u->buf_in;
    5212             : 
    5213             :     dd("after resuming data: bufs_in %p, buf_in %p, buf_in next %p",
    5214             :        u->bufs_in, u->buf_in, u->buf_in->next);
    5215             : 
    5216             : #if (DDEBUG)
    5217             :     for (cl = u->bufs_in; cl; cl = cl->next) {
    5218             :         b = cl->buf;
    5219             : 
    5220             :         dd("result buf after resuming data: %p: %.*s", cl,
    5221             :            (int) ngx_buf_size(b), b->pos);
    5222             :     }
    5223             : #endif
    5224             : 
    5225           0 :     return NGX_OK;
    5226             : }
    5227             : 
    5228             : 
    5229             : static ngx_int_t
    5230           1 : ngx_http_lua_socket_tcp_conn_resume(ngx_http_request_t *r)
    5231             : {
    5232           1 :     return ngx_http_lua_socket_tcp_resume_helper(r, SOCKET_OP_CONNECT);
    5233             : }
    5234             : 
    5235             : 
    5236             : static ngx_int_t
    5237           0 : ngx_http_lua_socket_tcp_read_resume(ngx_http_request_t *r)
    5238             : {
    5239           0 :     return ngx_http_lua_socket_tcp_resume_helper(r, SOCKET_OP_READ);
    5240             : }
    5241             : 
    5242             : 
    5243             : static ngx_int_t
    5244           0 : ngx_http_lua_socket_tcp_write_resume(ngx_http_request_t *r)
    5245             : {
    5246           0 :     return ngx_http_lua_socket_tcp_resume_helper(r, SOCKET_OP_WRITE);
    5247             : }
    5248             : 
    5249             : 
    5250             : static ngx_int_t
    5251           1 : ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op)
    5252             : {
    5253             :     int                          nret;
    5254             :     lua_State                   *vm;
    5255             :     ngx_int_t                    rc;
    5256             :     ngx_uint_t                   nreqs;
    5257             :     ngx_connection_t            *c;
    5258             :     ngx_http_lua_ctx_t          *ctx;
    5259             :     ngx_http_lua_co_ctx_t       *coctx;
    5260             : 
    5261             :     ngx_http_lua_socket_tcp_retval_handler  prepare_retvals;
    5262             : 
    5263             :     ngx_http_lua_socket_tcp_upstream_t      *u;
    5264             : 
    5265           1 :     ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
    5266           1 :     if (ctx == NULL) {
    5267           0 :         return NGX_ERROR;
    5268             :     }
    5269             : 
    5270           1 :     ctx->resume_handler = ngx_http_lua_wev_handler;
    5271             : 
    5272           1 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    5273             :                    "lua tcp operation done, resuming lua thread");
    5274             : 
    5275           1 :     coctx = ctx->cur_co_ctx;
    5276             : 
    5277             :     dd("coctx: %p", coctx);
    5278             : 
    5279           1 :     u = coctx->data;
    5280             : 
    5281           1 :     switch (socket_op) {
    5282           1 :     case SOCKET_OP_CONNECT:
    5283             :     case SOCKET_OP_WRITE:
    5284           1 :         prepare_retvals = u->write_prepare_retvals;
    5285           1 :         break;
    5286             : 
    5287           0 :     case SOCKET_OP_READ:
    5288           0 :         prepare_retvals = u->read_prepare_retvals;
    5289           0 :         break;
    5290             : 
    5291           0 :     default:
    5292             :         /* impossible to reach here */
    5293           0 :         return NGX_ERROR;
    5294             :     }
    5295             : 
    5296           1 :     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    5297             :                    "lua tcp socket calling prepare retvals handler %p, "
    5298             :                    "u:%p", prepare_retvals, u);
    5299             : 
    5300           1 :     nret = prepare_retvals(r, u, ctx->cur_co_ctx->co);
    5301           1 :     if (nret == NGX_AGAIN) {
    5302           0 :         return NGX_DONE;
    5303             :     }
    5304             : 
    5305           1 :     c = r->connection;
    5306           1 :     vm = ngx_http_lua_get_lua_vm(r, ctx);
    5307           1 :     nreqs = c->requests;
    5308             : 
    5309           1 :     rc = ngx_http_lua_run_thread(vm, r, ctx, nret);
    5310             : 
    5311           1 :     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    5312             :                    "lua run thread returned %d", rc);
    5313             : 
    5314           1 :     if (rc == NGX_AGAIN) {
    5315           0 :         return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
    5316             :     }
    5317             : 
    5318           1 :     if (rc == NGX_DONE) {
    5319           0 :         ngx_http_lua_finalize_request(r, NGX_DONE);
    5320           0 :         return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
    5321             :     }
    5322             : 
    5323           1 :     if (ctx->entered_content_phase) {
    5324           1 :         ngx_http_lua_finalize_request(r, rc);
    5325           1 :         return NGX_DONE;
    5326             :     }
    5327             : 
    5328           0 :     return rc;
    5329             : }
    5330             : 
    5331             : 
    5332             : static void
    5333           0 : ngx_http_lua_tcp_resolve_cleanup(void *data)
    5334             : {
    5335             :     ngx_resolver_ctx_t                      *rctx;
    5336             :     ngx_http_lua_socket_tcp_upstream_t      *u;
    5337           0 :     ngx_http_lua_co_ctx_t                   *coctx = data;
    5338             : 
    5339           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
    5340             :                    "lua tcp socket abort resolver");
    5341             : 
    5342           0 :     u = coctx->data;
    5343           0 :     if (u == NULL) {
    5344           0 :         return;
    5345             :     }
    5346             : 
    5347           0 :     rctx = u->resolved->ctx;
    5348           0 :     if (rctx == NULL) {
    5349           0 :         return;
    5350             :     }
    5351             : 
    5352             :     /* just to be safer */
    5353           0 :     rctx->handler = ngx_http_lua_socket_empty_resolve_handler;
    5354             : 
    5355           0 :     ngx_resolve_name_done(rctx);
    5356             : }
    5357             : 
    5358             : 
    5359             : static void
    5360           0 : ngx_http_lua_coctx_cleanup(void *data)
    5361             : {
    5362             :     ngx_http_lua_socket_tcp_upstream_t      *u;
    5363           0 :     ngx_http_lua_co_ctx_t                   *coctx = data;
    5364             : 
    5365             :     dd("running coctx cleanup");
    5366             : 
    5367           0 :     u = coctx->data;
    5368           0 :     if (u == NULL) {
    5369           0 :         return;
    5370             :     }
    5371             : 
    5372           0 :     if (u->request == NULL) {
    5373           0 :         return;
    5374             :     }
    5375             : 
    5376           0 :     ngx_http_lua_socket_tcp_finalize(u->request, u);
    5377             : }
    5378             : 
    5379             : 
    5380             : #if (NGX_HTTP_SSL)
    5381             : 
    5382             : static int
    5383           0 : ngx_http_lua_ssl_free_session(lua_State *L)
    5384             : {
    5385             :     ngx_ssl_session_t      **psession;
    5386             : 
    5387           0 :     psession = lua_touserdata(L, 1);
    5388           0 :     if (psession && *psession != NULL) {
    5389           0 :         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
    5390             :                        "lua ssl free session: %p:%d", *psession,
    5391             :                        (*psession)->references);
    5392             : 
    5393           0 :         ngx_ssl_free_session(*psession);
    5394             :     }
    5395             : 
    5396           0 :     return 0;
    5397             : }
    5398             : 
    5399             : #endif  /* NGX_HTTP_SSL */
    5400             : 
    5401             : 
    5402             : void
    5403          19 : ngx_http_lua_cleanup_conn_pools(lua_State *L)
    5404             : {
    5405             :     ngx_queue_t                         *q;
    5406             :     ngx_connection_t                    *c;
    5407             :     ngx_http_lua_socket_pool_t          *spool;
    5408             :     ngx_http_lua_socket_pool_item_t     *item;
    5409             : 
    5410          19 :     lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key);
    5411          19 :     lua_rawget(L, LUA_REGISTRYINDEX); /* table */
    5412             : 
    5413          19 :     lua_pushnil(L);  /* first key */
    5414          38 :     while (lua_next(L, -2) != 0) {
    5415             :         /* tb key val */
    5416           0 :         spool = lua_touserdata(L, -1);
    5417             : 
    5418           0 :         if (!ngx_queue_empty(&spool->cache)) {
    5419           0 :             q = ngx_queue_head(&spool->cache);
    5420           0 :             item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue);
    5421           0 :             c = item->connection;
    5422             : 
    5423           0 :             ngx_http_lua_socket_tcp_close_connection(c);
    5424             : 
    5425           0 :             ngx_queue_remove(q);
    5426             : 
    5427           0 :             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
    5428             :                            "lua tcp socket keepalive: free connection pool "
    5429             :                            "for \"%s\"", spool->key);
    5430             :         }
    5431             : 
    5432           0 :         lua_pop(L, 1);
    5433             :     }
    5434             : 
    5435          19 :     lua_pop(L, 1);
    5436          19 : }
    5437             : 
    5438             : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */

Generated by: LCOV version 1.13