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\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