PageRenderTime 50ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 1ms

/liquidfeedback/moonbridge/moonbridge_http.lua

https://gitlab.com/fuzzynemesis/hajaannu
Lua | 1205 lines | 1083 code | 11 blank | 111 comment | 267 complexity | 595978e6786d028fc15ec8006f81c04c MD5 | raw file
Possible License(s): Apache-2.0
  1. #!/usr/bin/env lua
  2. -- module preamble
  3. local _G, _M = _ENV, {}
  4. _ENV = setmetatable({}, {
  5. __index = function(self, key)
  6. local value = _M[key]; if value ~= nil then return value end
  7. return _G[key]
  8. end,
  9. __newindex = _M
  10. })
  11. -- function that encodes certain HTML entities:
  12. -- (not used by the library itself)
  13. function encode_html(text)
  14. return (
  15. string.gsub(
  16. text, '[<>&"]',
  17. function(char)
  18. if char == '<' then
  19. return "&lt;"
  20. elseif char == '>' then
  21. return "&gt;"
  22. elseif char == '&' then
  23. return "&amp;"
  24. elseif char == '"' then
  25. return "&quot;"
  26. end
  27. end
  28. )
  29. )
  30. end
  31. -- function that encodes special characters for URIs:
  32. -- (not used by the library itself)
  33. function encode_uri(text)
  34. return (
  35. string.gsub(text, "[^0-9A-Za-z_%.~-]",
  36. function (char)
  37. return string.format("%%%02x", string.byte(char))
  38. end
  39. )
  40. )
  41. end
  42. -- function undoing URL encoding:
  43. do
  44. local b0 = string.byte("0")
  45. local b9 = string.byte("9")
  46. local bA = string.byte("A")
  47. local bF = string.byte("F")
  48. local ba = string.byte("a")
  49. local bf = string.byte("f")
  50. function decode_uri(str)
  51. return (
  52. string.gsub(
  53. string.gsub(str, "%+", " "),
  54. "%%([0-9A-Fa-f][0-9A-Fa-f])",
  55. function(hex)
  56. local n1, n2 = string.byte(hex, 1, 2)
  57. if n1 >= b0 and n1 <= b9 then n1 = n1 - b0
  58. elseif n1 >= bA and n1 <= bF then n1 = n1 - bA + 10
  59. elseif n1 >= ba and n1 <= bf then n1 = n1 - ba + 10
  60. else error("Assertion failed") end
  61. if n2 >= b0 and n2 <= b9 then n2 = n2 - b0
  62. elseif n2 >= bA and n2 <= bF then n2 = n2 - bA + 10
  63. elseif n2 >= ba and n2 <= bf then n2 = n2 - ba + 10
  64. else error("Assertion failed") end
  65. return string.char(n1 * 16 + n2)
  66. end
  67. )
  68. )
  69. end
  70. end
  71. -- status codes that carry no response body (in addition to 1xx):
  72. -- (set to "zero_content_length" if Content-Length header is required)
  73. status_without_response_body = {
  74. ["101"] = true, -- list 101 to allow protocol switch
  75. ["204"] = true,
  76. ["205"] = "zero_content_length",
  77. ["304"] = true
  78. }
  79. -- handling of GET/POST param tables:
  80. local new_params_list -- defined later
  81. do
  82. local params_list_mapping = setmetatable({}, {__mode="k"})
  83. local function nextnonempty(tbl, key)
  84. while true do
  85. key = next(tbl, key)
  86. if key == nil then
  87. return nil
  88. end
  89. local value = tbl[key]
  90. if #value > 0 then
  91. return key, value
  92. end
  93. end
  94. end
  95. local function nextvalue(tbl, key)
  96. while true do
  97. key = next(tbl, key)
  98. if key == nil then
  99. return nil
  100. end
  101. local value = tbl[key][1]
  102. if value ~= nil then
  103. return key, value
  104. end
  105. end
  106. end
  107. local params_list_metatable = {
  108. __index = function(self, key)
  109. local tbl = {}
  110. self[key] = tbl
  111. return tbl
  112. end,
  113. __pairs = function(self)
  114. return nextnonempty, self, nil
  115. end
  116. }
  117. local params_metatable = {
  118. __index = function(self, key)
  119. return params_list_mapping[self][key][1]
  120. end,
  121. __newindex = function(self, key, value)
  122. params_list_mapping[self][key] = {value}
  123. end,
  124. __pairs = function(self)
  125. return nextvalue, params_list_mapping[self], nil
  126. end
  127. }
  128. -- function that returns a table to store key value-list pairs,
  129. -- and a second table automatically mapping keys to the first value
  130. -- using the key value-list pairs in the first table:
  131. new_params_list = function()
  132. local params_list = setmetatable({}, params_list_metatable)
  133. local params = setmetatable({}, params_metatable)
  134. params_list_mapping[params] = params_list
  135. return params_list, params
  136. end
  137. end
  138. -- function parsing URL encoded form data and storing it in
  139. -- a key value-list pairs structure that has to be
  140. -- previously obtained by calling by new_params_list():
  141. local function read_urlencoded_form(tbl, data)
  142. for rawkey, rawvalue in string.gmatch(data, "([^?=&]*)=([^?=&]*)") do
  143. local subtbl = tbl[decode_uri(rawkey)]
  144. subtbl[#subtbl+1] = decode_uri(rawvalue)
  145. end
  146. end
  147. -- function to convert a HTTP request handler to a socket handler:
  148. function generate_handler(handler, options)
  149. -- swap arguments if necessary (for convenience):
  150. if type(handler) ~= "function" and type(options) == "function" then
  151. handler, options = options, handler
  152. end
  153. -- helper function to process options:
  154. local function default(name, default_value)
  155. local value = options[name]
  156. if value == nil then
  157. return default_value
  158. else
  159. return value or nil
  160. end
  161. end
  162. -- process options:
  163. options = options or {}
  164. local preamble = "" -- preamble sent with every(!) HTTP response
  165. do
  166. -- named arg "static_headers" is used to create the preamble:
  167. local s = options.static_headers
  168. local t = {}
  169. if s then
  170. if type(s) == "string" then
  171. for line in string.gmatch(s, "[^\r\n]+") do
  172. t[#t+1] = line
  173. end
  174. else
  175. for i, kv in ipairs(s) do
  176. if type(kv) == "string" then
  177. t[#t+1] = kv
  178. else
  179. t[#t+1] = kv[1] .. ": " .. kv[2]
  180. end
  181. end
  182. end
  183. end
  184. t[#t+1] = ""
  185. preamble = table.concat(t, "\r\n")
  186. end
  187. local input_chunk_size = options.maximum_input_chunk_size or options.chunk_size or 16384
  188. local output_chunk_size = options.minimum_output_chunk_size or options.chunk_size or 1024
  189. local header_size_limit = options.header_size_limit or 1024*1024
  190. local body_size_limit = options.body_size_limit or 64*1024*1024
  191. local idle_timeout = default("idle_timeout", 65)
  192. local stall_timeout = default("stall_timeout", 60)
  193. local request_header_timeout = default("request_header_timeout", 120)
  194. local response_timeout = default("response_timeout", 3600)
  195. local drain_timeout = default("drain_timeout", 2)
  196. local poll = options.poll_function or moonbridge_io.poll
  197. -- return socket handler:
  198. return function(socket)
  199. local socket_set = {[socket] = true} -- used for poll function
  200. local survive = true -- set to false if process shall be terminated later
  201. local consume -- can be set to function that reads some input if possible
  202. -- function that may be used as "consume" function
  203. -- and which drains some input if possible:
  204. local function drain()
  205. local bytes, status = socket:drain_nb(input_chunk_size)
  206. if not bytes or status == "eof" then
  207. consume = nil
  208. end
  209. end
  210. -- function trying to unblock socket by reading:
  211. local function unblock()
  212. if consume then
  213. if not poll(socket_set, socket_set, stall_timeout) then
  214. socket:reset()
  215. error("Client connection stalled")
  216. end
  217. consume()
  218. else
  219. if not poll(nil, socket_set, stall_timeout) then
  220. socket:reset()
  221. error("Client connection stalled")
  222. end
  223. end
  224. end
  225. -- handle requests in a loop:
  226. repeat
  227. -- table for caching nil values:
  228. local headers_value_nil = {}
  229. -- create a new request object (methods are added later):
  230. local request -- allow references to local variable
  231. request = {
  232. -- allow access to underlying socket:
  233. socket = socket,
  234. -- cookies are simply stored in a table:
  235. cookies = {},
  236. -- table mapping header field names to value-lists
  237. -- (raw access, but case-insensitive):
  238. headers = setmetatable({}, {
  239. __index = function(self, key)
  240. assert(type(key) == "string", "Attempted to index headers table with a non-string key")
  241. local lowerkey = string.lower(key)
  242. local result = rawget(self, lowerkey)
  243. if result == nil then
  244. result = {}
  245. rawset(self, lowerkey, result)
  246. end
  247. rawset(self, key, result)
  248. return result
  249. end
  250. }),
  251. -- table mapping header field names to value-lists
  252. -- (for headers with comma separated values):
  253. headers_csv_table = setmetatable({}, {
  254. __index = function(self, key)
  255. local result = {}
  256. for i, line in ipairs(request.headers[key]) do
  257. for entry in string.gmatch(line, "[^,]+") do
  258. local value = string.match(entry, "^[ \t]*(..-)[ \t]*$")
  259. if value then
  260. result[#result+1] = value
  261. end
  262. end
  263. end
  264. self[key] = result
  265. return result
  266. end
  267. }),
  268. -- table mapping header field names to a comma separated string
  269. -- (for headers with comma separated values):
  270. headers_csv_string = setmetatable({}, {
  271. __index = function(self, key)
  272. local result = {}
  273. for i, line in ipairs(request.headers[key]) do
  274. result[#result+1] = line
  275. end
  276. result = table.concat(result, ", ")
  277. self[key] = result
  278. return result
  279. end
  280. }),
  281. -- table mapping header field names to a single string value
  282. -- (or false if header has been sent multiple times):
  283. headers_value = setmetatable({}, {
  284. __index = function(self, key)
  285. if headers_value_nil[key] then
  286. return nil
  287. end
  288. local values = request.headers_csv_table[key]
  289. if #values == 0 then
  290. headers_value_nil[key] = true
  291. else
  292. local result
  293. if #values == 1 then
  294. result = values[1]
  295. else
  296. result = false
  297. end
  298. self[key] = result
  299. return result
  300. end
  301. end
  302. }),
  303. -- table mapping header field names to a flag table,
  304. -- indicating if the comma separated value contains certain entries:
  305. headers_flags = setmetatable({}, {
  306. __index = function(self, key)
  307. local result = setmetatable({}, {
  308. __index = function(self, key)
  309. assert(type(key) == "string", "Attempted to index header flag table with a non-string key")
  310. local lowerkey = string.lower(key)
  311. local result = rawget(self, lowerkey) or false
  312. self[lowerkey] = result
  313. self[key] = result
  314. return result
  315. end
  316. })
  317. for i, value in ipairs(request.headers_csv_table[key]) do
  318. result[string.lower(value)] = true
  319. end
  320. self[key] = result
  321. return result
  322. end
  323. })
  324. }
  325. -- create metatable for request object:
  326. local request_mt = {}
  327. setmetatable(request, request_mt)
  328. -- callback for request body streaming:
  329. local process_body_chunk
  330. -- function to enable draining:
  331. local function enable_drain()
  332. consume = drain
  333. process_body_chunk = nil -- allow for early garbage collection
  334. end
  335. -- local variables to track the state:
  336. local state = "init" -- one of:
  337. -- "init" (initial state)
  338. -- "no_status_sent" (request body streaming config complete)
  339. -- "info_status_sent" (1xx status code has been sent)
  340. -- "bodyless_status_sent" (204/304 status code has been sent)
  341. -- "status_sent" (regular status code has been sent)
  342. -- "headers_sent" (headers have been terminated)
  343. -- "finished" (request has been answered completely)
  344. -- "faulty" (I/O or protocaol error)
  345. local request_body_content_length -- Content-Length of request body
  346. local close_requested = false -- "Connection: close" requested
  347. local close_responded = false -- "Connection: close" sent
  348. local content_length = nil -- value of Content-Length header sent
  349. local bytes_sent = 0 -- number of bytes sent if Content-Length is set
  350. local chunk_parts = {} -- list of chunks to send
  351. local chunk_bytes = 0 -- sum of lengths of chunks to send
  352. local streamed_post_params = {} -- mapping from POST field name to stream function
  353. local streamed_post_param_patterns = {} -- list of POST field pattern and stream function pairs
  354. -- function to report an error:
  355. local function request_error(throw_error, status, text)
  356. local response_sent = false
  357. if
  358. state == "init" or
  359. state == "no_status_sent" or
  360. state == "info_status_sent"
  361. then
  362. local error_response_status, errmsg = pcall(function()
  363. request:monologue()
  364. request:send_status(status)
  365. request:send_header("Content-Type", "text/plain")
  366. request:send_data(status, "\n")
  367. if text then
  368. request:send_data("\n", text, "\n")
  369. end
  370. request:finish()
  371. end)
  372. if not error_response_status then
  373. if text then
  374. error("Error while sending error response (" .. status .. " / " .. text .. "): " .. errmsg)
  375. else
  376. error("Error while sending error response (" .. status .. "): " .. errmsg)
  377. end
  378. end
  379. response_sent = true
  380. end
  381. if throw_error then
  382. local errmsg
  383. if response_sent then
  384. errmsg = "Error while reading request from client. Error response: "
  385. else
  386. errmsg = "Error while reading request from client: "
  387. end
  388. errmsg = errmsg .. status
  389. if text then
  390. errmsg = errmsg .. " (" .. text .. ")"
  391. end
  392. error(errmsg)
  393. else
  394. return survive
  395. end
  396. end
  397. -- function that enforces consumption of all input:
  398. local function consume_all(timeout)
  399. local starttime = timeout and moonbridge_io.timeref()
  400. while consume do
  401. if timeout then
  402. -- passed timeout does not get reset but refers to starttime
  403. if not poll(socket_set, nil, timeout-moonbridge_io.timeref(starttime)) then
  404. return false
  405. end
  406. else
  407. -- stall_timeout gets reset for every poll
  408. if not poll(socket_set, nil, stall_timeout) then
  409. request_error(true, "408 Request Timeout", "Timeout while waiting for request body")
  410. end
  411. end
  412. consume()
  413. end
  414. return true
  415. end
  416. -- function to assert non-faulty handle:
  417. local function assert_not_faulty()
  418. assert(state ~= "faulty", "Tried to use faulty request handle")
  419. end
  420. -- functions to send data to the browser:
  421. local function send(...)
  422. local old_state = state; state = "faulty"
  423. local success, errmsg = socket:write_call(unblock, ...)
  424. if not success then
  425. socket:reset()
  426. error("Could not send data to client: " .. errmsg)
  427. end
  428. state = old_state
  429. end
  430. local function send_flush(...)
  431. local old_state = state; state = "faulty"
  432. local success, errmsg = socket:flush_call(unblock, ...)
  433. if not success then
  434. socket:reset()
  435. error("Could not send data to client: " .. errmsg)
  436. end
  437. state = old_state
  438. end
  439. -- function to assert proper finish/close/reset:
  440. local function assert_close(retval, errmsg)
  441. if not retval then
  442. error("Could not finish sending data to client: " .. errmsg)
  443. end
  444. end
  445. -- function to finish request:
  446. local function finish()
  447. if close_responded then
  448. -- discard any input:
  449. enable_drain()
  450. -- close output stream:
  451. send_flush()
  452. assert_close(socket:finish())
  453. -- wait for EOF from peer to avoid immediate TCP RST condition:
  454. if consume_all(drain_timeout) then
  455. -- fully close socket:
  456. assert_close(socket:close())
  457. else
  458. -- send TCP RST if draining input takes too long:
  459. assert_close(socket:reset())
  460. end
  461. else
  462. -- flush outgoing data:
  463. send_flush()
  464. -- consume incoming data:
  465. consume_all()
  466. end
  467. end
  468. -- function that writes out buffered chunks (without flushing the socket):
  469. function send_chunk()
  470. if chunk_bytes > 0 then
  471. local old_state = state; state = "faulty"
  472. send(string.format("%x\r\n", chunk_bytes))
  473. for i = 1, #chunk_parts do
  474. send(chunk_parts[i])
  475. chunk_parts[i] = nil
  476. end
  477. chunk_bytes = 0
  478. send("\r\n")
  479. state = old_state
  480. end
  481. end
  482. -- read functions
  483. local function read(...)
  484. local data, status = socket:read_yield(...)
  485. if data == nil then
  486. request_error(true, "400 Bad Request", "Read error")
  487. end
  488. if status == "eof" then
  489. request_error(true, "400 Bad Request", "Unexpected EOF")
  490. end
  491. return data
  492. end
  493. local function read_eof(...)
  494. local data, status = socket:read_yield(...)
  495. if data == nil then
  496. request_error(true, "400 Bad Request", "Read error")
  497. end
  498. if status == "eof" then
  499. if data == "" then
  500. return nil
  501. else
  502. request_error(true, "400 Bad Request", "Unexpected EOF")
  503. end
  504. end
  505. return data
  506. end
  507. -- reads a number of bytes from the socket,
  508. -- optionally feeding these bytes chunk-wise into
  509. -- the "process_body_chunk" callback function:
  510. local function read_body_bytes(remaining)
  511. while remaining > 0 do
  512. coroutine.yield() -- do not read more than necessary
  513. local chunklen
  514. if remaining > input_chunk_size then
  515. chunklen = input_chunk_size
  516. else
  517. chunklen = remaining
  518. end
  519. local chunk = read(chunklen)
  520. remaining = remaining - chunklen
  521. if process_body_chunk then
  522. process_body_chunk(chunk)
  523. end
  524. end
  525. end
  526. -- coroutine for request body processing:
  527. local function read_body()
  528. if request.headers_flags["Transfer-Encoding"]["chunked"] then
  529. coroutine.yield() -- do not read on first invocation
  530. local limit = body_size_limit
  531. while true do
  532. local line = read(32 + limit, "\n")
  533. local zeros, lenstr = string.match(line, "^(0*)([1-9A-Fa-f]+[0-9A-Fa-f]*)\r?\n$")
  534. local chunkext
  535. if lenstr then
  536. chunkext = ""
  537. else
  538. zeros, lenstr, chunkext = string.match(line, "^(0*)([1-9A-Fa-f]+[0-9A-Fa-f]*)([ \t;].-)\r?\n$")
  539. end
  540. if not lenstr or #lenstr > 13 then
  541. request_error(true, "400 Bad Request", "Encoding error while reading chunk of request body")
  542. end
  543. local len = tonumber("0x" .. lenstr)
  544. limit = limit - (#zeros + #chunkext + len)
  545. if limit < 0 then
  546. request_error(true, "413 Request Entity Too Large", "Request body size limit exceeded")
  547. end
  548. if len == 0 then break end
  549. read_body_bytes(len)
  550. local term = read(2, "\n")
  551. if term ~= "\r\n" and term ~= "\n" then
  552. request_error(true, "400 Bad Request", "Encoding error while reading chunk of request body")
  553. end
  554. end
  555. while true do
  556. local line = read(2 + limit, "\n")
  557. if line == "\r\n" or line == "\n" then break end
  558. limit = limit - #line
  559. if limit < 0 then
  560. request_error(true, "413 Request Entity Too Large", "Request body size limit exceeded while reading trailer section of chunked request body")
  561. end
  562. end
  563. elseif request_body_content_length then
  564. read_body_bytes(request_body_content_length)
  565. end
  566. if process_body_chunk then
  567. process_body_chunk(nil) -- signal EOF
  568. end
  569. consume = nil -- avoid further resumes
  570. end
  571. -- function to setup default request body handling:
  572. local function default_request_body_handling()
  573. local post_params_list, post_params = new_params_list()
  574. local content_type = request.headers_value["Content-Type"]
  575. if content_type then
  576. if
  577. content_type == "application/x-www-form-urlencoded" or
  578. string.match(content_type, "^application/x%-www%-form%-urlencoded *;")
  579. then
  580. read_urlencoded_form(post_params_list, request.body)
  581. else
  582. local boundary = string.match(
  583. content_type,
  584. '^multipart/form%-data[ \t]*[;,][ \t]*boundary="([^"]+)"$'
  585. ) or string.match(
  586. content_type,
  587. '^multipart/form%-data[ \t]*[;,][ \t]*boundary=([^"; \t]+)$'
  588. )
  589. if boundary then
  590. local post_metadata_list, post_metadata = new_params_list()
  591. boundary = "--" .. boundary
  592. local headerdata = ""
  593. local streamer
  594. local field_name
  595. local metadata = {}
  596. local value_parts
  597. local function default_streamer(chunk)
  598. value_parts[#value_parts+1] = chunk
  599. end
  600. local function stream_part_finish()
  601. if streamer == default_streamer then
  602. local value = table.concat(value_parts)
  603. value_parts = nil
  604. if field_name then
  605. local values = post_params_list[field_name]
  606. values[#values+1] = value
  607. local metadata_entries = post_metadata_list[field_name]
  608. metadata_entries[#metadata_entries+1] = metadata
  609. end
  610. else
  611. streamer()
  612. end
  613. headerdata = ""
  614. streamer = nil
  615. field_name = nil
  616. metadata = {}
  617. end
  618. local function stream_part_chunk(chunk)
  619. if streamer then
  620. streamer(chunk)
  621. else
  622. headerdata = headerdata .. chunk
  623. while true do
  624. local line, remaining = string.match(headerdata, "^(.-)\r?\n(.*)$")
  625. if not line then
  626. break
  627. end
  628. if line == "" then
  629. streamer = streamed_post_params[field_name]
  630. if not streamer then
  631. for i, rule in ipairs(streamed_post_param_patterns) do
  632. if string.match(field_name, rule[1]) then
  633. streamer = rule[2]
  634. break
  635. end
  636. end
  637. end
  638. if not streamer then
  639. value_parts = {}
  640. streamer = default_streamer
  641. end
  642. streamer(remaining, field_name, metadata)
  643. return
  644. end
  645. headerdata = remaining
  646. local header_key, header_value = string.match(line, "^([^:]*):[ \t]*(.-)[ \t]*$")
  647. if not header_key then
  648. request_error(true, "400 Bad Request", "Invalid header in multipart/form-data part")
  649. end
  650. header_key = string.lower(header_key)
  651. if header_key == "content-disposition" then
  652. local escaped_header_value = string.gsub(header_value, '"[^"]*"', function(str)
  653. return string.gsub(str, "=", "==")
  654. end)
  655. field_name = string.match(escaped_header_value, ';[ \t]*name="([^"]*)"')
  656. if field_name then
  657. field_name = string.gsub(field_name, "==", "=")
  658. else
  659. field_name = string.match(header_value, ';[ \t]*name=([^"; \t]+)')
  660. end
  661. metadata.file_name = string.match(escaped_header_value, ';[ \t]*filename="([^"]*)"')
  662. if metadata.file_name then
  663. metadata.file_name = string.gsub(metadata.file_name, "==", "=")
  664. else
  665. string.match(header_value, ';[ \t]*filename=([^"; \t]+)')
  666. end
  667. elseif header_key == "content-type" then
  668. metadata.content_type = header_value
  669. elseif header_key == "content-transfer-encoding" then
  670. request_error(true, "400 Bad Request", "Content-transfer-encoding not supported by multipart/form-data parser")
  671. end
  672. end
  673. end
  674. end
  675. local skippart = true -- ignore data until first boundary
  676. local afterbound = false -- interpret 2 bytes after boundary ("\r\n" or "--")
  677. local terminated = false -- final boundary read
  678. local bigchunk = ""
  679. request:stream_request_body(function(chunk)
  680. if chunk == nil then
  681. if not terminated then
  682. request_error(true, "400 Bad Request", "Premature end of multipart/form-data request body")
  683. end
  684. request.post_params_list, request.post_params = post_params_list, post_params
  685. request.post_metadata_list, request.post_metadata = post_metadata_list, post_metadata
  686. end
  687. if terminated then
  688. return
  689. end
  690. bigchunk = bigchunk .. chunk
  691. while true do
  692. if afterbound then
  693. if #bigchunk <= 2 then
  694. return
  695. end
  696. local terminator = string.sub(bigchunk, 1, 2)
  697. if terminator == "\r\n" then
  698. afterbound = false
  699. bigchunk = string.sub(bigchunk, 3)
  700. elseif terminator == "--" then
  701. terminated = true
  702. bigchunk = nil
  703. return
  704. else
  705. request_error(true, "400 Bad Request", "Error while parsing multipart body (expected CRLF or double minus)")
  706. end
  707. end
  708. local pos1, pos2 = string.find(bigchunk, boundary, 1, true)
  709. if not pos1 then
  710. if not skippart then
  711. local safe = #bigchunk-#boundary
  712. if safe > 0 then
  713. stream_part_chunk(string.sub(bigchunk, 1, safe))
  714. bigchunk = string.sub(bigchunk, safe+1)
  715. end
  716. end
  717. return
  718. end
  719. if not skippart then
  720. stream_part_chunk(string.sub(bigchunk, 1, pos1 - 1))
  721. stream_part_finish()
  722. else
  723. boundary = "\r\n" .. boundary
  724. skippart = false
  725. end
  726. bigchunk = string.sub(bigchunk, pos2 + 1)
  727. afterbound = true
  728. end
  729. end)
  730. return -- finalization is executed in stream handler
  731. else
  732. request_error(true, "415 Unsupported Media Type", "Unknown Content-Type of request body")
  733. end
  734. end
  735. end
  736. request.post_params_list, request.post_params = post_params_list, post_params
  737. end
  738. -- function to prepare body processing:
  739. local function prepare()
  740. assert_not_faulty()
  741. if state ~= "init" then
  742. return
  743. end
  744. if process_body_chunk == nil then
  745. default_request_body_handling()
  746. end
  747. if state ~= "init" then -- re-check if state is still "init"
  748. return
  749. end
  750. consume = coroutine.wrap(read_body)
  751. consume() -- call coroutine once to avoid hangup on empty body
  752. state = "no_status_sent"
  753. if request.headers_flags["Expect"]["100-continue"] then
  754. request:send_status("100 Continue")
  755. request:finish_headers()
  756. end
  757. end
  758. -- method to ignore input and close connection after response:
  759. function request:monologue()
  760. assert_not_faulty()
  761. if
  762. state == "headers_sent" or
  763. state == "finished"
  764. then
  765. error("All HTTP headers have already been sent")
  766. end
  767. local old_state = state; state = "faulty"
  768. enable_drain()
  769. close_requested = true
  770. if old_state == "init" then
  771. state = "no_status_sent"
  772. else
  773. state = old_state
  774. end
  775. end
  776. -- method to send a HTTP response status (e.g. "200 OK"):
  777. function request:send_status(status)
  778. prepare()
  779. local old_state = state; state = "faulty"
  780. if old_state == "info_status_sent" then
  781. send_flush("\r\n")
  782. elseif old_state ~= "no_status_sent" then
  783. state = old_state
  784. error("HTTP status has already been sent")
  785. end
  786. local status1 = string.sub(status, 1, 1)
  787. local status3 = string.sub(status, 1, 3)
  788. send("HTTP/1.1 ", status, "\r\n", preamble)
  789. local wrb = status_without_response_body[status3]
  790. if wrb then
  791. state = "bodyless_status_sent"
  792. if wrb == "zero_content_length" then
  793. request:send_header("Content-Length", 0)
  794. end
  795. elseif status1 == "1" then
  796. state = "info_status_sent"
  797. else
  798. state = "status_sent"
  799. end
  800. end
  801. -- method to send a HTTP response header:
  802. -- (key and value must be provided as separate args)
  803. function request:send_header(key, value)
  804. assert_not_faulty()
  805. if state == "init" or state == "no_status_sent" then
  806. error("HTTP status has not been sent yet")
  807. elseif
  808. state == "headers_sent" or
  809. state == "finished"
  810. then
  811. error("All HTTP headers have already been sent")
  812. end
  813. local old_state = state; state = "faulty"
  814. local key_lower = string.lower(key)
  815. if key_lower == "content-length" then
  816. if old_state == "info_status_sent" then
  817. state = old_state
  818. error("Cannot set Content-Length for informational status response")
  819. end
  820. local cl = assert(tonumber(value), "Invalid content-length")
  821. if content_length == nil then
  822. content_length = cl
  823. elseif content_length == cl then
  824. return
  825. else
  826. error("Content-Length has been set multiple times with different values")
  827. end
  828. elseif key_lower == "connection" then
  829. for entry in string.gmatch(string.lower(value), "[^,]+") do
  830. if string.match(entry, "^[ \t]*close[ \t]*$") then
  831. if old_state == "info_status_sent" then
  832. state = old_state
  833. error("Cannot set \"Connection: close\" for informational status response")
  834. end
  835. close_responded = true
  836. break
  837. end
  838. end
  839. end
  840. send(key, ": ", value, "\r\n")
  841. state = old_state
  842. end
  843. -- method to announce (and enforce) connection close after sending the
  844. -- response:
  845. function request:close_after_finish()
  846. assert_not_faulty()
  847. if state == "headers_sent" or state == "finished" then
  848. error("All HTTP headers have already been sent")
  849. end
  850. close_requested = true
  851. end
  852. -- function to terminate header section in response, optionally flushing:
  853. -- (may be called multiple times unless response is finished)
  854. local function finish_headers(with_flush)
  855. if state == "finished" then
  856. error("Response has already been finished")
  857. elseif state == "info_status_sent" then
  858. state = "faulty"
  859. send_flush("\r\n")
  860. state = "no_status_sent"
  861. elseif state == "bodyless_status_sent" then
  862. if close_requested and not close_responded then
  863. request:send_header("Connection", "close")
  864. end
  865. state = "faulty"
  866. send("\r\n")
  867. finish()
  868. state = "finished"
  869. elseif state == "status_sent" then
  870. if not content_length then
  871. request:send_header("Transfer-Encoding", "chunked")
  872. end
  873. if close_requested and not close_responded then
  874. request:send_header("Connection", "close")
  875. end
  876. state = "faulty"
  877. send("\r\n")
  878. if request.method == "HEAD" then
  879. finish()
  880. elseif with_flush then
  881. send_flush()
  882. end
  883. state = "headers_sent"
  884. elseif state ~= "headers_sent" then
  885. error("HTTP status has not been sent yet")
  886. end
  887. end
  888. -- method to finish and flush headers:
  889. function request:finish_headers()
  890. assert_not_faulty()
  891. finish_headers(true)
  892. end
  893. -- method to send body data:
  894. function request:send_data(...)
  895. assert_not_faulty()
  896. if state == "info_status_sent" then
  897. error("No (non-informational) HTTP status has been sent yet")
  898. elseif state == "bodyless_status_sent" then
  899. error("Cannot send response data for body-less status message")
  900. end
  901. finish_headers(false)
  902. if state ~= "headers_sent" then
  903. error("Unexpected internal status in HTTP engine")
  904. end
  905. if request.method == "HEAD" then
  906. return
  907. end
  908. state = "faulty"
  909. for i = 1, select("#", ...) do
  910. local str = tostring(select(i, ...))
  911. if #str > 0 then
  912. if content_length then
  913. local bytes_to_send = #str
  914. if bytes_sent + bytes_to_send > content_length then
  915. error("Content length exceeded")
  916. else
  917. send(str)
  918. bytes_sent = bytes_sent + bytes_to_send
  919. end
  920. else
  921. chunk_bytes = chunk_bytes + #str
  922. chunk_parts[#chunk_parts+1] = str
  923. end
  924. end
  925. end
  926. if chunk_bytes >= output_chunk_size then
  927. send_chunk()
  928. end
  929. state = "headers_sent"
  930. end
  931. -- method to flush output buffer:
  932. function request:flush()
  933. assert_not_faulty()
  934. send_chunk()
  935. send_flush()
  936. end
  937. -- method to finish response:
  938. function request:finish()
  939. assert_not_faulty()
  940. if state == "finished" then
  941. return
  942. elseif state == "info_status_sent" then
  943. error("Informational HTTP response can be finished with :finish_headers() method")
  944. end
  945. finish_headers(false)
  946. if state == "headers_sent" then
  947. if request.method ~= "HEAD" then
  948. state = "faulty"
  949. if content_length then
  950. if bytes_sent ~= content_length then
  951. error("Content length not used")
  952. end
  953. else
  954. send_chunk()
  955. send("0\r\n\r\n")
  956. end
  957. finish()
  958. end
  959. state = "finished"
  960. elseif state ~= "finished" then
  961. error("Unexpected internal status in HTTP engine")
  962. end
  963. end
  964. -- method to register POST param stream handler for a single field name:
  965. function request:stream_post_param(field_name, callback)
  966. if state ~= "init" then
  967. error("Cannot setup request body streamer at this stage anymore")
  968. end
  969. streamed_post_params[field_name] = callback
  970. end
  971. -- method to register POST param stream handler for a field name pattern:
  972. function request:stream_post_params(pattern, callback)
  973. if state ~= "init" then
  974. error("Cannot setup request body streamer at this stage anymore")
  975. end
  976. streamed_post_param_patterns[#streamed_post_param_patterns+1] = {pattern, callback}
  977. end
  978. -- method to register request body stream handler
  979. function request:stream_request_body(callback)
  980. if state ~= "init" then
  981. error("Cannot setup request body streamer at this stage anymore")
  982. end
  983. local inprogress = false
  984. local eof = false
  985. local buffer = {}
  986. process_body_chunk = function(chunk)
  987. if inprogress then
  988. if chunk == nil then
  989. eof = true
  990. else
  991. buffer[#buffer+1] = chunk
  992. end
  993. else
  994. inprogress = true
  995. callback(chunk)
  996. while #buffer > 0 do
  997. chunk = table.concat(buffer)
  998. buffer = {}
  999. callback(chunk)
  1000. end
  1001. if eof then
  1002. callback() -- signal EOF
  1003. end
  1004. inprogress = false
  1005. end
  1006. end
  1007. end
  1008. -- method to start reading request body
  1009. function request:consume_input()
  1010. prepare()
  1011. consume_all()
  1012. end
  1013. -- method to stream request body
  1014. function request:stream_request_body_now(callback)
  1015. request:stream_request_body(function(chunk)
  1016. if chunk ~= nil then
  1017. callback(chunk)
  1018. end
  1019. end)
  1020. request:consume_input()
  1021. end
  1022. -- metamethod to read special attibutes of request object:
  1023. function request_mt:__index(key, value)
  1024. if key == "faulty" then
  1025. return state == "faulty"
  1026. elseif key == "fresh" then
  1027. return state == "init" and process_body_chunk == nil
  1028. elseif key == "body" then
  1029. local chunks = {}
  1030. request:stream_request_body_now(function(chunk)
  1031. chunks[#chunks+1] = chunk
  1032. end)
  1033. self.body = table.concat(chunks)
  1034. return self.body
  1035. elseif
  1036. key == "post_params_list" or key == "post_params" or
  1037. key == "post_metadata_list" or key == "post_metadata"
  1038. then
  1039. prepare()
  1040. consume_all()
  1041. return rawget(self, key)
  1042. end
  1043. end
  1044. -- variable to store request target
  1045. local target
  1046. -- coroutine for reading headers:
  1047. local function read_headers()
  1048. -- initialize limit:
  1049. local limit = header_size_limit
  1050. -- read and parse request line:
  1051. local line = read_eof(limit, "\n")
  1052. if not line then
  1053. return false, survive
  1054. end
  1055. limit = limit - #line
  1056. if limit == 0 then
  1057. return false, request_error(false, "414 Request-URI Too Long")
  1058. end
  1059. local proto
  1060. request.method, target, proto =
  1061. line:match("^([^ \t\r]+)[ \t]+([^ \t\r]+)[ \t]*([^ \t\r]*)[ \t]*\r?\n$")
  1062. if not request.method then
  1063. return false, request_error(false, "400 Bad Request")
  1064. elseif proto ~= "HTTP/1.1" then
  1065. return false, request_error(false, "505 HTTP Version Not Supported")
  1066. end
  1067. -- read and parse headers:
  1068. while true do
  1069. local line = read(limit, "\n");
  1070. limit = limit - #line
  1071. if line == "\r\n" or line == "\n" then
  1072. break
  1073. end
  1074. if limit == 0 then
  1075. return false, request_error(false, "431 Request Header Fields Too Large")
  1076. end
  1077. local key, value = string.match(line, "^([^ \t\r]+):[ \t]*(.-)[ \t]*\r?\n$")
  1078. if not key then
  1079. return false, request_error(false, "400 Bad Request")
  1080. end
  1081. local values = request.headers[key]
  1082. values[#values+1] = value
  1083. end
  1084. return true -- success
  1085. end
  1086. -- wait for input:
  1087. if not poll(socket_set, nil, idle_timeout) then
  1088. return request_error(false, "408 Request Timeout", "Idle connection timed out")
  1089. end
  1090. -- read headers (with timeout):
  1091. do
  1092. local coro = coroutine.wrap(read_headers)
  1093. local starttime = request_header_timeout and moonbridge_io.timeref()
  1094. while true do
  1095. local status, retval = coro()
  1096. if status == nil then
  1097. local timeout
  1098. if request_header_timeout then
  1099. timeout = request_header_timeout - moonbridge_io.timeref(starttime)
  1100. if stall_timeout and timeout > stall_timeout then
  1101. timeout = stall_timeout
  1102. end
  1103. else
  1104. timeout = stall_timeout
  1105. end
  1106. if not poll(socket_set, nil, timeout) then
  1107. return request_error(false, "408 Request Timeout", "Timeout while receiving headers")
  1108. end
  1109. elseif status == false then
  1110. return retval
  1111. elseif status == true then
  1112. break
  1113. else
  1114. error("Unexpected yield value")
  1115. end
  1116. end
  1117. end
  1118. -- process "Connection: close" header if existent:
  1119. connection_close_requested = request.headers_flags["Connection"]["close"]
  1120. -- process "Content-Length" header if existent:
  1121. do
  1122. local values = request.headers_csv_table["Content-Length"]
  1123. if #values > 0 then
  1124. request_body_content_length = tonumber(values[1])
  1125. local proper_value = tostring(request_body_content_length)
  1126. for i, value in ipairs(values) do
  1127. value = string.match(value, "^0*(.*)")
  1128. if value ~= proper_value then
  1129. return request_error(false, "400 Bad Request", "Content-Length header(s) invalid")
  1130. end
  1131. end
  1132. if request_body_content_length > body_size_limit then
  1133. return request_error(false, "413 Request Entity Too Large", "Announced request body size is too big")
  1134. end
  1135. end
  1136. end
  1137. -- process "Transfer-Encoding" header if existent:
  1138. do
  1139. local flag = request.headers_flags["Transfer-Encoding"]["chunked"]
  1140. local list = request.headers_csv_table["Transfer-Encoding"]
  1141. if (flag and #list ~= 1) or (not flag and #list ~= 0) then
  1142. return request_error(false, "400 Bad Request", "Unexpected Transfer-Encoding")
  1143. end
  1144. end
  1145. -- process "Expect" header if existent:
  1146. for i, value in ipairs(request.headers_csv_table["Expect"]) do
  1147. if string.lower(value) ~= "100-continue" then
  1148. return request_error(false, "417 Expectation Failed", "Unexpected Expect header")
  1149. end
  1150. end
  1151. -- get mandatory Host header according to RFC 7230:
  1152. request.host = request.headers_value["Host"]
  1153. if not request.host then
  1154. return request_error(false, "400 Bad Request", "No valid host header")
  1155. end
  1156. -- parse request target:
  1157. request.path, request.query = string.match(target, "^/([^?]*)(.*)$")
  1158. if not request.path then
  1159. local host2
  1160. host2, request.path, request.query = string.match(target, "^[Hh][Tt][Tt][Pp]://([^/?]+)/?([^?]*)(.*)$")
  1161. if host2 then
  1162. if request.host ~= host2 then
  1163. return request_error(false, "400 Bad Request", "No valid host header")
  1164. end
  1165. elseif not (target == "*" and request.method == "OPTIONS") then
  1166. return request_error(false, "400 Bad Request", "Invalid request target")
  1167. end
  1168. end
  1169. -- parse GET params:
  1170. request.get_params_list, request.get_params = new_params_list()
  1171. if request.query then
  1172. read_urlencoded_form(request.get_params_list, request.query)
  1173. end
  1174. -- parse cookies:
  1175. for i, line in ipairs(request.headers["Cookie"]) do
  1176. for rawkey, rawvalue in
  1177. string.gmatch(line, "([^=; ]*)=([^=; ]*)")
  1178. do
  1179. request.cookies[decode_uri(rawkey)] = decode_uri(rawvalue)
  1180. end
  1181. end
  1182. -- (re)set timeout for handler:
  1183. timeout(response_timeout or 0)
  1184. -- call underlying handler and remember boolean result:
  1185. if handler(request) ~= true then survive = false end
  1186. -- finish request (unless already done by underlying handler):
  1187. request:finish()
  1188. -- stop timeout timer:
  1189. timeout(0)
  1190. until close_responded
  1191. return survive
  1192. end
  1193. end
  1194. return _M