From Wet Plover, 7 Years ago, written in Lua.
This paste is a reply to Untitled from Aqua Owl - view diff
Embed
  1. -- mod_http_upload_external
  2. --
  3. -- Copyright (C) 2016 Sebastian Luksch
  4. --
  5. -- This file is MIT/X11 licensed.
  6. --
  7. -- Implementation of HTTP Upload file transfer mechanism used by Conversations
  8. --
  9. -- Query external HTTP server to retrieve URLs
  10. --
  11.  
  12. -- configuration
  13. local external_url = module:get_option("http_upload_external_url");
  14. local xmpp_server_key = module:get_option("http_upload_external_server_key");
  15.  
  16. -- imports
  17. local st = require"util.stanza";
  18. local http = require"socket.http";
  19. local json = require"util.json";
  20.  
  21. -- depends
  22. module:depends("disco");
  23.  
  24. -- namespace
  25. local xmlns_http_upload = "urn:xmpp:http:upload";
  26.  
  27. module:add_feature(xmlns_http_upload);
  28.  
  29. -- hooks
  30. module:hook("iq/host/"..xmlns_http_upload..":request", function (event)
  31.    local stanza, origin = event.stanza, event.origin;
  32.    local orig_from = stanza.attr.from;
  33.    local request = stanza.tags[1];
  34.    -- local clients only
  35.    if origin.type ~= "c2s" then
  36.       origin.send(st.error_reply(stanza, "cancel", "not-authorized"));
  37.       return true;
  38.    end
  39.    -- check configuration
  40.    if not external_url or not xmpp_server_key then
  41.       module:log("debug", "missing configuration options: http_upload_external_url and/or http_upload_external_server_key");
  42.       origin.send(st.error_reply(stanza, "cancel", "internal-server-error"));
  43.       return true;
  44.    end
  45.    -- validate
  46.    local filename = request:get_child_text("filename");
  47.    if not filename then
  48.       origin.send(st.error_reply(stanza, "modify", "bad-request", "Invalid filename"));
  49.       return true;
  50.    end
  51.    local filesize = tonumber(request:get_child_text("size"));
  52.    if not filesize then
  53.       origin.send(st.error_reply(stanza, "modify", "bad-request", "Missing or invalid file size"));
  54.       return true;
  55.    end
  56.  
  57.    local content_type = request:get_child_text("content-type");
  58.    
  59.    -- build the body
  60.    local reqbody = "xmpp_server_key=" .. xmpp_server_key .. "&size=" .. filesize .. "&filename=" .. filename .. "&user_jid=" .. orig_from;
  61.    if content_type then
  62.       reqbody = reqbody .. "&content_type=" .. content_type;
  63.    end
  64.  
  65.    -- the request
  66.    local respbody, statuscode = http.request(external_url, reqbody);
  67.    respbody = string.gsub(respbody, "\\/", "/")
  68.  
  69.    local get_url = nil;
  70.    local put_url = nil;
  71.  
  72.    -- check the response
  73.    if statuscode == 500 then
  74.       origin.send(st.error_reply(stanza, "cancel", "service-unavailable", respbody));
  75.    elseif statuscode == 406 or statuscode == 400 or statuscode == 403 then
  76.       local errobj, pos, err = json.decode(respbody);
  77.       if err then
  78.          origin.send(st.error_reply(stanza, "wait", "internal-server-error", err));
  79.          return true;
  80.       else
  81.          if errobj["err_code"] ~= nil and errobj["msg"] ~= nil then
  82.             if errobj.err_code == 1 then
  83.                origin.send(st.error_reply(stanza, "modify", "not-acceptable", errobj.msg));
  84.                return true;
  85.             elseif errobj.err_code == 2 then
  86.                origin.send(st.error_reply(stanza, "modify", "not-acceptable", errobj.msg,
  87.                   st.stanza("file-too-large", {xmlns=xmlns_http_upload})
  88.                      :tag("max-size"):text(errobj.parameters.max_file_size)));
  89.                return true;
  90.             elseif errobj.err_code == 3 then
  91.                origin.send(st.error_reply(stanza, "modify", "not-acceptable", errobj.msg,
  92.                   st.stanza("invalid-character", {xmlns=xmlns_http_upload})
  93.                      :text(errobj.parameters.invalid_character)));
  94.                return true;
  95.             elseif errobj.err_code == 4 then
  96.                origin.send(st.error_reply(stanza, "cancel", "internal-server-error", errobj.msg,
  97.                   st.stanza("missing-parameter", {xmlns=xmlns_http_upload})
  98.                      :text(errobj.parameters.missing_parameter)));
  99.                return true;
  100.             else
  101.                origin.send(st.error_reply(stanza, "cancel", "undefined-condition", "unknown err_code"));
  102.                return true;
  103.             end
  104.          elseif statuscode == 403 and errobj["msg"] ~= nil then
  105.             origin.send(st.error_reply(stanza, "cancel", "internal-server-error", errobj.msg));
  106.          else
  107.             origin.send(st.error_reply(stanza, "cancel", "undefined-condition", "msg or err_code not found"));
  108.             return true;
  109.          end
  110.       end
  111.    elseif statuscode == 200 then
  112.       local respobj, pos, err = json.decode(respbody);
  113.       if err then
  114.          origin.send(st.error_reply(stanza, "wait", "internal-server-error", err));
  115.          return true;
  116.       else
  117.          if respobj["get"] ~= nil and respobj["put"] ~= nil then
  118.             get_url = respobj.get;
  119.             put_url = respobj.put;
  120.          else
  121.             origin.send(st.error_reply(stanza, "cancel", "undefined-condition", "get or put not found"));
  122.             return true;
  123.          end
  124.       end
  125.    else
  126.       origin.send(st.error_reply(stanza, "cancel", "undefined-condition", "status code: " .. statuscode .. " response: " ..respbody));
  127.       return true;
  128.    end
  129.  
  130.    local reply = st.reply(stanza);
  131.    reply:tag("slot", { xmlns = xmlns_http_upload });
  132.    reply:tag("get"):text(get_url):up();
  133.    reply:tag("put"):text(put_url):up();
  134.    origin.send(reply);
  135.    return true;
  136. end);