diff --git a/FU.pm b/FU.pm index 8e47c1d..7d5df3b 100644 --- a/FU.pm +++ b/FU.pm @@ -292,7 +292,8 @@ sub _read_req($c) { : $r == -2 ? "I/O error while reading from FastCGI socket\n" : $r == -3 ? "FastCGI protocol error\n" : $r == -4 ? "Too long FastCGI parameter\n" - : $r == -5 ? "Too long request body\n" : undef if $r != -7; + : $r == -5 ? "Too long request body\n" + : $r == -8 ? "I/O error while writing to FastCGI socket\n" : undef if $r != -7; delete $c->{fcgi_obj}; fu->error(-1); } @@ -400,7 +401,13 @@ sub _do_req($c) { } $REQ->{trace_end} = clock_gettime(CLOCK_MONOTONIC); - fu->_flush($c->{fcgi_obj} || $c->{client_sock}); + eval { + fu->_flush($c->{fcgi_obj} || $c->{client_sock}); + 1; + } || do { + log_write "Error writing response: $@\n"; + $c->{client_sock} = $c->{fcgi_obj} = undef; + }; if (debug && $REQ->{trace_id} && $debug_info->{history} && $debug_info->{storage}) { require FU::DebugImpl; diff --git a/FU.xs b/FU.xs index 60ef7a6..1477a0a 100644 --- a/FU.xs +++ b/FU.xs @@ -3,7 +3,7 @@ #include /* struct timespec & clock_gettime() */ #include /* strerror() */ #include /* inet_ntop(), inet_ntoa() */ -#include /* fd passing */ +#include /* send(), fd passing */ #include /* fd passing */ #include /* dlopen() etc */ @@ -170,11 +170,11 @@ void print(fufcgi *ctx, SV *sv) CODE: STRLEN len; const char *buf = SvPVbyte(sv, len); - fufcgi_print(ctx, buf, len); + fufcgi_print(aTHX_ ctx, buf, len); void flush(fufcgi *ctx) CODE: - fufcgi_done(ctx); + fufcgi_done(aTHX_ ctx); void DESTROY(fufcgi *ctx) CODE: diff --git a/c/fcgi.c b/c/fcgi.c index 4f886dd..efcce6e 100644 --- a/c/fcgi.c +++ b/c/fcgi.c @@ -18,6 +18,7 @@ #define FUFE_CLEN -5 #define FUFE_ABORT -6 /* explicit abort or client-level EOF */ #define FUFE_NOREQ -7 /* protocol-level EOF before we received anything */ +#define FUFE_SEND -8 /* error in send() */ #define FUFCGI_MAX_DATA 65535 @@ -177,8 +178,8 @@ static int fufcgi_write_record(fufcgi *ctx, fufcgi_rec *hdr, char *buf) { buf[7] = 0; int len = hdr->len + 8; while (len > 0) { - int r = write(ctx->fd, buf, len); - if (r <= 0) return r == 0 ? FUFE_EOF : FUFE_IO; + int r = send(ctx->fd, buf, len, MSG_NOSIGNAL); + if (r <= 0) return FUFE_SEND; buf += r; len -= r; } @@ -409,18 +410,19 @@ static int fufcgi_read_req(pTHX_ fufcgi *ctx, SV *headers, SV *params) { } } -static void fufcgi_flush(fufcgi *ctx) { +static void fufcgi_flush(pTHX_ fufcgi *ctx) { fufcgi_rec hdr; if (ctx->len > 0) { hdr.len = ctx->len; hdr.type = FCGI_STDOUT; hdr.id = ctx->reqid; - fufcgi_write_record(ctx, &hdr, ctx->buf); + if (fufcgi_write_record(ctx, &hdr, ctx->buf) != FUFE_OK) + croak("write error: %s", strerror(errno)); ctx->len = 0; } } -static void fufcgi_print(fufcgi *ctx, const char *buf, int len) { +static void fufcgi_print(pTHX_ fufcgi *ctx, const char *buf, int len) { int r; while (len > 0) { r = len > FUFCGI_MAX_DATA - ctx->len ? FUFCGI_MAX_DATA - ctx->len : len; @@ -428,23 +430,25 @@ static void fufcgi_print(fufcgi *ctx, const char *buf, int len) { ctx->len += r; len -= r; buf += r; - if (ctx->len >= FUFCGI_MAX_DATA) fufcgi_flush(ctx); + if (ctx->len >= FUFCGI_MAX_DATA) fufcgi_flush(aTHX_ ctx); } } -static void fufcgi_done(fufcgi *ctx) { +static void fufcgi_done(pTHX_ fufcgi *ctx) { fufcgi_rec hdr; - fufcgi_flush(ctx); + fufcgi_flush(aTHX_ ctx); hdr.len = 0; hdr.type = FCGI_STDOUT; hdr.id = ctx->reqid; - fufcgi_write_record(ctx, &hdr, ctx->buf); + if (fufcgi_write_record(ctx, &hdr, ctx->buf) != FUFE_OK) + croak("write error: %s", strerror(errno)); memcpy(ctx->buf+8, "\0\0\0\0\0\0\0\0", 8); /* FCGI_REQUEST_COMPLETE */ hdr.type = FCGI_END_REQUEST; hdr.len = 8; - fufcgi_write_record(ctx, &hdr, ctx->buf); + if (fufcgi_write_record(ctx, &hdr, ctx->buf) != FUFE_OK) + croak("write error: %s", strerror(errno)); ctx->reqid = ctx->len = ctx->off = 0; } diff --git a/t/fcgi.t b/t/fcgi.t index d7860dc..85636e3 100644 --- a/t/fcgi.t +++ b/t/fcgi.t @@ -54,6 +54,11 @@ start; begin 1, 2; record 1, 4, ""; +start; +begin 3, 2, 1; +$remote->close; +iserr -8; + start; begin 3, 2, 1; begin 1, 1, 1; @@ -173,6 +178,9 @@ record 1, 4, "\x13\x01HTTP_CONTENT_LENGTH3\x0e\x01CONTENT_LENGTH0\x13\x01HTTP_CO record 1, 4, ""; record 1, 5, ""; isrec {'content-length','0'}, {body => ''}; +$remote->close; +ok !eval { $f->flush; 1 }; +like $@, qr/write error/; start; begin;