comparison src/http/modules/perl/nginx.xs @ 7525:575480d3fd01

Perl: propagate errors. When an error happens, the ctx->error bit is now set, and croak() is called to terminate further processing. The ctx->error bit is checked in ngx_http_perl_call_handler() to cancel further processing, and is also checked in various output functions - to make sure these won't be called if croak() was handled by an eval{} in perl code. In particular, this ensures that output chain won't be called after errors, as filters might not expect this to happen. This fixes some segmentation faults under low memory conditions. Also this stops request processing after filter finalization or request body reading errors. For cases where an HTTP error status can be additionally returned (for example, 416 (Requested Range Not Satisfiable) from the range filter), the ctx->status field is also added.
author Maxim Dounin <mdounin@mdounin.ru>
date Fri, 12 Jul 2019 13:56:21 +0300
parents deebe988cbd7
children 8125552a10ca
comparison
equal deleted inserted replaced
7524:deebe988cbd7 7525:575480d3fd01
123 CODE: 123 CODE:
124 124
125 ngx_http_request_t *r; 125 ngx_http_request_t *r;
126 ngx_http_perl_ctx_t *ctx; 126 ngx_http_perl_ctx_t *ctx;
127 SV *sv; 127 SV *sv;
128 128 ngx_int_t rc;
129 ngx_http_perl_set_request(r, ctx); 129
130 ngx_http_perl_set_request(r, ctx);
131
132 if (ctx->error) {
133 croak("send_http_header(): called after error");
134 }
130 135
131 if (r->headers_out.status == 0) { 136 if (r->headers_out.status == 0) {
132 r->headers_out.status = NGX_HTTP_OK; 137 r->headers_out.status = NGX_HTTP_OK;
133 } 138 }
134 139
149 } 154 }
150 } 155 }
151 156
152 r->disable_not_modified = 1; 157 r->disable_not_modified = 1;
153 158
154 (void) ngx_http_send_header(r); 159 rc = ngx_http_send_header(r);
160
161 if (rc == NGX_ERROR || rc > NGX_OK) {
162 ctx->error = 1;
163 ctx->status = rc;
164 croak("ngx_http_send_header() failed");
165 }
155 166
156 167
157 void 168 void
158 header_only(r) 169 header_only(r)
159 CODE: 170 CODE:
379 CODE: 390 CODE:
380 391
381 dXSTARG; 392 dXSTARG;
382 ngx_http_request_t *r; 393 ngx_http_request_t *r;
383 ngx_http_perl_ctx_t *ctx; 394 ngx_http_perl_ctx_t *ctx;
395 ngx_int_t rc;
384 396
385 ngx_http_perl_set_request(r, ctx); 397 ngx_http_perl_set_request(r, ctx);
386 398
387 if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) { 399 if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
388 XSRETURN_UNDEF; 400 XSRETURN_UNDEF;
396 408
397 if (r->request_body_in_file_only) { 409 if (r->request_body_in_file_only) {
398 r->request_body_file_log_level = 0; 410 r->request_body_file_log_level = 0;
399 } 411 }
400 412
401 ngx_http_read_client_request_body(r, ngx_http_perl_handle_request); 413 rc = ngx_http_read_client_request_body(r, ngx_http_perl_handle_request);
414
415 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
416 ctx->error = 1;
417 ctx->status = rc;
418 ctx->next = NULL;
419 croak("ngx_http_read_client_request_body() failed");
420 }
402 421
403 sv_upgrade(TARG, SVt_IV); 422 sv_upgrade(TARG, SVt_IV);
404 sv_setiv(TARG, 1); 423 sv_setiv(TARG, 1);
405 424
406 ST(0) = TARG; 425 ST(0) = TARG;
492 discard_request_body(r) 511 discard_request_body(r)
493 CODE: 512 CODE:
494 513
495 ngx_http_request_t *r; 514 ngx_http_request_t *r;
496 ngx_http_perl_ctx_t *ctx; 515 ngx_http_perl_ctx_t *ctx;
497 516 ngx_int_t rc;
498 ngx_http_perl_set_request(r, ctx); 517
499 518 ngx_http_perl_set_request(r, ctx);
500 ngx_http_discard_request_body(r); 519
520 rc = ngx_http_discard_request_body(r);
521
522 if (rc != NGX_OK) {
523 ctx->error = 1;
524 ctx->status = rc;
525 croak("ngx_http_discard_request_body() failed");
526 }
501 527
502 528
503 void 529 void
504 header_out(r, key, value) 530 header_out(r, key, value)
505 CODE: 531 CODE:
509 SV *key; 535 SV *key;
510 SV *value; 536 SV *value;
511 ngx_table_elt_t *header; 537 ngx_table_elt_t *header;
512 538
513 ngx_http_perl_set_request(r, ctx); 539 ngx_http_perl_set_request(r, ctx);
540
541 if (ctx->error) {
542 croak("header_out(): called after error");
543 }
514 544
515 key = ST(1); 545 key = ST(1);
516 value = ST(2); 546 value = ST(2);
517 547
518 header = ngx_list_push(&r->headers_out.headers); 548 header = ngx_list_push(&r->headers_out.headers);
586 SV *sv; 616 SV *sv;
587 int i; 617 int i;
588 u_char *p; 618 u_char *p;
589 size_t size; 619 size_t size;
590 STRLEN len; 620 STRLEN len;
621 ngx_int_t rc;
591 ngx_buf_t *b; 622 ngx_buf_t *b;
592 623
593 ngx_http_perl_set_request(r, ctx); 624 ngx_http_perl_set_request(r, ctx);
625
626 if (ctx->error) {
627 croak("print(): called after error");
628 }
594 629
595 if (items == 2) { 630 if (items == 2) {
596 631
597 /* 632 /*
598 * do zero copy for prolate single read-only SV: 633 * do zero copy for prolate single read-only SV:
669 b->last = ngx_cpymem(b->last, p, len); 704 b->last = ngx_cpymem(b->last, p, len);
670 } 705 }
671 706
672 out: 707 out:
673 708
674 (void) ngx_http_perl_output(r, ctx, b); 709 rc = ngx_http_perl_output(r, ctx, b);
710
711 if (rc == NGX_ERROR) {
712 ctx->error = 1;
713 croak("ngx_http_perl_output() failed");
714 }
675 715
676 716
677 void 717 void
678 sendfile(r, filename, offset = -1, bytes = 0) 718 sendfile(r, filename, offset = -1, bytes = 0)
679 CODE: 719 CODE:
681 ngx_http_request_t *r; 721 ngx_http_request_t *r;
682 ngx_http_perl_ctx_t *ctx; 722 ngx_http_perl_ctx_t *ctx;
683 char *filename; 723 char *filename;
684 off_t offset; 724 off_t offset;
685 size_t bytes; 725 size_t bytes;
726 ngx_int_t rc;
686 ngx_str_t path; 727 ngx_str_t path;
687 ngx_buf_t *b; 728 ngx_buf_t *b;
688 ngx_open_file_info_t of; 729 ngx_open_file_info_t of;
689 ngx_http_core_loc_conf_t *clcf; 730 ngx_http_core_loc_conf_t *clcf;
690 731
691 ngx_http_perl_set_request(r, ctx); 732 ngx_http_perl_set_request(r, ctx);
733
734 if (ctx->error) {
735 croak("sendfile(): called after error");
736 }
692 737
693 filename = SvPV_nolen(ST(1)); 738 filename = SvPV_nolen(ST(1));
694 739
695 if (filename == NULL) { 740 if (filename == NULL) {
696 croak("sendfile(): NULL filename"); 741 croak("sendfile(): NULL filename");
760 805
761 b->file->fd = of.fd; 806 b->file->fd = of.fd;
762 b->file->log = r->connection->log; 807 b->file->log = r->connection->log;
763 b->file->directio = of.is_directio; 808 b->file->directio = of.is_directio;
764 809
765 (void) ngx_http_perl_output(r, ctx, b); 810 rc = ngx_http_perl_output(r, ctx, b);
811
812 if (rc == NGX_ERROR) {
813 ctx->error = 1;
814 croak("ngx_http_perl_output() failed");
815 }
766 816
767 817
768 void 818 void
769 flush(r) 819 flush(r)
770 CODE: 820 CODE:
771 821
772 ngx_http_request_t *r; 822 ngx_http_request_t *r;
773 ngx_http_perl_ctx_t *ctx; 823 ngx_http_perl_ctx_t *ctx;
824 ngx_int_t rc;
774 ngx_buf_t *b; 825 ngx_buf_t *b;
775 826
776 ngx_http_perl_set_request(r, ctx); 827 ngx_http_perl_set_request(r, ctx);
828
829 if (ctx->error) {
830 croak("flush(): called after error");
831 }
777 832
778 b = ngx_calloc_buf(r->pool); 833 b = ngx_calloc_buf(r->pool);
779 if (b == NULL) { 834 if (b == NULL) {
780 XSRETURN_EMPTY; 835 XSRETURN_EMPTY;
781 } 836 }
782 837
783 b->flush = 1; 838 b->flush = 1;
784 839
785 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "$r->flush"); 840 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "$r->flush");
786 841
787 (void) ngx_http_perl_output(r, ctx, b); 842 rc = ngx_http_perl_output(r, ctx, b);
843
844 if (rc == NGX_ERROR) {
845 ctx->error = 1;
846 croak("ngx_http_perl_output() failed");
847 }
788 848
789 XSRETURN_EMPTY; 849 XSRETURN_EMPTY;
790 850
791 851
792 void 852 void