Opened 4 months ago

Closed 4 months ago

#1991 closed defect (invalid)

Empty response of nginx with ngx_http_perl_module

Reported by: https://stackoverflow.com/users/1520793/sotona Owned by:
Priority: minor Milestone:
Component: nginx-module Version: 1.14.x
Keywords: perl Cc:
uname -a: Linux centos8 4.18.0-147.el8.x86_64 #1 SMP Wed Dec 4 21:51:45 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.14.1
built by gcc 8.2.1 20180905 (Red Hat 8.2.1-3) (GCC)
built with OpenSSL 1.1.1 FIPS 11 Sep 2018 (running with OpenSSL 1.1.1c FIPS 28 May 2019)
TLS SNI support enabled
configure arguments: --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --user=nginx --group=nginx --with-file-aio --with-ipv6 --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_slice_module --with-http_stub_status_module --with-http_perl_module=dynamic --with-http_auth_request_module --with-mail=dynamic --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream=dynamic --with-stream_ssl_module --with-debug --with-cc-opt='-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,-E'

Description

I have to run a very simplistic piece of perl code in response to HTTP request.
The nginx config is:

    http { 

        perl_modules perl/lib;
        perl_require errors.pm;

        server {
            listen       80;
            server_name  _;
            root         /usr/share/nginx/html;

            location / {
                    perl errors::response;
            }
        }
    }

The code I try to run is:

package errors;

use strict;
use warnings;
use nginx;

my $errors  =  {
        ThisIsNotOK => {
                'code'          => '409',
                'amzcode'       => 'NOK',
                'message'       => 'Something went really wrong'
        },

        ItsOK => {
                'code'          => '200',
                'amzcode'       => 'OK',
                'message'       => 'Okay'
        },
};

my $fmt =<<ENDFMT;
<?xml version="1.0" encoding="UTF-8"?>
<Error>
        <Code>%s</Code>
        <Message>%s</Message>
        <Resource>/mybucket/whatever.1</Resource>
        <RequestId>DEADBEEFBEDAEDA</RequestId>
</Error>
ENDFMT

sub response() {
        my $r = shift();

        my $curr_err = (keys %$errors)[rand keys %$errors];

        $r->send_http_header("application/xml");
        $r->status($errors->{$curr_err}{'code'});

        $r->print(sprintf($fmt,$errors->{$curr_err}{'amzcode'}, $errors->{$curr_err}{'message'}));
        return $errors->{$curr_err}{'code'};

}

1;

__END__

The problem is when this code returns something other than 200/OK, I get the empty response error:

% curl -iX GET localhost
curl: (52) Empty reply from server

Change History (1)

comment:1 by Maxim Dounin, 4 months ago

Resolution: invalid
Status: newclosed

The problem is that the perl handler sends a response, and then returns an HTTP error code.

Returning an HTTP error code triggers sending an error response (either builtin or redefined via error_page) and should only be used when no response is already returned by the perl handler. In your case this results in an attempt to send an additional response. As soon as nginx detects the problem, it logs the "header already sent" alert and closes the affected connection.

To fix this, avoid returning HTTP error codes if your code already sent a response. Instead, use return OK; as in the documentation.

Note: See TracTickets for help on using tickets.