mod_pubsub_feed/mod_pubsub_feed.lua
changeset 323 433bf7dc3e7a
parent 322 637dc0a04052
child 324 100b3ad2e10c
equal deleted inserted replaced
322:637dc0a04052 323:433bf7dc3e7a
    30 local parse_feed = require "feeds".feed_from_string;
    30 local parse_feed = require "feeds".feed_from_string;
    31 local st = require "util.stanza";
    31 local st = require "util.stanza";
    32 local httpserver = require "net.httpserver";
    32 local httpserver = require "net.httpserver";
    33 local formencode = require "net.http".formencode;
    33 local formencode = require "net.http".formencode;
    34 local dump = require "util.serialization".serialize;
    34 local dump = require "util.serialization".serialize;
       
    35 local uuid = require "util.uuid".generate;
    35 
    36 
    36 local urldecode = require "net.http".urldecode;
    37 local urldecode = require "net.http".urldecode;
    37 local urlencode = require "net.http".urlencode;
    38 local urlencode = require "net.http".urlencode;
    38 local urlparams = --require "net.http".getQueryParams or whatever MattJ names it, FIXME
    39 local urlparams = --require "net.http".getQueryParams or whatever MattJ names it, FIXME
    39 function(s)
    40 function(s)
    56 for node, url in pairs(config) do
    57 for node, url in pairs(config) do
    57 	feed_list[node] = { url = url; node = node; last_update = 0 };
    58 	feed_list[node] = { url = url; node = node; last_update = 0 };
    58 end
    59 end
    59 
    60 
    60 local response_codes = {
    61 local response_codes = {
       
    62 	["200"] = "OK";
    61 	["202"] = "Accepted";
    63 	["202"] = "Accepted";
    62 	["400"] = "Bad Request";
    64 	["400"] = "Bad Request";
       
    65 	["404"] = "Not Found";
    63 	["501"] = "Not Implemented";
    66 	["501"] = "Not Implemented";
    64 };
    67 };
    65 
    68 
    66 local function http_response(code, headers, body)
    69 local function http_response(code, headers, body)
    67 	return {
    70 	return {
   157 		end
   160 		end
   158 	end
   161 	end
   159 	return refresh_interval;
   162 	return refresh_interval;
   160 end
   163 end
   161 
   164 
   162 function subscribe(feed, challenge)
   165 function subscribe(feed)
       
   166 	local token = uuid();
   163 	local _body, body = {
   167 	local _body, body = {
   164 		["hub.callback"] = "http://"..module.host..":5280/callback?node=" .. urlencode(feed.node); --FIXME figure out your own hostname reliably?
   168 		["hub.callback"] = "http://"..module.host..":5280/callback?node=" .. urlencode(feed.node); --FIXME figure out your own hostname reliably?
   165 		["hub.mode"] = "subscribe"; --TODO unsubscribe
   169 		["hub.mode"] = "subscribe"; --TODO unsubscribe
   166 		["hub.topic"] = feed.url;
   170 		["hub.topic"] = feed.url;
   167 		["hub.verify"] = "async";
   171 		["hub.verify"] = "async";
   168 		["hub.verify_token"] = challenge;
   172 		["hub.verify_token"] = token;
       
   173 		--["hub.secret"] = ""; -- TODO http://pubsubhubbub.googlecode.com/svn/trunk/pubsubhubbub-core-0.3.html#authednotify
   169 		--["hub.lease_seconds"] = "";
   174 		--["hub.lease_seconds"] = "";
   170 	}, { };
   175 	}, { };
   171 	for name, value in pairs(_body) do
   176 	for name, value in pairs(_body) do
   172 		t_insert(body, { name = name, value = value });
   177 		t_insert(body, { name = name, value = value });
   173 	end --FIXME Why do I have to do this?
   178 	end --FIXME Why do I have to do this?
   174 	body = formencode(body);
   179 	body = formencode(body);
   175 
   180 
   176 	--module:log("debug", "subscription request, body: %s", body);
   181 	--module:log("debug", "subscription request, body: %s", body);
   177 
   182 
   178 	--FIXME The subscription states and related stuff
   183 	--FIXME The subscription states and related stuff
   179 	--feed.subscription = challenge and "asked" or "asking";
   184 	feed.subscription = "subscribe";
   180 	feed.subscription = "asking";
       
   181 	http.request(feed.hub, { body = body }, function(data, code, req) 
   185 	http.request(feed.hub, { body = body }, function(data, code, req) 
   182 		local code = tostring(code);
   186 		local code = tostring(code);
   183 		module:log("debug", "subscription to %s submitted, staus %s", feed.node, code);
   187 		module:log("debug", "subscription to %s submitted, staus %s", feed.node, code);
   184 		if code == '202' then
       
   185 			if challenge then
       
   186 				module:log("debug", "subscribe to %s confirmed", feed.node);
       
   187 				feed.subscription = "active";
       
   188 			else
       
   189 				module:log("debug", "subscription to %s submitted", feed.node);
       
   190 				--feed.subscription = "incomplete"; 
       
   191 			end
       
   192 		end
       
   193 	end);
   188 	end);
   194 end
   189 end
   195 
   190 
   196 function handle_http_request(method, body, request)
   191 function handle_http_request(method, body, request)
   197 	--module:log("debug", "%s request to %s%s with body %s", method, request.url.path, request.url.query and "?" .. request.url.query or "", #body > 0 and body or "empty");
   192 	--module:log("debug", "%s request to %s%s with body %s", method, request.url.path, request.url.query and "?" .. request.url.query or "", #body > 0 and body or "empty");
   199 	if query and type(query) == "string" then
   194 	if query and type(query) == "string" then
   200 		query = urlparams(query);
   195 		query = urlparams(query);
   201 		--module:log("debug", "GET data: %s", dump(query));
   196 		--module:log("debug", "GET data: %s", dump(query));
   202 	end
   197 	end
   203 
   198 
   204 	-- TODO http://pubsubhubbub.googlecode.com/svn/trunk/pubsubhubbub-core-0.3.html#authednotify
       
   205 
       
   206 	if method == "GET" then
   199 	if method == "GET" then
   207 		if query.node and feed_list[query.node] then
   200 		if query.node and feed_list[query.node] then
   208 			local feed = feed_list[query.node];
   201 			local feed = feed_list[query.node];
   209 			local challenge = query["hub.challenge"];
   202 			if query["hub.topic"] ~= feed.url then
   210 			if challenge and feed.subscription == "asking" then
   203 				module:log("debug", "Invalid topic: %s", tostring(query["hub.topic"]))
   211 				module:log("debug", "got a challenge for %s: %s", feed.node, challenge);
   204 				return http_response(404)
   212 				subscribe(feed, challenge);
   205 			end
   213 				return http_response(202);
   206 			if query["hub.mode"] ~= feed.subscription then
   214 			end
   207 				module:log("debug", "Invalid mode: %s", tostring(query["hub.mode"]))
       
   208 				return http_response(400)
       
   209 				-- Would this work for unsubscribe?
       
   210 				-- Also, if feed.subscription is changed here,
       
   211 				-- it would probably invalidate the subscription
       
   212 				-- when/if the hub asks if it should be renewed
       
   213 			end
       
   214 			if query["hub.verify"] ~= feed.token then
       
   215 				module:log("debug", "Invalid verify_token: %s", tostring(query["hub.verify"]))
       
   216 				return http_response(401)
       
   217 			end
       
   218 			module:log("debug", "Confirming %s request to %s", feed.subscription, feed.url)
       
   219 			return http_response(200, nil, query["hub.challenge"])
   215 		end
   220 		end
   216 		return http_response(400);
   221 		return http_response(400);
   217 	elseif method == "POST" then
   222 	elseif method == "POST" then
       
   223 		-- TODO http://pubsubhubbub.googlecode.com/svn/trunk/pubsubhubbub-core-0.3.html#authednotify
   218 		if #body > 0 and feed_list[query.node] then
   224 		if #body > 0 and feed_list[query.node] then
   219 			module:log("debug", "got %d bytes PuSHed for %s", #body, query.node);
   225 			module:log("debug", "got %d bytes PuSHed for %s", #body, query.node);
   220 			local feed = feed_list[query.node];
   226 			local feed = feed_list[query.node];
   221 			feed.data = body;
   227 			feed.data = body;
   222 			update_entry(feed);
   228 			update_entry(feed);