PageRenderTime 38ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/deps/http.lua

https://gitlab.com/kidaa/luvit
Lua | 448 lines | 343 code | 54 blank | 51 comment | 68 complexity | a2f12d48b0f335173b6ad3df53b66155 MD5 | raw file
  1. --[[
  2. Copyright 2015 The Luvit Authors. All Rights Reserved.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS-IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. --]]
  13. exports.name = "luvit/http"
  14. exports.version = "1.1.1-1"
  15. exports.dependencies = {
  16. "luvit/net@1.1.1",
  17. "luvit/url@1.0.4",
  18. "luvit/http-codec@1.0.0",
  19. "luvit/stream@1.1.0",
  20. "luvit/utils@1.0.0",
  21. }
  22. exports.license = "Apache 2"
  23. exports.homepage = "https://github.com/luvit/luvit/blob/master/deps/http.lua"
  24. exports.description = "Node-style http client and server module for luvit"
  25. exports.tags = {"luvit", "http", "stream"}
  26. local net = require('net')
  27. local url = require('url')
  28. local codec = require('http-codec')
  29. local Writable = require('stream').Writable
  30. local date = require('os').date
  31. local luvi = require('luvi')
  32. local utils = require('utils')
  33. local IncomingMessage = net.Socket:extend()
  34. exports.IncomingMessage = IncomingMessage
  35. function IncomingMessage:initialize(head, socket)
  36. net.Socket.initialize(self)
  37. self.httpVersion = tostring(head.version)
  38. local headers = {}
  39. for i = 1, #head do
  40. local name, value = unpack(head[i])
  41. headers[name:lower()] = value
  42. end
  43. self.headers = headers
  44. if head.method then
  45. -- server specific
  46. self.method = head.method
  47. self.url = head.path
  48. else
  49. -- client specific
  50. self.statusCode = head.code
  51. self.statusMessage = head.reason
  52. end
  53. self.socket = socket
  54. end
  55. function IncomingMessage:_read()
  56. self.socket:resume()
  57. end
  58. local ServerResponse = Writable:extend()
  59. exports.ServerResponse = ServerResponse
  60. function ServerResponse:initialize(socket)
  61. local encode = codec.encoder()
  62. self.socket = socket
  63. self.encode = encode
  64. self.statusCode = 200
  65. self.headersSent = false
  66. self.headers = {}
  67. for _, evt in pairs({'close', 'finish'}) do
  68. self.socket:on(evt, utils.bind(self.emit, self, evt))
  69. end
  70. end
  71. -- Override this in the instance to not send the date
  72. ServerResponse.sendDate = true
  73. function ServerResponse:setHeader(name, value)
  74. assert(not self.headersSent, "headers already sent")
  75. self.headers[name] = value
  76. end
  77. function ServerResponse:getHeader(name)
  78. assert(not self.headersSent, "headers already sent")
  79. local lower = name:lower()
  80. for key, value in pairs(self.headers) do
  81. if lower == key:lower() then
  82. return value
  83. end
  84. end
  85. end
  86. function ServerResponse:removeHeader(name)
  87. assert(not self.headersSent, "headers already sent")
  88. local lower = name:lower()
  89. local toRemove = {}
  90. for key in pairs(self.headers) do
  91. if lower == key:lower() then
  92. toRemove[#toRemove + 1] = key
  93. end
  94. end
  95. for i = 1, #toRemove do
  96. self.headers[toRemove[i]] = nil
  97. end
  98. end
  99. function ServerResponse:flushHeaders()
  100. if self.headersSent then return end
  101. self:writeHead(self.statusCode, self.headers)
  102. end
  103. function ServerResponse:write(chunk, callback)
  104. self:flushHeaders()
  105. return self.socket:write(self.encode(chunk), callback)
  106. end
  107. function ServerResponse:finish(chunk)
  108. self:flushHeaders()
  109. local last = ""
  110. if chunk then
  111. last = last .. self.encode(chunk)
  112. end
  113. last = last .. (self.encode("") or "")
  114. if #last > 0 then
  115. self.socket:write(last, function()
  116. self.socket:_end()
  117. end)
  118. else
  119. self.socket:_end()
  120. end
  121. end
  122. function ServerResponse:writeHead(statusCode, headers)
  123. assert(not self.headersSent, "headers already sent")
  124. self.headersSent = true
  125. headers = headers or {}
  126. local head = {}
  127. local lower = {}
  128. for key, value in pairs(headers) do
  129. lower[key:lower()] = value
  130. head[#head + 1] = {tostring(key), tostring(value)}
  131. end
  132. if not lower.date and self.sendDate then
  133. head[#head + 1] = {"Date", date("!%a, %d %b %Y %H:%M:%S GMT")}
  134. end
  135. if not lower["content-length"] and not lower["transfer-encoding"] then
  136. head[#head + 1] = {"Transfer-Encoding", "chunked"}
  137. end
  138. head.code = statusCode
  139. self.socket:write(self.encode(head))
  140. end
  141. function exports.handleConnection(socket, onRequest)
  142. -- Initialize the two halves of the stateful decoder and encoder for HTTP.
  143. local decode = codec.decoder()
  144. local buffer = ""
  145. local req, res
  146. local function flush()
  147. req:push()
  148. req = nil
  149. end
  150. socket:on('data', function (chunk)
  151. -- Run the chunk through the decoder by concatenating and looping
  152. buffer = buffer .. chunk
  153. while true do
  154. local R, event, extra = pcall(decode,buffer)
  155. if R then
  156. -- nil extra means the decoder needs more data, we're done here.
  157. if not extra then break end
  158. -- Store the leftover data.
  159. buffer = extra
  160. if type(event) == "table" then
  161. -- If there was an old request that never closed, end it.
  162. if req then flush() end
  163. -- Create a new request object
  164. req = IncomingMessage:new(event, socket)
  165. -- Create a new response object
  166. res = ServerResponse:new(socket)
  167. -- Call the user callback to handle the request
  168. onRequest(req, res)
  169. elseif req and type(event) == "string" then
  170. if #event == 0 then
  171. -- Empty string in http-decoder means end of body
  172. -- End the request stream and remove the req reference.
  173. flush()
  174. else
  175. -- Forward non-empty body chunks to the req stream.
  176. if not req:push(event) then
  177. -- If it's queue is full, pause the source stream
  178. -- This will be resumed by IncomingMessage:_read
  179. socket:pause()
  180. end
  181. end
  182. end
  183. else
  184. self:emit('error',event)
  185. break
  186. end
  187. end
  188. end)
  189. socket:on('end', function ()
  190. -- Just in case the stream ended and we still had an open request,
  191. -- end it.
  192. if req then flush() end
  193. end)
  194. end
  195. function exports.createServer(onRequest)
  196. return net.createServer(function (socket)
  197. return exports.handleConnection(socket, onRequest)
  198. end)
  199. end
  200. local ClientRequest = Writable:extend()
  201. exports.ClientRequest = ClientRequest
  202. function exports.ClientRequest.getDefaultUserAgent()
  203. if exports.ClientRequest._defaultUserAgent == nil then
  204. exports.ClientRequest._defaultUserAgent = 'luvit/http/' .. exports.version .. ' luvi/' .. luvi.version
  205. end
  206. return exports.ClientRequest._defaultUserAgent
  207. end
  208. function ClientRequest:initialize(options, callback)
  209. Writable.initialize(self)
  210. self:cork()
  211. local headers = options.headers or { }
  212. local host_found, connection_found, user_agent
  213. for i, header in ipairs(headers) do
  214. local key, value = unpack(header)
  215. local hfound = key:lower() == 'host'
  216. if hfound then
  217. host_found = value
  218. end
  219. local cfound = key:lower() == 'connection'
  220. if cfound then
  221. connection_found = value
  222. end
  223. local uafound = key:lower() == 'user-agent'
  224. if uafound then
  225. user_agent = value
  226. end
  227. table.insert(self, header)
  228. end
  229. if not user_agent then
  230. user_agent = self.getDefaultUserAgent()
  231. end
  232. if user_agent ~= '' then
  233. table.insert(self, 1, { 'user-agent', user_agent })
  234. end
  235. if not host_found and options.host then
  236. table.insert(self, 1, { 'host', options.host })
  237. end
  238. self.host = options.host
  239. self.method = (options.method or 'GET'):upper()
  240. self.path = options.path or '/'
  241. self.port = options.port or 80
  242. self.self_sent = false
  243. self.connection = connection_found
  244. self.encode = codec.encoder()
  245. self.decode = codec.decoder()
  246. local buffer = ''
  247. local res
  248. local function flush()
  249. res:_end()
  250. res = nil
  251. end
  252. local socket = options.socket or net.createConnection(self.port, self.host)
  253. local connect_emitter = options.connect_emitter or 'connect'
  254. self.socket = socket
  255. socket:on('error',function(...) self:emit('error',...) end)
  256. socket:on(connect_emitter, function()
  257. self.connected = true
  258. self:emit('socket', socket)
  259. socket:on('data', function(chunk)
  260. -- Run the chunk through the decoder by concatenating and looping
  261. buffer = buffer .. chunk
  262. while true do
  263. local R, event, extra = pcall(self.decode,buffer)
  264. if R==true then
  265. -- nil extra means the decoder needs more data, we're done here.
  266. if not extra then break end
  267. -- Store the leftover data.
  268. buffer = extra
  269. if type(event) == "table" then
  270. if self.method ~= 'CONNECT' or res == nil then
  271. -- If there was an old response that never closed, end it.
  272. if res then flush() end
  273. -- Create a new response object
  274. res = IncomingMessage:new(event, socket)
  275. -- Call the user callback to handle the response
  276. if callback then
  277. callback(res)
  278. end
  279. self:emit('response', res)
  280. end
  281. if self.method == 'CONNECT' then
  282. self:emit('connect', res, socket, event)
  283. end
  284. elseif res and type(event) == "string" then
  285. if #event == 0 then
  286. -- Empty string in http-decoder means end of body
  287. -- End the res stream and remove the res reference.
  288. flush()
  289. else
  290. -- Forward non-empty body chunks to the res stream.
  291. if not res:push(event) then
  292. -- If it's queue is full, pause the source stream
  293. -- This will be resumed by IncomingMessage:_read
  294. socket:pause()
  295. end
  296. end
  297. end
  298. else
  299. self:emit('error', event)
  300. break
  301. end
  302. end
  303. end)
  304. socket:on('end', function ()
  305. -- Just in case the stream ended and we still had an open response,
  306. -- end it.
  307. if res then flush() end
  308. end)
  309. if self.ended then
  310. self:_done(self.ended.data, self.ended.cb)
  311. end
  312. end)
  313. end
  314. function ClientRequest:flushHeaders()
  315. if not self.headers_sent then
  316. self.headers_sent = true
  317. -- set connection
  318. self:_setConnection()
  319. Writable.write(self, self.encode(self))
  320. end
  321. end
  322. function ClientRequest:write(data, cb)
  323. self:flushHeaders()
  324. local encoded = self.encode(data)
  325. -- Don't write empty strings to the socket, it breaks HTTPS.
  326. if #encoded > 0 then
  327. Writable.write(self, encoded, cb)
  328. else
  329. if cb then
  330. cb()
  331. end
  332. end
  333. end
  334. function ClientRequest:_write(data, cb)
  335. self.socket:write(data, cb)
  336. end
  337. function ClientRequest:_done(data, cb)
  338. self:_end(data, function()
  339. if cb then
  340. cb()
  341. end
  342. end)
  343. end
  344. function ClientRequest:_setConnection()
  345. if not self.connection then
  346. table.insert(self, { 'connection', 'close' })
  347. end
  348. end
  349. function ClientRequest:done(data, cb)
  350. -- Optionally send one more chunk
  351. if data then self:write(data) end
  352. self:flushHeaders()
  353. local ended =
  354. {
  355. cb = cb or function() end,
  356. data = ''
  357. }
  358. if self.connected then
  359. self:_done(ended.data, ended.cb)
  360. else
  361. self.ended = ended
  362. end
  363. end
  364. function ClientRequest:setTimeout(msecs, callback)
  365. if self.socket then
  366. self.socket:setTimeout(msecs,callback)
  367. end
  368. end
  369. function ClientRequest:destroy()
  370. if self.socket then
  371. self.socket:destroy()
  372. end
  373. end
  374. function exports.parseUrl(options)
  375. if type(options) == 'string' then
  376. options = url.parse(options)
  377. end
  378. return options
  379. end
  380. function exports.request(options, onResponse)
  381. return ClientRequest:new(exports.parseUrl(options), onResponse)
  382. end
  383. function exports.get(options, onResponse)
  384. options = exports.parseUrl(options)
  385. options.method = 'GET'
  386. local req = exports.request(options, onResponse)
  387. req:done()
  388. return req
  389. end