gluahttp_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. package gluahttp
  2. import "github.com/yuin/gopher-lua"
  3. import "testing"
  4. import "io/ioutil"
  5. import "net/http"
  6. import "net"
  7. import "fmt"
  8. import "net/http/cookiejar"
  9. import "strings"
  10. func TestRequestNoMethod(t *testing.T) {
  11. if err := evalLua(t, `
  12. local http = require("http")
  13. response, error = http.request()
  14. assert_equal(nil, response)
  15. assert_contains('unsupported protocol scheme ""', error)
  16. `); err != nil {
  17. t.Errorf("Failed to evaluate script: %s", err)
  18. }
  19. }
  20. func TestRequestNoUrl(t *testing.T) {
  21. if err := evalLua(t, `
  22. local http = require("http")
  23. response, error = http.request("get")
  24. assert_equal(nil, response)
  25. assert_contains('unsupported protocol scheme ""', error)
  26. `); err != nil {
  27. t.Errorf("Failed to evaluate script: %s", err)
  28. }
  29. }
  30. func TestRequestBatch(t *testing.T) {
  31. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  32. setupServer(listener)
  33. if err := evalLua(t, `
  34. local http = require("http")
  35. responses, errors = http.request_batch({
  36. {"get", "http://`+listener.Addr().String()+`", {query="page=1"}},
  37. {"post", "http://`+listener.Addr().String()+`/set_cookie"},
  38. {"post", ""},
  39. 1
  40. })
  41. -- the requests are send asynchronously, so the errors might not be in the same order
  42. -- if we don't sort, the test will be flaky
  43. local errorStrings = {}
  44. for _, err in pairs(errors) do
  45. table.insert(errorStrings, tostring(err))
  46. end
  47. table.sort(errorStrings)
  48. assert_contains('Post : unsupported protocol scheme ""', errorStrings[1])
  49. assert_equal('Request must be a table', errorStrings[2])
  50. assert_equal(nil, errorStrings[3])
  51. assert_equal(nil, errorStrings[4])
  52. assert_equal('Requested GET / with query "page=1"', responses[1]["body"])
  53. assert_equal('Cookie set!', responses[2]["body"])
  54. assert_equal('12345', responses[2]["cookies"]["session_id"])
  55. assert_equal(nil, responses[3])
  56. assert_equal(nil, responses[4])
  57. responses, errors = http.request_batch({
  58. {"get", "http://`+listener.Addr().String()+`/get_cookie"}
  59. })
  60. assert_equal(nil, errors)
  61. assert_equal("session_id=12345", responses[1]["body"])
  62. `); err != nil {
  63. t.Errorf("Failed to evaluate script: %s", err)
  64. }
  65. }
  66. func TestRequestGet(t *testing.T) {
  67. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  68. setupServer(listener)
  69. if err := evalLua(t, `
  70. local http = require("http")
  71. response, error = http.request("get", "http://`+listener.Addr().String()+`")
  72. assert_equal('Requested GET / with query ""', response['body'])
  73. assert_equal(200, response['status_code'])
  74. assert_equal('29', response['headers']['Content-Length'])
  75. assert_equal('text/plain; charset=utf-8', response['headers']['Content-Type'])
  76. `); err != nil {
  77. t.Errorf("Failed to evaluate script: %s", err)
  78. }
  79. }
  80. func TestRequestGetWithRedirect(t *testing.T) {
  81. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  82. setupServer(listener)
  83. if err := evalLua(t, `
  84. local http = require("http")
  85. response, error = http.request("get", "http://`+listener.Addr().String()+`/redirect")
  86. assert_equal('Requested GET / with query ""', response['body'])
  87. assert_equal(200, response['status_code'])
  88. assert_equal('http://`+listener.Addr().String()+`/', response['url'])
  89. `); err != nil {
  90. t.Errorf("Failed to evaluate script: %s", err)
  91. }
  92. }
  93. func TestRequestPostForm(t *testing.T) {
  94. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  95. setupServer(listener)
  96. if err := evalLua(t, `
  97. local http = require("http")
  98. response, error = http.request("post", "http://`+listener.Addr().String()+`", {
  99. form="username=bob&password=secret"
  100. })
  101. assert_equal(
  102. 'Requested POST / with query ""' ..
  103. 'Content-Type: application/x-www-form-urlencoded' ..
  104. 'Content-Length: 28' ..
  105. 'Body: username=bob&password=secret', response['body'])
  106. `); err != nil {
  107. t.Errorf("Failed to evaluate script: %s", err)
  108. }
  109. }
  110. func TestRequestHeaders(t *testing.T) {
  111. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  112. setupServer(listener)
  113. if err := evalLua(t, `
  114. local http = require("http")
  115. response, error = http.request("post", "http://`+listener.Addr().String()+`", {
  116. headers={
  117. ["Content-Type"]="application/json"
  118. }
  119. })
  120. assert_equal(
  121. 'Requested POST / with query ""' ..
  122. 'Content-Type: application/json' ..
  123. 'Content-Length: 0' ..
  124. 'Body: ', response['body'])
  125. `); err != nil {
  126. t.Errorf("Failed to evaluate script: %s", err)
  127. }
  128. }
  129. func TestRequestQuery(t *testing.T) {
  130. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  131. setupServer(listener)
  132. if err := evalLua(t, `
  133. local http = require("http")
  134. response, error = http.request("get", "http://`+listener.Addr().String()+`", {
  135. query="page=2"
  136. })
  137. assert_equal('Requested GET / with query "page=2"', response['body'])
  138. `); err != nil {
  139. t.Errorf("Failed to evaluate script: %s", err)
  140. }
  141. }
  142. func TestGet(t *testing.T) {
  143. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  144. setupServer(listener)
  145. if err := evalLua(t, `
  146. local http = require("http")
  147. response, error = http.get("http://`+listener.Addr().String()+`", {
  148. query="page=1"
  149. })
  150. assert_equal('Requested GET / with query "page=1"', response['body'])
  151. assert_equal(200, response['status_code'])
  152. assert_equal('35', response['headers']['Content-Length'])
  153. assert_equal('text/plain; charset=utf-8', response['headers']['Content-Type'])
  154. `); err != nil {
  155. t.Errorf("Failed to evaluate script: %s", err)
  156. }
  157. }
  158. func TestDelete(t *testing.T) {
  159. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  160. setupServer(listener)
  161. if err := evalLua(t, `
  162. local http = require("http")
  163. response, error = http.delete("http://`+listener.Addr().String()+`", {
  164. query="page=1"
  165. })
  166. assert_equal('Requested DELETE / with query "page=1"', response['body'])
  167. assert_equal(200, response['status_code'])
  168. assert_equal('38', response['headers']['Content-Length'])
  169. assert_equal('text/plain; charset=utf-8', response['headers']['Content-Type'])
  170. `); err != nil {
  171. t.Errorf("Failed to evaluate script: %s", err)
  172. }
  173. }
  174. func TestHead(t *testing.T) {
  175. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  176. setupServer(listener)
  177. if err := evalLua(t, `
  178. local http = require("http")
  179. response, error = http.head("http://`+listener.Addr().String()+`/head", {
  180. query="page=1"
  181. })
  182. assert_equal(200, response['status_code'])
  183. assert_equal("/head?page=1", response['headers']['X-Request-Uri'])
  184. `); err != nil {
  185. t.Errorf("Failed to evaluate script: %s", err)
  186. }
  187. }
  188. func TestPost(t *testing.T) {
  189. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  190. setupServer(listener)
  191. if err := evalLua(t, `
  192. local http = require("http")
  193. response, error = http.post("http://`+listener.Addr().String()+`", {
  194. body="username=bob&password=secret"
  195. })
  196. assert_equal(
  197. 'Requested POST / with query ""' ..
  198. 'Content-Type: ' ..
  199. 'Content-Length: 28' ..
  200. 'Body: username=bob&password=secret', response['body'])
  201. `); err != nil {
  202. t.Errorf("Failed to evaluate script: %s", err)
  203. }
  204. }
  205. func TestPatch(t *testing.T) {
  206. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  207. setupServer(listener)
  208. if err := evalLua(t, `
  209. local http = require("http")
  210. response, error = http.patch("http://`+listener.Addr().String()+`", {
  211. body='{"username":"bob"}',
  212. headers={
  213. ["Content-Type"]="application/json"
  214. }
  215. })
  216. assert_equal(
  217. 'Requested PATCH / with query ""' ..
  218. 'Content-Type: application/json' ..
  219. 'Content-Length: 18' ..
  220. 'Body: {"username":"bob"}', response['body'])
  221. `); err != nil {
  222. t.Errorf("Failed to evaluate script: %s", err)
  223. }
  224. }
  225. func TestPut(t *testing.T) {
  226. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  227. setupServer(listener)
  228. if err := evalLua(t, `
  229. local http = require("http")
  230. response, error = http.put("http://`+listener.Addr().String()+`", {
  231. body="username=bob&password=secret",
  232. headers={
  233. ["Content-Type"]="application/x-www-form-urlencoded"
  234. }
  235. })
  236. assert_equal(
  237. 'Requested PUT / with query ""' ..
  238. 'Content-Type: application/x-www-form-urlencoded' ..
  239. 'Content-Length: 28' ..
  240. 'Body: username=bob&password=secret', response['body'])
  241. `); err != nil {
  242. t.Errorf("Failed to evaluate script: %s", err)
  243. }
  244. }
  245. func TestResponseCookies(t *testing.T) {
  246. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  247. setupServer(listener)
  248. if err := evalLua(t, `
  249. local http = require("http")
  250. response, error = http.get("http://`+listener.Addr().String()+`/set_cookie")
  251. assert_equal('Cookie set!', response["body"])
  252. assert_equal('12345', response["cookies"]["session_id"])
  253. `); err != nil {
  254. t.Errorf("Failed to evaluate script: %s", err)
  255. }
  256. }
  257. func TestRequestCookies(t *testing.T) {
  258. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  259. setupServer(listener)
  260. if err := evalLua(t, `
  261. local http = require("http")
  262. response, error = http.get("http://`+listener.Addr().String()+`/get_cookie", {
  263. cookies={
  264. ["session_id"]="test"
  265. }
  266. })
  267. assert_equal('session_id=test', response["body"])
  268. assert_equal(15, response["body_size"])
  269. `); err != nil {
  270. t.Errorf("Failed to evaluate script: %s", err)
  271. }
  272. }
  273. func TestResponseBodySize(t *testing.T) {
  274. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  275. setupServer(listener)
  276. if err := evalLua(t, `
  277. local http = require("http")
  278. response, error = http.get("http://`+listener.Addr().String()+`/")
  279. assert_equal(29, response["body_size"])
  280. `); err != nil {
  281. t.Errorf("Failed to evaluate script: %s", err)
  282. }
  283. }
  284. func TestResponseBody(t *testing.T) {
  285. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  286. setupServer(listener)
  287. if err := evalLua(t, `
  288. local http = require("http")
  289. response, error = http.get("http://`+listener.Addr().String()+`/")
  290. assert_equal("Requested XXX / with query \"\"", string.gsub(response.body, "GET", "XXX"))
  291. `); err != nil {
  292. t.Errorf("Failed to evaluate script: %s", err)
  293. }
  294. }
  295. func TestResponseUrl(t *testing.T) {
  296. listener, _ := net.Listen("tcp", "127.0.0.1:0")
  297. setupServer(listener)
  298. if err := evalLua(t, `
  299. local http = require("http")
  300. response, error = http.get("http://`+listener.Addr().String()+`/redirect")
  301. assert_equal("http://`+listener.Addr().String()+`/", response["url"])
  302. response, error = http.get("http://`+listener.Addr().String()+`/get_cookie")
  303. assert_equal("http://`+listener.Addr().String()+`/get_cookie", response["url"])
  304. `); err != nil {
  305. t.Errorf("Failed to evaluate script: %s", err)
  306. }
  307. }
  308. func evalLua(t *testing.T, script string) error {
  309. L := lua.NewState()
  310. defer L.Close()
  311. cookieJar, _ := cookiejar.New(nil)
  312. L.PreloadModule("http", NewHttpModule(&http.Client{
  313. Jar: cookieJar,
  314. },
  315. ).Loader)
  316. L.SetGlobal("assert_equal", L.NewFunction(func(L *lua.LState) int {
  317. expected := L.Get(1)
  318. actual := L.Get(2)
  319. if expected.Type() != actual.Type() || expected.String() != actual.String() {
  320. t.Errorf("Expected %s %q, got %s %q", expected.Type(), expected, actual.Type(), actual)
  321. }
  322. return 0
  323. }))
  324. L.SetGlobal("assert_contains", L.NewFunction(func(L *lua.LState) int {
  325. contains := L.Get(1)
  326. actual := L.Get(2)
  327. if !strings.Contains(actual.String(), contains.String()) {
  328. t.Errorf("Expected %s %q contains %s %q", actual.Type(), actual, contains.Type(), contains)
  329. }
  330. return 0
  331. }))
  332. return L.DoString(script)
  333. }
  334. func setupServer(listener net.Listener) {
  335. mux := http.NewServeMux()
  336. mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
  337. fmt.Fprintf(w, "Requested %s / with query %q", req.Method, req.URL.RawQuery)
  338. if req.Method == "POST" || req.Method == "PATCH" || req.Method == "PUT" {
  339. body, _ := ioutil.ReadAll(req.Body)
  340. fmt.Fprintf(w, "Content-Type: %s", req.Header.Get("Content-Type"))
  341. fmt.Fprintf(w, "Content-Length: %s", req.Header.Get("Content-Length"))
  342. fmt.Fprintf(w, "Body: %s", body)
  343. }
  344. })
  345. mux.HandleFunc("/head", func(w http.ResponseWriter, req *http.Request) {
  346. if req.Method == "HEAD" {
  347. w.Header().Set("X-Request-Uri", req.URL.String())
  348. w.WriteHeader(http.StatusOK)
  349. } else {
  350. w.WriteHeader(http.StatusNotFound)
  351. }
  352. })
  353. mux.HandleFunc("/set_cookie", func(w http.ResponseWriter, req *http.Request) {
  354. http.SetCookie(w, &http.Cookie{Name: "session_id", Value: "12345"})
  355. fmt.Fprint(w, "Cookie set!")
  356. })
  357. mux.HandleFunc("/get_cookie", func(w http.ResponseWriter, req *http.Request) {
  358. session_id, _ := req.Cookie("session_id")
  359. fmt.Fprint(w, session_id)
  360. })
  361. mux.HandleFunc("/redirect", func(w http.ResponseWriter, req *http.Request) {
  362. http.Redirect(w, req, "/", http.StatusFound)
  363. })
  364. s := &http.Server{
  365. Handler: mux,
  366. }
  367. go s.Serve(listener)
  368. }