Handle multiple connections simultaneously
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 2m2s
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 2m2s
This commit changes the implementationt to store connected clients file-descriptors and to iterate through them all periodically to handle requests and to time-out stale connections. This means that even if one connection is in progress, the program can still handle new connections from other clients. Note this does this not by threads but by taking advantage of non-blocking io to handle each connection. Fixes #8 .
This commit is contained in:
parent
d4b3c3af8b
commit
fef2d154ce
4 changed files with 269 additions and 206 deletions
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#define C_SIMPLE_HTTP_SLEEP_NANOS 1000000
|
#define C_SIMPLE_HTTP_SLEEP_NANOS 1000000
|
||||||
#define C_SIMPLE_HTTP_NONBLOCK_SLEEP_NANOS 1000000
|
#define C_SIMPLE_HTTP_NONBLOCK_SLEEP_NANOS 1000000
|
||||||
|
#define C_SIMPLE_HTTP_CONNECTION_TIMEOUT_SECONDS 3
|
||||||
#define C_SIMPLE_HTTP_MAX_NONBLOCK_WAIT_NANOS 3500000000
|
#define C_SIMPLE_HTTP_MAX_NONBLOCK_WAIT_NANOS 3500000000
|
||||||
#define C_SIMPLE_HTTP_TRY_CONFIG_RELOAD_NANOS 4000000000
|
#define C_SIMPLE_HTTP_TRY_CONFIG_RELOAD_NANOS 4000000000
|
||||||
#define C_SIMPLE_HTTP_TRY_CONFIG_RELOAD_TICKS \
|
#define C_SIMPLE_HTTP_TRY_CONFIG_RELOAD_TICKS \
|
||||||
|
|
465
src/main.c
465
src/main.c
|
@ -37,6 +37,7 @@
|
||||||
// Local includes.
|
// Local includes.
|
||||||
#include "arg_parse.h"
|
#include "arg_parse.h"
|
||||||
#include "big_endian.h"
|
#include "big_endian.h"
|
||||||
|
#include "config.h"
|
||||||
#include "tcp_socket.h"
|
#include "tcp_socket.h"
|
||||||
#include "signal_handling.h"
|
#include "signal_handling.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
@ -45,19 +46,55 @@
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "static.h"
|
#include "static.h"
|
||||||
|
|
||||||
#define CHECK_ERROR_WRITE(write_expr) \
|
#define CHECK_ERROR_WRITE(connection_fd, write_expr) \
|
||||||
if (write_expr < 0) { \
|
if (write_expr < 0) { \
|
||||||
close(connection_fd); \
|
close(connection_fd); \
|
||||||
fprintf(stderr, "ERROR Failed to write to connected peer, closing...\n"); \
|
fprintf(stderr, "ERROR Failed to write to connected peer, closing...\n"); \
|
||||||
return 1; \
|
return 1; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_ERROR_WRITE_CONTINUE(write_expr) \
|
void c_simple_http_print_ipv6_addr(FILE *out, const struct in6_addr *addr) {
|
||||||
if (write_expr < 0) { \
|
for (uint32_t idx = 0; idx < 16; ++idx) {
|
||||||
close(connection_fd); \
|
if (idx % 2 == 0 && idx > 0) {
|
||||||
fprintf(stderr, "ERROR Failed to write to connected peer, closing...\n"); \
|
fprintf(out, ":");
|
||||||
continue; \
|
|
||||||
}
|
}
|
||||||
|
fprintf(out, "%02x", addr->s6_addr[idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct ConnectionItem {
|
||||||
|
int fd;
|
||||||
|
struct timespec time_point;
|
||||||
|
struct in6_addr peer_addr;
|
||||||
|
} ConnectionItem;
|
||||||
|
|
||||||
|
typedef struct ConnectionContext {
|
||||||
|
char *buf;
|
||||||
|
const Args *args;
|
||||||
|
C_SIMPLE_HTTP_ParsedConfig *parsed;
|
||||||
|
} ConnectionContext;
|
||||||
|
|
||||||
|
void c_simple_http_cleanup_connection_item(void *data) {
|
||||||
|
ConnectionItem *citem = data;
|
||||||
|
if (citem) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
fprintf(stderr, "Closed connection to peer ");
|
||||||
|
c_simple_http_print_ipv6_addr(stderr, &citem->peer_addr);
|
||||||
|
#endif
|
||||||
|
if (citem->fd >= 0) {
|
||||||
|
close(citem->fd);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
fprintf(stderr, ", fd %d\n", citem->fd);
|
||||||
|
#endif
|
||||||
|
citem->fd = -1;
|
||||||
|
} else {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
free(citem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int c_simple_http_headers_check_print(void *data, void *ud) {
|
int c_simple_http_headers_check_print(void *data, void *ud) {
|
||||||
SDArchiverHashMap *headers_map = ud;
|
SDArchiverHashMap *headers_map = ud;
|
||||||
|
@ -92,22 +129,204 @@ int c_simple_http_on_error(
|
||||||
size_t response_size;
|
size_t response_size;
|
||||||
if (response) {
|
if (response) {
|
||||||
response_size = strlen(response);
|
response_size = strlen(response);
|
||||||
CHECK_ERROR_WRITE(write(connection_fd, response, response_size));
|
CHECK_ERROR_WRITE(connection_fd,
|
||||||
|
write(connection_fd, response, response_size));
|
||||||
} else {
|
} else {
|
||||||
CHECK_ERROR_WRITE(write(
|
CHECK_ERROR_WRITE(connection_fd, write(
|
||||||
connection_fd, "HTTP/1.1 500 Internal Server Error\n", 35));
|
connection_fd, "HTTP/1.1 500 Internal Server Error\n", 35));
|
||||||
CHECK_ERROR_WRITE(write(connection_fd, "Allow: GET\n", 11));
|
CHECK_ERROR_WRITE(connection_fd, write(connection_fd, "Allow: GET\n", 11));
|
||||||
CHECK_ERROR_WRITE(write(connection_fd, "Connection: close\n", 18));
|
CHECK_ERROR_WRITE(connection_fd,
|
||||||
CHECK_ERROR_WRITE(write(
|
write(connection_fd, "Connection: close\n", 18));
|
||||||
connection_fd, "Content-Type: text/html\n", 24));
|
CHECK_ERROR_WRITE(connection_fd,
|
||||||
CHECK_ERROR_WRITE(write(connection_fd, "Content-Length: 35\n", 19));
|
write(connection_fd, "Content-Type: text/html\n", 24));
|
||||||
CHECK_ERROR_WRITE(write(
|
CHECK_ERROR_WRITE(connection_fd,
|
||||||
connection_fd, "\n<h1>500 Internal Server Error</h1>\n", 36));
|
write(connection_fd, "Content-Length: 35\n", 19));
|
||||||
|
CHECK_ERROR_WRITE(connection_fd,
|
||||||
|
write(connection_fd,
|
||||||
|
"\n<h1>500 Internal Server Error</h1>\n",
|
||||||
|
36));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int c_simple_http_manage_connections(void *data, void *ud) {
|
||||||
|
ConnectionItem *citem = data;
|
||||||
|
ConnectionContext *ctx = ud;
|
||||||
|
char *recv_buf = ctx->buf;
|
||||||
|
const Args *args = ctx->args;
|
||||||
|
C_SIMPLE_HTTP_ParsedConfig *parsed = ctx->parsed;
|
||||||
|
|
||||||
|
struct timespec current_monotonic;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, ¤t_monotonic);
|
||||||
|
if (current_monotonic.tv_sec - citem->time_point.tv_sec
|
||||||
|
>= C_SIMPLE_HTTP_CONNECTION_TIMEOUT_SECONDS) {
|
||||||
|
fprintf(stderr, "Peer ");
|
||||||
|
c_simple_http_print_ipv6_addr(stderr, &citem->peer_addr);
|
||||||
|
fprintf(stderr, " timed out.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t read_ret = read(citem->fd, recv_buf, C_SIMPLE_HTTP_RECV_BUF_SIZE);
|
||||||
|
if (read_ret < 0) {
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Peer ");
|
||||||
|
c_simple_http_print_ipv6_addr(stderr, &citem->peer_addr);
|
||||||
|
fprintf(stderr, " error.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// DEBUG print received buf.
|
||||||
|
for (uint32_t idx = 0;
|
||||||
|
idx < C_SIMPLE_HTTP_RECV_BUF_SIZE && idx < read_ret;
|
||||||
|
++idx) {
|
||||||
|
if ((recv_buf[idx] >= 0x20 && recv_buf[idx] <= 0x7E)
|
||||||
|
|| recv_buf[idx] == '\n' || recv_buf[idx] == '\r') {
|
||||||
|
printf("%c", recv_buf[idx]);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
puts("");
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
SDArchiverHashMap *headers_map = c_simple_http_request_to_headers_map(
|
||||||
|
(const char*)recv_buf,
|
||||||
|
(size_t)read_ret);
|
||||||
|
simple_archiver_list_get(
|
||||||
|
args->list_of_headers_to_log,
|
||||||
|
c_simple_http_headers_check_print,
|
||||||
|
headers_map);
|
||||||
|
simple_archiver_hash_map_free(&headers_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t response_size = 0;
|
||||||
|
enum C_SIMPLE_HTTP_ResponseCode response_code;
|
||||||
|
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
|
||||||
|
char *request_path = NULL;
|
||||||
|
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
|
||||||
|
char *response = c_simple_http_request_response(
|
||||||
|
(const char*)recv_buf,
|
||||||
|
(uint32_t)read_ret,
|
||||||
|
parsed,
|
||||||
|
&response_size,
|
||||||
|
&response_code,
|
||||||
|
args,
|
||||||
|
&request_path);
|
||||||
|
if (response && response_code == C_SIMPLE_HTTP_Response_200_OK) {
|
||||||
|
CHECK_ERROR_WRITE(citem->fd, write(
|
||||||
|
citem->fd, "HTTP/1.1 200 OK\n", 16));
|
||||||
|
CHECK_ERROR_WRITE(citem->fd, write(citem->fd, "Allow: GET\n", 11));
|
||||||
|
CHECK_ERROR_WRITE(citem->fd, write(
|
||||||
|
citem->fd, "Connection: close\n", 18));
|
||||||
|
CHECK_ERROR_WRITE(citem->fd, write(
|
||||||
|
citem->fd, "Content-Type: text/html\n", 24));
|
||||||
|
char content_length_buf[128];
|
||||||
|
size_t content_length_buf_size = 0;
|
||||||
|
memcpy(content_length_buf, "Content-Length: ", 16);
|
||||||
|
content_length_buf_size = 16;
|
||||||
|
int32_t written = 0;
|
||||||
|
snprintf(
|
||||||
|
content_length_buf + content_length_buf_size,
|
||||||
|
127 - content_length_buf_size,
|
||||||
|
"%lu\n%n",
|
||||||
|
response_size,
|
||||||
|
&written);
|
||||||
|
if (written <= 0) {
|
||||||
|
close(citem->fd);
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"WARNING Failed to write in response, closing connection...\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
content_length_buf_size += (size_t)written;
|
||||||
|
CHECK_ERROR_WRITE(citem->fd, write(
|
||||||
|
citem->fd, content_length_buf, content_length_buf_size));
|
||||||
|
CHECK_ERROR_WRITE(citem->fd, write(citem->fd, "\n", 1));
|
||||||
|
CHECK_ERROR_WRITE(citem->fd, write(
|
||||||
|
citem->fd, response, response_size));
|
||||||
|
} else if (
|
||||||
|
response_code == C_SIMPLE_HTTP_Response_404_Not_Found
|
||||||
|
&& args->static_dir) {
|
||||||
|
__attribute__((cleanup(c_simple_http_cleanup_static_file_info)))
|
||||||
|
C_SIMPLE_HTTP_StaticFileInfo file_info =
|
||||||
|
c_simple_http_get_file(args->static_dir, request_path, 0);
|
||||||
|
if (file_info.result == STATIC_FILE_RESULT_NoXDGMimeAvailable) {
|
||||||
|
file_info = c_simple_http_get_file(args->static_dir, request_path, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_info.result != STATIC_FILE_RESULT_OK
|
||||||
|
|| !file_info.buf
|
||||||
|
|| file_info.buf_size == 0
|
||||||
|
|| !file_info.mime_type) {
|
||||||
|
if (file_info.result == STATIC_FILE_RESULT_FileError
|
||||||
|
|| file_info.result == STATIC_FILE_RESULT_InternalError) {
|
||||||
|
response_code = C_SIMPLE_HTTP_Response_500_Internal_Server_Error;
|
||||||
|
} else if (file_info.result == STATIC_FILE_RESULT_InvalidParameter) {
|
||||||
|
response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
|
||||||
|
} else if (file_info.result == STATIC_FILE_RESULT_404NotFound) {
|
||||||
|
response_code = C_SIMPLE_HTTP_Response_404_Not_Found;
|
||||||
|
} else if (file_info.result == STATIC_FILE_RESULT_InvalidPath) {
|
||||||
|
response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
|
||||||
|
} else {
|
||||||
|
response_code = C_SIMPLE_HTTP_Response_500_Internal_Server_Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
c_simple_http_on_error(response_code, citem->fd);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
CHECK_ERROR_WRITE(citem->fd, write(
|
||||||
|
citem->fd, "HTTP/1.1 200 OK\n", 16));
|
||||||
|
CHECK_ERROR_WRITE(citem->fd, write(citem->fd, "Allow: GET\n", 11));
|
||||||
|
CHECK_ERROR_WRITE(citem->fd, write(
|
||||||
|
citem->fd, "Connection: close\n", 18));
|
||||||
|
uint64_t mime_length = strlen(file_info.mime_type);
|
||||||
|
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
|
||||||
|
char *mime_type_buf = malloc(mime_length + 1 + 14 + 1);
|
||||||
|
snprintf(
|
||||||
|
mime_type_buf,
|
||||||
|
mime_length + 1 + 14 + 1,
|
||||||
|
"Content-Type: %s\n",
|
||||||
|
file_info.mime_type);
|
||||||
|
CHECK_ERROR_WRITE(citem->fd, write(
|
||||||
|
citem->fd, mime_type_buf, mime_length + 1 + 14));
|
||||||
|
uint64_t content_str_len = 0;
|
||||||
|
for(uint64_t buf_size_temp = file_info.buf_size;
|
||||||
|
buf_size_temp > 0;
|
||||||
|
buf_size_temp /= 10) {
|
||||||
|
++content_str_len;
|
||||||
|
}
|
||||||
|
if (content_str_len == 0) {
|
||||||
|
content_str_len = 1;
|
||||||
|
}
|
||||||
|
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
|
||||||
|
char *content_length_buf = malloc(content_str_len + 1 + 16 + 1);
|
||||||
|
snprintf(
|
||||||
|
content_length_buf,
|
||||||
|
content_str_len + 1 + 16 + 1,
|
||||||
|
"Content-Length: %lu\n",
|
||||||
|
file_info.buf_size);
|
||||||
|
CHECK_ERROR_WRITE(citem->fd, write(
|
||||||
|
citem->fd, content_length_buf, content_str_len + 1 + 16));
|
||||||
|
CHECK_ERROR_WRITE(citem->fd, write(citem->fd, "\n", 1));
|
||||||
|
CHECK_ERROR_WRITE(citem->fd, write(
|
||||||
|
citem->fd, file_info.buf, file_info.buf_size));
|
||||||
|
fprintf(stderr,
|
||||||
|
"NOTICE Found static file for path \"%s\"\n",
|
||||||
|
request_path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c_simple_http_on_error(response_code, citem->fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
__attribute__((cleanup(c_simple_http_free_args)))
|
__attribute__((cleanup(c_simple_http_free_args)))
|
||||||
Args args = parse_args(argc, argv);
|
Args args = parse_args(argc, argv);
|
||||||
|
@ -186,10 +405,19 @@ int main(int argc, char **argv) {
|
||||||
memset(&peer_info, 0, sizeof(struct sockaddr_in6));
|
memset(&peer_info, 0, sizeof(struct sockaddr_in6));
|
||||||
peer_info.sin6_family = AF_INET6;
|
peer_info.sin6_family = AF_INET6;
|
||||||
|
|
||||||
|
__attribute__((cleanup(simple_archiver_list_free)))
|
||||||
|
SDArchiverLinkedList *connections = simple_archiver_list_init();
|
||||||
|
|
||||||
|
char recv_buf[C_SIMPLE_HTTP_RECV_BUF_SIZE];
|
||||||
|
|
||||||
|
ConnectionContext connection_context;
|
||||||
|
connection_context.buf = recv_buf;
|
||||||
|
connection_context.args = &args;
|
||||||
|
connection_context.parsed = &parsed_config;
|
||||||
|
|
||||||
signal(SIGINT, C_SIMPLE_HTTP_handle_sigint);
|
signal(SIGINT, C_SIMPLE_HTTP_handle_sigint);
|
||||||
signal(SIGUSR1, C_SIMPLE_HTTP_handle_sigusr1);
|
signal(SIGUSR1, C_SIMPLE_HTTP_handle_sigusr1);
|
||||||
|
signal(SIGPIPE, C_SIMPLE_HTTP_handle_sigpipe);
|
||||||
unsigned char recv_buf[C_SIMPLE_HTTP_RECV_BUF_SIZE];
|
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
ssize_t read_ret;
|
ssize_t read_ret;
|
||||||
|
@ -342,13 +570,8 @@ int main(int argc, char **argv) {
|
||||||
// Received connection, handle it.
|
// Received connection, handle it.
|
||||||
if ((args.flags & 1) == 0) {
|
if ((args.flags & 1) == 0) {
|
||||||
printf("Peer connected: addr is ");
|
printf("Peer connected: addr is ");
|
||||||
for (uint32_t idx = 0; idx < 16; ++idx) {
|
c_simple_http_print_ipv6_addr(stdout, &peer_info.sin6_addr);
|
||||||
if (idx % 2 == 0 && idx > 0) {
|
printf(", fd is %d\n", ret);
|
||||||
printf(":");
|
|
||||||
}
|
|
||||||
printf("%02x", peer_info.sin6_addr.s6_addr[idx]);
|
|
||||||
}
|
|
||||||
puts("");
|
|
||||||
} else {
|
} else {
|
||||||
printf("Peer connected.\n");
|
printf("Peer connected.\n");
|
||||||
}
|
}
|
||||||
|
@ -362,191 +585,21 @@ int main(int argc, char **argv) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
ConnectionItem *citem = malloc(sizeof(ConnectionItem));
|
||||||
const struct timespec non_block_wait_time =
|
memset(citem, 0, sizeof(ConnectionItem));
|
||||||
(struct timespec){.tv_sec = 0,
|
citem->fd = connection_fd;
|
||||||
.tv_nsec = C_SIMPLE_HTTP_NONBLOCK_SLEEP_NANOS};
|
ret = clock_gettime(CLOCK_MONOTONIC, &citem->time_point);
|
||||||
uint64_t nanoseconds_waited = 0;
|
citem->peer_addr = peer_info.sin6_addr;
|
||||||
int_fast8_t continue_after = 0;
|
simple_archiver_list_add(connections,
|
||||||
while (1) {
|
citem,
|
||||||
read_ret = read(connection_fd, recv_buf, C_SIMPLE_HTTP_RECV_BUF_SIZE);
|
c_simple_http_cleanup_connection_item);
|
||||||
if (read_ret < 0) {
|
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
||||||
nanosleep(&non_block_wait_time, NULL);
|
|
||||||
nanoseconds_waited += (uint64_t)non_block_wait_time.tv_nsec;
|
|
||||||
if (nanoseconds_waited >= C_SIMPLE_HTTP_MAX_NONBLOCK_WAIT_NANOS) {
|
|
||||||
fprintf(stderr, "WARNING Connection timed out!\n");
|
|
||||||
close(connection_fd);
|
|
||||||
continue_after = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
close(connection_fd);
|
|
||||||
fprintf(
|
|
||||||
stderr,
|
|
||||||
"WARNING Failed to read from new connection, closing...\n");
|
|
||||||
continue_after = 1;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (continue_after) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifndef NDEBUG
|
|
||||||
// DEBUG print received buf.
|
|
||||||
for (uint32_t idx = 0;
|
|
||||||
idx < C_SIMPLE_HTTP_RECV_BUF_SIZE && idx < read_ret;
|
|
||||||
++idx) {
|
|
||||||
if ((recv_buf[idx] >= 0x20 && recv_buf[idx] <= 0x7E)
|
|
||||||
|| recv_buf[idx] == '\n' || recv_buf[idx] == '\r') {
|
|
||||||
printf("%c", recv_buf[idx]);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
puts("");
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
SDArchiverHashMap *headers_map = c_simple_http_request_to_headers_map(
|
|
||||||
(const char*)recv_buf,
|
|
||||||
(size_t)read_ret);
|
|
||||||
simple_archiver_list_get(
|
|
||||||
args.list_of_headers_to_log,
|
|
||||||
c_simple_http_headers_check_print,
|
|
||||||
headers_map);
|
|
||||||
simple_archiver_hash_map_free(&headers_map);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t response_size = 0;
|
|
||||||
enum C_SIMPLE_HTTP_ResponseCode response_code;
|
|
||||||
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
|
|
||||||
char *request_path = NULL;
|
|
||||||
const char *response = c_simple_http_request_response(
|
|
||||||
(const char*)recv_buf,
|
|
||||||
(uint32_t)read_ret,
|
|
||||||
&parsed_config,
|
|
||||||
&response_size,
|
|
||||||
&response_code,
|
|
||||||
&args,
|
|
||||||
&request_path);
|
|
||||||
if (response && response_code == C_SIMPLE_HTTP_Response_200_OK) {
|
|
||||||
CHECK_ERROR_WRITE_CONTINUE(write(
|
|
||||||
connection_fd, "HTTP/1.1 200 OK\n", 16));
|
|
||||||
CHECK_ERROR_WRITE_CONTINUE(write(connection_fd, "Allow: GET\n", 11));
|
|
||||||
CHECK_ERROR_WRITE_CONTINUE(write(
|
|
||||||
connection_fd, "Connection: close\n", 18));
|
|
||||||
CHECK_ERROR_WRITE_CONTINUE(write(
|
|
||||||
connection_fd, "Content-Type: text/html\n", 24));
|
|
||||||
char content_length_buf[128];
|
|
||||||
size_t content_length_buf_size = 0;
|
|
||||||
memcpy(content_length_buf, "Content-Length: ", 16);
|
|
||||||
content_length_buf_size = 16;
|
|
||||||
int32_t written = 0;
|
|
||||||
snprintf(
|
|
||||||
content_length_buf + content_length_buf_size,
|
|
||||||
127 - content_length_buf_size,
|
|
||||||
"%lu\n%n",
|
|
||||||
response_size,
|
|
||||||
&written);
|
|
||||||
if (written <= 0) {
|
|
||||||
close(connection_fd);
|
|
||||||
fprintf(
|
|
||||||
stderr,
|
|
||||||
"WARNING Failed to write in response, closing connection...\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
content_length_buf_size += (size_t)written;
|
|
||||||
CHECK_ERROR_WRITE_CONTINUE(write(
|
|
||||||
connection_fd, content_length_buf, content_length_buf_size));
|
|
||||||
CHECK_ERROR_WRITE_CONTINUE(write(connection_fd, "\n", 1));
|
|
||||||
CHECK_ERROR_WRITE_CONTINUE(write(
|
|
||||||
connection_fd, response, response_size));
|
|
||||||
|
|
||||||
free((void*)response);
|
|
||||||
} else if (
|
|
||||||
response_code == C_SIMPLE_HTTP_Response_404_Not_Found
|
|
||||||
&& args.static_dir) {
|
|
||||||
__attribute__((cleanup(c_simple_http_cleanup_static_file_info)))
|
|
||||||
C_SIMPLE_HTTP_StaticFileInfo file_info =
|
|
||||||
c_simple_http_get_file(args.static_dir, request_path, 0);
|
|
||||||
if (file_info.result == STATIC_FILE_RESULT_NoXDGMimeAvailable) {
|
|
||||||
file_info = c_simple_http_get_file(args.static_dir, request_path, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_info.result != STATIC_FILE_RESULT_OK
|
|
||||||
|| !file_info.buf
|
|
||||||
|| file_info.buf_size == 0
|
|
||||||
|| !file_info.mime_type) {
|
|
||||||
if (file_info.result == STATIC_FILE_RESULT_FileError
|
|
||||||
|| file_info.result == STATIC_FILE_RESULT_InternalError) {
|
|
||||||
response_code = C_SIMPLE_HTTP_Response_500_Internal_Server_Error;
|
|
||||||
} else if (file_info.result == STATIC_FILE_RESULT_InvalidParameter) {
|
|
||||||
response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
|
|
||||||
} else if (file_info.result == STATIC_FILE_RESULT_404NotFound) {
|
|
||||||
response_code = C_SIMPLE_HTTP_Response_404_Not_Found;
|
|
||||||
} else if (file_info.result == STATIC_FILE_RESULT_InvalidPath) {
|
|
||||||
response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
|
|
||||||
} else {
|
|
||||||
response_code = C_SIMPLE_HTTP_Response_500_Internal_Server_Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c_simple_http_on_error(response_code, connection_fd)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
CHECK_ERROR_WRITE_CONTINUE(write(
|
|
||||||
connection_fd, "HTTP/1.1 200 OK\n", 16));
|
|
||||||
CHECK_ERROR_WRITE_CONTINUE(write(connection_fd, "Allow: GET\n", 11));
|
|
||||||
CHECK_ERROR_WRITE_CONTINUE(write(
|
|
||||||
connection_fd, "Connection: close\n", 18));
|
|
||||||
uint64_t mime_length = strlen(file_info.mime_type);
|
|
||||||
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
|
|
||||||
char *mime_type_buf = malloc(mime_length + 1 + 14 + 1);
|
|
||||||
snprintf(
|
|
||||||
mime_type_buf,
|
|
||||||
mime_length + 1 + 14 + 1,
|
|
||||||
"Content-Type: %s\n",
|
|
||||||
file_info.mime_type);
|
|
||||||
CHECK_ERROR_WRITE_CONTINUE(write(
|
|
||||||
connection_fd, mime_type_buf, mime_length + 1 + 14));
|
|
||||||
uint64_t content_str_len = 0;
|
|
||||||
for(uint64_t buf_size_temp = file_info.buf_size;
|
|
||||||
buf_size_temp > 0;
|
|
||||||
buf_size_temp /= 10) {
|
|
||||||
++content_str_len;
|
|
||||||
}
|
|
||||||
if (content_str_len == 0) {
|
|
||||||
content_str_len = 1;
|
|
||||||
}
|
|
||||||
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
|
|
||||||
char *content_length_buf = malloc(content_str_len + 1 + 16 + 1);
|
|
||||||
snprintf(
|
|
||||||
content_length_buf,
|
|
||||||
content_str_len + 1 + 16 + 1,
|
|
||||||
"Content-Length: %lu\n",
|
|
||||||
file_info.buf_size);
|
|
||||||
CHECK_ERROR_WRITE_CONTINUE(write(
|
|
||||||
connection_fd, content_length_buf, content_str_len + 1 + 16));
|
|
||||||
CHECK_ERROR_WRITE_CONTINUE(write(connection_fd, "\n", 1));
|
|
||||||
CHECK_ERROR_WRITE_CONTINUE(write(
|
|
||||||
connection_fd, file_info.buf, file_info.buf_size));
|
|
||||||
fprintf(stderr,
|
|
||||||
"NOTICE Found static file for path \"%s\"\n",
|
|
||||||
request_path);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (c_simple_http_on_error(response_code, connection_fd)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(connection_fd);
|
|
||||||
} else {
|
} else {
|
||||||
printf("WARNING: accept: Unknown invalid state!\n");
|
printf("WARNING: accept: Unknown invalid state!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simple_archiver_list_remove(connections,
|
||||||
|
c_simple_http_manage_connections,
|
||||||
|
&connection_context);
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
//printf(".");
|
//printf(".");
|
||||||
//fflush(stdout);
|
//fflush(stdout);
|
||||||
|
|
|
@ -43,4 +43,12 @@ void C_SIMPLE_HTTP_handle_sigusr1(int signal) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void C_SIMPLE_HTTP_handle_sigpipe(int signal) {
|
||||||
|
if (signal == SIGPIPE) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
fprintf(stderr, "WARNING Recieved SIGPIPE\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// vim: et ts=2 sts=2 sw=2
|
// vim: et ts=2 sts=2 sw=2
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
void C_SIMPLE_HTTP_handle_sigint(int signal);
|
void C_SIMPLE_HTTP_handle_sigint(int signal);
|
||||||
void C_SIMPLE_HTTP_handle_sigusr1(int signal);
|
void C_SIMPLE_HTTP_handle_sigusr1(int signal);
|
||||||
|
void C_SIMPLE_HTTP_handle_sigpipe(int signal);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue