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:
		@@ -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,10 +402,17 @@ 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) {
 | 
				
			||||||
 | 
							if (isWebsocket) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (bodyToRead == -1) {
 | 
				
			||||||
			setTimeout(function() {
 | 
								setTimeout(function() {
 | 
				
			||||||
			if (bodyToRead == -1 && requestCount == requestIndex) {
 | 
									if (requestCount == requestIndex) {
 | 
				
			||||||
 | 
										client.info = 'timed out';
 | 
				
			||||||
					if (requestCount == 0) {
 | 
										if (requestCount == 0) {
 | 
				
			||||||
						badRequest(client, 'Timed out waiting for request.');
 | 
											badRequest(client, 'Timed out waiting for request.');
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
@@ -410,6 +420,19 @@ function handleConnection(client) {
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}, 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();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user