Changeset

13718:569fae28a2f3 13.0

mod_http_altconnect: Imported from prosody-modules 6d5a19bdd718 w/changes Changes from community version: - Add options to allow explicit control over whether BOSH/WS is advertised - Always serve XML at /host-meta (no guessing based on Accept), least surprising
author Matthew Wild <mwild1@gmail.com>
date Sun, 16 Feb 2025 13:19:05 +0000
parents 13717:4f173a44370b
children 13719:4309c934e813
files CHANGES core/features.lua plugins/mod_http_altconnect.lua
diffstat 3 files changed, 55 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES	Sun Feb 16 13:17:00 2025 +0000
+++ b/CHANGES	Sun Feb 16 13:19:05 2025 +0000
@@ -84,6 +84,7 @@
 - Support for systemd socket activation in server_epoll
 - mod_invites_adhoc gained a command for creating password resets
 - mod_cloud_notify imported from community modules for push notification support
+- mod_http_altconnect imported from community modules, simplifying web clients
 
 ## Removed
 
--- a/core/features.lua	Sun Feb 16 13:17:00 2025 +0000
+++ b/core/features.lua	Sun Feb 16 13:19:05 2025 +0000
@@ -12,6 +12,8 @@
 		"mod_cloud_notify";
 		-- mod_muc has built-in vcard support
 		"muc_vcard";
+		-- mod_http_altconnect bundled
+		"http_altconnect";
 		-- Roles, module.may and per-session authz
 		"permissions";
 		-- prosody.* namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mod_http_altconnect.lua	Sun Feb 16 13:19:05 2025 +0000
@@ -0,0 +1,52 @@
+-- mod_http_altconnect
+-- XEP-0156: Discovering Alternative XMPP Connection Methods
+
+module:depends"http";
+
+local mm = require "prosody.core.modulemanager";
+local json = require"prosody.util.json";
+local st = require"prosody.util.stanza";
+local array = require"prosody.util.array";
+
+local advertise_bosh = module:get_option_boolean("advertise_bosh", true);
+local advertise_websocket = module:get_option_boolean("advertise_websocket", true);
+
+local function get_supported()
+	local uris = array();
+	if advertise_bosh and (mm.is_loaded(module.host, "bosh") or mm.is_loaded("*", "bosh")) then
+		uris:push({ rel = "urn:xmpp:alt-connections:xbosh", href = module:http_url("bosh", "/http-bind") });
+	end
+	if advertise_websocket and (mm.is_loaded(module.host, "websocket") or  mm.is_loaded("*", "websocket")) then
+		uris:push({ rel = "urn:xmpp:alt-connections:websocket", href = module:http_url("websocket", "xmpp-websocket"):gsub("^http", "ws") });
+	end
+	return uris;
+end
+
+
+local function GET_xml(event)
+	local response = event.response;
+	local xrd = st.stanza("XRD", { xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0' });
+	local uris = get_supported();
+	for _, method in ipairs(uris) do
+		xrd:tag("Link", method):up();
+	end
+	response.headers.content_type = "application/xrd+xml"
+	response.headers.access_control_allow_origin = "*";
+	return '<?xml version="1.0" encoding="UTF-8"?>' .. tostring(xrd);
+end
+
+local function GET_json(event)
+	local response = event.response;
+	local jrd = { links = get_supported() };
+	response.headers.content_type = "application/json"
+	response.headers.access_control_allow_origin = "*";
+	return json.encode(jrd);
+end;
+
+module:provides("http", {
+	default_path = "/.well-known";
+	route = {
+		["GET /host-meta"] = GET_xml;
+		["GET /host-meta.json"] = GET_json;
+	};
+});