Advertisement
Snusmumriken

Http request through pure tcp-luasocket

Jun 18th, 2018
202
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 3.19 KB | None | 0 0
  1. local function httpRequest(url, verb, headers, data, timeout)
  2.   if type(url) == 'table' then
  3.     verb    = url.verb
  4.     headers = url.headers
  5.     data    = url.data
  6.     timeout = url.timeout
  7.     url     = url.url
  8.   end
  9.  
  10.   local socket = require('socket')
  11.  
  12. ---------------------------------[REQUEST PART]---------------------------------
  13.  
  14.   --                                   Protocol   host   path
  15.   local proto, host, path = url:match('(https?://)([^/]+)(/?.*)')
  16.   -- proto: 'http(s)://', host: 'ru.wikipedia.org', path: '/wiki/HTTP'
  17.  
  18.   if not proto then return nil, 'Invalid request' end
  19.  
  20.   path = #path == 0 and '/' or path
  21.  
  22.   local port = proto:find('https') and 433 or 80
  23.  
  24.   do -- host -> (ru.wikipedia.org):(8080) <- port
  25.     local _host, _port = host:match('(.-):(%d+)')
  26.     if _host then
  27.       host = _host
  28.       port = tonumber(_port)
  29.     end
  30.   end
  31.  
  32.   verb    = verb or 'GET'
  33.   headers = headers or {}
  34.  
  35.   --[==[
  36.   HTTP-request is string like this (without "[" and "]", is formatting boundaries):
  37.  
  38.   [POST /wiki/HTTP HTTP/1.1]
  39.   [Host: ru.wikipedia.org]
  40.   [User-Agent: Mozilla/5.0]
  41.   [Content-Length: 6]
  42.   [(empty string)]
  43.   [qwerty] <- Content-Length, if defined
  44.  
  45.   Delmitter between lines is [\r\n] (line feed + newline)
  46.   ]==]
  47.  
  48.   local Request = {} -- request table
  49.   Request[1] = verb .. ' ' .. path .. ' HTTP/1.1'
  50.   Request[2] = 'Host: ' .. host
  51.   Request[3] = 'User-Agent: Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9b5)' ..
  52.                'Gecko/2008050509 Firefox/3.0b5'
  53.  
  54.   for k, v in pairs(headers) do
  55.     Request[#Request + 1] = k .. ': ' .. v
  56.   end
  57.  
  58.   if data then
  59.     Request[#Request + 1] = 'Content-length: ' .. #data
  60.     Request[#Request + 1] = ''
  61.     Request[#Request + 1] = data
  62.   else
  63.     Request[#Request + 1] = ''
  64.   end
  65.  
  66.   Request = table.concat(Request, '\r\n')
  67.  
  68.   -- if proto:find('https') then connect through luasec
  69.   local connection, status = socket.connect(host, port)
  70.   if not connection then return nil, status end
  71.  
  72.   connection:settimeout((timeout or 60) * 1000)
  73.  
  74.   local sended_bytes, status = connection:send(Request)
  75.  
  76.   if sended_bytes ~= #Request then
  77.     return nil, 'Request error: ' .. tostring(status)
  78.   end
  79.  
  80. ---------------------------------[RESPONSE PART]--------------------------------
  81.  
  82.   --[==[
  83.   HTTP-response is string like this (without "[" and "]", is formatting boundaries):
  84.  
  85.   [HTTP/1.1 200 OK]
  86.   [Content-Length: 10]
  87.   [(empty string)]
  88.   [qwertyuiop] <- Content-Length, if defined
  89.  
  90.   Delmitter between lines is [\r\n] (line feed + newline)
  91.   ]==]
  92.  
  93.   local data, status = connection:receive('*l')
  94.  
  95.   if not data then return nil, status end
  96.  
  97.   local responseStatus = data:match(' (%d+)') -- HTTP/1.1 (200) OK
  98.  
  99.   local headers = {}
  100.  
  101.   data, status = connection:receive('*l')
  102.   while data and #data > 0 do
  103.     local key, value = data:match('(.-): (.*)')
  104.     if key then
  105.       headers[key:lower()] = value
  106.     end
  107.     data, status = connection:receive('*l')
  108.   end
  109.  
  110.   local responseData
  111.   if headers['content-length'] then
  112.     responseData = connection:receive(tonumber(headers['content-length']))
  113.   end
  114.  
  115.   return responseData, responseStatus, headers
  116. end
  117.  
  118. print(httpRequest('http://google.ru'))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement