0

I am trying to interact with the Cleverbot API with Lua. I've got a key and a username, so I tested with Postman and it worked perfectly. Then I tried to do the same thing with Lua but I'm having a weird error.

This is the code:

local https = require("ssl.https")
local string = require("string")
local ltn12 = require ("ltn12")
local funcs = (loadfile "./libs/functions.lua")()

local function cleverbot(msg)
    local params = {
        ['user'] = 'SyR2nvN1cAxxxxxx',
        ['key'] = 'ckym8oDRNvpYO95GmTD14O9PuGxxxxxx',
        ['nick'] = 'cleverbot',
        ['text'] = tostring(msg),
    }

    local body = funcs.encode_table(params)
    local response = {}
    ok, code, headers, status = https.request({
        method = "POST",
        url = "https://cleverbot.io/1.0/ask/",
        headers = {
            ['Accept'] = '*/*',
            ['content-type'] = 'application/x-www-form-urlencoded',
            ['accept-encoding'] = 'gzip',
            ['content-length'] = tostring(#body),
        },
        print(tostring(ok)),
        print(tostring(code)),
        print(tostring(headers)),
        print(tostring(status)),

        source = ltn12.source.string(body),
        sink = ltn12.sink.table(response)
    })

    response = table.concat(response)

    if code ~= 200 then
       return 
    end

    if response[1] ~= nil then
       return tostring(response)
    end
end

However, when I call this, this is what those 4 prints shows:

nil
tlsv1 alert internal error
nil
nil

I tried to connect using HTTP instead, but this is what happens:

1
301
table: 0xe5f7d60
HTTP/1.1 301 Moved Permanently

response is always empty. Please, what am I doing wrong? Thanks!

bokirov
  • 13
  • 1
  • 4
  • The way you call https.request is definitely wrong. Why do you pass a result of a print function to https.request arguments table? – marsgpl Dec 06 '15 at 11:10
  • Oh, hey @marsgpl, I didn't know that could affect the outcome. I removed it and put a `print(ok, code, headers, status)` outside of it. I've also removed that `funcs.encode_table(params)` thing, and I'm testing with an already formatted param string. I've also added `protocol = "tlsv1"` in there, but the result is exactly the same. What else is wrong? – bokirov Dec 06 '15 at 16:18
  • well, try to check the presence of the openssl library, make sure it is not outdated. – marsgpl Dec 06 '15 at 18:25
  • It is present and I just updated it, @marsgpl. I have other scripts using `https.request` in the simple form, and they work fine. The only problem is this generic form that is reporting this tlsv1 error. – bokirov Dec 06 '15 at 20:05
  • You might consider using my library lua-http instead: https://github.com/daurnimator/lua-http – daurnimator Dec 07 '15 at 11:26

1 Answers1

1

My strong suspicion is, that the target host (cleverbot.io) insists to get a hostname through SNI (server name indication), which the ssl-library you use does not send. Usually, servers use a default site then, but of course they are free to let the handshake fail then. Seems like this is, what cloudflare (where cleverbot.io is hosted or proxied through) does.

Unfortunately there is no easy way to fix this, unless the underlying ssl-libraries are changed to use sni with hostname cleverbot.io for the ssl handshake.

See also

Fails:
openssl s_client -connect cleverbot.io:443  -tls1_1 

Succeeds:
openssl s_client -servername cleverbot.io -connect cleverbot.io:443  -tls1_1

This means, not only the underlying ssl libraries have to support sni, but also have to be told, which servername to use by the lua-binding-layer in between. Luasec for example does not make use of sni currently, afaik

Ctx
  • 18,090
  • 24
  • 36
  • 51
  • I've found this: https://github.com/brunoos/luasec/blob/master/samples/sni/client.lua I'll try and see if this works. Otherwise I'll find a way to do it in js. Thank you for your detailed answer! – bokirov Dec 07 '15 at 00:02