comparison src/http/modules/perl/nginx.xs @ 7524:deebe988cbd7

Perl: reworked perl module to pass ctx instead of request. This ensures that correct ctx is always available, including after filter finalization. In particular, this fixes a segmentation fault with the following configuration: location / { image_filter test; perl 'sub { my $r = shift; $r->send_http_header(); $r->print("foo\n"); $r->print("bar\n"); }'; } This also seems to be the only way to correctly handle filter finalization in various complex cases, for example, when embedded perl is used both in the original handler and in an error page called after filter finalization.
author Maxim Dounin <mdounin@mdounin.ru>
date Fri, 12 Jul 2019 11:29:22 +0300
parents 36c52a0f6ded
children 575480d3fd01
comparison
equal deleted inserted replaced
7523:919a5c6c828c 7524:deebe988cbd7
13 #include <ngx_http_perl_module.h> 13 #include <ngx_http_perl_module.h>
14 14
15 #include "XSUB.h" 15 #include "XSUB.h"
16 16
17 17
18 #define ngx_http_perl_set_request(r) \ 18 #define ngx_http_perl_set_request(r, ctx) \
19 r = INT2PTR(ngx_http_request_t *, SvIV((SV *) SvRV(ST(0)))) 19 \
20 ctx = INT2PTR(ngx_http_perl_ctx_t *, SvIV((SV *) SvRV(ST(0)))); \
21 r = ctx->request
20 22
21 23
22 #define ngx_http_perl_set_targ(p, len) \ 24 #define ngx_http_perl_set_targ(p, len) \
23 \ 25 \
24 SvUPGRADE(TARG, SVt_PV); \ 26 SvUPGRADE(TARG, SVt_PV); \
62 return NGX_OK; 64 return NGX_OK;
63 } 65 }
64 66
65 67
66 static ngx_int_t 68 static ngx_int_t
67 ngx_http_perl_output(ngx_http_request_t *r, ngx_buf_t *b) 69 ngx_http_perl_output(ngx_http_request_t *r, ngx_http_perl_ctx_t *ctx,
70 ngx_buf_t *b)
68 { 71 {
69 ngx_chain_t out; 72 ngx_chain_t out;
70 #if (NGX_HTTP_SSI) 73 #if (NGX_HTTP_SSI)
71 ngx_chain_t *cl; 74 ngx_chain_t *cl;
72 ngx_http_perl_ctx_t *ctx;
73
74 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
75 75
76 if (ctx->ssi) { 76 if (ctx->ssi) {
77 cl = ngx_alloc_chain_link(r->pool); 77 cl = ngx_alloc_chain_link(r->pool);
78 if (cl == NULL) { 78 if (cl == NULL) {
79 return NGX_ERROR; 79 return NGX_ERROR;
103 103
104 void 104 void
105 status(r, code) 105 status(r, code)
106 CODE: 106 CODE:
107 107
108 ngx_http_request_t *r; 108 ngx_http_request_t *r;
109 109 ngx_http_perl_ctx_t *ctx;
110 ngx_http_perl_set_request(r); 110
111 ngx_http_perl_set_request(r, ctx);
111 112
112 r->headers_out.status = SvIV(ST(1)); 113 r->headers_out.status = SvIV(ST(1));
113 114
114 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 115 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
115 "perl status: %d", r->headers_out.status); 116 "perl status: %d", r->headers_out.status);
119 120
120 void 121 void
121 send_http_header(r, ...) 122 send_http_header(r, ...)
122 CODE: 123 CODE:
123 124
124 ngx_http_request_t *r; 125 ngx_http_request_t *r;
125 SV *sv; 126 ngx_http_perl_ctx_t *ctx;
126 127 SV *sv;
127 ngx_http_perl_set_request(r); 128
129 ngx_http_perl_set_request(r, ctx);
128 130
129 if (r->headers_out.status == 0) { 131 if (r->headers_out.status == 0) {
130 r->headers_out.status = NGX_HTTP_OK; 132 r->headers_out.status = NGX_HTTP_OK;
131 } 133 }
132 134
155 void 157 void
156 header_only(r) 158 header_only(r)
157 CODE: 159 CODE:
158 160
159 dXSTARG; 161 dXSTARG;
160 ngx_http_request_t *r; 162 ngx_http_request_t *r;
161 163 ngx_http_perl_ctx_t *ctx;
162 ngx_http_perl_set_request(r); 164
165 ngx_http_perl_set_request(r, ctx);
163 166
164 sv_upgrade(TARG, SVt_IV); 167 sv_upgrade(TARG, SVt_IV);
165 sv_setiv(TARG, r->header_only); 168 sv_setiv(TARG, r->header_only);
166 169
167 ST(0) = TARG; 170 ST(0) = TARG;
170 void 173 void
171 uri(r) 174 uri(r)
172 CODE: 175 CODE:
173 176
174 dXSTARG; 177 dXSTARG;
175 ngx_http_request_t *r; 178 ngx_http_request_t *r;
176 179 ngx_http_perl_ctx_t *ctx;
177 ngx_http_perl_set_request(r); 180
181 ngx_http_perl_set_request(r, ctx);
178 ngx_http_perl_set_targ(r->uri.data, r->uri.len); 182 ngx_http_perl_set_targ(r->uri.data, r->uri.len);
179 183
180 ST(0) = TARG; 184 ST(0) = TARG;
181 185
182 186
183 void 187 void
184 args(r) 188 args(r)
185 CODE: 189 CODE:
186 190
187 dXSTARG; 191 dXSTARG;
188 ngx_http_request_t *r; 192 ngx_http_request_t *r;
189 193 ngx_http_perl_ctx_t *ctx;
190 ngx_http_perl_set_request(r); 194
195 ngx_http_perl_set_request(r, ctx);
191 ngx_http_perl_set_targ(r->args.data, r->args.len); 196 ngx_http_perl_set_targ(r->args.data, r->args.len);
192 197
193 ST(0) = TARG; 198 ST(0) = TARG;
194 199
195 200
196 void 201 void
197 request_method(r) 202 request_method(r)
198 CODE: 203 CODE:
199 204
200 dXSTARG; 205 dXSTARG;
201 ngx_http_request_t *r; 206 ngx_http_request_t *r;
202 207 ngx_http_perl_ctx_t *ctx;
203 ngx_http_perl_set_request(r); 208
209 ngx_http_perl_set_request(r, ctx);
204 ngx_http_perl_set_targ(r->method_name.data, r->method_name.len); 210 ngx_http_perl_set_targ(r->method_name.data, r->method_name.len);
205 211
206 ST(0) = TARG; 212 ST(0) = TARG;
207 213
208 214
209 void 215 void
210 remote_addr(r) 216 remote_addr(r)
211 CODE: 217 CODE:
212 218
213 dXSTARG; 219 dXSTARG;
214 ngx_http_request_t *r; 220 ngx_http_request_t *r;
215 221 ngx_http_perl_ctx_t *ctx;
216 ngx_http_perl_set_request(r); 222
223 ngx_http_perl_set_request(r, ctx);
217 ngx_http_perl_set_targ(r->connection->addr_text.data, 224 ngx_http_perl_set_targ(r->connection->addr_text.data,
218 r->connection->addr_text.len); 225 r->connection->addr_text.len);
219 226
220 ST(0) = TARG; 227 ST(0) = TARG;
221 228
224 header_in(r, key) 231 header_in(r, key)
225 CODE: 232 CODE:
226 233
227 dXSTARG; 234 dXSTARG;
228 ngx_http_request_t *r; 235 ngx_http_request_t *r;
236 ngx_http_perl_ctx_t *ctx;
229 SV *key; 237 SV *key;
230 u_char *p, *lowcase_key, *value, sep; 238 u_char *p, *lowcase_key, *value, sep;
231 STRLEN len; 239 STRLEN len;
232 ssize_t size; 240 ssize_t size;
233 ngx_uint_t i, n, hash; 241 ngx_uint_t i, n, hash;
235 ngx_list_part_t *part; 243 ngx_list_part_t *part;
236 ngx_table_elt_t *h, **ph; 244 ngx_table_elt_t *h, **ph;
237 ngx_http_header_t *hh; 245 ngx_http_header_t *hh;
238 ngx_http_core_main_conf_t *cmcf; 246 ngx_http_core_main_conf_t *cmcf;
239 247
240 ngx_http_perl_set_request(r); 248 ngx_http_perl_set_request(r, ctx);
241 249
242 key = ST(1); 250 key = ST(1);
243 251
244 if (SvROK(key) && SvTYPE(SvRV(key)) == SVt_PV) { 252 if (SvROK(key) && SvTYPE(SvRV(key)) == SVt_PV) {
245 key = SvRV(key); 253 key = SvRV(key);
372 380
373 dXSTARG; 381 dXSTARG;
374 ngx_http_request_t *r; 382 ngx_http_request_t *r;
375 ngx_http_perl_ctx_t *ctx; 383 ngx_http_perl_ctx_t *ctx;
376 384
377 ngx_http_perl_set_request(r); 385 ngx_http_perl_set_request(r, ctx);
378 386
379 if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) { 387 if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
380 XSRETURN_UNDEF; 388 XSRETURN_UNDEF;
381 } 389 }
382 390
383 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
384 ctx->next = SvRV(ST(1)); 391 ctx->next = SvRV(ST(1));
385 392
386 r->request_body_in_single_buf = 1; 393 r->request_body_in_single_buf = 1;
387 r->request_body_in_persistent_file = 1; 394 r->request_body_in_persistent_file = 1;
388 r->request_body_in_clean_file = 1; 395 r->request_body_in_clean_file = 1;
402 void 409 void
403 request_body(r) 410 request_body(r)
404 CODE: 411 CODE:
405 412
406 dXSTARG; 413 dXSTARG;
407 ngx_http_request_t *r; 414 ngx_http_request_t *r;
408 u_char *p, *data; 415 ngx_http_perl_ctx_t *ctx;
409 size_t len; 416 u_char *p, *data;
410 ngx_buf_t *buf; 417 size_t len;
411 ngx_chain_t *cl; 418 ngx_buf_t *buf;
412 419 ngx_chain_t *cl;
413 ngx_http_perl_set_request(r); 420
421 ngx_http_perl_set_request(r, ctx);
414 422
415 if (r->request_body == NULL 423 if (r->request_body == NULL
416 || r->request_body->temp_file 424 || r->request_body->temp_file
417 || r->request_body->bufs == NULL) 425 || r->request_body->bufs == NULL)
418 { 426 {
463 void 471 void
464 request_body_file(r) 472 request_body_file(r)
465 CODE: 473 CODE:
466 474
467 dXSTARG; 475 dXSTARG;
468 ngx_http_request_t *r; 476 ngx_http_request_t *r;
469 477 ngx_http_perl_ctx_t *ctx;
470 ngx_http_perl_set_request(r); 478
479 ngx_http_perl_set_request(r, ctx);
471 480
472 if (r->request_body == NULL || r->request_body->temp_file == NULL) { 481 if (r->request_body == NULL || r->request_body->temp_file == NULL) {
473 XSRETURN_UNDEF; 482 XSRETURN_UNDEF;
474 } 483 }
475 484
481 490
482 void 491 void
483 discard_request_body(r) 492 discard_request_body(r)
484 CODE: 493 CODE:
485 494
486 ngx_http_request_t *r; 495 ngx_http_request_t *r;
487 496 ngx_http_perl_ctx_t *ctx;
488 ngx_http_perl_set_request(r); 497
498 ngx_http_perl_set_request(r, ctx);
489 499
490 ngx_http_discard_request_body(r); 500 ngx_http_discard_request_body(r);
491 501
492 502
493 void 503 void
494 header_out(r, key, value) 504 header_out(r, key, value)
495 CODE: 505 CODE:
496 506
497 ngx_http_request_t *r; 507 ngx_http_request_t *r;
498 SV *key; 508 ngx_http_perl_ctx_t *ctx;
499 SV *value; 509 SV *key;
500 ngx_table_elt_t *header; 510 SV *value;
501 511 ngx_table_elt_t *header;
502 ngx_http_perl_set_request(r); 512
513 ngx_http_perl_set_request(r, ctx);
503 514
504 key = ST(1); 515 key = ST(1);
505 value = ST(2); 516 value = ST(2);
506 517
507 header = ngx_list_push(&r->headers_out.headers); 518 header = ngx_list_push(&r->headers_out.headers);
540 void 551 void
541 filename(r) 552 filename(r)
542 CODE: 553 CODE:
543 554
544 dXSTARG; 555 dXSTARG;
556 ngx_http_request_t *r;
557 ngx_http_perl_ctx_t *ctx;
545 size_t root; 558 size_t root;
546 ngx_http_request_t *r; 559
547 ngx_http_perl_ctx_t *ctx; 560 ngx_http_perl_set_request(r, ctx);
548 561
549 ngx_http_perl_set_request(r);
550
551 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
552 if (ctx->filename.data) { 562 if (ctx->filename.data) {
553 goto done; 563 goto done;
554 } 564 }
555 565
556 if (ngx_http_map_uri_to_path(r, &ctx->filename, &root, 0) == NULL) { 566 if (ngx_http_map_uri_to_path(r, &ctx->filename, &root, 0) == NULL) {
569 579
570 void 580 void
571 print(r, ...) 581 print(r, ...)
572 CODE: 582 CODE:
573 583
574 ngx_http_request_t *r; 584 ngx_http_request_t *r;
575 SV *sv; 585 ngx_http_perl_ctx_t *ctx;
576 int i; 586 SV *sv;
577 u_char *p; 587 int i;
578 size_t size; 588 u_char *p;
579 STRLEN len; 589 size_t size;
580 ngx_buf_t *b; 590 STRLEN len;
581 591 ngx_buf_t *b;
582 ngx_http_perl_set_request(r); 592
593 ngx_http_perl_set_request(r, ctx);
583 594
584 if (items == 2) { 595 if (items == 2) {
585 596
586 /* 597 /*
587 * do zero copy for prolate single read-only SV: 598 * do zero copy for prolate single read-only SV:
658 b->last = ngx_cpymem(b->last, p, len); 669 b->last = ngx_cpymem(b->last, p, len);
659 } 670 }
660 671
661 out: 672 out:
662 673
663 (void) ngx_http_perl_output(r, b); 674 (void) ngx_http_perl_output(r, ctx, b);
664 675
665 676
666 void 677 void
667 sendfile(r, filename, offset = -1, bytes = 0) 678 sendfile(r, filename, offset = -1, bytes = 0)
668 CODE: 679 CODE:
669 680
670 ngx_http_request_t *r; 681 ngx_http_request_t *r;
682 ngx_http_perl_ctx_t *ctx;
671 char *filename; 683 char *filename;
672 off_t offset; 684 off_t offset;
673 size_t bytes; 685 size_t bytes;
674 ngx_str_t path; 686 ngx_str_t path;
675 ngx_buf_t *b; 687 ngx_buf_t *b;
676 ngx_open_file_info_t of; 688 ngx_open_file_info_t of;
677 ngx_http_core_loc_conf_t *clcf; 689 ngx_http_core_loc_conf_t *clcf;
678 690
679 ngx_http_perl_set_request(r); 691 ngx_http_perl_set_request(r, ctx);
680 692
681 filename = SvPV_nolen(ST(1)); 693 filename = SvPV_nolen(ST(1));
682 694
683 if (filename == NULL) { 695 if (filename == NULL) {
684 croak("sendfile(): NULL filename"); 696 croak("sendfile(): NULL filename");
748 760
749 b->file->fd = of.fd; 761 b->file->fd = of.fd;
750 b->file->log = r->connection->log; 762 b->file->log = r->connection->log;
751 b->file->directio = of.is_directio; 763 b->file->directio = of.is_directio;
752 764
753 (void) ngx_http_perl_output(r, b); 765 (void) ngx_http_perl_output(r, ctx, b);
754 766
755 767
756 void 768 void
757 flush(r) 769 flush(r)
758 CODE: 770 CODE:
759 771
760 ngx_http_request_t *r; 772 ngx_http_request_t *r;
761 ngx_buf_t *b; 773 ngx_http_perl_ctx_t *ctx;
762 774 ngx_buf_t *b;
763 ngx_http_perl_set_request(r); 775
776 ngx_http_perl_set_request(r, ctx);
764 777
765 b = ngx_calloc_buf(r->pool); 778 b = ngx_calloc_buf(r->pool);
766 if (b == NULL) { 779 if (b == NULL) {
767 XSRETURN_EMPTY; 780 XSRETURN_EMPTY;
768 } 781 }
769 782
770 b->flush = 1; 783 b->flush = 1;
771 784
772 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "$r->flush"); 785 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "$r->flush");
773 786
774 (void) ngx_http_perl_output(r, b); 787 (void) ngx_http_perl_output(r, ctx, b);
775 788
776 XSRETURN_EMPTY; 789 XSRETURN_EMPTY;
777 790
778 791
779 void 792 void
780 internal_redirect(r, uri) 793 internal_redirect(r, uri)
781 CODE: 794 CODE:
782 795
783 ngx_http_request_t *r; 796 ngx_http_request_t *r;
797 ngx_http_perl_ctx_t *ctx;
784 SV *uri; 798 SV *uri;
785 ngx_uint_t i; 799 ngx_uint_t i;
786 ngx_http_perl_ctx_t *ctx; 800
787 801 ngx_http_perl_set_request(r, ctx);
788 ngx_http_perl_set_request(r);
789 802
790 uri = ST(1); 803 uri = ST(1);
791
792 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
793 804
794 if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) { 805 if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) {
795 XSRETURN_EMPTY; 806 XSRETURN_EMPTY;
796 } 807 }
797 808
809 820
810 void 821 void
811 allow_ranges(r) 822 allow_ranges(r)
812 CODE: 823 CODE:
813 824
814 ngx_http_request_t *r; 825 ngx_http_request_t *r;
815 826 ngx_http_perl_ctx_t *ctx;
816 ngx_http_perl_set_request(r); 827
828 ngx_http_perl_set_request(r, ctx);
817 829
818 r->allow_ranges = 1; 830 r->allow_ranges = 1;
819 831
820 832
821 void 833 void
822 unescape(r, text, type = 0) 834 unescape(r, text, type = 0)
823 CODE: 835 CODE:
824 836
825 dXSTARG; 837 dXSTARG;
826 ngx_http_request_t *r; 838 ngx_http_request_t *r;
827 SV *text; 839 ngx_http_perl_ctx_t *ctx;
828 int type; 840 SV *text;
829 u_char *p, *dst, *src; 841 int type;
830 STRLEN len; 842 u_char *p, *dst, *src;
831 843 STRLEN len;
832 ngx_http_perl_set_request(r); 844
845 ngx_http_perl_set_request(r, ctx);
833 846
834 text = ST(1); 847 text = ST(1);
835 848
836 src = (u_char *) SvPV(text, len); 849 src = (u_char *) SvPV(text, len);
837 850
856 variable(r, name, value = NULL) 869 variable(r, name, value = NULL)
857 CODE: 870 CODE:
858 871
859 dXSTARG; 872 dXSTARG;
860 ngx_http_request_t *r; 873 ngx_http_request_t *r;
874 ngx_http_perl_ctx_t *ctx;
861 SV *name, *value; 875 SV *name, *value;
862 u_char *p, *lowcase; 876 u_char *p, *lowcase;
863 STRLEN len; 877 STRLEN len;
864 ngx_str_t var, val; 878 ngx_str_t var, val;
865 ngx_uint_t i, hash; 879 ngx_uint_t i, hash;
866 ngx_http_perl_var_t *v; 880 ngx_http_perl_var_t *v;
867 ngx_http_perl_ctx_t *ctx;
868 ngx_http_variable_value_t *vv; 881 ngx_http_variable_value_t *vv;
869 882
870 ngx_http_perl_set_request(r); 883 ngx_http_perl_set_request(r, ctx);
871 884
872 name = ST(1); 885 name = ST(1);
873 886
874 if (SvROK(name) && SvTYPE(SvRV(name)) == SVt_PV) { 887 if (SvROK(name) && SvTYPE(SvRV(name)) == SVt_PV) {
875 name = SvRV(name); 888 name = SvRV(name);
916 if (vv == NULL) { 929 if (vv == NULL) {
917 XSRETURN_UNDEF; 930 XSRETURN_UNDEF;
918 } 931 }
919 932
920 if (vv->not_found) { 933 if (vv->not_found) {
921
922 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
923 934
924 if (ctx->variables) { 935 if (ctx->variables) {
925 936
926 v = ctx->variables->elts; 937 v = ctx->variables->elts;
927 for (i = 0; i < ctx->variables->nelts; i++) { 938 for (i = 0; i < ctx->variables->nelts; i++) {
989 void 1000 void
990 sleep(r, sleep, next) 1001 sleep(r, sleep, next)
991 CODE: 1002 CODE:
992 1003
993 ngx_http_request_t *r; 1004 ngx_http_request_t *r;
1005 ngx_http_perl_ctx_t *ctx;
994 ngx_msec_t sleep; 1006 ngx_msec_t sleep;
995 ngx_http_perl_ctx_t *ctx; 1007
996 1008 ngx_http_perl_set_request(r, ctx);
997 ngx_http_perl_set_request(r);
998 1009
999 sleep = (ngx_msec_t) SvIV(ST(1)); 1010 sleep = (ngx_msec_t) SvIV(ST(1));
1000 1011
1001 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1012 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1002 "perl sleep: %M", sleep); 1013 "perl sleep: %M", sleep);
1003 1014
1004 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
1005
1006 ctx->next = SvRV(ST(2)); 1015 ctx->next = SvRV(ST(2));
1007 1016
1008 r->connection->write->delayed = 1; 1017 r->connection->write->delayed = 1;
1009 ngx_add_timer(r->connection->write, sleep); 1018 ngx_add_timer(r->connection->write, sleep);
1010 1019
1014 1023
1015 void 1024 void
1016 log_error(r, err, msg) 1025 log_error(r, err, msg)
1017 CODE: 1026 CODE:
1018 1027
1019 ngx_http_request_t *r; 1028 ngx_http_request_t *r;
1020 SV *err, *msg; 1029 ngx_http_perl_ctx_t *ctx;
1021 u_char *p; 1030 SV *err, *msg;
1022 STRLEN len; 1031 u_char *p;
1023 ngx_err_t e; 1032 STRLEN len;
1024 1033 ngx_err_t e;
1025 ngx_http_perl_set_request(r); 1034
1035 ngx_http_perl_set_request(r, ctx);
1026 1036
1027 err = ST(1); 1037 err = ST(1);
1028 1038
1029 if (SvROK(err) && SvTYPE(SvRV(err)) == SVt_PV) { 1039 if (SvROK(err) && SvTYPE(SvRV(err)) == SVt_PV) {
1030 err = SvRV(err); 1040 err = SvRV(err);