Fix issues that caused the server to hang
This commit is contained in:
+95
-49
@@ -21,6 +21,10 @@ int http_server_init(HTTP_Server *server)
|
||||
server->input_buffer_limit = 1<<20;
|
||||
server->output_buffer_limit = 1<<20;
|
||||
|
||||
server->trace_bytes = false;
|
||||
server->reuse_addr = false;
|
||||
server->backlog = 32;
|
||||
|
||||
server->num_conns = 0;
|
||||
for (int i = 0; i < HTTP_SERVER_CAPACITY; i++) {
|
||||
server->conns[i].state = HTTP_SERVER_CONN_FREE;
|
||||
@@ -60,10 +64,26 @@ void http_server_set_output_limit(HTTP_Server *server, uint32_t limit)
|
||||
server->output_buffer_limit = limit;
|
||||
}
|
||||
|
||||
void http_server_set_trace_bytes(HTTP_Server *server, bool value)
|
||||
{
|
||||
server->trace_bytes = value;
|
||||
}
|
||||
|
||||
void http_server_set_reuse_addr(HTTP_Server *server, bool reuse)
|
||||
{
|
||||
server->reuse_addr = reuse;
|
||||
}
|
||||
|
||||
void http_server_set_backlog(HTTP_Server *server, int backlog)
|
||||
{
|
||||
server->backlog = backlog;
|
||||
}
|
||||
|
||||
int http_server_listen_tcp(HTTP_Server *server,
|
||||
HTTP_String addr, Port port)
|
||||
{
|
||||
if (socket_manager_listen_tcp(&server->sockets, addr, port) < 0)
|
||||
if (socket_manager_listen_tcp(&server->sockets, addr,
|
||||
port, server->backlog, server->reuse_addr) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
@@ -73,7 +93,8 @@ int http_server_listen_tls(HTTP_Server *server,
|
||||
HTTP_String key_file_name)
|
||||
{
|
||||
if (socket_manager_listen_tls(&server->sockets, addr,
|
||||
port, cert_file_name, key_file_name) < 0)
|
||||
port, server->backlog, server->reuse_addr,
|
||||
cert_file_name, key_file_name) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
@@ -133,7 +154,7 @@ check_request_buffer(HTTP_Server *server, HTTP_ServerConn *conn)
|
||||
} else {
|
||||
|
||||
// Ready
|
||||
assert(ret == 1);
|
||||
assert(ret > 0);
|
||||
|
||||
conn->state = HTTP_SERVER_CONN_WAIT_STATUS;
|
||||
conn->request_len = ret;
|
||||
@@ -147,6 +168,67 @@ check_request_buffer(HTTP_Server *server, HTTP_ServerConn *conn)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
http_server_conn_process_events(HTTP_Server *server, HTTP_ServerConn *conn)
|
||||
{
|
||||
if (conn->state == HTTP_SERVER_CONN_FLUSHING) {
|
||||
|
||||
ByteView src = byte_queue_read_buf(&conn->output);
|
||||
|
||||
int num = 0;
|
||||
if (src.len)
|
||||
num = socket_send(&server->sockets, conn->handle, src.ptr, src.len);
|
||||
|
||||
if (server->trace_bytes)
|
||||
print_bytes(HTTP_STR("<< "), (HTTP_String) { src.ptr, num });
|
||||
|
||||
byte_queue_read_ack(&conn->output, num);
|
||||
|
||||
if (byte_queue_error(&conn->output)) {
|
||||
socket_close(&server->sockets, conn->handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (byte_queue_empty(&conn->output)) {
|
||||
// We finished sending the response. Now we can
|
||||
// either close the connection or process a new
|
||||
// buffered request.
|
||||
if (conn->closing) {
|
||||
socket_close(&server->sockets, conn->handle);
|
||||
return;
|
||||
}
|
||||
conn->state = HTTP_SERVER_CONN_BUFFERING;
|
||||
}
|
||||
}
|
||||
|
||||
if (conn->state == HTTP_SERVER_CONN_BUFFERING) {
|
||||
|
||||
int min_recv = 1<<10;
|
||||
byte_queue_write_setmincap(&conn->input, min_recv);
|
||||
|
||||
// Note that it's extra important that we don't
|
||||
// buffer while the user is building the response.
|
||||
// If we did that, a resize would invalidate all
|
||||
// pointers on the parsed request structure.
|
||||
ByteView dst = byte_queue_write_buf(&conn->input);
|
||||
|
||||
int num = 0;
|
||||
if (dst.len)
|
||||
num = socket_recv(&server->sockets, conn->handle, dst.ptr, dst.len);
|
||||
|
||||
if (server->trace_bytes)
|
||||
print_bytes(HTTP_STR(">> "), (HTTP_String) { dst.ptr, num });
|
||||
|
||||
byte_queue_write_ack(&conn->input, num);
|
||||
|
||||
if (byte_queue_error(&conn->output)) {
|
||||
socket_close(&server->sockets, conn->handle);
|
||||
} else {
|
||||
check_request_buffer(server, conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int http_server_process_events(HTTP_Server *server,
|
||||
EventRegister *reg)
|
||||
{
|
||||
@@ -173,13 +255,13 @@ int http_server_process_events(HTTP_Server *server,
|
||||
continue;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while (server->conns[i].state != HTTP_SERVER_CONN_FREE) {
|
||||
i++;
|
||||
int j = 0;
|
||||
while (server->conns[j].state != HTTP_SERVER_CONN_FREE) {
|
||||
j++;
|
||||
assert(i < HTTP_SERVER_CAPACITY);
|
||||
}
|
||||
|
||||
conn = &server->conns[i];
|
||||
conn = &server->conns[j];
|
||||
http_server_conn_init(conn,
|
||||
events[i].handle,
|
||||
server->input_buffer_limit,
|
||||
@@ -189,45 +271,7 @@ int http_server_process_events(HTTP_Server *server,
|
||||
socket_set_user(&server->sockets, events[i].handle, conn);
|
||||
}
|
||||
|
||||
if (conn->state == HTTP_SERVER_CONN_BUFFERING) {
|
||||
|
||||
int min_recv = 1<<10;
|
||||
byte_queue_write_setmincap(&conn->input, min_recv);
|
||||
|
||||
// Note that it's extra important that we don't
|
||||
// buffer while the user is building the response.
|
||||
// If we did that, a resize would invalidate all
|
||||
// pointers on the parsed request structure.
|
||||
int num = 0;
|
||||
ByteView dst = byte_queue_write_buf(&conn->input);
|
||||
if (dst.len) num = socket_recv(&server->sockets, conn->handle, dst.ptr, dst.len);
|
||||
byte_queue_write_ack(&conn->input, num);
|
||||
|
||||
if (byte_queue_error(&conn->output))
|
||||
socket_close(&server->sockets, conn->handle);
|
||||
else
|
||||
check_request_buffer(server, conn);
|
||||
|
||||
} else if (conn->state == HTTP_SERVER_CONN_FLUSHING) {
|
||||
|
||||
int num = 0;
|
||||
ByteView src = byte_queue_read_buf(&conn->output);
|
||||
if (src.len) num = socket_send(&server->sockets, conn->handle, src.ptr, src.len);
|
||||
byte_queue_read_ack(&conn->output, num);
|
||||
|
||||
if (byte_queue_error(&conn->output))
|
||||
socket_close(&server->sockets, conn->handle);
|
||||
else if (byte_queue_empty(&conn->output)) {
|
||||
// We finished sending the response. Now we can
|
||||
// either close the connection or process a new
|
||||
// buffered request.
|
||||
if (conn->closing) {
|
||||
socket_close(&server->sockets, conn->handle);
|
||||
} else {
|
||||
check_request_buffer(server, conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
http_server_conn_process_events(server, conn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,10 +441,10 @@ static void append_special_headers(HTTP_ServerConn *conn)
|
||||
HTTP_String s;
|
||||
|
||||
if (conn->closing) {
|
||||
s = HTTP_STR("Connection: Close");
|
||||
s = HTTP_STR("Connection: Close\r\n");
|
||||
byte_queue_write(&conn->output, s.ptr, s.len);
|
||||
} else {
|
||||
s = HTTP_STR("Connection: Keep-Alive");
|
||||
s = HTTP_STR("Connection: Keep-Alive\r\n");
|
||||
byte_queue_write(&conn->output, s.ptr, s.len);
|
||||
}
|
||||
|
||||
@@ -447,7 +491,7 @@ void http_response_builder_body(HTTP_ResponseBuilder builder, HTTP_String str)
|
||||
byte_queue_write(&conn->output, str.ptr, str.len);
|
||||
}
|
||||
|
||||
void http_response_builder_send(HTTP_ResponseBuilder builder, HTTP_String str)
|
||||
void http_response_builder_send(HTTP_ResponseBuilder builder)
|
||||
{
|
||||
HTTP_ServerConn *conn = builder_to_conn(builder);
|
||||
if (conn == NULL)
|
||||
@@ -471,4 +515,6 @@ void http_response_builder_send(HTTP_ResponseBuilder builder, HTTP_String str)
|
||||
|
||||
conn->state = HTTP_SERVER_CONN_FLUSHING;
|
||||
conn->gen++;
|
||||
|
||||
http_server_conn_process_events(builder.server, conn);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user