chore: update README with author, testing section, and per-route auth config

This commit is contained in:
2025-12-12 21:20:34 +00:00
parent 1ec7101289
commit 0461f21d5a
3 changed files with 133 additions and 86 deletions
+14 -6
View File
@@ -86,19 +86,27 @@ static char* read_file_to_string(const char *filename) {
FILE *f = fopen(filename, "rb");
if (!f) return NULL;
fseek(f, 0, SEEK_END);
if (fseek(f, 0, SEEK_END) != 0) {
fclose(f);
return NULL;
}
long length = ftell(f);
if (length < 0 || length > 1024*1024) {
fclose(f);
return NULL;
}
fseek(f, 0, SEEK_SET);
char *buffer = malloc(length + 1);
if (buffer) {
size_t read_len = fread(buffer, 1, length, f);
buffer[read_len] = '\0';
if (fseek(f, 0, SEEK_SET) != 0) {
fclose(f);
return NULL;
}
char *buffer = malloc((size_t)length + 1);
if (!buffer) {
fclose(f);
return NULL;
}
size_t read_len = fread(buffer, 1, (size_t)length, f);
buffer[read_len] = '\0';
fclose(f);
return buffer;
}
+59 -23
View File
@@ -15,6 +15,7 @@
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@@ -46,13 +47,21 @@ int connection_set_non_blocking(int fd) {
void connection_set_tcp_keepalive(int fd) {
int yes = 1;
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes));
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) < 0) {
log_debug("setsockopt SO_KEEPALIVE failed for fd %d: %s", fd, strerror(errno));
}
int idle = 60;
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle));
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)) < 0) {
log_debug("setsockopt TCP_KEEPIDLE failed for fd %d: %s", fd, strerror(errno));
}
int interval = 10;
setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval)) < 0) {
log_debug("setsockopt TCP_KEEPINTVL failed for fd %d: %s", fd, strerror(errno));
}
int maxpkt = 6;
setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &maxpkt, sizeof(maxpkt));
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &maxpkt, sizeof(maxpkt)) < 0) {
log_debug("setsockopt TCP_KEEPCNT failed for fd %d: %s", fd, strerror(errno));
}
}
void connection_add_to_epoll(int fd, uint32_t events) {
@@ -297,7 +306,12 @@ void connection_send_error_response(connection_t *conn, int code, const char* st
time_t now = time(NULL);
struct tm *gmt = gmtime(&now);
char date_buf[64];
strftime(date_buf, sizeof(date_buf), "%a, %d %b %Y %H:%M:%S GMT", gmt);
if (gmt) {
strftime(date_buf, sizeof(date_buf), "%a, %d %b %Y %H:%M:%S GMT", gmt);
} else {
strncpy(date_buf, "Thu, 01 Jan 1970 00:00:00 GMT", sizeof(date_buf) - 1);
date_buf[sizeof(date_buf) - 1] = '\0';
}
char response[ERROR_RESPONSE_SIZE];
int len = snprintf(response, sizeof(response),
@@ -331,7 +345,12 @@ void connection_send_auth_required(connection_t *conn, const char *realm) {
time_t now = time(NULL);
struct tm *gmt = gmtime(&now);
char date_buf[64];
strftime(date_buf, sizeof(date_buf), "%a, %d %b %Y %H:%M:%S GMT", gmt);
if (gmt) {
strftime(date_buf, sizeof(date_buf), "%a, %d %b %Y %H:%M:%S GMT", gmt);
} else {
strncpy(date_buf, "Thu, 01 Jan 1970 00:00:00 GMT", sizeof(date_buf) - 1);
date_buf[sizeof(date_buf) - 1] = '\0';
}
const char *body = "401 Unauthorized - Authentication required";
char response[ERROR_RESPONSE_SIZE];
@@ -385,6 +404,17 @@ static int try_upstream_connect(struct sockaddr_in *addr, int *out_fd) {
return 0;
}
static void cleanup_upstream_partial(connection_t *up, int up_fd, connection_t *client, int free_read, int free_write) {
if (free_read) buffer_free(&up->read_buf);
if (free_write) buffer_free(&up->write_buf);
if (up->config) config_ref_dec(up->config);
close(up_fd);
memset(up, 0, sizeof(connection_t));
up->type = CONN_TYPE_UNUSED;
up->fd = -1;
if (client) client->pair = NULL;
}
void connection_connect_to_upstream(connection_t *client, const char *data, size_t data_len) {
if (!client || !data) return;
@@ -466,21 +496,12 @@ void connection_connect_to_upstream(connection_t *client, const char *data, size
config_ref_inc(up->config);
if (buffer_init(&up->read_buf, CHUNK_SIZE) < 0) {
close(up_fd);
memset(up, 0, sizeof(connection_t));
up->type = CONN_TYPE_UNUSED;
up->fd = -1;
client->pair = NULL;
cleanup_upstream_partial(up, up_fd, client, 0, 0);
connection_send_error_response(client, 502, "Bad Gateway", "Memory allocation failed");
return;
}
if (buffer_init(&up->write_buf, CHUNK_SIZE) < 0) {
buffer_free(&up->read_buf);
close(up_fd);
memset(up, 0, sizeof(connection_t));
up->type = CONN_TYPE_UNUSED;
up->fd = -1;
client->pair = NULL;
cleanup_upstream_partial(up, up_fd, client, 1, 0);
connection_send_error_response(client, 502, "Bad Gateway", "Memory allocation failed");
return;
}
@@ -521,10 +542,14 @@ void connection_connect_to_upstream(connection_t *client, const char *data, size
}
}
if (buffer_ensure_capacity(&up->write_buf, len_to_send) == 0) {
memcpy(up->write_buf.data, data_to_send, len_to_send);
up->write_buf.tail = len_to_send;
if (buffer_ensure_capacity(&up->write_buf, len_to_send) < 0) {
if (modified_request) free(modified_request);
cleanup_upstream_partial(up, up_fd, client, 1, 1);
connection_send_error_response(client, 502, "Bad Gateway", "Memory allocation failed");
return;
}
memcpy(up->write_buf.data, data_to_send, len_to_send);
up->write_buf.tail = len_to_send;
if (modified_request) {
free(modified_request);
@@ -533,7 +558,8 @@ void connection_connect_to_upstream(connection_t *client, const char *data, size
if (route->use_ssl) {
up->ssl = SSL_new(ssl_ctx);
if (!up->ssl) {
connection_close(client->fd);
cleanup_upstream_partial(up, up_fd, client, 1, 1);
connection_send_error_response(client, 502, "Bad Gateway", "SSL initialization failed");
return;
}
@@ -665,7 +691,12 @@ static void handle_client_read(connection_t *conn) {
route_config_t *route = config_find_route(conn->request.host);
if (route && route->use_auth) {
char auth_header[1024] = "";
const char *headers_start = data_start + (strstr(data_start, "\r\n") - data_start + 2);
const char *first_crlf = strstr(data_start, "\r\n");
if (!first_crlf || first_crlf >= data_start + headers_len - 2) {
connection_send_error_response(conn, 400, "Bad Request", "Malformed HTTP request headers.");
return;
}
const char *headers_start = first_crlf + 2;
http_find_header_value(headers_start, headers_len - (headers_start - data_start), "Authorization", auth_header, sizeof(auth_header));
char error_msg[256] = "";
@@ -838,7 +869,12 @@ static void handle_forwarding(connection_t *conn) {
if (result.output_len > 0 && result.size_delta != 0) {
output_data = patched_buf;
output_len = result.output_len;
conn->content_length_delta += result.size_delta;
if ((result.size_delta > 0 && conn->content_length_delta > LONG_MAX - result.size_delta) ||
(result.size_delta < 0 && conn->content_length_delta < LONG_MIN - result.size_delta)) {
log_debug("Content-length delta overflow detected on fd %d", conn->fd);
} else {
conn->content_length_delta += result.size_delta;
}
log_debug("Patched data: %zu -> %zu bytes (delta: %ld)", src_len, output_len, result.size_delta);
} else if (result.output_len > 0) {
output_data = patched_buf;