Trying harder still to curb stale connections.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3900 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2022-06-17 18:51:24 +00:00
parent 4293e75082
commit b5b6ed8ba5
2 changed files with 61 additions and 8 deletions

View File

@ -5,6 +5,7 @@ var gSocketHandlers = [];
var gBadRequests = {}; var gBadRequests = {};
const kRequestTimeout = 15000; const kRequestTimeout = 15000;
const kStallTimeout = 60000;
function logError(error) { function logError(error) {
print("ERROR " + error); print("ERROR " + error);
@ -388,10 +389,12 @@ function allowRequest(client) {
function handleConnection(client) { function handleConnection(client) {
if (!allowRequest(client)) { if (!allowRequest(client)) {
print('Rejecting client for too many bad requests: ', client.peerName, gBadRequests[client.peerName].reason); print('Rejecting client for too many bad requests: ', client.peerName, gBadRequests[client.peerName].reason);
client.info = 'rejected';
client.close(); client.close();
return; return;
} }
client.info = 'accepted';
var inputBuffer = new Uint8Array(0); var inputBuffer = new Uint8Array(0);
var request; var request;
var headers = {}; var headers = {};
@ -399,17 +402,37 @@ function handleConnection(client) {
var bodyToRead = -1; var bodyToRead = -1;
var body; var body;
var requestCount = -1; var requestCount = -1;
var readCount = 0;
var isWebsocket = false;
function resetTimeout(requestIndex) { function resetTimeout(requestIndex) {
setTimeout(function() { if (isWebsocket) {
if (bodyToRead == -1 && requestCount == requestIndex) { return;
if (requestCount == 0) { }
badRequest(client, 'Timed out waiting for request.'); if (bodyToRead == -1) {
} else { setTimeout(function() {
client.close(); if (requestCount == requestIndex) {
client.info = 'timed out';
if (requestCount == 0) {
badRequest(client, 'Timed out waiting for request.');
} else {
client.close();
}
} }
} }, kRequestTimeout);
}, kRequestTimeout); } else {
var lastReadCount = readCount;
setTimeout(function() {
if (readCount == lastReadCount) {
client.info = 'stalled';
if (requestCount == 0) {
badRequest(client, 'Request stalled.');
} else {
client.close();
}
}
}, kStallTimeout);
}
} }
resetTimeout(++requestCount); resetTimeout(++requestCount);
@ -421,10 +444,12 @@ function handleConnection(client) {
lineByLine = true; lineByLine = true;
bodyToRead = -1; bodyToRead = -1;
body = undefined; body = undefined;
client.info = 'reset';
resetTimeout(++requestCount); resetTimeout(++requestCount);
} }
function finish() { function finish() {
client.info = 'finishing';
var requestObject = new Request(request[0], request[1], request[2], headers, body, client); var requestObject = new Request(request[0], request[1], request[2], headers, body, client);
var response = new Response(requestObject, client); var response = new Response(requestObject, client);
try { try {
@ -468,11 +493,14 @@ function handleConnection(client) {
return false; return false;
} }
body = new Uint8Array(bodyToRead); body = new Uint8Array(bodyToRead);
client.info = 'waiting for body';
return true; return true;
} else if (headers["connection"] } else if (headers["connection"]
&& headers["connection"].toLowerCase().split(",").map(x => x.trim()).indexOf("upgrade") != -1 && headers["connection"].toLowerCase().split(",").map(x => x.trim()).indexOf("upgrade") != -1
&& headers["upgrade"] && headers["upgrade"]
&& headers["upgrade"].toLowerCase() == "websocket") { && headers["upgrade"].toLowerCase() == "websocket") {
isWebsocket = true;
client.info = 'websocket';
var requestObject = new Request(request[0], request[1], request[2], headers, body, client); var requestObject = new Request(request[0], request[1], request[2], headers, body, client);
var response = new Response(requestObject, client); var response = new Response(requestObject, client);
handleWebSocketRequest(requestObject, response, client); handleWebSocketRequest(requestObject, response, client);
@ -504,7 +532,11 @@ function handleConnection(client) {
}); });
client.read(function(data) { client.read(function(data) {
readCount++;
if (data) { if (data) {
if (bodyToRead != -1 && !isWebsocket) {
resetTimeout(requestCount);
}
const kMaxLineLength = 4096; const kMaxLineLength = 4096;
var newBuffer = new Uint8Array(inputBuffer.length + data.length); var newBuffer = new Uint8Array(inputBuffer.length + data.length);
newBuffer.set(inputBuffer, 0); newBuffer.set(inputBuffer, 0);
@ -537,6 +569,9 @@ function handleConnection(client) {
inputBuffer = new Uint8Array(0); inputBuffer = new Uint8Array(0);
} }
} }
} else {
client.info = 'EOF';
client.close();
} }
}); });
} }

View File

@ -45,6 +45,7 @@ typedef struct _socket_t {
JSValue _onConnect; JSValue _onConnect;
JSValue _onRead; JSValue _onRead;
JSValue _onError; JSValue _onError;
JSValue _info;
uint64_t created_ms; uint64_t created_ms;
} socket_t; } socket_t;
@ -67,6 +68,7 @@ static JSValue _socket_getPeerName(JSContext* context, JSValueConst this_val, in
static JSValue _socket_getPeerCertificate(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _socket_getPeerCertificate(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
static JSValue _socket_getNoDelay(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _socket_getNoDelay(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
static JSValue _socket_setNoDelay(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _socket_setNoDelay(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
static JSValue _socket_setInfo(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
static JSValue _sockets_get(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _sockets_get(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
static void _socket_onClose(uv_handle_t* handle); static void _socket_onClose(uv_handle_t* handle);
@ -122,6 +124,7 @@ static void _socket_gc_mark(JSRuntime* runtime, JSValueConst value, JS_MarkFunc
JS_MarkValue(runtime, socket->_onConnect, mark_func); JS_MarkValue(runtime, socket->_onConnect, mark_func);
JS_MarkValue(runtime, socket->_onRead, mark_func); JS_MarkValue(runtime, socket->_onRead, mark_func);
JS_MarkValue(runtime, socket->_onError, mark_func); JS_MarkValue(runtime, socket->_onError, mark_func);
JS_MarkValue(runtime, socket->_info, mark_func);
} }
} }
@ -212,6 +215,11 @@ socket_t* _socket_create_internal(JSContext* context)
JS_DefinePropertyGetSet(context, object, atom, get_no_delay, set_no_delay, 0); JS_DefinePropertyGetSet(context, object, atom, get_no_delay, set_no_delay, 0);
JS_FreeAtom(context, atom); JS_FreeAtom(context, atom);
atom = JS_NewAtom(context, "info");
JSValue set_info = JS_NewCFunction(context, _socket_setInfo, "setInfo", 1);
JS_DefinePropertyGetSet(context, object, atom, JS_UNDEFINED, set_info, 0);
JS_FreeAtom(context, atom);
++_open_count; ++_open_count;
uv_tcp_init(tf_task_get_loop(socket->_task), &socket->_socket); uv_tcp_init(tf_task_get_loop(socket->_task), &socket->_socket);
socket->_socket.data = socket; socket->_socket.data = socket;
@ -1065,6 +1073,15 @@ JSValue _socket_setNoDelay(JSContext* context, JSValueConst this_val, int argc,
return JS_UNDEFINED; return JS_UNDEFINED;
} }
JSValue _socket_setInfo(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
socket_t* socket = JS_GetOpaque(this_val, _classId);
JSValue old = socket->_info;
socket->_info = JS_DupValue(context, argv[0]);
JS_FreeValue(context, old);
return JS_UNDEFINED;
}
JSValue _sockets_get(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) JSValue _sockets_get(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{ {
JSValue array = JS_NewArray(context); JSValue array = JS_NewArray(context);
@ -1077,6 +1094,7 @@ JSValue _sockets_get(JSContext* context, JSValueConst this_val, int argc, JSValu
JS_SetPropertyStr(context, entry, "connected", JS_NewBool(context, s->_connected)); JS_SetPropertyStr(context, entry, "connected", JS_NewBool(context, s->_connected));
JS_SetPropertyStr(context, entry, "tls", JS_NewBool(context, s->_tls != NULL)); JS_SetPropertyStr(context, entry, "tls", JS_NewBool(context, s->_tls != NULL));
JS_SetPropertyStr(context, entry, "age_seconds", JS_NewFloat64(context, (uv_now(tf_task_get_loop(s->_task)) - s->created_ms) / 1000.f)); JS_SetPropertyStr(context, entry, "age_seconds", JS_NewFloat64(context, (uv_now(tf_task_get_loop(s->_task)) - s->created_ms) / 1000.f));
JS_SetPropertyStr(context, entry, "info", JS_DupValue(context, s->_info));
JS_SetPropertyUint32(context, array, i, entry); JS_SetPropertyUint32(context, array, i, entry);
} }
return array; return array;