commit 9cf6f814e802841666ed6d891f676b891205f18d
parent b5ec0c12b2b23718acb41bdc2af75829805b3411
Author: Sophie <info@soophie.de>
Date: Mon, 3 Feb 2025 08:42:22 +0000
feat: Added socket read timeout
Diffstat:
M | src/libhttp.h | | | 99 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
1 file changed, 57 insertions(+), 42 deletions(-)
diff --git a/src/libhttp.h b/src/libhttp.h
@@ -6,15 +6,17 @@
#include <sys/socket.h>
typedef enum {
- HTTP_ERR_OK = 0,
- HTTP_ERR_NO_SOCKET = 1,
- HTTP_ERR_UNKNOWN_HOST = 2,
- HTTP_ERR_NO_ADDR_REUSE = 3,
- HTTP_ERR_ADDR_IN_USE = 4,
- HTTP_ERR_NO_LISTEN = 5,
- HTTP_ERR_NO_SSL_CONTEXT = 6,
- HTTP_ERR_INVALID_CERTIFICATE = 7,
- HTTP_ERR_INVALID_PRIVATE_KEY = 8,
+ HTTP_ERR_OK = 0,
+ HTTP_ERR_NO_SOCKET = 1,
+ HTTP_ERR_UNKNOWN_HOST = 2,
+ HTTP_ERR_NO_ADDR_REUSE = 3,
+ HTTP_ERR_ADDR_IN_USE = 4,
+ HTTP_ERR_NO_LISTEN = 5,
+ HTTP_ERR_NO_SSL_CONTEXT = 6,
+ HTTP_ERR_INVALID_CERTIFICATE = 7,
+ HTTP_ERR_INVALID_PRIVATE_KEY = 8,
+ HTTP_ERR_READ_TIMEOUT = 9,
+ HTTP_ERR_REQUEST_TOO_LONG = 10,
} http_error_t;
typedef enum {
@@ -164,8 +166,8 @@ void http_close(http_t *http);
#include <pthread.h>
#include <netdb.h>
#include <poll.h>
+#include <errno.h>
#include <signal.h>
-#include <fcntl.h>
#include <openssl/ssl.h>
#include <sys/socket.h>
@@ -450,12 +452,12 @@ void http_response_free(http_response_t *response) {
}
}
-http_request_t http_read_request(http_conn_t *conn) {
+http_error_t http_read_request(http_conn_t *conn, http_request_t *request) {
int len = 0;
int ln = 0;
int start = 0;
char buffer[HTTP_MAX_REQUEST_HEAD_SIZE];
- http_request_t request = {
+ *request = (http_request_t) {
.conn = conn,
.method = NULL,
.url = NULL,
@@ -472,10 +474,15 @@ http_request_t http_read_request(http_conn_t *conn) {
if (read == 0) {
break;
}
+ // read timeout
+ if (read == -1 || read == SSL_ERROR_SYSCALL) {
+ if (errno == EWOULDBLOCK || errno == EAGAIN) {
+ return HTTP_ERR_READ_TIMEOUT;
+ }
+ }
// break if too long
if (len == HTTP_MAX_REQUEST_HEAD_SIZE) {
- perror("request is too long");
- break;
+ return HTTP_ERR_REQUEST_TOO_LONG;
}
buffer[len] = c;
len++;
@@ -498,23 +505,23 @@ http_request_t http_read_request(http_conn_t *conn) {
// read method
if (arg == 0) {
int method_length = i - start;
- request.method = (char *) malloc(sizeof(char) * (method_length + 1));
- memcpy(request.method, line + start, method_length);
- request.method[method_length] = '\0';
+ request->method = (char *) malloc(sizeof(char) * (method_length + 1));
+ memcpy(request->method, line + start, method_length);
+ request->method[method_length] = '\0';
}
// read url
if (arg == 1) {
int url_length = i - start;
- request.url = (char *) malloc(sizeof(char) * (url_length + 1));
- memcpy(request.url, line + start, url_length);
- request.url[url_length] = '\0';
+ request->url = (char *) malloc(sizeof(char) * (url_length + 1));
+ memcpy(request->url, line + start, url_length);
+ request->url[url_length] = '\0';
}
// read version
if (arg == 2) {
int version_length = i - start;
- request.version = (char *) malloc(sizeof(char) * (version_length + 1));
- memcpy(request.version, line + start, version_length);
- request.version[version_length] = '\0';
+ request->version = (char *) malloc(sizeof(char) * (version_length + 1));
+ memcpy(request->version, line + start, version_length);
+ request->version[version_length] = '\0';
}
start = i + 1;
arg++;
@@ -524,9 +531,9 @@ http_request_t http_read_request(http_conn_t *conn) {
// read headers
else {
int sep = 0;
- request.headers = (http_header_t *) realloc(request.headers, sizeof(http_header_t) * (request.headers_len + 1));
- http_header_t *header = &request.headers[request.headers_len];
- request.headers_len++;
+ request->headers = (http_header_t *) realloc(request->headers, sizeof(http_header_t) * (request->headers_len + 1));
+ http_header_t *header = &request->headers[request->headers_len];
+ request->headers_len++;
for (int i = 0; i < line_len; i++) {
if (line[i] == ':') {
int key_len = i;
@@ -551,20 +558,20 @@ http_request_t http_read_request(http_conn_t *conn) {
if (len >= 4) {
char *slice = buffer + (len - 4);
if (strncmp(slice, "\r\n\r\n", 4) == 0) {
- char *content_length = http_header_get(&request, (char *) "Content-Length");
+ char *content_length = http_header_get(request, (char *) "Content-Length");
if (content_length != NULL) {
- request.body_len = strtol(content_length, NULL, 10);
- if (request.body_len > 0) {
- request.body = (char *) malloc(sizeof(char) * (request.body_len + 1));
- http_read(conn, request.body, request.body_len);
- request.body[request.body_len] = '\0';
+ request->body_len = strtol(content_length, NULL, 10);
+ if (request->body_len > 0) {
+ request->body = (char *) malloc(sizeof(char) * (request->body_len + 1));
+ http_read(conn, request->body, request->body_len);
+ request->body[request->body_len] = '\0';
}
}
break;
}
}
}
- return request;
+ return HTTP_ERR_OK;
}
void http_write_response(http_conn_t *conn, http_response_t response) {
@@ -597,27 +604,35 @@ void *http_handle_client(void *ptr) {
pthread_exit(0);
}
http_conn_t *conn = (http_conn_t *) ptr;
+ struct timeval timeout;
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+ if (setsockopt(conn->sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout)) < 0) {
+ close(conn->sockfd);
+ free(conn);
+ pthread_exit(0);
+ }
if (conn->curr_bind->hosts_len > 0) {
SSL_CTX_set_tlsext_servername_arg(conn->http->ssl_ctx, (void *) conn);
conn->ssl = SSL_new(conn->http->ssl_ctx);
SSL_set_fd(conn->ssl, conn->sockfd);
if (SSL_accept(conn->ssl) <= 0) {
+ close(conn->sockfd);
+ free(conn);
pthread_exit(0);
}
}
- int flags = fcntl(conn->sockfd, F_GETFL, 0);
- if (flags == -1) {
- close(conn->sockfd);
- free(conn);
- pthread_exit(0);
- }
- flags |= O_NONBLOCK;
- if (fcntl(conn->sockfd, F_SETFL, flags) == -1) {
+ http_request_t request;
+ http_error_t err = http_read_request(conn, &request);
+ if (err != HTTP_ERR_OK) {
+ if (conn->ssl != NULL) {
+ SSL_shutdown(conn->ssl);
+ SSL_free(conn->ssl);
+ }
close(conn->sockfd);
free(conn);
pthread_exit(0);
}
- http_request_t request = http_read_request(conn);
if (request.method != NULL && request.url != NULL) {
if (conn->http->on_request_fn != NULL) {
http_response_t response = conn->http->on_request_fn(&request);