lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Cosmin Apreutesei <cosmin.apreutesei@gmail.com> wrote

> I was also thinking about LuaSec for https + LuaSocket for TCP +
> LuaSocket.http for encoding/decoding the http stream. Did anyone tried
> such a crazy scheme?

Sometime ago, I wrote this HTTPS module, using some code taken from
a previous post by James McLaughlin [1]. It emulates the 
socket.http.request() interface, so, there is no much things to learn
before start using it. But I advice some caution -- It's almost untested.

[1] http://lua-users.org/lists/lua-l/2009-02/msg00270.html 

-- 
Alexandre Erwin Ittner - alexandre@ittner.com.br
OpenPGP pubkey 0x0041A1FB @ http://pgp.mit.edu

----
module("https", package.seeall)

local socket = require "socket"
local http = require "socket.http"
local ssl = require "ssl"
local ltn12 = require "ltn12"

local try = socket.try
local protect = socket.protect

local DEFAULT_PROTOCOL = "sslv23"
local DEFAULT_CAFILE = "/etc/ssl/certs/ca-certificates.crt"
local DEFAULT_VERIFY = "peer"
local DEFAULT_OPTIONS = "all"
local DEFAULT_CIPHERS = "ADH-AES256-SHA:ADH-AES128-SHA:HIGH:MEDIUM"
local DEFAULT_HTTPS_PORT = 443

local https_mt = {
    -- Create proxy functions for each call through the metatable
    __index = function(tbl, key)
        local f = function(prxy, ...)
            local c = prxy.c
            return c[key](c, ...)
        end
        tbl[key] = f    -- Save new proxy function in cache for speed
        return f
    end
}

local function new_create(params)
    return function()
        local t = { c = try(socket.tcp()) }
        function t:connect(host, port)
            try(self.c:connect(host, port))
            self.c = try(ssl.wrap(self.c, params))
            try(self.c:dohandshake())
            return 1
        end
        return setmetatable(t, https_mt)
    end
end

local function request_generic(args)
    local sslparams = {
        mode = "client",
        protocol = args.protocol or DEFAULT_PROTOCOL,
        cafile = args.cafile or DEFAULT_CAFILE,
        verify = args.verify or DEFAULT_VERIFY,
        options = args.options or DEFAULT_OPTIONS,
        ciphers = args.ciphers or DEFAULT_CIPHERS
    }
    local req = {
      url = args.url,
      port = args.port or DEFAULT_HTTPS_PORT,
      sink = args.sink,
      method = args.method,
      headers = args.headers,
      source = args.source,
      step = args.step,
      proxy = args.proxy,       -- Buggy?
      redirect = args.redirect,
      create = new_create(sslparams)
    }
    return http.request(req)
end

local function request_simple(url, body)
    local tbl = { }
    local req = {
        url = url,
        sink = ltn12.sink.table(tbl)
    }
    if body then
        req.method = "POST"
        req.source = ltn12.source.string(body)
        req.headers = {
            ["Content-length"] = #body,
            ["Content-type"] = "application/x-www-form-urlencoded"
        }
    end
    local _, status, headers = request_generic(req)
    return table.concat(tbl), status, headers
end


function request(req_or_url, body)
    if type(req_or_url) == "string" then
        return request_simple(req_or_url, body)
    else
        return request_generic(req_or_url)
    end
end