From 6c13922f2f1ee3f6ba2de8a96e7da5ba18869af8 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Sat, 20 Nov 2021 14:04:08 +0100 Subject: [PATCH] Add redirect document --- src/client.c | 57 +++++++++++++++++++++++++++++-------- src/lib/fastcgi.c | 66 +++++++++++++++++++++++++++++++++++++++++++ src/lib/fastcgi.h | 2 ++ src/lib/http_static.c | 2 ++ src/lib/rev_proxy.c | 4 +-- src/lib/rev_proxy.h | 2 +- 6 files changed, 118 insertions(+), 15 deletions(-) diff --git a/src/client.c b/src/client.c index 67badab..c4dacbd 100644 --- a/src/client.c +++ b/src/client.c @@ -54,19 +54,26 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int struct timespec begin, end; long ret; int client_keep_alive; + char buf0[1024], buf1[1024]; char msg_buf[8192], msg_pre_buf_1[4096], msg_pre_buf_2[4096], err_msg[256]; + char msg_content[1024]; char buffer[CHUNK_SIZE]; - err_msg[0] = 0; char host[256], *host_ptr, *hdr_connection; - host_config *conf = NULL; - long content_length = 0; - FILE *file = NULL; + msg_buf[0] = 0; + err_msg[0] = 0; + msg_content[0] = 0; + + host_config *conf = NULL; + FILE *file = NULL; + + long content_length = 0; int accept_if_modified_since = 0; int use_fastcgi = 0; int use_rev_proxy = 0; int p_len; + fastcgi_conn fcgi_conn = {.socket = 0, .req_id = 0}; http_status custom_status; @@ -431,6 +438,21 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int sprintf(err_msg, "The status code was set to an invalid or unknown value."); goto respond; } + + if (status_code >= 300 && status_code < 600) { + const char *content_type = http_get_header_field(&res.hdr, "Content-Type"); + const char *content_length_f = http_get_header_field(&res.hdr, "Content-Length"); + const char *content_encoding = http_get_header_field(&res.hdr, "Content-Encoding"); + if (content_encoding == NULL && content_type != NULL && content_length_f != NULL && + strncmp(content_type, "text/html", 9) == 0) + { + long content_len = strtol(content_length_f, NULL, 10); + if (content_len <= sizeof(msg_content)) { + fastcgi_dump(&fcgi_conn, msg_content, content_len); + goto respond; + } + } + } } content_length = -1; @@ -461,17 +483,20 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int ret = rev_proxy_init(&req, &res, &ctx, conf, client, &custom_status, err_msg); use_rev_proxy = (ret == 0); - if (use_rev_proxy && res.status->code >= 400 && res.status->code < 600) { + // Let 300 be formatted by origin server + if (use_rev_proxy && res.status->code >= 301 && res.status->code < 600) { const char *content_type = http_get_header_field(&res.hdr, "Content-Type"); const char *content_length_f = http_get_header_field(&res.hdr, "Content-Length"); - if (content_type != NULL && content_length_f != NULL && strncmp(content_type, "text/html", 9) == 0) { + const char *content_encoding = http_get_header_field(&res.hdr, "Content-Encoding"); + if (content_encoding == NULL && content_type != NULL && content_length_f != NULL && + strncmp(content_type, "text/html", 9) == 0) + { long content_len = strtol(content_length_f, NULL, 10); - if (content_len <= 1000) { + if (content_len <= sizeof(msg_content)) { ctx.status = res.status->code; - ctx.origin = SERVER; - + ctx.origin = res.status->code >= 400 ? SERVER : NONE; use_rev_proxy = 0; - rev_proxy_void(); + rev_proxy_dump(msg_content, content_len); } } } @@ -512,7 +537,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int if (http_get_header_field(&res.hdr, "Accept-Ranges") == NULL) { http_add_header_field(&res.hdr, "Accept-Ranges", "none"); } - if (!use_fastcgi && file == NULL && ((res.status->code >= 400 && res.status->code < 600) || err_msg[0] != 0)) { + if (!use_fastcgi && file == NULL && ((res.status->code >= 300 && res.status->code < 600) || err_msg[0] != 0)) { http_remove_header_field(&res.hdr, "Date", HTTP_REMOVE_ALL); http_remove_header_field(&res.hdr, "Server", HTTP_REMOVE_ALL); http_remove_header_field(&res.hdr, "Cache-Control", HTTP_REMOVE_ALL); @@ -527,6 +552,14 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int const http_doc_info *info = http_get_status_info(res.status); const http_status_msg *http_msg = http_get_error_msg(res.status); + if (res.status->code >= 300 && res.status->code < 400 && msg_content[0] == 0) { + const char *location = http_get_header_field(&res.hdr, "Location"); + if (location != NULL) { + snprintf(msg_content, sizeof(msg_content), + "\n", location); + } + } + char *rev_proxy_doc = ""; if (conf->type == CONFIG_TYPE_REVERSE_PROXY) { const http_status *status = http_get_status(ctx.status); @@ -554,7 +587,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int http_msg != NULL ? http_msg->msg : "", err_msg[0] != 0 ? err_msg : ""); content_length = snprintf(msg_buf, sizeof(msg_buf), http_default_document, res.status->code, res.status->msg, msg_pre_buf_1, info->mode, info->icon, info->color, host, - rev_proxy_doc); + rev_proxy_doc, msg_content[0] != 0 ? msg_content : ""); } if (content_length >= 0) { sprintf(buf0, "%li", content_length); diff --git a/src/lib/fastcgi.c b/src/lib/fastcgi.c index 432f2e2..0c153d9 100644 --- a/src/lib/fastcgi.c +++ b/src/lib/fastcgi.c @@ -513,6 +513,72 @@ int fastcgi_send(fastcgi_conn *conn, sock *client, int flags) { } } +int fastcgi_dump(fastcgi_conn *conn, char *buf, long len) { + FCGI_Header header; + long ret; + char buf0[256]; + char *content, *ptr = buf; + unsigned short req_id, 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) { + ret = recv(conn->socket, &header, sizeof(header), 0); + if (ret < 0) { + print(ERR_STR "Unable to receive from FastCGI socket: %s" CLR_STR, strerror(errno)); + return -1; + } else if (ret != sizeof(header)) { + print(ERR_STR "Unable to receive from FastCGI socket: received len (%li) != header len (%li)" CLR_STR, + ret, sizeof(header)); + return -1; + } + + req_id = (header.requestIdB1 << 8) | header.requestIdB0; + content_len = (header.contentLengthB1 << 8) | header.contentLengthB0; + content = malloc(content_len + header.paddingLength); + + long rcv_len = 0; + while (rcv_len < content_len + header.paddingLength) { + ret = recv(conn->socket, content + rcv_len, content_len + header.paddingLength - rcv_len, 0); + if (ret < 0) { + print(ERR_STR "Unable to receive from FastCGI socket: %s" CLR_STR, strerror(errno)); + free(content); + return -1; + } + rcv_len += ret; + } + + if (header.type == FCGI_END_REQUEST) { + FCGI_EndRequestBody *body = (FCGI_EndRequestBody *) content; + int app_status = (body->appStatusB3 << 24) | (body->appStatusB2 << 16) | (body->appStatusB1 << 8) | + body->appStatusB0; + if (body->protocolStatus != FCGI_REQUEST_COMPLETE) { + print(ERR_STR "FastCGI protocol error: %i" CLR_STR, body->protocolStatus); + } + if (app_status != 0) { + print(ERR_STR "FastCGI app terminated with exit code %i" CLR_STR, app_status); + } + close(conn->socket); + conn->socket = 0; + free(content); + + return 0; + } else if (header.type == FCGI_STDERR) { + // TODO implement Necronda backend error handling + if (conn->mode == FASTCGI_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 { + print(ERR_STR "Unknown FastCGI type: %i" CLR_STR, header.type); + } + free(content); + } +} + int fastcgi_receive(fastcgi_conn *conn, sock *client, unsigned long len) { unsigned long rcv_len = 0; char *buf[16384]; diff --git a/src/lib/fastcgi.h b/src/lib/fastcgi.h index 11bd6d0..2d7d9ec 100644 --- a/src/lib/fastcgi.h +++ b/src/lib/fastcgi.h @@ -49,6 +49,8 @@ int fastcgi_header(fastcgi_conn *conn, http_res *res, char *err_msg); int fastcgi_send(fastcgi_conn *conn, sock *client, int flags); +int fastcgi_dump(fastcgi_conn *conn, char *buf, long len); + int fastcgi_receive(fastcgi_conn *conn, sock *client, unsigned long len); #endif //NECRONDA_SERVER_FASTCGI_H diff --git a/src/lib/http_static.c b/src/lib/http_static.c index bd433f3..e3931db 100644 --- a/src/lib/http_static.c +++ b/src/lib/http_static.c @@ -126,6 +126,7 @@ const char http_default_document[] = "\t\tp{text-align:center;font-size:0.875em;}\n" "\t\tdiv.footer{color:var(--soft);font-size:0.75em;text-align:center;margin:2em 0 0.5em 0;}\n" "\t\tdiv.footer a{color:var(--soft);}\n" + "\t\tul,ol{width:fit-content;margin:auto;}\n" "\n" "\t\tsection.error-ctx{display:flex;padding:0;border:none;}\n" "\t\tdiv.box{flex:100%% 1 1;border:1px solid var(--info);color:var(--info);position:relative;padding:1em;box-sizing:border-box;text-align:center;}\n" @@ -200,6 +201,7 @@ const char http_default_document[] = "\t
\n" "\t\t
\n" "%3$s" + "%9$s" "\t\t\t
%7$s - " SERVER_STR_HTML "
\n" "\t\t
\n" "%8$s" diff --git a/src/lib/rev_proxy.c b/src/lib/rev_proxy.c index 05dd579..4d25f54 100644 --- a/src/lib/rev_proxy.c +++ b/src/lib/rev_proxy.c @@ -534,8 +534,8 @@ int rev_proxy_send(sock *client, unsigned long len_to_send, int flags) { return 0; } -int rev_proxy_void() { - // FIXME rev_proxy_void +int rev_proxy_dump(char *buf, long len) { + sock_recv(&rev_proxy, buf, len, 0); sock_close(&rev_proxy); return 0; } diff --git a/src/lib/rev_proxy.h b/src/lib/rev_proxy.h index 5d14eea..d7d372a 100644 --- a/src/lib/rev_proxy.h +++ b/src/lib/rev_proxy.h @@ -33,6 +33,6 @@ int rev_proxy_init(http_req *req, http_res *res, http_status_ctx *ctx, host_conf int rev_proxy_send(sock *client, unsigned long len_to_send, int flags); -int rev_proxy_void(); +int rev_proxy_dump(char *buf, long len); #endif //NECRONDA_SERVER_REV_PROXY_H