FastCGI: Improve handling of EPIPE while writing response
That would previously result in the worker getting killed with SIGPIPE. Which works, but we can also recover from that error without restarting the process.
This commit is contained in:
parent
d300f4d791
commit
48fe393d5f
4 changed files with 34 additions and 15 deletions
11
FU.pm
11
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;
|
||||
|
|
|
|||
6
FU.xs
6
FU.xs
|
|
@ -3,7 +3,7 @@
|
|||
#include <time.h> /* struct timespec & clock_gettime() */
|
||||
#include <string.h> /* strerror() */
|
||||
#include <arpa/inet.h> /* inet_ntop(), inet_ntoa() */
|
||||
#include <sys/socket.h> /* fd passing */
|
||||
#include <sys/socket.h> /* send(), fd passing */
|
||||
#include <sys/un.h> /* fd passing */
|
||||
#include <dlfcn.h> /* 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:
|
||||
|
|
|
|||
24
c/fcgi.c
24
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;
|
||||
}
|
||||
|
|
|
|||
8
t/fcgi.t
8
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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue