On the net, I found a couple of examples of how to perform an HTTPS request. However, they all have a very serious drawback: they close the TCP connection as soon as they receive all the data from the server. This is no good.

Here is one example.

https = require('ssl.https') local data, code = https.request('https://httpbin.org/get') 

How to supplement it with minimal pain so that the connection does not close?

  • Search for "persistent connection http", "http keep alive", "http connection reuse". may have an option to make your http permanent and call request by request without breaking the connection. - Sergey
  • If I'm not mistaken, LuaSocket does not support persistent connections for http (s), so you need to either write on the sockets yourself, or look for another library. - zed
  • @zed, could you tell me which library to pay attention to? - mymedia
  • Lua-cURL should be a good alternative: github.com/Lua-cURL/Lua-cURLv3 - zed
  • @zed, yes, thanks, it seems it works. Maybe we should arrange this as an answer - mymedia

2 answers 2

The LuaSocket library (which is used in the example code) does not support persistent connections over http (s). Therefore, the minimum pain can not do, and we must use some other library.

For example, you can take Lua-cURL :

 local curl = require "cURL" local function main() local e = curl.easy() -- включает подробный вывод о ходе соединения e:setopt_verbose(true) e:setopt_url("https://httpbin.org/get") e:perform() -- выполняет загрузку и НЕ закрывает соединение -- отключает переиспользование соединений e:setopt_forbid_reuse(true) e:setopt_url("https://httpbin.org/ip") e:perform() -- выполняет загрузку и закрывает соединение e:close() end main() 

In this library, on the contrary, connections by default are not closed and reused (even after calling e:close ) and here you must use the special option CURLOPT_FORBID_REUSE so that connections are broken (if necessary).

The whole process of opening / re-using / closing connections can be seen in the log:

 * Trying 23.22.14.18... * Connected to httpbin.org (23.22.14.18) port 443 (#0) * ALPN, offering http/1.1 * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs * NPN, negotiated HTTP1.1 * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server did not agree to a protocol * Server certificate: * subject: OU=Domain Control Validated; OU=EssentialSSL Wildcard; CN=*.httpbin.org * start date: Jan 12 00:00:00 2016 GMT * expire date: Jan 19 23:59:59 2017 GMT * subjectAltName: httpbin.org matched * issuer: C=GB; ST=Greater Manchester; L=Salford; O=COMODO CA Limited; CN=COMODO RSA Domain Validation Secure Server CA * SSL certificate verify ok. > GET /get HTTP/1.1 Host: httpbin.org Accept: */* { "args": {}, "headers": { "Accept": "*/*", "Host": "httpbin.org" }, "origin": "xx.xx.xx.xx", "url": "https://httpbin.org/get" } < HTTP/1.1 200 OK < Server: nginx < Date: Tue, 04 Oct 2016 19:46:13 GMT < Content-Type: application/json < Content-Length: 154 < Connection: keep-alive < Access-Control-Allow-Origin: * < Access-Control-Allow-Credentials: true < * Connection #0 to host httpbin.org left intact * Found bundle for host httpbin.org: 0x95eac28 [can pipeline] * Re-using existing connection! (#0) with host httpbin.org * Connected to httpbin.org (23.22.14.18) port 443 (#0) > GET /ip HTTP/1.1 Host: httpbin.org Accept: */* { "origin": "xx.xx.xx.xx" } < HTTP/1.1 200 OK < Server: nginx < Date: Tue, 04 Oct 2016 19:46:13 GMT < Content-Type: application/json < Content-Length: 33 < Connection: keep-alive < Access-Control-Allow-Origin: * < Access-Control-Allow-Credentials: true < * Closing connection 0 

After the first query is executed, curl reports that the connection has been left open:

 Connection #0 to host httpbin.org left intact 

Before executing the second query, it finds it and happily re-uses:

 Found bundle for host httpbin.org: 0x95eac28 [can pipeline] Re-using existing connection! (#0) with host httpbin.org 

But after the second request, due to the fact that in the example before the second request, the ban on reusing connections is indicated, it closes:

 Closing connection 0 
  • You can screw keep-alive support to LuaSocket, but you have to rewrite https.request partially. - Mikalai Ramanovich
  • Thank you so much for the example. Do I understand correctly that a function passed as a writefunction parameter is called only once for a single request. I just need to get the body and response code in Lua variables. Am I doing this right? pastebin.com/2k8t2Lqb - mymedia
  • @mymedia No, for each request this function may be called several times and the body must be accumulated. See an example here: stackoverflow.com/a/29844130/6219657 - zed
  • one
    @mymedia Here is an adapted example: pastebin.com/q3Ks6uTP - zed
  • thanks, the general idea is clear - mymedia

On sockets:

 require("socket") require("ssl") ----- local params = { mode = "client", protocol = "tlsv1", verify = "none", options = { "all", "no_sslv2", "no_sslv3", "no_ticket", "no_compression" } } ----------------------------- local url = 'https://httpbin.org/get' local host, file = url:match("://(.+)(/.+)") local headers = "HTTP/1.1\nHost: "..host.."\nConnection: keep-alive\n\n" local conn = socket.tcp() conn:connect(host, 443) conn = ssl.wrap(conn, params) conn:dohandshake() conn:send( "GET ".. file.." "..headers ) -- local len, s, status = 0 local str, answer = "","" while true do s, status = conn:receive('*l') if s==nil or status =="closed" then break end str=str..s..'\n' if s:find("Content%-Length") then len = s:match("Content%-Length:%s?(%d+)") end if s=="" then answer, status = conn:receive(len) break end end print(str) print(answer) conn:close()