Add async support for FastCGI
This commit is contained in:
4
Makefile
4
Makefile
@ -59,7 +59,7 @@ bin/res/%.txt: res/%.*
|
||||
bin/sesimos: bin/server.o bin/logger.o bin/cache_handler.o bin/async.o bin/workers.o \
|
||||
bin/worker/request_handler.o bin/worker/tcp_acceptor.o \
|
||||
bin/worker/fastcgi_handler.o bin/worker/local_handler.o bin/worker/proxy_handler.o \
|
||||
bin/worker/ws_frame_handler.o bin/worker/chunk_handler.o \
|
||||
bin/worker/ws_frame_handler.o bin/worker/chunk_handler.o bin/worker/fastcgi_frame_handler.o \
|
||||
bin/lib/http_static.o bin/res/default.o bin/res/proxy.o bin/res/style.o \
|
||||
bin/res/icon_error.o bin/res/icon_info.o bin/res/icon_success.o bin/res/icon_warning.o \
|
||||
bin/res/globe.o \
|
||||
@ -92,6 +92,8 @@ bin/worker/proxy_handler.o: src/worker/func.h
|
||||
|
||||
bin/worker/ws_frame_handler.o: src/worker/func.h
|
||||
|
||||
bin/worker/fastcgi_frame_handler.o: src/worker/func.h
|
||||
|
||||
bin/worker/chunk_handler.o: src/worker/func.h
|
||||
|
||||
bin/lib/compress.o: src/lib/compress.h
|
||||
|
@ -11,12 +11,14 @@
|
||||
#include "utils.h"
|
||||
#include "../logger.h"
|
||||
#include "list.h"
|
||||
#include "../workers.h"
|
||||
|
||||
#include <sys/un.h>
|
||||
#include <sys/socket.h>
|
||||
#include <string.h>
|
||||
|
||||
// TODO use pipes for stdin, stdout, stderr in FastCGI
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
char *fastcgi_add_param(char *buf, const char *key, const char *value) {
|
||||
char *ptr = buf;
|
||||
@ -76,9 +78,9 @@ int fastcgi_send_data(fastcgi_cnx_t *cnx, unsigned char type, unsigned short len
|
||||
int fastcgi_init(fastcgi_cnx_t *conn, int mode, unsigned int req_num, const sock *client, const http_req *req, const http_uri *uri) {
|
||||
conn->mode = mode;
|
||||
conn->req_id = (req_num + 1) & 0xFFFF;
|
||||
conn->out_buf = NULL;
|
||||
conn->out_off = 0;
|
||||
conn->webroot = uri->webroot;
|
||||
conn->err = NULL;
|
||||
sock_init(&conn->out, 0, SOCK_PIPE);
|
||||
|
||||
conn->socket.enc = 0;
|
||||
if ((conn->socket.socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
||||
@ -183,16 +185,39 @@ int fastcgi_init(fastcgi_cnx_t *conn, int mode, unsigned int req_num, const sock
|
||||
if (fastcgi_send_data(conn, FCGI_PARAMS, 0, NULL) == -1)
|
||||
return -1;
|
||||
|
||||
int pipes[2][2];
|
||||
if (pipe(pipes[0]) == -1 || pipe(pipes[1]) == -1)
|
||||
return -1;
|
||||
|
||||
conn->fd_out = pipes[1][1];
|
||||
conn->out.socket = pipes[1][0];
|
||||
|
||||
conn->fd_err = pipes[0][1];
|
||||
conn->err = fdopen(pipes[0][0], "r");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fastcgi_close_cnx(fastcgi_cnx_t *cnx) {
|
||||
int e = errno;
|
||||
|
||||
if (cnx->err) fclose(cnx->err);
|
||||
cnx->err = NULL;
|
||||
if (cnx->socket.socket) sock_close(&cnx->socket);
|
||||
|
||||
sock_close(&cnx->out);
|
||||
close(cnx->fd_err);
|
||||
close(cnx->fd_out);
|
||||
|
||||
errno = e;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fastcgi_close_stdin(fastcgi_cnx_t *conn) {
|
||||
if (fastcgi_send_data(conn, FCGI_STDIN, 0, NULL) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
return (fastcgi_send_data(conn, FCGI_STDIN, 0, NULL) == -1) ? -1 : 0;
|
||||
}
|
||||
|
||||
// TODO show/log php stderr
|
||||
int fastcgi_php_error(const fastcgi_cnx_t *conn, const char *msg, int msg_len, char *err_msg) {
|
||||
char *msg_str = malloc(msg_len + 1);
|
||||
char *ptr0 = msg_str;
|
||||
@ -201,7 +226,6 @@ int fastcgi_php_error(const fastcgi_cnx_t *conn, const char *msg, int msg_len, c
|
||||
char *ptr1 = NULL;
|
||||
int len, err = 0;
|
||||
|
||||
// FIXME *msg is part of a stream, handle fragmented lines
|
||||
while (1) {
|
||||
log_lvl_t msg_type = LOG_INFO;
|
||||
int msg_pre_len = 0;
|
||||
@ -260,74 +284,97 @@ int fastcgi_php_error(const fastcgi_cnx_t *conn, const char *msg, int msg_len, c
|
||||
return err;
|
||||
}
|
||||
|
||||
int fastcgi_header(fastcgi_cnx_t *conn, http_res *res, char *err_msg) {
|
||||
int fastcgi_recv_frame(fastcgi_cnx_t *cnx) {
|
||||
FCGI_Header header;
|
||||
char *content;
|
||||
unsigned short content_len, req_id;
|
||||
long ret;
|
||||
int err = 0;
|
||||
unsigned short req_id, content_len;
|
||||
|
||||
while (1) {
|
||||
if (sock_recv_x(&conn->socket, &header, sizeof(header), 0) == -1) {
|
||||
res->status = http_get_status(500);
|
||||
sprintf(err_msg, "Unable to communicate with FastCGI socket.");
|
||||
error("Unable to receive from FastCGI socket");
|
||||
return 1;
|
||||
}
|
||||
req_id = ntohs(header.requestId);
|
||||
content_len = ntohs(header.contentLength);
|
||||
content = malloc(content_len + header.paddingLength);
|
||||
if (sock_recv_x(&conn->socket, content, content_len + header.paddingLength, 0) == -1) {
|
||||
res->status = http_get_status(500);
|
||||
sprintf(err_msg, "Unable to communicate with FastCGI socket.");
|
||||
error("Unable to receive from FastCGI socket");
|
||||
free(content);
|
||||
return 1;
|
||||
}
|
||||
if (sock_recv_x(&cnx->socket, &header, sizeof(header), 0) == -1)
|
||||
return -1;
|
||||
|
||||
if (req_id != conn->req_id) {
|
||||
continue;
|
||||
}
|
||||
req_id = ntohs(header.requestId);
|
||||
content_len = ntohs(header.contentLength);
|
||||
|
||||
if (header.type == FCGI_END_REQUEST) {
|
||||
FCGI_EndRequestBody *body = (FCGI_EndRequestBody *) content;
|
||||
int app_status = ntohl(body->appStatus);
|
||||
if (body->protocolStatus != FCGI_REQUEST_COMPLETE) {
|
||||
error("FastCGI protocol error: %i", body->protocolStatus);
|
||||
}
|
||||
if (app_status != 0) {
|
||||
error("FastCGI app terminated with exit code %i", app_status);
|
||||
}
|
||||
sock_close(&conn->socket);
|
||||
free(content);
|
||||
return 1;
|
||||
} else if (header.type == FCGI_STDERR) {
|
||||
if (conn->mode == FASTCGI_BACKEND_PHP) {
|
||||
err = err || fastcgi_php_error(conn, content, content_len, err_msg);
|
||||
}
|
||||
} else if (header.type == FCGI_STDOUT) {
|
||||
break;
|
||||
} else {
|
||||
error("Unknown FastCGI type: %i", header.type);
|
||||
}
|
||||
|
||||
free(content);
|
||||
if (req_id != cnx->req_id) {
|
||||
warning("Invalid request id from FastCGI socket");
|
||||
char content[256 * 256];
|
||||
sock_recv_x(&cnx->socket, content, content_len + header.paddingLength, 0);
|
||||
return -1;
|
||||
}
|
||||
if (err) {
|
||||
|
||||
if (header.type == FCGI_STDOUT || header.type == FCGI_STDERR) {
|
||||
char buf[256];
|
||||
if (header.type == FCGI_STDOUT) {
|
||||
uint64_t len = content_len;
|
||||
if (write(cnx->fd_out, &len, sizeof(len)) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd = (header.type == FCGI_STDOUT) ? cnx->fd_out : cnx->fd_err;
|
||||
for (long ret, sent = 0; sent < content_len; sent += ret) {
|
||||
if ((ret = splice(cnx->socket.socket, 0, fd, 0, content_len - sent, 0)) == -1) {
|
||||
if (errno == EINTR) {
|
||||
errno = 0, ret = 0;
|
||||
continue;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sock_recv_x(&cnx->socket, buf, header.paddingLength, 0) == -1)
|
||||
return -1;
|
||||
|
||||
return header.type;
|
||||
}
|
||||
|
||||
char content[256 * 256];
|
||||
if (sock_recv_x(&cnx->socket, content, content_len + header.paddingLength, 0) == -1)
|
||||
return -1;
|
||||
|
||||
if (header.type == FCGI_END_REQUEST) {
|
||||
FCGI_EndRequestBody *body = (FCGI_EndRequestBody *) content;
|
||||
cnx->app_status = ntohl(body->appStatus);
|
||||
if (body->protocolStatus != FCGI_REQUEST_COMPLETE)
|
||||
error("FastCGI protocol error: %i", body->protocolStatus);
|
||||
} else {
|
||||
warning("Unknown FastCGI type: %i", header.type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return header.type;
|
||||
}
|
||||
|
||||
long fastcgi_send(fastcgi_cnx_t *cnx, sock *client) {
|
||||
char buf[CHUNK_SIZE];
|
||||
return sock_splice_all(client, &cnx->out, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
int fastcgi_header(fastcgi_cnx_t *cnx, http_res *res, char *err_msg) {
|
||||
long ret, len;
|
||||
char content[CLIENT_MAX_HEADER_SIZE];
|
||||
|
||||
if ((len = sock_recv_chunk_header(&cnx->out)) == -1) {
|
||||
res->status = http_get_status(500);
|
||||
return 2;
|
||||
sprintf(err_msg, "Unable to communicate with FastCGI socket.");
|
||||
error("Unable to receive from FastCGI socket (1)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
conn->out_buf = content;
|
||||
conn->out_len = content_len;
|
||||
conn->out_off = (unsigned short) (strstr(content, "\r\n\r\n") - content + 4);
|
||||
if ((ret = sock_recv_x(&cnx->out, content, len, 0)) == -1) {
|
||||
res->status = http_get_status(500);
|
||||
sprintf(err_msg, "Unable to communicate with FastCGI socket.");
|
||||
error("Unable to receive from FastCGI socket (2)");
|
||||
return -1;
|
||||
}
|
||||
content[ret] = 0;
|
||||
|
||||
char *buf = content;
|
||||
unsigned short header_len = conn->out_off;
|
||||
if (header_len <= 0) {
|
||||
char *h_pos = strstr(content, "\r\n\r\n");
|
||||
if (h_pos == NULL) {
|
||||
error("Unable to parse header: End of header not found");
|
||||
return 1;
|
||||
}
|
||||
long header_len = h_pos - content + 4;
|
||||
|
||||
for (int i = 0; i < header_len; i++) {
|
||||
if ((buf[i] >= 0x00 && buf[i] <= 0x1F && buf[i] != '\r' && buf[i] != '\n') || buf[i] == 0x7F) {
|
||||
@ -356,135 +403,12 @@ int fastcgi_header(fastcgi_cnx_t *conn, http_res *res, char *err_msg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fastcgi_send(fastcgi_cnx_t *conn, sock *client, int flags) {
|
||||
FCGI_Header header;
|
||||
long ret;
|
||||
char buf0[256], *content, *ptr;
|
||||
int len;
|
||||
unsigned short content_len;
|
||||
|
||||
if (conn->out_buf != NULL && conn->out_len > conn->out_off) {
|
||||
content = conn->out_buf;
|
||||
ptr = content + conn->out_off;
|
||||
content_len = conn->out_len - conn->out_off;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if ((sock_recv_x(&conn->socket, &header, sizeof(header), 0)) == -1) {
|
||||
error("Unable to receive from FastCGI socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
content_len = ntohs(header.contentLength);
|
||||
content = malloc(content_len + header.paddingLength);
|
||||
ptr = content;
|
||||
|
||||
long rcv_len = 0;
|
||||
while (rcv_len < content_len + header.paddingLength) {
|
||||
ret = sock_recv(&conn->socket, content + rcv_len, content_len + header.paddingLength - rcv_len, 0);
|
||||
if (ret < 0) {
|
||||
error("Unable to receive from FastCGI socket");
|
||||
free(content);
|
||||
return -1;
|
||||
}
|
||||
rcv_len += ret;
|
||||
}
|
||||
|
||||
if (header.type == FCGI_END_REQUEST) {
|
||||
FCGI_EndRequestBody *body = (FCGI_EndRequestBody *) content;
|
||||
int app_status = ntohl(body->appStatus);
|
||||
if (body->protocolStatus != FCGI_REQUEST_COMPLETE) {
|
||||
error("FastCGI protocol error: %i", body->protocolStatus);
|
||||
}
|
||||
if (app_status != 0) {
|
||||
error("FastCGI app terminated with exit code %i", app_status);
|
||||
}
|
||||
sock_close(&conn->socket);
|
||||
free(content);
|
||||
|
||||
if (flags & FASTCGI_CHUNKED)
|
||||
if (sock_send_last_chunk(client) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
} else if (header.type == FCGI_STDERR) {
|
||||
if (conn->mode == FASTCGI_BACKEND_PHP) {
|
||||
fastcgi_php_error(conn, content, content_len, buf0);
|
||||
}
|
||||
} else if (header.type == FCGI_STDOUT) {
|
||||
out:
|
||||
if (content_len != 0) {
|
||||
if (flags & FASTCGI_CHUNKED) if (sock_send_chunk_header(client, content_len) == -1) return -1;
|
||||
if (sock_send_x(client, ptr, content_len, 0) == -1) return -1;
|
||||
if (flags & FASTCGI_CHUNKED) if (sock_send_chunk_trailer(client) == -1) return -1;
|
||||
}
|
||||
} else {
|
||||
error("Unknown FastCGI type: %i", header.type);
|
||||
}
|
||||
free(content);
|
||||
}
|
||||
int fastcgi_dump(fastcgi_cnx_t *cnx, char *buf, long len) {
|
||||
return sock_recv_x(&cnx->socket, buf, len, 0) == -1 ? -1 : 0;
|
||||
}
|
||||
|
||||
int fastcgi_dump(fastcgi_cnx_t *conn, char *buf, long len) {
|
||||
FCGI_Header header;
|
||||
long ret;
|
||||
char buf0[256];
|
||||
char *content, *ptr = buf;
|
||||
unsigned short content_len;
|
||||
|
||||
if (conn->out_buf != NULL && conn->out_len > conn->out_off) {
|
||||
ptr += snprintf(ptr, len, "%.*s", conn->out_len - conn->out_off, conn->out_buf + conn->out_off);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (sock_recv_x(&conn->socket, &header, sizeof(header), 0) == -1) {
|
||||
error("Unable to receive from FastCGI socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
content_len = ntohs(header.contentLength);
|
||||
content = malloc(content_len + header.paddingLength);
|
||||
|
||||
long rcv_len = 0;
|
||||
while (rcv_len < content_len + header.paddingLength) {
|
||||
ret = sock_recv(&conn->socket, content + rcv_len, content_len + header.paddingLength - rcv_len, 0);
|
||||
if (ret < 0) {
|
||||
error("Unable to receive from FastCGI socket");
|
||||
free(content);
|
||||
return -1;
|
||||
}
|
||||
rcv_len += ret;
|
||||
}
|
||||
|
||||
if (header.type == FCGI_END_REQUEST) {
|
||||
FCGI_EndRequestBody *body = (FCGI_EndRequestBody *) content;
|
||||
int app_status = ntohl(body->appStatus);
|
||||
if (body->protocolStatus != FCGI_REQUEST_COMPLETE) {
|
||||
error("FastCGI protocol error: %i", body->protocolStatus);
|
||||
}
|
||||
if (app_status != 0) {
|
||||
error("FastCGI app terminated with exit code %i", app_status);
|
||||
}
|
||||
sock_close(&conn->socket);
|
||||
free(content);
|
||||
|
||||
return 0;
|
||||
} else if (header.type == FCGI_STDERR) {
|
||||
if (conn->mode == FASTCGI_BACKEND_PHP) {
|
||||
fastcgi_php_error(conn, content, content_len, buf0);
|
||||
}
|
||||
} else if (header.type == FCGI_STDOUT) {
|
||||
ptr += snprintf(ptr, len - (ptr - buf), "%.*s", content_len, content);
|
||||
} else {
|
||||
error("Unknown FastCGI type: %i", header.type);
|
||||
}
|
||||
free(content);
|
||||
}
|
||||
}
|
||||
|
||||
int fastcgi_receive(fastcgi_cnx_t *conn, sock *client, unsigned long len) {
|
||||
char *buf[16384];
|
||||
int fastcgi_receive(fastcgi_cnx_t *cnx, sock *client, unsigned long len) {
|
||||
char buf[CHUNK_SIZE];
|
||||
|
||||
for (long to_send = (long) len, ret; to_send > 0; to_send -= ret) {
|
||||
if ((ret = sock_recv(client, buf, (to_send > sizeof(buf)) ? sizeof(buf) : to_send, 0)) <= 0) {
|
||||
@ -492,14 +416,14 @@ int fastcgi_receive(fastcgi_cnx_t *conn, sock *client, unsigned long len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fastcgi_send_data(conn, FCGI_STDIN, ret, buf) == -1)
|
||||
if (fastcgi_send_data(cnx, FCGI_STDIN, ret, buf) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fastcgi_receive_chunked(fastcgi_cnx_t *conn, sock *client) {
|
||||
int fastcgi_receive_chunked(fastcgi_cnx_t *cnx, sock *client) {
|
||||
for (long ret;;) {
|
||||
if ((ret = sock_recv_chunk_header(client)) < 0) {
|
||||
return (int) ret;
|
||||
@ -507,7 +431,7 @@ int fastcgi_receive_chunked(fastcgi_cnx_t *conn, sock *client) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ret = fastcgi_receive(conn, client, ret)) < 0)
|
||||
if ((ret = fastcgi_receive(cnx, client, ret)) < 0)
|
||||
return (int) ret;
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "http.h"
|
||||
#include "uri.h"
|
||||
|
||||
#define FASTCGI_CHUNKED 1
|
||||
#define FASTCGI_TIMEOUT 3600
|
||||
|
||||
#define FASTCGI_BACKEND_PHP 1
|
||||
|
||||
@ -23,12 +23,12 @@
|
||||
|
||||
typedef struct {
|
||||
int mode;
|
||||
sock socket;
|
||||
int in, out, err;
|
||||
sock socket, out;
|
||||
int fd_err, fd_out;
|
||||
FILE *err;
|
||||
unsigned short req_id;
|
||||
int app_status;
|
||||
const char *webroot;
|
||||
char *out_buf;
|
||||
unsigned short out_len, out_off;
|
||||
char *r_addr;
|
||||
char *r_host;
|
||||
} fastcgi_cnx_t;
|
||||
@ -37,18 +37,24 @@ char *fastcgi_add_param(char *buf, const char *key, const char *value);
|
||||
|
||||
int fastcgi_init(fastcgi_cnx_t *conn, int mode, unsigned int req_num, const sock *client, const http_req *req, const http_uri *uri);
|
||||
|
||||
int fastcgi_close_cnx(fastcgi_cnx_t *cnx);
|
||||
|
||||
int fastcgi_close_stdin(fastcgi_cnx_t *conn);
|
||||
|
||||
int fastcgi_php_error(const fastcgi_cnx_t *conn, const char *msg, int msg_len, char *err_msg);
|
||||
|
||||
int fastcgi_header(fastcgi_cnx_t *conn, http_res *res, char *err_msg);
|
||||
int fastcgi_recv_frame(fastcgi_cnx_t *cnx);
|
||||
|
||||
int fastcgi_send(fastcgi_cnx_t *conn, sock *client, int flags);
|
||||
int fastcgi_header(fastcgi_cnx_t *cnx, http_res *res, char *err_msg);
|
||||
|
||||
int fastcgi_dump(fastcgi_cnx_t *conn, char *buf, long len);
|
||||
long fastcgi_send(fastcgi_cnx_t *cnx, sock *client);
|
||||
|
||||
int fastcgi_dump(fastcgi_cnx_t *cnx, char *buf, long len);
|
||||
|
||||
int fastcgi_receive(fastcgi_cnx_t *cnx, sock *client, unsigned long len);
|
||||
|
||||
int fastcgi_receive_chunked(fastcgi_cnx_t *cnx, sock *client);
|
||||
|
||||
int fastcgi_receive(fastcgi_cnx_t *conn, sock *client, unsigned long len);
|
||||
|
||||
int fastcgi_receive_chunked(fastcgi_cnx_t *conn, sock *client);
|
||||
|
||||
#endif //SESIMOS_FASTCGI_H
|
||||
|
70
src/worker/fastcgi_frame_handler.c
Normal file
70
src/worker/fastcgi_frame_handler.c
Normal file
@ -0,0 +1,70 @@
|
||||
/**
|
||||
* sesimos - secure, simple, modern web server
|
||||
* @brief FastCGI frame handler
|
||||
* @file src/worker/fcti_frame_handler.c
|
||||
* @author Lorenz Stechauner
|
||||
* @date 2023-01-22
|
||||
*/
|
||||
|
||||
#include "func.h"
|
||||
#include "../lib/fastcgi.h"
|
||||
#include "../logger.h"
|
||||
#include "../workers.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <memory.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void fastcgi_frame_handler_func(fastcgi_ctx_t *ctx) {
|
||||
logger_set_prefix("[%*s]%s", ADDRSTRLEN, ctx->client->socket.s_addr, ctx->client->log_prefix);
|
||||
|
||||
switch (fastcgi_recv_frame(&ctx->cnx)) {
|
||||
case FCGI_STDOUT:
|
||||
case FCGI_STDERR:
|
||||
fastcgi_handle_frame(ctx);
|
||||
break;
|
||||
case -1:
|
||||
error("Unable to receive FastCGI frame");
|
||||
ctx->client->s_keep_alive = 0;
|
||||
fastcgi_close(ctx);
|
||||
break;
|
||||
default:
|
||||
// end of request received
|
||||
write(ctx->cnx.fd_out, "\0\0\0\0\0\0\0\0\r\n", 10);
|
||||
fastcgi_close(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
int fastcgi_handle_connection(client_ctx_t *ctx, fastcgi_cnx_t **cnx) {
|
||||
sock_set_timeout(&(*cnx)->socket, FASTCGI_TIMEOUT);
|
||||
sock_set_socket_timeout(&(*cnx)->socket, 1);
|
||||
|
||||
fastcgi_ctx_t *a = malloc(sizeof(fastcgi_ctx_t));
|
||||
a->closed = 0;
|
||||
a->client = ctx;
|
||||
memcpy(&a->cnx, *cnx, sizeof(fastcgi_cnx_t));
|
||||
ctx->fcgi_cnx = a;
|
||||
fastcgi_handle_frame(a);
|
||||
*cnx = &a->cnx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fastcgi_close(fastcgi_ctx_t *ctx) {
|
||||
if (ctx->closed == 0) {
|
||||
ctx->closed++;
|
||||
return;
|
||||
}
|
||||
|
||||
logger_set_prefix("[%*s]%s", ADDRSTRLEN, ctx->client->socket.s_addr, ctx->client->log_prefix);
|
||||
|
||||
if (ctx->cnx.app_status != 0)
|
||||
error("FastCGI app terminated with exit code %i", ctx->cnx.app_status);
|
||||
|
||||
debug("Closing FastCGI connection");
|
||||
|
||||
fastcgi_close_cnx(&ctx->cnx);
|
||||
ctx->client->fcgi_cnx = NULL;
|
||||
free(ctx);
|
||||
errno = 0;
|
||||
}
|
@ -9,40 +9,48 @@
|
||||
#include "func.h"
|
||||
#include "../logger.h"
|
||||
#include "../lib/utils.h"
|
||||
#include "../lib/compress.h"
|
||||
#include "../workers.h"
|
||||
#include "../lib/fastcgi.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int fastcgi_handler_1(client_ctx_t *ctx, fastcgi_cnx_t *fcgi_cnx);
|
||||
static int fastcgi_handler_1(client_ctx_t *ctx, fastcgi_cnx_t **fcgi_cnx);
|
||||
static int fastcgi_handler_2(client_ctx_t *ctx, fastcgi_cnx_t *fcgi_cnx);
|
||||
|
||||
void fastcgi_handler_func(client_ctx_t *ctx) {
|
||||
logger_set_prefix("[%s%*s%s]%s", BLD_STR, ADDRSTRLEN, ctx->req_host, CLR_STR, ctx->log_prefix);
|
||||
|
||||
fastcgi_cnx_t fcgi_cnx;
|
||||
int ret = fastcgi_handler_1(ctx, &fcgi_cnx);
|
||||
respond(ctx);
|
||||
if (ret == 0) fastcgi_handler_2(ctx, &fcgi_cnx);
|
||||
request_complete(ctx);
|
||||
if (!ctx->chunks_transferred) {
|
||||
fastcgi_cnx_t *fcgi_cnx = NULL;
|
||||
int ret = fastcgi_handler_1(ctx, &fcgi_cnx);
|
||||
respond(ctx);
|
||||
if (ret == 0) {
|
||||
switch (fastcgi_handler_2(ctx, fcgi_cnx)) {
|
||||
case 1: return;
|
||||
case 2: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request_complete(ctx);
|
||||
handle_request(ctx);
|
||||
}
|
||||
|
||||
static int fastcgi_handler_1(client_ctx_t *ctx, fastcgi_cnx_t *fcgi_cnx) {
|
||||
static int fastcgi_handler_1(client_ctx_t *ctx, fastcgi_cnx_t **fcgi_cnx) {
|
||||
http_res *res = &ctx->res;
|
||||
http_req *req = &ctx->req;
|
||||
http_uri *uri = &ctx->uri;
|
||||
sock *client = &ctx->socket;
|
||||
char *err_msg = ctx->err_msg;
|
||||
|
||||
fcgi_cnx->socket.socket = 0;
|
||||
fcgi_cnx->socket.enc = 0;
|
||||
fcgi_cnx->req_id = 0;
|
||||
fcgi_cnx->r_addr = ctx->socket.addr;
|
||||
fcgi_cnx->r_host = (ctx->host[0] != 0) ? ctx->host : NULL;
|
||||
fastcgi_cnx_t fcgi_cnx_buf;
|
||||
(*fcgi_cnx) = &fcgi_cnx_buf;
|
||||
sock_init(&(*fcgi_cnx)->socket, 0, 0);
|
||||
(*fcgi_cnx)->req_id = 0;
|
||||
(*fcgi_cnx)->r_addr = ctx->socket.addr;
|
||||
(*fcgi_cnx)->r_host = (ctx->host[0] != 0) ? ctx->host : NULL;
|
||||
|
||||
char buf[1024];
|
||||
|
||||
@ -61,19 +69,21 @@ static int fastcgi_handler_1(client_ctx_t *ctx, fastcgi_cnx_t *fcgi_cnx) {
|
||||
http_add_header_field(&res->hdr, "Last-Modified", last_modified);
|
||||
|
||||
res->status = http_get_status(200);
|
||||
if (fastcgi_init(fcgi_cnx, mode, ctx->req_num, client, req, uri) != 0) {
|
||||
if (fastcgi_init(*fcgi_cnx, mode, ctx->req_num, client, req, uri) != 0) {
|
||||
res->status = http_get_status(503);
|
||||
sprintf(err_msg, "Unable to communicate with FastCGI socket.");
|
||||
return 2;
|
||||
}
|
||||
|
||||
fastcgi_handle_connection(ctx, fcgi_cnx);
|
||||
|
||||
const char *client_content_length = http_get_header_field(&req->hdr, "Content-Length");
|
||||
const char *client_transfer_encoding = http_get_header_field(&req->hdr, "Transfer-Encoding");
|
||||
if (client_content_length != NULL) {
|
||||
unsigned long client_content_len = strtoul(client_content_length, NULL, 10);
|
||||
ret = fastcgi_receive(fcgi_cnx, client, client_content_len);
|
||||
ret = fastcgi_receive(*fcgi_cnx, client, client_content_len);
|
||||
} else if (strcontains(client_transfer_encoding, "chunked")) {
|
||||
ret = fastcgi_receive_chunked(fcgi_cnx, client);
|
||||
ret = fastcgi_receive_chunked(*fcgi_cnx, client);
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
@ -86,10 +96,11 @@ static int fastcgi_handler_1(client_ctx_t *ctx, fastcgi_cnx_t *fcgi_cnx) {
|
||||
res->status = http_get_status(502);
|
||||
return 2;
|
||||
}
|
||||
fastcgi_close_stdin(fcgi_cnx);
|
||||
fastcgi_close_stdin(*fcgi_cnx);
|
||||
|
||||
ret = fastcgi_header(fcgi_cnx, res, err_msg);
|
||||
ret = fastcgi_header(*fcgi_cnx, res, err_msg);
|
||||
if (ret != 0) {
|
||||
res->status = http_get_status(502);
|
||||
return (ret < 0) ? -1 : 1;
|
||||
}
|
||||
|
||||
@ -121,7 +132,7 @@ static int fastcgi_handler_1(client_ctx_t *ctx, fastcgi_cnx_t *fcgi_cnx) {
|
||||
ctx->content_length != -1 &&
|
||||
ctx->content_length <= sizeof(ctx->msg_content) - 1)
|
||||
{
|
||||
fastcgi_dump(fcgi_cnx, ctx->msg_content, sizeof(ctx->msg_content));
|
||||
fastcgi_dump(*fcgi_cnx, ctx->msg_content, sizeof(ctx->msg_content));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -135,19 +146,43 @@ static int fastcgi_handler_1(client_ctx_t *ctx, fastcgi_cnx_t *fcgi_cnx) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fastcgi_next_cb(chunk_ctx_t *ctx) {
|
||||
if(ctx->client->fcgi_cnx) {
|
||||
fastcgi_close(ctx->client->fcgi_cnx);
|
||||
ctx->client->fcgi_cnx = NULL;
|
||||
}
|
||||
|
||||
fastcgi_handle(ctx->client);
|
||||
}
|
||||
|
||||
static void fastcgi_error_cb(chunk_ctx_t *ctx) {
|
||||
if (ctx->client->chunks_transferred)
|
||||
return;
|
||||
|
||||
logger_set_prefix("[%s%*s%s]%s", BLD_STR, ADDRSTRLEN, ctx->client->req_host, CLR_STR, ctx->client->log_prefix);
|
||||
|
||||
warning("Closing connection due to FastCGI error");
|
||||
if(ctx->client->fcgi_cnx) {
|
||||
fastcgi_close(ctx->client->fcgi_cnx);
|
||||
ctx->client->fcgi_cnx = NULL;
|
||||
}
|
||||
|
||||
tcp_close(ctx->client);
|
||||
|
||||
errno = 0;
|
||||
}
|
||||
|
||||
static int fastcgi_handler_2(client_ctx_t *ctx, fastcgi_cnx_t *fcgi_cnx) {
|
||||
int chunked = strcontains(http_get_header_field(&ctx->res.hdr, "Transfer-Encoding"), "chunked");
|
||||
|
||||
int flags = (chunked ? FASTCGI_CHUNKED : 0);
|
||||
int ret = fastcgi_send(fcgi_cnx, &ctx->socket, flags);
|
||||
if (ret < 0) {
|
||||
ctx->c_keep_alive = 0;
|
||||
errno = 0;
|
||||
if (chunked) {
|
||||
handle_chunks(ctx, &fcgi_cnx->out, SOCK_CHUNKED, fastcgi_next_cb, fastcgi_error_cb);
|
||||
return 1;
|
||||
} else {
|
||||
fastcgi_send(fcgi_cnx, &ctx->socket);
|
||||
fastcgi_close(ctx->fcgi_cnx);
|
||||
ctx->fcgi_cnx = NULL;
|
||||
fastcgi_handle(ctx);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (fcgi_cnx->socket.socket != 0) {
|
||||
sock_close(&fcgi_cnx->socket);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "../lib/uri.h"
|
||||
#include "../lib/config.h"
|
||||
#include "../lib/proxy.h"
|
||||
#include "../lib/fastcgi.h"
|
||||
|
||||
typedef struct {
|
||||
sock socket;
|
||||
@ -35,6 +36,7 @@ typedef struct {
|
||||
long content_length;
|
||||
char *msg_buf, *msg_buf_ptr, msg_content[1024];
|
||||
proxy_ctx_t *proxy;
|
||||
void *fcgi_cnx;
|
||||
} client_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
@ -43,6 +45,12 @@ typedef struct {
|
||||
void *other;
|
||||
} ws_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
int closed:2;
|
||||
client_ctx_t *client;
|
||||
fastcgi_cnx_t cnx;
|
||||
} fastcgi_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
client_ctx_t *client;
|
||||
sock *socket;
|
||||
@ -59,6 +67,8 @@ void local_handler_func(client_ctx_t *ctx);
|
||||
|
||||
void fastcgi_handler_func(client_ctx_t *ctx);
|
||||
|
||||
void fastcgi_frame_handler_func(fastcgi_ctx_t *ctx);
|
||||
|
||||
void proxy_handler_func(client_ctx_t *ctx);
|
||||
|
||||
void ws_frame_handler_func(ws_ctx_t *ctx);
|
||||
@ -79,4 +89,8 @@ void ws_close(ws_ctx_t *ctx);
|
||||
|
||||
int handle_chunks(client_ctx_t *ctx, sock *socket, int flags, void (*next_cb)(chunk_ctx_t *), void (*err_cb)(chunk_ctx_t *));
|
||||
|
||||
int fastcgi_handle_connection(client_ctx_t *ctx, fastcgi_cnx_t **cnx);
|
||||
|
||||
void fastcgi_close(fastcgi_ctx_t *ctx);
|
||||
|
||||
#endif //SESIMOS_FUNC_H
|
||||
|
@ -49,6 +49,7 @@ static void init_ctx(client_ctx_t *ctx) {
|
||||
ctx->proxy = NULL;
|
||||
ctx->use_fastcgi = 0;
|
||||
ctx->chunks_transferred = 0;
|
||||
ctx->fcgi_cnx = NULL;
|
||||
ctx->use_proxy = 0;
|
||||
ctx->ws_close = 0;
|
||||
ctx->proxy = NULL;
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "async.h"
|
||||
|
||||
static mpmc_t tcp_acceptor_ctx, request_handler_ctx, local_handler_ctx, fastcgi_handler_ctx, proxy_handler_ctx,
|
||||
ws_frame_handler_ctx, chunk_handler_ctx;
|
||||
ws_frame_handler_ctx, chunk_handler_ctx, fastcgi_frame_handler_ctx;
|
||||
|
||||
int workers_init(void) {
|
||||
mpmc_init(&tcp_acceptor_ctx, 8, 64, (void (*)(void *)) tcp_acceptor_func, "tcp");
|
||||
@ -23,6 +23,7 @@ int workers_init(void) {
|
||||
mpmc_init(&proxy_handler_ctx, 8, 64, (void (*)(void *)) proxy_handler_func, "proxy");
|
||||
mpmc_init(&ws_frame_handler_ctx, 8, 64, (void (*)(void *)) ws_frame_handler_func, "ws");
|
||||
mpmc_init(&chunk_handler_ctx, 8, 64, (void (*)(void *)) chunk_handler_func, "chunk");
|
||||
mpmc_init(&fastcgi_frame_handler_ctx, 8, 64, (void (*)(void *)) fastcgi_frame_handler_func, "fcgi_f");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -34,6 +35,7 @@ void workers_stop(void) {
|
||||
mpmc_stop(&request_handler_ctx);
|
||||
mpmc_stop(&ws_frame_handler_ctx);
|
||||
mpmc_stop(&chunk_handler_ctx);
|
||||
mpmc_stop(&fastcgi_frame_handler_ctx);
|
||||
}
|
||||
|
||||
void workers_destroy(void) {
|
||||
@ -44,6 +46,7 @@ void workers_destroy(void) {
|
||||
mpmc_destroy(&request_handler_ctx);
|
||||
mpmc_destroy(&ws_frame_handler_ctx);
|
||||
mpmc_destroy(&chunk_handler_ctx);
|
||||
mpmc_destroy(&fastcgi_frame_handler_ctx);
|
||||
}
|
||||
|
||||
int tcp_accept(client_ctx_t *ctx) {
|
||||
@ -74,6 +77,17 @@ int fastcgi_handle(client_ctx_t *ctx) {
|
||||
return mpmc_queue(&fastcgi_handler_ctx, ctx);
|
||||
}
|
||||
|
||||
static int fastcgi_handle_frame_cb(fastcgi_ctx_t *ctx) {
|
||||
return mpmc_queue(&fastcgi_frame_handler_ctx, ctx);
|
||||
}
|
||||
|
||||
int fastcgi_handle_frame(fastcgi_ctx_t *ctx) {
|
||||
return async(&ctx->cnx.socket, ASYNC_WAIT_READ, 0, ctx,
|
||||
(void (*)(void *)) fastcgi_handle_frame_cb,
|
||||
(void (*)(void *)) fastcgi_close,
|
||||
(void (*)(void *)) fastcgi_close);
|
||||
}
|
||||
|
||||
int proxy_handle(client_ctx_t *ctx) {
|
||||
return mpmc_queue(&proxy_handler_ctx, ctx);
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ int local_handle(client_ctx_t *ctx);
|
||||
|
||||
int fastcgi_handle(client_ctx_t *ctx);
|
||||
|
||||
int fastcgi_handle_frame(fastcgi_ctx_t *ctx);
|
||||
|
||||
int proxy_handle(client_ctx_t *ctx);
|
||||
|
||||
int ws_handle_frame(ws_ctx_t *ctx);
|
||||
|
Reference in New Issue
Block a user