basic handling for persistent connections

This commit is contained in:
overflowerror 2021-05-12 14:44:21 +02:00
parent e946217ec2
commit 3929b19bdd
2 changed files with 66 additions and 6 deletions

View file

@ -71,9 +71,14 @@ void cleanup() {
long diffms = timespacAgeMs(connection->timing.lastUpdate);
pthread_mutex_lock(&(connection->lock));
if (connection->state != OPENED) {
if (connection->state == KEEP_ALIVE) {
// KEEP_ALIVE means that the connection is persistent but there is an active handler
// don't unlink; don't abort connection
} else if (connection->state != OPENED) {
unlink = true;
} else if (diffms > networkingConfig.connectionTimeout) {
// the connection is open too long without data from the client
// TODO: add custom timeout if connection isPersistent
connection->state = ABORTED;
}
pthread_mutex_unlock(&(connection->lock));
@ -112,6 +117,44 @@ void cleanup() {
pthread_join(connection->threads.response, NULL);
}
if (connection->state == ABORTED && connection->writefd >= 0) {
// either the client took too long to send the headers
// or this connection was persistent and the client didn't produce a request
// either way: since the writefd is still available
// let's send a 408 status before closing the connection
int dupfd = dup(connection->writefd);
if (dupfd < 0) {
error("networking: couldn't dup fd for 408 handling: %s", strerror(errno));
goto CONTINUE_CLEANUP;
}
FILE* stream = fdopen(dupfd, "w");
if (stream == NULL) {
error("networking: couldn't create FILE for 408 handling: %s", strerror(errno));
close(dupfd);
goto CONTINUE_CLEANUP;
}
struct headers headers = headers_create();
for(int i = 0; i < networkingConfig.defaultHeaders.number; i++) {
headers_mod(&headers, networkingConfig.defaultHeaders.headers[i].key, networkingConfig.defaultHeaders.headers[i].value);
}
// set connection close header as required by the standard
headers_mod(&headers, "Connection", "close");
// no content
headers_mod(&headers, "Content-Length", "0");
fprintf(stream, "%s %d %s\r\n", protocolString(connection->metaData), 408, getStatusStrings(408).statusString);
headers_dump(&headers, stream);
headers_free(&headers);
fprintf(stream, "\r\n");
fclose(stream); // will close dup as well
}
CONTINUE_CLEANUP:
#ifdef SSL_SUPPORT
if (connection->sslConnection != NULL)
ssl_closeConnection(connection->sslConnection);
@ -466,6 +509,7 @@ void dataHandler(int signo) {
struct connection* connection = link->data;
pthread_mutex_lock(&(connection->lock));
// we don't support pipelining, current request has to be finished for the next to start
if (connection->state != OPENED) {
pthread_mutex_unlock(&(connection->lock));
continue;
@ -517,8 +561,22 @@ void dataHandler(int signo) {
debug("networking: headers complete");
connection->isPersistent = true;
const char* connectionHeader = headers_get(&(connection->headers), "Connection");
if (connectionHeader == NULL) {
// assume keep alive
connection->isPersistent = true;
} else if (strcasecmp(connectionHeader, "close")) {
connection->isPersistent = false;
} else if (strcasecmp(connectionHeader, "keep-alive")) {
connection->isPersistent = true;
}
pthread_mutex_lock(&(connection->lock));
connection->state = PROCESSING;
if (connection->isPersistent) {
} else {
connection->state = PROCESSING;
}
connection->inUse++;
pthread_mutex_unlock(&(connection->lock));

View file

@ -19,10 +19,11 @@
#define NR_CONNECTION_STATE (5)
enum connectionState {
OPENED = 0,
PROCESSING = 1,
ABORTED = 2,
CLOSED = 3,
FREED = 4
PROCESSING = 1,
KEEP_ALIVE = 2,
ABORTED = 3,
CLOSED = 4,
FREED = 5
};
struct timing {
@ -52,6 +53,7 @@ struct connection {
char* currentHeader;
struct timing timing;
struct threads threads;
bool isPersistent;
#ifdef SSL_SUPPORT
struct ssl_connection* sslConnection;
#endif