|
|
|
@ -64,6 +64,8 @@ struct FCGI_Record {
|
|
|
|
|
guint16 requestID; |
|
|
|
|
guint16 contentLength; |
|
|
|
|
guint8 paddingLength; |
|
|
|
|
gint remainingContent, remainingPadding; |
|
|
|
|
gboolean valid, first; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -162,7 +164,7 @@ static void fastcgi_context_acquire(fastcgi_context *ctx) {
|
|
|
|
|
static void fastcgi_fd_cb(struct ev_loop *loop, ev_io *w, int revents); |
|
|
|
|
|
|
|
|
|
static fastcgi_connection* fastcgi_connection_new(vrequest *vr, fastcgi_context *ctx) { |
|
|
|
|
fastcgi_connection* fcon = g_slice_new(fastcgi_connection); |
|
|
|
|
fastcgi_connection* fcon = g_slice_new0(fastcgi_connection); |
|
|
|
|
|
|
|
|
|
fastcgi_context_acquire(ctx); |
|
|
|
|
fcon->ctx = ctx; |
|
|
|
@ -467,7 +469,22 @@ static void fastcgi_forward_request(vrequest *vr, fastcgi_connection *fcon) {
|
|
|
|
|
|
|
|
|
|
static gboolean fastcgi_get_packet(fastcgi_connection *fcon) { |
|
|
|
|
const unsigned char *data; |
|
|
|
|
gint len; |
|
|
|
|
|
|
|
|
|
/* already got packet */ |
|
|
|
|
if (fcon->fcgi_in_record.valid) { |
|
|
|
|
if (0 == fcon->fcgi_in_record.remainingContent) { |
|
|
|
|
/* wait for padding data ? */ |
|
|
|
|
gint len = fcon->fcgi_in->length; |
|
|
|
|
if (len > fcon->fcgi_in_record.remainingPadding) len = fcon->fcgi_in_record.remainingPadding; |
|
|
|
|
chunkqueue_skip(fcon->fcgi_in, len); |
|
|
|
|
fcon->fcgi_in_record.remainingPadding -= len; |
|
|
|
|
if (0 != fcon->fcgi_in_record.remainingPadding) return TRUE; /* wait for data */ |
|
|
|
|
fcon->fcgi_in_record.valid = FALSE; /* read next packet */ |
|
|
|
|
} else { |
|
|
|
|
return TRUE; /* wait for/handle more content */ |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!chunkqueue_extract_to(fcon->vr, fcon->fcgi_in, FCGI_HEADER_LEN, fcon->buf_in_record)) return FALSE; /* need more data */ |
|
|
|
|
|
|
|
|
|
data = (const unsigned char*) fcon->buf_in_record->str; |
|
|
|
@ -476,18 +493,30 @@ static gboolean fastcgi_get_packet(fastcgi_connection *fcon) {
|
|
|
|
|
fcon->fcgi_in_record.requestID = (data[2] << 8) | (data[3]); |
|
|
|
|
fcon->fcgi_in_record.contentLength = (data[4] << 8) | (data[5]); |
|
|
|
|
fcon->fcgi_in_record.paddingLength = data[6]; |
|
|
|
|
fcon->fcgi_in_record.remainingContent = fcon->fcgi_in_record.contentLength; |
|
|
|
|
fcon->fcgi_in_record.remainingPadding = fcon->fcgi_in_record.paddingLength; |
|
|
|
|
fcon->fcgi_in_record.valid = TRUE; |
|
|
|
|
fcon->fcgi_in_record.first = TRUE; |
|
|
|
|
|
|
|
|
|
len = ((gint) fcon->fcgi_in_record.contentLength) + fcon->fcgi_in_record.paddingLength + FCGI_HEADER_LEN; |
|
|
|
|
|
|
|
|
|
if (len > fcon->fcgi_in->length) return FALSE; /* need more data */ |
|
|
|
|
chunkqueue_skip(fcon->fcgi_in, FCGI_HEADER_LEN); |
|
|
|
|
|
|
|
|
|
return TRUE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* get available data and mark it as read (subtract it from contentLength) */ |
|
|
|
|
static int fastcgi_available(fastcgi_connection *fcon) { |
|
|
|
|
gint len = fcon->fcgi_in->length; |
|
|
|
|
if (len > fcon->fcgi_in_record.remainingContent) len = fcon->fcgi_in_record.remainingContent; |
|
|
|
|
fcon->fcgi_in_record.remainingContent -= len; |
|
|
|
|
return len; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static gboolean fastcgi_parse_response(fastcgi_connection *fcon) { |
|
|
|
|
vrequest *vr = fcon->vr; |
|
|
|
|
plugin *p = fcon->ctx->plugin; |
|
|
|
|
gint len; |
|
|
|
|
while (fastcgi_get_packet(fcon)) { |
|
|
|
|
VR_WARNING(vr, "Fastcgi record type %i", (gint) fcon->fcgi_in_record.type); |
|
|
|
|
if (fcon->fcgi_in_record.version != FCGI_VERSION_1) { |
|
|
|
|
VR_ERROR(vr, "Unknown fastcgi protocol version %i", (gint) fcon->fcgi_in_record.version); |
|
|
|
|
close(fcon->fd); |
|
|
|
@ -495,34 +524,34 @@ static gboolean fastcgi_parse_response(fastcgi_connection *fcon) {
|
|
|
|
|
vrequest_error(vr); |
|
|
|
|
return FALSE; |
|
|
|
|
} |
|
|
|
|
chunkqueue_skip(fcon->fcgi_in, FCGI_HEADER_LEN); |
|
|
|
|
switch (fcon->fcgi_in_record.type) { |
|
|
|
|
case FCGI_END_REQUEST: |
|
|
|
|
chunkqueue_skip(fcon->fcgi_in, fcon->fcgi_in_record.contentLength); |
|
|
|
|
chunkqueue_skip(fcon->fcgi_in, fastcgi_available(fcon)); |
|
|
|
|
fcon->stdout->is_closed = TRUE; |
|
|
|
|
break; |
|
|
|
|
case FCGI_STDOUT: |
|
|
|
|
if (0 == fcon->fcgi_in_record.contentLength) { |
|
|
|
|
fcon->stdout->is_closed = TRUE; |
|
|
|
|
} else { |
|
|
|
|
chunkqueue_steal_len(fcon->stdout, fcon->fcgi_in, fcon->fcgi_in_record.contentLength); |
|
|
|
|
chunkqueue_steal_len(fcon->stdout, fcon->fcgi_in, fastcgi_available(fcon)); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case FCGI_STDERR: |
|
|
|
|
chunkqueue_extract_to(vr, fcon->fcgi_in, fcon->fcgi_in_record.contentLength, vr->con->wrk->tmp_str); |
|
|
|
|
len = fastcgi_available(fcon); |
|
|
|
|
chunkqueue_extract_to(vr, fcon->fcgi_in, len, vr->con->wrk->tmp_str); |
|
|
|
|
if (FASTCGI_OPTION(FASTCGI_OPTION_LOG_PLAIN_ERRORS).boolean) { |
|
|
|
|
log_split_lines(vr->con->srv, vr, LOG_LEVEL_BACKEND, 0, vr->con->wrk->tmp_str->str, ""); |
|
|
|
|
} else { |
|
|
|
|
VR_BACKEND_LINES(vr, vr->con->wrk->tmp_str->str, "%s", "(fcgi-stderr) "); |
|
|
|
|
} |
|
|
|
|
chunkqueue_skip(fcon->fcgi_in, fcon->fcgi_in_record.contentLength); |
|
|
|
|
chunkqueue_skip(fcon->fcgi_in, len); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
VR_WARNING(vr, "Unhandled fastcgi record type %i", (gint) fcon->fcgi_in_record.type); |
|
|
|
|
chunkqueue_skip(fcon->fcgi_in, fcon->fcgi_in_record.contentLength); |
|
|
|
|
if (fcon->fcgi_in_record.first) VR_WARNING(vr, "Unhandled fastcgi record type %i", (gint) fcon->fcgi_in_record.type); |
|
|
|
|
chunkqueue_skip(fcon->fcgi_in, fastcgi_available(fcon)); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
chunkqueue_skip(fcon->fcgi_in, fcon->fcgi_in_record.paddingLength); |
|
|
|
|
fcon->fcgi_in_record.first = FALSE; |
|
|
|
|
} |
|
|
|
|
return TRUE; |
|
|
|
|
} |
|
|
|
@ -703,7 +732,7 @@ static handler_t fastcgi_handle(vrequest *vr, gpointer param, gpointer *context)
|
|
|
|
|
chunkqueue_set_limit(fcon->fcgi_in, vr->out->limit); |
|
|
|
|
chunkqueue_set_limit(fcon->stdout, vr->out->limit); |
|
|
|
|
chunkqueue_set_limit(fcon->fcgi_out, vr->in->limit); |
|
|
|
|
vr->out->limit->io_watcher = &fcon->fd_watcher; |
|
|
|
|
if (vr->out->limit) vr->out->limit->io_watcher = &fcon->fd_watcher; |
|
|
|
|
|
|
|
|
|
return fastcgi_statemachine(vr, fcon); |
|
|
|
|
} |
|
|
|
@ -720,7 +749,7 @@ static void fastcgi_close(vrequest *vr, plugin *p) {
|
|
|
|
|
fastcgi_connection *fcon = (fastcgi_connection*) g_ptr_array_index(vr->plugin_ctx, p->id); |
|
|
|
|
g_ptr_array_index(vr->plugin_ctx, p->id) = NULL; |
|
|
|
|
if (fcon) { |
|
|
|
|
vr->out->limit->io_watcher = NULL; |
|
|
|
|
if (vr->out->limit) vr->out->limit->io_watcher = NULL; |
|
|
|
|
fastcgi_connection_free(fcon); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|