Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement lua-http for HTTP(S) 1.0, 1.1 and 2.0 #594

Closed
Frenzie opened this issue Jan 30, 2018 · 5 comments
Closed

Implement lua-http for HTTP(S) 1.0, 1.1 and 2.0 #594

Frenzie opened this issue Jan 30, 2018 · 5 comments

Comments

@Frenzie
Copy link
Member

Frenzie commented Jan 30, 2018

Alternative lazy option, patch luasocket and luasec, see lunarmodules/luasec#38

# expose parseRequest() from https://github.com/diegonehab/luasocket/pull/133 (without ftp.lua and smtp.lua)
set(PATCH_CMD "${PATCH_CMD} && patch -N -p1 < ${CMAKE_CURRENT_SOURCE_DIR}/parserequest.patch || true")

parserequest.patch for luasocket updated for current master

diff --git a/src/ftp.lua b/src/ftp.lua
index 6286f90..a894c1c 100644
--- a/src/ftp.lua
+++ b/src/ftp.lua
@@ -34,8 +34,13 @@ _M.PASSWORD = "[email protected]"
 -----------------------------------------------------------------------------
 local metat = { __index = {} }
 
-function _M.open(server, port, create)
-    local tp = socket.try(tp.connect(server, port or _M.PORT, _M.TIMEOUT, create))
+function _M.open(params)
+    local tp = socket.try(tp.connect(
+        params.server, 
+        params.port or _M.PORT, 
+        _M.TIMEOUT, 
+        function() return params:create() end  -- wrap create as a method call
+      ))
     local f = base.setmetatable({ tp = tp }, metat)
     -- make sure everything gets closed in an exception
     f.try = socket.newtry(function() f:close() end)
@@ -203,7 +208,7 @@ end
 local function tput(putt)
     putt = override(putt)
     socket.try(putt.host, "missing hostname")
-    local f = _M.open(putt.host, putt.port, putt.create)
+    local f = _M.open(putt)
     f:greet()
     f:login(putt.user, putt.password)
     if putt.type then f:type(putt.type) end
@@ -235,7 +240,7 @@ end
 local function tget(gett)
     gett = override(gett)
     socket.try(gett.host, "missing hostname")
-    local f = _M.open(gett.host, gett.port, gett.create)
+    local f = _M.open(gett)
     f:greet()
     f:login(gett.user, gett.password)
     if gett.type then f:type(gett.type) end
@@ -262,7 +267,8 @@ _M.command = socket.protect(function(cmdt)
     cmdt = override(cmdt)
     socket.try(cmdt.host, "missing hostname")
     socket.try(cmdt.command, "missing command")
-    local f = _M.open(cmdt.host, cmdt.port, cmdt.create)
+    cmdt.create = cmdt.create or socket.tcp
+    local f = _M.open(cmdt)
     f:greet()
     f:login(cmdt.user, cmdt.password)
     f.try(f.tp:command(cmdt.command, cmdt.argument))
@@ -277,6 +283,7 @@ _M.put = socket.protect(function(putt, body)
       tput(putt)
       return table.concat(putt.target)
     else 
+      putt.create = putt.create or socket.tcp
       return tput(putt) 
     end
 end)
@@ -287,6 +294,7 @@ _M.get = socket.protect(function(gett)
       tget(gett)
       return table.concat(gett.target)
     else 
+      gett.create = gett.create or socket.tcp
       return tget(gett) 
     end
 end)
diff --git a/src/http.lua b/src/http.lua
index 550634c..d926e72 100644
--- a/src/http.lua
+++ b/src/http.lua
@@ -106,15 +106,15 @@ end
 -----------------------------------------------------------------------------
 local metat = { __index = {} }
 
-function _M.open(host, port, create)
-    -- create socket with user connect function, or with default
-    local c = socket.try((create or socket.tcp)())
+function _M.open(reqt)
+    -- create socket with user connect function
+    local c = socket.try(reqt:create())   -- method call, passing reqt table as self!
     local h = base.setmetatable({ c = c }, metat)
     -- create finalized try
     h.try = socket.newtry(function() h:close() end)
     -- set timeout before connecting
     h.try(c:settimeout(_M.TIMEOUT))
-    h.try(c:connect(host, port or PORT))
+    h.try(c:connect(reqt.host, reqt.port or PORT))
     -- here everything worked
     return h
 end
@@ -294,7 +294,7 @@ end
     -- we loop until we get what we want, or
     -- until we are sure there is no way to get it
     local nreqt = adjustrequest(reqt)
-    local h = _M.open(nreqt.host, nreqt.port, nreqt.create)
+    local h = _M.open(nreqt)
     -- send request line and headers
     h:sendrequestline(nreqt.method, nreqt.uri)
     h:sendheaders(nreqt.headers)
@@ -352,9 +352,10 @@ end
 _M.request = socket.protect(function(reqt, body)
-    if base.type(reqt) == "string" then return srequest(reqt, body)
+    if  base.type(reqt) == "string" then 
+      local t, code, headers, status = reqt.target, socket.skip(1, _M.request(reqt))
       return table.concat(t), code, headers, status
-    else return trequest(reqt) end
+    else
+      reqt.create = reqt.create or socket.tcp
+       return trequest(reqt) 
+     end
 end)
diff --git a/src/smtp.lua b/src/smtp.lua
index b113d00..ea52873 100644
--- a/src/smtp.lua
+++ b/src/smtp.lua
@@ -113,9 +113,13 @@ function metat.__index:send(mailt)
     self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step)
 end
 
-function _M.open(server, port, create)
-    local tp = socket.try(tp.connect(server or _M.SERVER, port or _M.PORT,
-        _M.TIMEOUT, create))
+function _M.open(mailt)
+    local tp = socket.try(tp.connect(
+        mailt.server or _M.SERVER, 
+        mailt.port or _M.PORT,
+        _M.TIMEOUT, 
+        function() return mailt:create() end  -- wrap to do a method call
+      ))
     local s = base.setmetatable({tp = tp}, metat)
     -- make sure tp is closed if we get an exception
     s.try = socket.newtry(function()
@@ -245,7 +249,8 @@ end
 -- High level SMTP API
 -----------------------------------------------------------------------------
 _M.send = socket.protect(function(mailt)
-    local s = _M.open(mailt.server, mailt.port, mailt.create)
+    mailt.create = mailt.create or socket.tcp
+    local s = _M.open(mailt)
     local ext = s:greet(mailt.domain)
     s:auth(mailt.user, mailt.password, ext)
     s:send(mailt)
@Frenzie
Copy link
Member Author

Frenzie commented Jan 31, 2018

And for luasec (needs to be updated for current master)

set(PATCH_CMD sh -c "patch -N -p1 < ${CMAKE_CURRENT_SOURCE_DIR}/redirects.patch || true")

redirects.patch

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9976b19
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+/src/*.o
+/src/luasocket/*.o
+/ssl.dll
diff --git a/src/https.lua b/src/https.lua
index c0594db..b7bb611 100644
--- a/src/https.lua
+++ b/src/https.lua
@@ -13,7 +13,6 @@ local http   = require("socket.http")
 local url    = require("socket.url")
 
 local table  = require("table")
-local string = require("string")
 
 local try          = socket.try
 local type         = type
@@ -38,15 +37,10 @@ local cfg = {
 -- Auxiliar Functions
 --------------------------------------------------------------------
 
--- Insert default HTTPS port.
-local function default_https_port(u)
-   return url.build(url.parse(u, {port = PORT}))
-end
-
 -- Convert an URL to a table according to Luasocket needs.
 local function urlstring_totable(url, body, result_table)
    url = {
-      url = default_https_port(url),
+      url = url,
       method = body and "POST" or "GET",
       sink = ltn12.sink.table(result_table)
    }
@@ -81,9 +75,12 @@ local function tcp(params)
    end
    -- Force client mode
    params.mode = "client"
+   -- upvalue to track https -> http redirection
+   local washttps = false
    -- 'create' function for LuaSocket
    return function (reqt)
-      if (reqt.scheme or (url.parse(reqt.url or "") or {}).scheme) == "https" then
+      local u = url.parse(reqt.url)
+      if (reqt.scheme or u.scheme) == "https" then
         -- https, provide an ssl wrapped socket
         local conn = {}
         conn.sock = try(socket.tcp())
@@ -99,12 +96,22 @@ local function tcp(params)
            reg(self, getmetatable(self.sock))
            return 1
         end
+        -- insert https default port, overriding http port inserted by LuaSocket
+        if not u.port then
+           u.port = PORT
+           reqt.url = url.build(u)
+           reqt.port = PORT 
+        end
+        washttps = true
         return conn
       else
         -- regular http, needs just a socket...
+        if washttps and params.redirect ~= "all" then
+          try(nil, "Unallowed insecure redirect https to http")
+        end
         return socket.tcp()
-      end
-  end
+      end  
+   end
 end
 
 --------------------------------------------------------------------
@@ -124,16 +131,12 @@ function request(url, body)
   local stringrequest = type(url) == "string"
   if stringrequest then
     url = urlstring_totable(url, body, result_table)
-  else
-    url.url = default_https_port(url.url)
   end
   if http.PROXY or url.proxy then
     return nil, "proxy not supported"
-  elseif url.create then
-    return nil, "create function not permitted"
   end
-  -- New 'create' function to establish a secure connection
-  url.create = tcp(url)
+  -- New 'create' function to establish the proper connection
+  url.create = url.create or tcp(url)
   local res, code, headers, status = http.request(url)
   if res and stringrequest then
     return table.concat(result_table), code, headers, status

@mwoz123
Copy link

mwoz123 commented Jul 5, 2018

I don't quite follow, but I'd like to move http library at least one step forward...

how about using this lua http library:
https://github.com/lusis/lua-httpclient
?
it's not developed but maybe it's enought mature?
At least it require less dependencies so maybe it'll be easier to add to koreader?

also found this : https://steve.fi/Software/lua/lua-httpd/ (client) but it's probably too simple.

also fount howto for https +lua http://notebook.kulchenko.com/programming/https-ssl-calls-with-lua-and-luasec but we'd rather want library

Just found this https://github.com/luvit/luvit does it mean we can use javascript (node.js) apps in lua?
do I understand correclty if yes it means we do not have to use lua-http, maybe we can choose one from thousands other JS http libaries???

@mwoz123
Copy link

mwoz123 commented Jul 7, 2018

I tried above lua-httpclient but it doesn't solves our problems as I had:
["err"] = "tlsv1 alert protocol version".
Probably too old unmaintained code, so removing this from lua-http alternatives.

@Frenzie
Copy link
Member Author

Frenzie commented Dec 12, 2018

Just found this https://github.com/luvit/luvit does it mean we can use javascript (node.js) apps in lua?
do I understand correclty if yes it means we do not have to use lua-http, maybe we can choose one from thousands other JS http libaries???

I must've missed this. :-)

No, it looks like the Node.js API style in Lua. Which could still be quite interesting.

@Frenzie
Copy link
Member Author

Frenzie commented Apr 17, 2019

Closing because redirects are now supported by Luasec 0.8 combined with up-to-date LuaSocket.

See lunarmodules/luasec#132, lunarmodules/luasocket#268 and koreader/koreader#3516 (comment).

@Frenzie Frenzie closed this as completed Apr 17, 2019
Frenzie added a commit to Frenzie/koreader that referenced this issue Jun 25, 2020
See <koreader/koreader-base#594 (comment)>.

LuaSocket takes care of everything now, so all similar code can be simplified.
Frenzie added a commit to Frenzie/koreader that referenced this issue Jun 25, 2020
See <koreader/koreader-base#594 (comment)>.

LuaSocket takes care of everything now, so all similar code can be simplified.
Frenzie added a commit to Frenzie/koreader that referenced this issue Jun 25, 2020
See <koreader/koreader-base#594 (comment)>.

LuaSocket takes care of everything now, so all similar code can be simplified.
Frenzie added a commit to Frenzie/koreader that referenced this issue Jun 25, 2020
See <koreader/koreader-base#594 (comment)>.

LuaSocket takes care of everything now, so all similar code can be simplified.
Frenzie added a commit to koreader/koreader that referenced this issue Jun 27, 2020
See <koreader/koreader-base#594 (comment)>.

LuaSocket takes care of everything now, so all similar code can be simplified.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants