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: */
|