httptest.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. -- needs Alias from /home/c/diego/tec/luasocket/test to
  2. -- "/luasocket-test" and "/luasocket-test/"
  3. -- needs ScriptAlias from /home/c/diego/tec/luasocket/test/cgi
  4. -- to "/luasocket-test-cgi" and "/luasocket-test-cgi/"
  5. -- needs "AllowOverride AuthConfig" on /home/c/diego/tec/luasocket/test/auth
  6. local socket = require("socket")
  7. local http = require("socket.http")
  8. local url = require("socket.url")
  9. local mime = require("mime")
  10. local ltn12 = require("ltn12")
  11. -- override protection to make sure we see all errors
  12. -- socket.protect = function(s) return s end
  13. dofile("testsupport.lua")
  14. local host, proxy, request, response, index_file
  15. local ignore, expect, index, prefix, cgiprefix, index_crlf
  16. http.TIMEOUT = 10
  17. local t = socket.gettime()
  18. --host = host or "diego.student.princeton.edu"
  19. --host = host or "diego.student.princeton.edu"
  20. host = host or "localhost"
  21. proxy = proxy or "http://localhost:3128"
  22. prefix = prefix or "/luasocket-test"
  23. cgiprefix = cgiprefix or "/luasocket-test-cgi"
  24. index_file = "index.html"
  25. -- read index with CRLF convention
  26. index = readfile(index_file)
  27. local check_result = function(response, expect, ignore)
  28. for i,v in pairs(response) do
  29. if not ignore[i] then
  30. if v ~= expect[i] then
  31. local f = io.open("err", "w")
  32. f:write(tostring(v), "\n\n versus\n\n", tostring(expect[i]))
  33. f:close()
  34. fail(i .. " differs!")
  35. end
  36. end
  37. end
  38. for i,v in pairs(expect) do
  39. if not ignore[i] then
  40. if v ~= response[i] then
  41. local f = io.open("err", "w")
  42. f:write(tostring(response[i]), "\n\n versus\n\n", tostring(v))
  43. v = string.sub(type(v) == "string" and v or "", 1, 70)
  44. f:close()
  45. fail(i .. " differs!")
  46. end
  47. end
  48. end
  49. print("ok")
  50. end
  51. local check_request = function(request, expect, ignore)
  52. local t
  53. if not request.sink then request.sink, t = ltn12.sink.table() end
  54. request.source = request.source or
  55. (request.body and ltn12.source.string(request.body))
  56. local response = {}
  57. response.code, response.headers, response.status =
  58. socket.skip(1, http.request(request))
  59. if t and #t > 0 then response.body = table.concat(t) end
  60. check_result(response, expect, ignore)
  61. end
  62. ------------------------------------------------------------------------
  63. io.write("testing request uri correctness: ")
  64. local forth = cgiprefix .. "/request-uri?" .. "this+is+the+query+string"
  65. local back, c, h = http.request("http://" .. host .. forth)
  66. if not back then fail(c) end
  67. back = url.parse(back)
  68. if similar(back.query, "this+is+the+query+string") then print("ok")
  69. else fail(back.query) end
  70. ------------------------------------------------------------------------
  71. io.write("testing query string correctness: ")
  72. forth = "this+is+the+query+string"
  73. back = http.request("http://" .. host .. cgiprefix ..
  74. "/query-string?" .. forth)
  75. if similar(back, forth) then print("ok")
  76. else fail("failed!") end
  77. ------------------------------------------------------------------------
  78. io.write("testing document retrieval: ")
  79. request = {
  80. url = "http://" .. host .. prefix .. "/index.html"
  81. }
  82. expect = {
  83. body = index,
  84. code = 200
  85. }
  86. ignore = {
  87. status = 1,
  88. headers = 1
  89. }
  90. check_request(request, expect, ignore)
  91. ------------------------------------------------------------------------
  92. io.write("testing redirect loop: ")
  93. request = {
  94. url = "http://" .. host .. cgiprefix .. "/redirect-loop"
  95. }
  96. expect = {
  97. code = 302
  98. }
  99. ignore = {
  100. status = 1,
  101. headers = 1,
  102. body = 1
  103. }
  104. check_request(request, expect, ignore)
  105. ------------------------------------------------------------------------
  106. io.write("testing invalid url: ")
  107. local r, e = http.request{url = host .. prefix}
  108. assert(r == nil and e == "invalid host ''")
  109. r, re = http.request(host .. prefix)
  110. assert(r == nil and e == re, tostring(r) ..", " .. tostring(re) ..
  111. " vs " .. tostring(e))
  112. print("ok")
  113. io.write("testing invalid empty port: ")
  114. request = {
  115. url = "http://" .. host .. ":" .. prefix .. "/index.html"
  116. }
  117. expect = {
  118. body = index,
  119. code = 200
  120. }
  121. ignore = {
  122. status = 1,
  123. headers = 1
  124. }
  125. check_request(request, expect, ignore)
  126. ------------------------------------------------------------------------
  127. io.write("testing post method: ")
  128. -- wanted to test chunked post, but apache doesn't support it...
  129. request = {
  130. url = "http://" .. host .. cgiprefix .. "/cat",
  131. method = "POST",
  132. body = index,
  133. -- remove content-length header to send chunked body
  134. headers = { ["content-length"] = string.len(index) }
  135. }
  136. expect = {
  137. body = index,
  138. code = 200
  139. }
  140. ignore = {
  141. status = 1,
  142. headers = 1
  143. }
  144. check_request(request, expect, ignore)
  145. ------------------------------------------------------------------------
  146. --[[
  147. io.write("testing proxy with post method: ")
  148. request = {
  149. url = "http://" .. host .. cgiprefix .. "/cat",
  150. method = "POST",
  151. body = index,
  152. headers = { ["content-length"] = string.len(index) },
  153. proxy= proxy
  154. }
  155. expect = {
  156. body = index,
  157. code = 200
  158. }
  159. ignore = {
  160. status = 1,
  161. headers = 1
  162. }
  163. check_request(request, expect, ignore)
  164. ]]
  165. ------------------------------------------------------------------------
  166. io.write("testing simple post function: ")
  167. back = http.request("http://" .. host .. cgiprefix .. "/cat", index)
  168. assert(back == index)
  169. print("ok")
  170. ------------------------------------------------------------------------
  171. io.write("testing ltn12.(sink|source).file: ")
  172. request = {
  173. url = "http://" .. host .. cgiprefix .. "/cat",
  174. method = "POST",
  175. source = ltn12.source.file(io.open(index_file, "rb")),
  176. sink = ltn12.sink.file(io.open(index_file .. "-back", "wb")),
  177. headers = { ["content-length"] = string.len(index) }
  178. }
  179. expect = {
  180. code = 200
  181. }
  182. ignore = {
  183. status = 1,
  184. headers = 1
  185. }
  186. check_request(request, expect, ignore)
  187. back = readfile(index_file .. "-back")
  188. assert(back == index)
  189. os.remove(index_file .. "-back")
  190. ------------------------------------------------------------------------
  191. io.write("testing ltn12.(sink|source).chain and mime.(encode|decode): ")
  192. local function b64length(len)
  193. local a = math.ceil(len/3)*4
  194. local l = math.ceil(a/76)
  195. return a + l*2
  196. end
  197. local source = ltn12.source.chain(
  198. ltn12.source.file(io.open(index_file, "rb")),
  199. ltn12.filter.chain(
  200. mime.encode("base64"),
  201. mime.wrap("base64")
  202. )
  203. )
  204. local sink = ltn12.sink.chain(
  205. mime.decode("base64"),
  206. ltn12.sink.file(io.open(index_file .. "-back", "wb"))
  207. )
  208. request = {
  209. url = "http://" .. host .. cgiprefix .. "/cat",
  210. method = "POST",
  211. source = source,
  212. sink = sink,
  213. headers = { ["content-length"] = b64length(string.len(index)) }
  214. }
  215. expect = {
  216. code = 200
  217. }
  218. ignore = {
  219. body_cb = 1,
  220. status = 1,
  221. headers = 1
  222. }
  223. check_request(request, expect, ignore)
  224. back = readfile(index_file .. "-back")
  225. assert(back == index)
  226. os.remove(index_file .. "-back")
  227. ------------------------------------------------------------------------
  228. io.write("testing http redirection: ")
  229. request = {
  230. url = "http://" .. host .. prefix
  231. }
  232. expect = {
  233. body = index,
  234. code = 200
  235. }
  236. ignore = {
  237. status = 1,
  238. headers = 1
  239. }
  240. check_request(request, expect, ignore)
  241. ------------------------------------------------------------------------
  242. --[[
  243. io.write("testing proxy with redirection: ")
  244. request = {
  245. url = "http://" .. host .. prefix,
  246. proxy = proxy
  247. }
  248. expect = {
  249. body = index,
  250. code = 200
  251. }
  252. ignore = {
  253. status = 1,
  254. headers = 1
  255. }
  256. check_request(request, expect, ignore)
  257. ]]
  258. ------------------------------------------------------------------------
  259. io.write("testing automatic auth failure: ")
  260. request = {
  261. url = "http://really:wrong@" .. host .. prefix .. "/auth/index.html"
  262. }
  263. expect = {
  264. code = 401
  265. }
  266. ignore = {
  267. body = 1,
  268. status = 1,
  269. headers = 1
  270. }
  271. check_request(request, expect, ignore)
  272. ------------------------------------------------------------------------
  273. io.write("testing http redirection failure: ")
  274. request = {
  275. url = "http://" .. host .. prefix,
  276. redirect = false
  277. }
  278. expect = {
  279. code = 301
  280. }
  281. ignore = {
  282. body = 1,
  283. status = 1,
  284. headers = 1
  285. }
  286. check_request(request, expect, ignore)
  287. ------------------------------------------------------------------------
  288. io.write("testing document not found: ")
  289. request = {
  290. url = "http://" .. host .. "/wrongdocument.html"
  291. }
  292. expect = {
  293. code = 404
  294. }
  295. ignore = {
  296. body = 1,
  297. status = 1,
  298. headers = 1
  299. }
  300. check_request(request, expect, ignore)
  301. ------------------------------------------------------------------------
  302. io.write("testing auth failure: ")
  303. request = {
  304. url = "http://" .. host .. prefix .. "/auth/index.html"
  305. }
  306. expect = {
  307. code = 401
  308. }
  309. ignore = {
  310. body = 1,
  311. status = 1,
  312. headers = 1
  313. }
  314. check_request(request, expect, ignore)
  315. ------------------------------------------------------------------------
  316. io.write("testing manual basic auth: ")
  317. request = {
  318. url = "http://" .. host .. prefix .. "/auth/index.html",
  319. headers = {
  320. authorization = "Basic " .. (mime.b64("luasocket:password"))
  321. }
  322. }
  323. expect = {
  324. code = 200,
  325. body = index
  326. }
  327. ignore = {
  328. status = 1,
  329. headers = 1
  330. }
  331. check_request(request, expect, ignore)
  332. ------------------------------------------------------------------------
  333. io.write("testing automatic basic auth: ")
  334. request = {
  335. url = "http://luasocket:password@" .. host .. prefix .. "/auth/index.html"
  336. }
  337. expect = {
  338. code = 200,
  339. body = index
  340. }
  341. ignore = {
  342. status = 1,
  343. headers = 1
  344. }
  345. check_request(request, expect, ignore)
  346. ------------------------------------------------------------------------
  347. io.write("testing auth info overriding: ")
  348. request = {
  349. url = "http://really:wrong@" .. host .. prefix .. "/auth/index.html",
  350. user = "luasocket",
  351. password = "password"
  352. }
  353. expect = {
  354. code = 200,
  355. body = index
  356. }
  357. ignore = {
  358. status = 1,
  359. headers = 1
  360. }
  361. check_request(request, expect, ignore)
  362. ------------------------------------------------------------------------
  363. io.write("testing cgi output retrieval (probably chunked...): ")
  364. request = {
  365. url = "http://" .. host .. cgiprefix .. "/cat-index-html"
  366. }
  367. expect = {
  368. body = index,
  369. code = 200
  370. }
  371. ignore = {
  372. status = 1,
  373. headers = 1
  374. }
  375. check_request(request, expect, ignore)
  376. ------------------------------------------------------------------------
  377. local body
  378. io.write("testing simple request function: ")
  379. body = http.request("http://" .. host .. prefix .. "/index.html")
  380. assert(body == index)
  381. print("ok")
  382. ------------------------------------------------------------------------
  383. io.write("testing HEAD method: ")
  384. local r, c, h = http.request {
  385. method = "HEAD",
  386. url = "http://www.tecgraf.puc-rio.br/~diego/"
  387. }
  388. assert(r and h and (c == 200), c)
  389. print("ok")
  390. ------------------------------------------------------------------------
  391. io.write("testing host not found: ")
  392. local c, e = socket.connect("example.invalid", 80)
  393. local r, re = http.request{url = "http://example.invalid/does/not/exist"}
  394. assert(r == nil and e == re, tostring(r) .. " " .. tostring(re))
  395. r, re = http.request("http://example.invalid/does/not/exist")
  396. assert(r == nil and e == re)
  397. print("ok")
  398. ------------------------------------------------------------------------
  399. print("passed all tests")
  400. os.remove("err")
  401. print(string.format("done in %.2fs", socket.gettime() - t))