1# vim:set ft= ts=4 sw=4 et fdm=marker:
2use lib '.';
3use t::TestCore;
4use Cwd qw(cwd);
5
6#worker_connections(1014);
7#master_process_enabled(1);
8log_level('debug');
9
10#repeat_each(120);
11repeat_each(2);
12
13plan tests => repeat_each() * (blocks() * 3 + 11);
14
15#no_diff();
16#no_long_string();
17
18my $pwd = cwd();
19
20add_block_preprocessor(sub {
21    my $block = shift;
22
23    my $http_config = $block->http_config || '';
24
25    $http_config .= <<_EOC_;
26
27    lua_package_path "$pwd/lib/?.lua;\$prefix/html/?.lua;../lua-resty-lrucache/lib/?.lua;;";
28    init_by_lua_block {
29        local verbose = false
30        if verbose then
31            local dump = require "jit.dump"
32            dump.on(nil, "$Test::Nginx::Util::ErrLogFile")
33        else
34            local v = require "jit.v"
35            v.on("$Test::Nginx::Util::ErrLogFile")
36        end
37
38        require "resty.core"
39        -- jit.off()
40    }
41_EOC_
42
43    $block->set_value("http_config", $http_config);
44});
45
46check_accum_error_log();
47
48$ENV{TEST_NGINX_HTML_DIR} ||= html_dir();
49
50run_tests();
51
52__DATA__
53
54=== TEST 1: get ngx.ctx
55--- config
56    location = /t {
57        content_by_lua_block {
58            for i = 1, 100 do
59                ngx.ctx.foo = i
60            end
61            ngx.say("ctx.foo = ", ngx.ctx.foo)
62        }
63    }
64--- request
65GET /t
66--- response_body
67ctx.foo = 100
68--- no_error_log
69[error]
70 -- NYI:
71 bad argument
72--- error_log eval
73qr/\[TRACE\s+\d+\s+content_by_lua\(nginx\.conf:\d+\):2 loop\]/
74
75
76
77=== TEST 2: set ngx.ctx
78--- config
79    location = /t {
80        content_by_lua_block {
81            for i = 1, 100 do
82                ngx.ctx = {foo = i}
83            end
84            ngx.say("ctx.foo = ", ngx.ctx.foo)
85        }
86    }
87--- request
88GET /t
89--- response_body
90ctx.foo = 100
91--- no_error_log
92[error]
93 -- NYI:
94 bad argument
95--- error_log eval
96qr/\[TRACE\s+\d+\s+content_by_lua\(nginx\.conf:\d+\):2 loop\]/
97
98
99
100=== TEST 3: ngx.ctx in ssl_certificate_by_lua
101--- http_config
102    server {
103        listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
104        server_name   test.com;
105        ssl_certificate_by_lua_block {
106            ngx.ctx.answer = 42
107            ngx.log(ngx.WARN, "ngx.ctx.answer = ", ngx.ctx.answer)
108
109            ngx.ctx.count = 0
110        }
111        ssl_certificate ../../cert/test.crt;
112        ssl_certificate_key ../../cert/test.key;
113
114        server_tokens off;
115        location /foo {
116            content_by_lua_block {
117                ngx.say(ngx.ctx.answer)
118                ngx.ctx.count = ngx.ctx.count + 1
119                ngx.say(ngx.ctx.count)
120            }
121        }
122    }
123--- config
124    lua_ssl_trusted_certificate ../../cert/test.crt;
125
126    location /t {
127        content_by_lua_block {
128            do
129                local sock = ngx.socket.tcp()
130
131                sock:settimeout(3000)
132
133                local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
134                if not ok then
135                    ngx.say("failed to connect: ", err)
136                    return
137                end
138
139                local sess, err = sock:sslhandshake(nil, "test.com", true)
140                if not sess then
141                    ngx.say("failed to do SSL handshake: ", err)
142                    return
143                end
144
145                for i = 1, 2 do
146                    local req = "GET /foo HTTP/1.1\r\nHost: test.com\r\n\r\n"
147                    local bytes, err = sock:send(req)
148                    if not bytes then
149                        ngx.say("failed to send http request: ", err)
150                        return
151                    end
152
153                    local body_seen = false
154                    while true do
155                        local line, err = sock:receive()
156                        if not line then
157                            break
158                        end
159
160                        if body_seen then
161                            if line == "0" then
162                                assert(sock:receive())
163                                break
164                            end
165                            local line, err = sock:receive(line)
166                            ngx.print("received: ", line)
167                            assert(sock:receive())
168
169                        elseif line == "" then
170                            body_seen = true
171                        end
172                    end
173                end
174
175                sock:close()
176            end  -- do
177            -- collectgarbage()
178        }
179    }
180
181--- request
182GET /t
183--- response_body
184received: 42
185received: 1
186received: 42
187received: 1
188--- error_log
189ngx.ctx.answer = 42
190--- grep_error_log eval
191qr/lua release ngx.ctx at ref \d+/
192--- grep_error_log_out eval
193["lua release ngx.ctx at ref 2
194lua release ngx.ctx at ref 2
195lua release ngx.ctx at ref 1
196",
197"lua release ngx.ctx at ref 2
198lua release ngx.ctx at ref 2
199lua release ngx.ctx at ref 1
200lua release ngx.ctx at ref 2
201lua release ngx.ctx at ref 2
202lua release ngx.ctx at ref 1
203"]
204--- no_error_log
205[error]
206
207
208
209=== TEST 4: ngx.ctx in ssl_certificate_by_lua (share objects)
210--- http_config
211    server {
212        listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
213        server_name   test.com;
214        ssl_certificate_by_lua_block {
215            ngx.ctx.req = { count = 0 }
216        }
217        ssl_certificate ../../cert/test.crt;
218        ssl_certificate_key ../../cert/test.key;
219
220        server_tokens off;
221        location /foo {
222            content_by_lua_block {
223                ngx.ctx.req.count = ngx.ctx.req.count + 1
224                ngx.say(ngx.ctx.req.count)
225            }
226        }
227    }
228--- config
229    lua_ssl_trusted_certificate ../../cert/test.crt;
230
231    location /t {
232        content_by_lua_block {
233            do
234                local sock = ngx.socket.tcp()
235
236                sock:settimeout(3000)
237
238                local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
239                if not ok then
240                    ngx.say("failed to connect: ", err)
241                    return
242                end
243
244                local sess, err = sock:sslhandshake(nil, "test.com", true)
245                if not sess then
246                    ngx.say("failed to do SSL handshake: ", err)
247                    return
248                end
249
250                for i = 1, 2 do
251                    local req = "GET /foo HTTP/1.1\r\nHost: test.com\r\n\r\n"
252                    local bytes, err = sock:send(req)
253                    if not bytes then
254                        ngx.say("failed to send http request: ", err)
255                        return
256                    end
257
258                    local body_seen = false
259                    while true do
260                        local line, err = sock:receive()
261                        if not line then
262                            break
263                        end
264
265                        if body_seen then
266                            if line == "0" then
267                                assert(sock:receive())
268                                break
269                            end
270                            local line, err = sock:receive(line)
271                            ngx.print("received: ", line)
272                            assert(sock:receive())
273
274                        elseif line == "" then
275                            body_seen = true
276                        end
277                    end
278                end
279
280                sock:close()
281            end  -- do
282            -- collectgarbage()
283        }
284    }
285
286--- request
287GET /t
288--- response_body
289received: 1
290received: 2
291--- no_error_log
292[error]
293
294
295
296=== TEST 5: ngx.ctx in ssl_certificate_by_lua (release ctx when client aborted)
297--- http_config
298    server {
299        listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
300        server_name   test.com;
301        ssl_certificate_by_lua_block {
302            local ssl = require "ngx.ssl"
303            ssl.clear_certs()
304            ngx.ctx.answer = 42
305        }
306        ssl_certificate ../../cert/test.crt;
307        ssl_certificate_key ../../cert/test.key;
308
309        server_tokens off;
310        location /foo {
311            return 200 "ok";
312        }
313    }
314--- config
315    lua_ssl_trusted_certificate ../../cert/test.crt;
316
317    location /t {
318        content_by_lua_block {
319            do
320                local sock = ngx.socket.tcp()
321                sock:settimeout(3000)
322
323                local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
324                if not ok then
325                    ngx.say("failed to connect: ", err)
326                    return
327                end
328
329                local sess, err = sock:sslhandshake(nil, "test.com", true)
330                if not sess then
331                    ngx.say("failed to do SSL handshake: ", err)
332                end
333
334                sock:close()
335            end  -- do
336            -- collectgarbage()
337        }
338    }
339
340--- request
341GET /t
342--- response_body
343failed to do SSL handshake: handshake failed
344--- grep_error_log eval
345qr/lua release ngx.ctx at ref \d+/
346--- grep_error_log_out eval
347["lua release ngx.ctx at ref 1
348",
349"lua release ngx.ctx at ref 1
350lua release ngx.ctx at ref 1
351"]
352
353
354
355=== TEST 6: ngx.ctx in ssl_session_store_by_lua
356--- http_config
357    ssl_session_store_by_lua_block {
358        ngx.ctx.answer = 42
359        ngx.log(ngx.WARN, "ngx.ctx.answer = ", ngx.ctx.answer)
360
361        ngx.ctx.count = 0
362    }
363
364    server {
365        listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
366        server_name test.com;
367        ssl_session_tickets off;
368        ssl_certificate ../../cert/test.crt;
369        ssl_certificate_key ../../cert/test.key;
370
371        server_tokens off;
372        location /foo {
373            content_by_lua_block {
374                ngx.say(ngx.ctx.answer)
375                ngx.ctx.count = ngx.ctx.count + 1
376                ngx.say(ngx.ctx.count)
377            }
378        }
379    }
380--- config
381    lua_ssl_trusted_certificate ../../cert/test.crt;
382
383    location /t {
384        content_by_lua_block {
385            do
386                local sock = ngx.socket.tcp()
387                sock:settimeout(3000)
388
389                local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
390                if not ok then
391                    ngx.say("failed to connect: ", err)
392                    return
393                end
394
395                local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true)
396                if not sess then
397                    ngx.say("failed to do SSL handshake: ", err)
398                    return
399                end
400
401                for i = 1, 2 do
402                    local req = "GET /foo HTTP/1.1\r\nHost: test.com\r\n\r\n"
403                    local bytes, err = sock:send(req)
404                    if not bytes then
405                        ngx.say("failed to send http request: ", err)
406                        return
407                    end
408
409                    local body_seen = false
410                    while true do
411                        local line, err = sock:receive()
412                        if not line then
413                            break
414                        end
415
416                        if body_seen then
417                            if line == "0" then
418                                assert(sock:receive())
419                                break
420                            end
421                            local line, err = sock:receive(line)
422                            ngx.print("received: ", line)
423                            assert(sock:receive())
424
425                        elseif line == "" then
426                            body_seen = true
427                        end
428                    end
429                end
430
431                package.loaded.session = sess
432                sock:close()
433            end  -- do
434        }
435    }
436--- request
437GET /t
438--- response_body
439received: 42
440received: 1
441received: 42
442received: 1
443--- error_log
444ngx.ctx.answer = 42
445--- grep_error_log eval
446qr/lua release ngx.ctx at ref \d+/
447--- grep_error_log_out eval
448["lua release ngx.ctx at ref 2
449lua release ngx.ctx at ref 2
450lua release ngx.ctx at ref 1
451",
452"lua release ngx.ctx at ref 2
453lua release ngx.ctx at ref 2
454lua release ngx.ctx at ref 1
455lua release ngx.ctx at ref 2
456lua release ngx.ctx at ref 2
457lua release ngx.ctx at ref 1
458"]
459--- no_error_log
460[error]
461
462
463
464=== TEST 7: ngx.ctx in ssl_session_store_by_lua (release ctx when client aborted)
465--- http_config
466    ssl_session_store_by_lua_block {
467        ngx.ctx.answer = 42
468    }
469
470    server {
471        listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
472        server_name test.com;
473        ssl_session_tickets off;
474        ssl_certificate ../../cert/test.crt;
475        ssl_certificate_key ../../cert/test.key;
476
477        server_tokens off;
478        location /foo {
479            return 200 "ok";
480        }
481    }
482--- config
483    lua_ssl_trusted_certificate ../../cert/test.crt;
484
485    location /t {
486        content_by_lua_block {
487            do
488                local sock = ngx.socket.tcp()
489                sock:settimeout(3000)
490
491                local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
492                if not ok then
493                    ngx.say("failed to connect: ", err)
494                    return
495                end
496
497                local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true)
498                if not sess then
499                    ngx.say("failed to do SSL handshake: ", err)
500                    return
501                end
502
503                ngx.say("closed")
504                sock:close()
505            end  -- do
506        }
507    }
508--- request
509GET /t
510--- response_body
511closed
512--- grep_error_log eval
513qr/lua release ngx.ctx at ref \d+/
514--- grep_error_log_out eval
515["lua release ngx.ctx at ref 1
516",
517"lua release ngx.ctx at ref 1
518lua release ngx.ctx at ref 1
519"]
520--- no_error_log
521[error]
522
523
524
525=== TEST 8: ngx.ctx in ssl_session_fetch_by_lua
526--- http_config
527    ssl_session_fetch_by_lua_block {
528        ngx.ctx.answer = 42
529        ngx.ctx.count = 0
530    }
531
532    server {
533        listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
534        server_name test.com;
535        ssl_session_tickets off;
536        ssl_certificate ../../cert/test.crt;
537        ssl_certificate_key ../../cert/test.key;
538
539        server_tokens off;
540        location /foo {
541            content_by_lua_block {
542                if package.loaded.session then
543                    ngx.say(ngx.ctx.answer)
544                    ngx.ctx.count = ngx.ctx.count + 1
545                    ngx.say(ngx.ctx.count)
546                end
547            }
548        }
549    }
550--- config
551    lua_ssl_trusted_certificate ../../cert/test.crt;
552
553    location /t {
554        content_by_lua_block {
555            do
556                local sock = ngx.socket.tcp()
557                sock:settimeout(3000)
558
559                local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
560                if not ok then
561                    ngx.say("failed to connect: ", err)
562                    return
563                end
564
565                local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true)
566                if not sess then
567                    ngx.say("failed to do SSL handshake: ", err)
568                    return
569                end
570
571                for i = 1, 2 do
572                    local req = "GET /foo HTTP/1.1\r\nHost: test.com\r\n\r\n"
573                    local bytes, err = sock:send(req)
574                    if not bytes then
575                        ngx.say("failed to send http request: ", err)
576                        return
577                    end
578
579                    local body_seen = false
580                    while true do
581                        local line, err = sock:receive()
582                        if not line then
583                            break
584                        end
585
586                        if body_seen then
587                            if line == "0" then
588                                assert(sock:receive())
589                                break
590                            end
591                            local line, err = sock:receive(line)
592                            ngx.log(ngx.WARN, "received: ", line)
593                            assert(sock:receive())
594
595                        elseif line == "" then
596                            body_seen = true
597                        end
598                    end
599                end
600
601                package.loaded.session = sess
602                sock:close()
603            end  -- do
604        }
605    }
606--- request
607GET /t
608--- grep_error_log eval
609qr/(received: \w+|lua release ngx.ctx at ref \d+)/
610--- grep_error_log_out eval
611["",
612"lua release ngx.ctx at ref 2
613received: 42
614received: 1
615lua release ngx.ctx at ref 2
616received: 42
617received: 1
618lua release ngx.ctx at ref 1
619"]
620--- no_error_log
621[error]
622
623
624
625=== TEST 9: ngx.ctx in ssl_session_fetch_by_lua (release ctx when client aborted)
626--- http_config
627    ssl_session_fetch_by_lua_block {
628        ngx.ctx.answer = 42
629    }
630
631    server {
632        listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
633        server_name test.com;
634        ssl_session_tickets off;
635        ssl_certificate ../../cert/test.crt;
636        ssl_certificate_key ../../cert/test.key;
637
638        server_tokens off;
639        location /foo {
640            return 200 "ok";
641        }
642    }
643--- config
644    lua_ssl_trusted_certificate ../../cert/test.crt;
645
646    location /t {
647        content_by_lua_block {
648            do
649                local sock = ngx.socket.tcp()
650                sock:settimeout(3000)
651
652                local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
653                if not ok then
654                    ngx.say("failed to connect: ", err)
655                    return
656                end
657
658                local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true)
659                if not sess then
660                    ngx.say("failed to do SSL handshake: ", err)
661                    return
662                end
663
664                package.loaded.session = sess
665                ngx.say("closed")
666                sock:close()
667            end  -- do
668        }
669    }
670--- request
671GET /t
672--- response_body
673closed
674--- grep_error_log eval
675qr/lua release ngx.ctx at ref \d+/
676--- grep_error_log_out eval
677["",
678"lua release ngx.ctx at ref 1
679"]
680--- no_error_log
681[error]
682
683
684
685=== TEST 10: ngx.ctx in ssl* and other phases
686--- http_config
687    ssl_session_store_by_lua_block {
688        ngx.ctx.count = ngx.ctx.count and (ngx.ctx.count + 1) or 1
689    }
690
691    ssl_session_fetch_by_lua_block {
692        ngx.ctx.count = ngx.ctx.count and (ngx.ctx.count + 10) or 10
693    }
694
695    server {
696        listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
697        server_name test.com;
698        ssl_session_tickets off;
699        ssl_certificate ../../cert/test.crt;
700        ssl_certificate_key ../../cert/test.key;
701
702        ssl_certificate_by_lua_block {
703            ngx.ctx.count = ngx.ctx.count and (ngx.ctx.count + 100) or 100
704        }
705        server_tokens off;
706        location /foo {
707            content_by_lua_block {
708                ngx.ctx.count = ngx.ctx.count + 1
709                ngx.say(ngx.ctx.count)
710            }
711        }
712    }
713--- config
714    lua_ssl_trusted_certificate ../../cert/test.crt;
715
716    location /t {
717        content_by_lua_block {
718            do
719                local sock = ngx.socket.tcp()
720                sock:settimeout(3000)
721
722                local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
723                if not ok then
724                    ngx.say("failed to connect: ", err)
725                    return
726                end
727
728                local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true)
729                if not sess then
730                    ngx.say("failed to do SSL handshake: ", err)
731                    return
732                end
733
734                for i = 1, 2 do
735                    local req = "GET /foo HTTP/1.1\r\nHost: test.com\r\n\r\n"
736                    local bytes, err = sock:send(req)
737                    if not bytes then
738                        ngx.say("failed to send http request: ", err)
739                        return
740                    end
741
742                    local body_seen = false
743                    while true do
744                        local line, err = sock:receive()
745                        if not line then
746                            break
747                        end
748
749                        if body_seen then
750                            if line == "0" then
751                                assert(sock:receive())
752                                break
753                            end
754                            local line, err = sock:receive(line)
755                            ngx.log(ngx.WARN, "received: ", line)
756                            assert(sock:receive())
757
758                        elseif line == "" then
759                            body_seen = true
760                        end
761                    end
762                end
763
764                package.loaded.session = sess
765                sock:close()
766            end  -- do
767        }
768    }
769--- request
770GET /t
771--- grep_error_log eval
772qr/(received: \w+|lua release ngx.ctx at ref \d+)/
773--- grep_error_log_out eval
774["lua release ngx.ctx at ref 2
775received: 102
776lua release ngx.ctx at ref 2
777received: 102
778lua release ngx.ctx at ref 1
779",
780"lua release ngx.ctx at ref 2
781received: 102
782lua release ngx.ctx at ref 2
783received: 102
784lua release ngx.ctx at ref 1
785lua release ngx.ctx at ref 2
786received: 112
787lua release ngx.ctx at ref 2
788received: 112
789lua release ngx.ctx at ref 1
790"]
791--- no_error_log
792[error]
793
794
795
796=== TEST 11: overwrite values will only take affect in the current http request
797--- http_config
798    server {
799        listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
800        server_name   test.com;
801        ssl_certificate_by_lua_block {
802            ngx.ctx.answer = 0
803        }
804        ssl_certificate ../../cert/test.crt;
805        ssl_certificate_key ../../cert/test.key;
806
807        server_tokens off;
808        location /foo1 {
809            content_by_lua_block {
810                ngx.say(ngx.ctx.answer)
811                ngx.ctx.answer = 42
812            }
813        }
814        location /foo2 {
815            content_by_lua_block {
816                ngx.say(ngx.ctx.answer)
817            }
818        }
819    }
820--- config
821    lua_ssl_trusted_certificate ../../cert/test.crt;
822
823    location /t {
824        content_by_lua_block {
825            do
826                local sock = ngx.socket.tcp()
827
828                sock:settimeout(3000)
829
830                local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
831                if not ok then
832                    ngx.say("failed to connect: ", err)
833                    return
834                end
835
836                local sess, err = sock:sslhandshake(nil, "test.com", true)
837                if not sess then
838                    ngx.say("failed to do SSL handshake: ", err)
839                    return
840                end
841
842                for i = 1, 2 do
843                    local req = "GET /foo" .. i .. " HTTP/1.1\r\nHost: test.com\r\n\r\n"
844                    local bytes, err = sock:send(req)
845                    if not bytes then
846                        ngx.say("failed to send http request: ", err)
847                        return
848                    end
849
850                    local body_seen = false
851                    while true do
852                        local line, err = sock:receive()
853                        if not line then
854                            break
855                        end
856
857                        if body_seen then
858                            if line == "0" then
859                                assert(sock:receive())
860                                break
861                            end
862                            local line, err = sock:receive(line)
863                            ngx.print("received: ", line)
864                            assert(sock:receive())
865
866                        elseif line == "" then
867                            body_seen = true
868                        end
869                    end
870                end
871
872                sock:close()
873            end  -- do
874            -- collectgarbage()
875        }
876    }
877
878--- request
879GET /t
880--- response_body
881received: 0
882received: 0
883
884
885
886=== TEST 12: prohibit setting ngx.ctx to non-table value
887--- config
888    location = /t {
889        content_by_lua_block {
890            local ok, err = pcall(function()
891                ngx.ctx = nil
892            end)
893            if not ok then
894                ngx.say(err)
895            end
896        }
897    }
898--- request
899GET /t
900--- response_body_like
901ctx should be a table while getting a nil
902--- no_error_log
903[error]
904
905
906
907=== TEST 13: get_ctx_table
908--- config
909    location = /t {
910        content_by_lua_block {
911            local get_ctx_table = require "resty.core.ctx" .get_ctx_table
912
913            local reused_ctx = {}
914            local ctx = get_ctx_table(reused_ctx)
915            if ctx == reused_ctx then
916                ngx.say("reused")
917            end
918
919            local ctx2 = get_ctx_table()
920            if ctx2 == reused_ctx then
921                ngx.say("reused again")
922            end
923        }
924    }
925--- request
926GET /t
927--- response_body
928reused
929reused again
930--- no_error_log
931[error]
932