Diff

net/http.lua @ 13319:6d6291dfe735

net.http: Add simple connection pooling This should speed up repeated requests to the same site by keeping their connections around and sending more requests on them. Sending multiple requests at the same time is not supported, instead a request started while another to the same authority is in progress would open a new one and the first one to complete would go back in the pool. This could be investigated in the future. Some http servers limit the number of requests per connection and this is not tested and could cause one request to fail, but hopefully it will close the connection and prevent it from being reused.
author Kim Alvefur <zash@zash.se>
date Sat, 11 Nov 2023 23:08:34 +0100
parent 12974:ba409c67353b
child 13320:23f95714c386
line wrap: on
line diff
--- a/net/http.lua	Mon Jul 17 04:30:35 2023 +0200
+++ b/net/http.lua	Sat Nov 11 23:08:34 2023 +0100
@@ -51,10 +51,19 @@
 	return ...;
 end
 
-local function destroy_request(request)
+local function destroy_request(request, force)
 	local conn = request.conn;
 	if conn then
 		request.conn = nil;
+		local pool = request.http.pool;
+		if pool and not force then
+			local pool_id = request.scheme .. "://" .. request.authority;
+			if not pool[pool_id] then
+				pool[conn] = pool_id;
+				pool[pool_id] = conn;
+				return;
+			end
+		end
 		conn:close()
 	end
 end
@@ -193,6 +202,13 @@
 	if request and request.conn then
 		request:reader(nil, err or "closed");
 	end
+	if request and request.http.pool then
+		local pool = request.http.pool;
+		local pool_id = pool[conn];
+		if pool_id then
+			pool[pool_id], pool[conn] = nil, nil;
+		end
+	end
 	requests[conn] = nil;
 end
 
@@ -296,6 +312,23 @@
 		end
 	end
 
+	if self.pool then
+		local pool_id = req.scheme .. "://" .. req.authority;
+		local conn = self.pool[pool_id];
+		if conn then
+			log("debug", "Re-using connection to %s from pool", req.host);
+			self.pool[pool_id] = nil;
+			self.pool[conn] = nil;
+			req.conn = conn;
+			requests[conn] = req;
+			self.events.fire_event("request", { http = self, request = req, url = u });
+			listener.onconnect(conn);
+			return req;
+		else
+			log("debug", "Opening a new connection for this request");
+		end
+	end
+
 	local http_service = basic_resolver.new(host, port_number, "tcp", { servername = req.host; use_dane = use_dane });
 	connect(http_service, listener, { sslctx = sslctx }, req);
 
@@ -332,6 +365,10 @@
 		end or new;
 		events = events.new();
 	};
+	if options and options.connection_pooling then
+		-- util.cache in the future?
+		http.pool = {};
+	end
 	return http;
 end