Implement connection activity timeouts.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4706 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
parent
b6a3923b27
commit
2f6a92168e
69
src/http.c
69
src/http.c
@ -16,11 +16,14 @@
|
|||||||
#include <alloca.h>
|
#include <alloca.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static const int k_timeout_ms = 60000;
|
||||||
|
|
||||||
typedef struct _tf_http_connection_t
|
typedef struct _tf_http_connection_t
|
||||||
{
|
{
|
||||||
tf_http_t* http;
|
tf_http_t* http;
|
||||||
uv_tcp_t tcp;
|
uv_tcp_t tcp;
|
||||||
uv_shutdown_t shutdown;
|
uv_shutdown_t shutdown;
|
||||||
|
uv_timer_t timeout;
|
||||||
|
|
||||||
int ref_count;
|
int ref_count;
|
||||||
|
|
||||||
@ -77,6 +80,7 @@ typedef struct _tf_http_t
|
|||||||
static const char* _http_connection_get_header(const tf_http_connection_t* connection, const char* name);
|
static const char* _http_connection_get_header(const tf_http_connection_t* connection, const char* name);
|
||||||
static void _http_connection_destroy(tf_http_connection_t* connection, const char* reason);
|
static void _http_connection_destroy(tf_http_connection_t* connection, const char* reason);
|
||||||
static const char* _http_status_text(int status);
|
static const char* _http_status_text(int status);
|
||||||
|
static void _http_timer_reset(tf_http_connection_t* connection);
|
||||||
|
|
||||||
tf_http_t* tf_http_create(uv_loop_t* loop)
|
tf_http_t* tf_http_create(uv_loop_t* loop)
|
||||||
{
|
{
|
||||||
@ -119,6 +123,7 @@ bool _http_find_handler(tf_http_t* http, const char* path, tf_http_callback_t**
|
|||||||
|
|
||||||
static void _http_on_write(uv_write_t* write, int status)
|
static void _http_on_write(uv_write_t* write, int status)
|
||||||
{
|
{
|
||||||
|
_http_timer_reset(write->data);
|
||||||
tf_free(write);
|
tf_free(write);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,11 +136,19 @@ static void _http_connection_on_close(uv_handle_t* handle)
|
|||||||
|
|
||||||
static void _http_connection_destroy(tf_http_connection_t* connection, const char* reason)
|
static void _http_connection_destroy(tf_http_connection_t* connection, const char* reason)
|
||||||
{
|
{
|
||||||
if (connection->tcp.data)
|
if (connection->tcp.data && !uv_is_closing((uv_handle_t*)&connection->tcp))
|
||||||
{
|
{
|
||||||
uv_close((uv_handle_t*)&connection->tcp, _http_connection_on_close);
|
uv_close((uv_handle_t*)&connection->tcp, _http_connection_on_close);
|
||||||
}
|
}
|
||||||
else if (connection->ref_count == 0)
|
if (connection->timeout.data && !uv_is_closing((uv_handle_t*)&connection->timeout))
|
||||||
|
{
|
||||||
|
uv_close((uv_handle_t*)&connection->timeout, _http_connection_on_close);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connection->ref_count == 0 &&
|
||||||
|
!connection->tcp.data &&
|
||||||
|
!connection->shutdown.data &&
|
||||||
|
!connection->timeout.data)
|
||||||
{
|
{
|
||||||
tf_http_t* http = connection->http;
|
tf_http_t* http = connection->http;
|
||||||
for (int i = 0; i < http->connections_count; i++)
|
for (int i = 0; i < http->connections_count; i++)
|
||||||
@ -298,6 +311,7 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d
|
|||||||
static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t* buffer)
|
static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t* buffer)
|
||||||
{
|
{
|
||||||
tf_http_connection_t* connection = stream->data;
|
tf_http_connection_t* connection = stream->data;
|
||||||
|
_http_timer_reset(connection);
|
||||||
if (read_size > 0)
|
if (read_size > 0)
|
||||||
{
|
{
|
||||||
if (!connection->headers_done)
|
if (!connection->headers_done)
|
||||||
@ -389,6 +403,29 @@ static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _http_timer_callback(uv_timer_t* timer)
|
||||||
|
{
|
||||||
|
tf_printf("_http_timer_callback\n");
|
||||||
|
_http_connection_destroy(timer->data, "_http_timer_callback");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _http_timer_reset(tf_http_connection_t* connection)
|
||||||
|
{
|
||||||
|
if (connection->timeout.data)
|
||||||
|
{
|
||||||
|
int r = uv_timer_stop(&connection->timeout);
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
tf_printf("uv_timer_stop: %s\n", uv_strerror(r));
|
||||||
|
}
|
||||||
|
r = uv_timer_start(&connection->timeout, _http_timer_callback, k_timeout_ms, 0);
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
tf_printf("uv_timer_start: %s\n", uv_strerror(r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void _http_on_connection(uv_stream_t* stream, int status)
|
static void _http_on_connection(uv_stream_t* stream, int status)
|
||||||
{
|
{
|
||||||
tf_http_t* http = stream->data;
|
tf_http_t* http = stream->data;
|
||||||
@ -398,7 +435,23 @@ static void _http_on_connection(uv_stream_t* stream, int status)
|
|||||||
if (r)
|
if (r)
|
||||||
{
|
{
|
||||||
tf_printf("uv_tcp_init: %s\n", uv_strerror(r));
|
tf_printf("uv_tcp_init: %s\n", uv_strerror(r));
|
||||||
tf_free(connection);
|
_http_connection_destroy(connection, "uv_tcp_init");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = uv_timer_init(connection->http->loop, &connection->timeout);
|
||||||
|
connection->timeout.data = connection;
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
tf_printf("uv_timer_init: %s\n", uv_strerror(r));
|
||||||
|
_http_connection_destroy(connection, "uv_timer_init");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r = uv_timer_start(&connection->timeout, _http_timer_callback, k_timeout_ms, 0);
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
tf_printf("uv_timer_start: %s\n", uv_strerror(r));
|
||||||
|
_http_connection_destroy(connection, "uv_timer_start");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,17 +459,15 @@ static void _http_on_connection(uv_stream_t* stream, int status)
|
|||||||
if (r)
|
if (r)
|
||||||
{
|
{
|
||||||
tf_printf("uv_accept: %s\n", uv_strerror(r));
|
tf_printf("uv_accept: %s\n", uv_strerror(r));
|
||||||
uv_close((uv_handle_t*)&connection->tcp, NULL);
|
_http_connection_destroy(connection, "uv_accept");
|
||||||
tf_free(connection);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = uv_read_start((uv_stream_t*)&connection->tcp, _http_allocate_buffer, _http_on_read);
|
r = uv_read_start((uv_stream_t*)&connection->tcp, _http_allocate_buffer, _http_on_read);
|
||||||
if (r)
|
if (r)
|
||||||
{
|
{
|
||||||
tf_printf("uv_read-start: %s\n", uv_strerror(r));
|
tf_printf("uv_read_start: %s\n", uv_strerror(r));
|
||||||
uv_close((uv_handle_t*)&connection->tcp, NULL);
|
_http_connection_destroy(connection, "uv_read_start");
|
||||||
tf_free(connection);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -533,6 +584,7 @@ static void _http_on_shutdown(uv_shutdown_t* request, int status)
|
|||||||
|
|
||||||
static void _http_write(tf_http_connection_t* connection, const void* data, size_t size)
|
static void _http_write(tf_http_connection_t* connection, const void* data, size_t size)
|
||||||
{
|
{
|
||||||
|
_http_timer_reset(connection);
|
||||||
uv_write_t* write = tf_malloc(sizeof(uv_write_t) + size);
|
uv_write_t* write = tf_malloc(sizeof(uv_write_t) + size);
|
||||||
*write = (uv_write_t) { .data = connection };
|
*write = (uv_write_t) { .data = connection };
|
||||||
memcpy(write + 1, data, size);
|
memcpy(write + 1, data, size);
|
||||||
@ -599,6 +651,7 @@ void tf_http_respond(tf_http_request_t* request, int status, const char** header
|
|||||||
{
|
{
|
||||||
memcpy(buffer + offset, body, content_length);
|
memcpy(buffer + offset, body, content_length);
|
||||||
}
|
}
|
||||||
|
_http_timer_reset(request->connection);
|
||||||
int r = uv_write(write, (uv_stream_t*)&request->connection->tcp, &(uv_buf_t) { .base = buffer, .len = headers_length + content_length }, 1, _http_on_write);
|
int r = uv_write(write, (uv_stream_t*)&request->connection->tcp, &(uv_buf_t) { .base = buffer, .len = headers_length + content_length }, 1, _http_on_write);
|
||||||
if (r)
|
if (r)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user