/debian/modules/nginx-lua/src/ngx_http_lua_headers.c

https://github.com/tgbyte/nginx-passenger-debian · C · 496 lines · 357 code · 125 blank · 14 comment · 88 complexity · 8466dfc41f5b67efde5b389831133090 MD5 · raw file

  1. #ifndef DDEBUG
  2. #define DDEBUG 0
  3. #endif
  4. #include "ddebug.h"
  5. #include "ngx_http_lua_headers.h"
  6. #include "ngx_http_lua_headers_out.h"
  7. #include "ngx_http_lua_headers_in.h"
  8. #include "ngx_http_lua_util.h"
  9. static int ngx_http_lua_ngx_req_header_set_helper(lua_State *L);
  10. static int ngx_http_lua_ngx_header_get(lua_State *L);
  11. static int ngx_http_lua_ngx_header_set(lua_State *L);
  12. static int ngx_http_lua_ngx_req_get_headers(lua_State *L);
  13. static int ngx_http_lua_ngx_req_header_clear(lua_State *L);
  14. static int ngx_http_lua_ngx_req_header_set(lua_State *L);
  15. static int
  16. ngx_http_lua_ngx_req_get_headers(lua_State *L) {
  17. ngx_list_part_t *part;
  18. ngx_table_elt_t *header;
  19. ngx_http_request_t *r;
  20. ngx_uint_t i;
  21. int n;
  22. int max;
  23. int raw = 0;
  24. int count = 0;
  25. n = lua_gettop(L);
  26. if (n >= 1) {
  27. if (lua_isnil(L, 1)) {
  28. max = NGX_HTTP_LUA_MAX_HEADERS;
  29. } else {
  30. max = luaL_checkinteger(L, 1);
  31. lua_pop(L, 1);
  32. }
  33. if (n >= 2) {
  34. raw = lua_toboolean(L, 2);
  35. }
  36. } else {
  37. max = NGX_HTTP_LUA_MAX_HEADERS;
  38. }
  39. lua_pushlightuserdata(L, &ngx_http_lua_request_key);
  40. lua_rawget(L, LUA_GLOBALSINDEX);
  41. r = lua_touserdata(L, -1);
  42. lua_pop(L, 1);
  43. if (r == NULL) {
  44. return luaL_error(L, "no request object found");
  45. }
  46. lua_createtable(L, 0, 4);
  47. if (!raw) {
  48. lua_pushlightuserdata(L, &ngx_http_lua_req_get_headers_metatable_key);
  49. lua_rawget(L, LUA_REGISTRYINDEX);
  50. lua_setmetatable(L, -2);
  51. }
  52. part = &r->headers_in.headers.part;
  53. header = part->elts;
  54. for (i = 0; /* void */; i++) {
  55. dd("stack top: %d", lua_gettop(L));
  56. if (i >= part->nelts) {
  57. if (part->next == NULL) {
  58. break;
  59. }
  60. part = part->next;
  61. header = part->elts;
  62. i = 0;
  63. }
  64. if (raw) {
  65. lua_pushlstring(L, (char *) header[i].key.data, header[i].key.len);
  66. } else {
  67. lua_pushlstring(L, (char *) header[i].lowcase_key,
  68. header[i].key.len);
  69. }
  70. /* stack: table key */
  71. lua_pushlstring(L, (char *) header[i].value.data,
  72. header[i].value.len); /* stack: table key value */
  73. ngx_http_lua_set_multi_value_table(L, -3);
  74. ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  75. "lua request header: \"%V: %V\"",
  76. &header[i].key, &header[i].value);
  77. if (max > 0 && ++count == max) {
  78. ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  79. "lua hit request header limit %d", max);
  80. return 1;
  81. }
  82. }
  83. return 1;
  84. }
  85. static int
  86. ngx_http_lua_ngx_header_get(lua_State *L)
  87. {
  88. ngx_http_request_t *r;
  89. u_char *p;
  90. ngx_str_t key;
  91. ngx_uint_t i;
  92. size_t len;
  93. ngx_http_lua_loc_conf_t *llcf;
  94. lua_pushlightuserdata(L, &ngx_http_lua_request_key);
  95. lua_rawget(L, LUA_GLOBALSINDEX);
  96. r = lua_touserdata(L, -1);
  97. lua_pop(L, 1);
  98. if (r == NULL) {
  99. return luaL_error(L, "no request object found");
  100. }
  101. /* we skip the first argument that is the table */
  102. p = (u_char *) luaL_checklstring(L, 2, &len);
  103. dd("key: %.*s, len %d", (int) len, p, (int) len);
  104. llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
  105. if (llcf->transform_underscores_in_resp_headers) {
  106. /* replace "_" with "-" */
  107. for (i = 0; i < len; i++) {
  108. if (p[i] == '_') {
  109. p[i] = '-';
  110. }
  111. }
  112. }
  113. key.data = ngx_palloc(r->pool, len + 1);
  114. if (key.data == NULL) {
  115. return luaL_error(L, "out of memory");
  116. }
  117. ngx_memcpy(key.data, p, len);
  118. key.data[len] = '\0';
  119. key.len = len;
  120. return ngx_http_lua_get_output_header(L, r, &key);
  121. }
  122. static int
  123. ngx_http_lua_ngx_header_set(lua_State *L)
  124. {
  125. ngx_http_request_t *r;
  126. u_char *p;
  127. ngx_str_t key;
  128. ngx_str_t value;
  129. ngx_uint_t i;
  130. size_t len;
  131. ngx_http_lua_ctx_t *ctx;
  132. ngx_int_t rc;
  133. ngx_uint_t n;
  134. ngx_http_lua_loc_conf_t *llcf;
  135. lua_pushlightuserdata(L, &ngx_http_lua_request_key);
  136. lua_rawget(L, LUA_GLOBALSINDEX);
  137. r = lua_touserdata(L, -1);
  138. lua_pop(L, 1);
  139. if (r == NULL) {
  140. return luaL_error(L, "no request object found");
  141. }
  142. ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
  143. if (ctx->headers_sent) {
  144. return luaL_error(L, "attempt to set ngx.header.HEADER after "
  145. "sending out response headers");
  146. }
  147. /* we skip the first argument that is the table */
  148. p = (u_char *) luaL_checklstring(L, 2, &len);
  149. dd("key: %.*s, len %d", (int) len, p, (int) len);
  150. llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
  151. if (llcf->transform_underscores_in_resp_headers) {
  152. /* replace "_" with "-" */
  153. for (i = 0; i < len; i++) {
  154. if (p[i] == '_') {
  155. p[i] = '-';
  156. }
  157. }
  158. }
  159. key.data = ngx_palloc(r->pool, len + 1);
  160. if (key.data == NULL) {
  161. return luaL_error(L, "out of memory");
  162. }
  163. ngx_memcpy(key.data, p, len);
  164. key.data[len] = '\0';
  165. key.len = len;
  166. if (!ctx->headers_set) {
  167. rc = ngx_http_set_content_type(r);
  168. if (rc != NGX_OK) {
  169. return luaL_error(L,
  170. "failed to set default content type: %d",
  171. (int) rc);
  172. }
  173. ctx->headers_set = 1;
  174. }
  175. if (lua_type(L, 3) == LUA_TNIL) {
  176. value.data = NULL;
  177. value.len = 0;
  178. } else if (lua_type(L, 3) == LUA_TTABLE) {
  179. n = luaL_getn(L, 3);
  180. if (n == 0) {
  181. value.data = NULL;
  182. value.len = 0;
  183. } else {
  184. for (i = 1; i <= n; i++) {
  185. dd("header value table index %d", (int) i);
  186. lua_rawgeti(L, 3, i);
  187. p = (u_char *) luaL_checklstring(L, -1, &len);
  188. value.data = ngx_palloc(r->pool, len);
  189. if (value.data == NULL) {
  190. return luaL_error(L, "out of memory");
  191. }
  192. ngx_memcpy(value.data, p, len);
  193. value.len = len;
  194. rc = ngx_http_lua_set_output_header(r, key, value,
  195. i == 1 /* override */);
  196. if (rc == NGX_ERROR) {
  197. return luaL_error(L,
  198. "failed to set header %s (error: %d)",
  199. key.data, (int) rc);
  200. }
  201. }
  202. return 0;
  203. }
  204. } else {
  205. p = (u_char *) luaL_checklstring(L, 3, &len);
  206. value.data = ngx_palloc(r->pool, len);
  207. if (value.data == NULL) {
  208. return luaL_error(L, "out of memory");
  209. }
  210. ngx_memcpy(value.data, p, len);
  211. value.len = len;
  212. }
  213. dd("key: %.*s, value: %.*s",
  214. (int) key.len, key.data, (int) value.len, value.data);
  215. rc = ngx_http_lua_set_output_header(r, key, value, 1 /* override */);
  216. if (rc == NGX_ERROR) {
  217. return luaL_error(L, "failed to set header %s (error: %d)",
  218. key.data, (int) rc);
  219. }
  220. return 0;
  221. }
  222. static int
  223. ngx_http_lua_ngx_req_header_clear(lua_State *L)
  224. {
  225. if (lua_gettop(L) != 1) {
  226. return luaL_error(L, "expecting one arguments, but seen %d",
  227. lua_gettop(L));
  228. }
  229. lua_pushnil(L);
  230. return ngx_http_lua_ngx_req_header_set_helper(L);
  231. }
  232. static int
  233. ngx_http_lua_ngx_req_header_set(lua_State *L)
  234. {
  235. if (lua_gettop(L) != 2) {
  236. return luaL_error(L, "expecting two arguments, but seen %d",
  237. lua_gettop(L));
  238. }
  239. return ngx_http_lua_ngx_req_header_set_helper(L);
  240. }
  241. static int
  242. ngx_http_lua_ngx_req_header_set_helper(lua_State *L)
  243. {
  244. ngx_http_request_t *r;
  245. u_char *p;
  246. ngx_str_t key;
  247. ngx_str_t value;
  248. ngx_uint_t i;
  249. size_t len;
  250. ngx_int_t rc;
  251. ngx_uint_t n;
  252. lua_pushlightuserdata(L, &ngx_http_lua_request_key);
  253. lua_rawget(L, LUA_GLOBALSINDEX);
  254. r = lua_touserdata(L, -1);
  255. lua_pop(L, 1);
  256. if (r == NULL) {
  257. return luaL_error(L, "no request object found");
  258. }
  259. p = (u_char *) luaL_checklstring(L, 1, &len);
  260. dd("key: %.*s, len %d", (int) len, p, (int) len);
  261. /* replace "_" with "-" */
  262. for (i = 0; i < len; i++) {
  263. if (p[i] == '_') {
  264. p[i] = '-';
  265. }
  266. }
  267. key.data = ngx_palloc(r->pool, len + 1);
  268. if (key.data == NULL) {
  269. return luaL_error(L, "out of memory");
  270. }
  271. ngx_memcpy(key.data, p, len);
  272. key.data[len] = '\0';
  273. key.len = len;
  274. if (lua_type(L, 2) == LUA_TNIL) {
  275. value.data = NULL;
  276. value.len = 0;
  277. } else if (lua_type(L, 2) == LUA_TTABLE) {
  278. n = luaL_getn(L, 2);
  279. if (n == 0) {
  280. value.data = NULL;
  281. value.len = 0;
  282. } else {
  283. for (i = 1; i <= n; i++) {
  284. dd("header value table index %d, top: %d", (int) i,
  285. lua_gettop(L));
  286. lua_rawgeti(L, 2, i);
  287. p = (u_char *) luaL_checklstring(L, -1, &len);
  288. /*
  289. * we also copy the trailling '\0' char here because nginx
  290. * header values must be null-terminated
  291. * */
  292. value.data = ngx_palloc(r->pool, len + 1);
  293. if (value.data == NULL) {
  294. return luaL_error(L, "out of memory");
  295. }
  296. ngx_memcpy(value.data, p, len + 1);
  297. value.len = len;
  298. rc = ngx_http_lua_set_input_header(r, key, value,
  299. i == 1 /* override */);
  300. if (rc == NGX_ERROR) {
  301. return luaL_error(L,
  302. "failed to set header %s (error: %d)",
  303. key.data, (int) rc);
  304. }
  305. }
  306. return 0;
  307. }
  308. } else {
  309. /*
  310. * we also copy the trailling '\0' char here because nginx
  311. * header values must be null-terminated
  312. * */
  313. p = (u_char *) luaL_checklstring(L, 2, &len);
  314. value.data = ngx_palloc(r->pool, len + 1);
  315. if (value.data == NULL) {
  316. return luaL_error(L, "out of memory");
  317. }
  318. ngx_memcpy(value.data, p, len + 1);
  319. value.len = len;
  320. }
  321. dd("key: %.*s, value: %.*s",
  322. (int) key.len, key.data, (int) value.len, value.data);
  323. rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */);
  324. if (rc == NGX_ERROR) {
  325. return luaL_error(L, "failed to set header %s (error: %d)",
  326. key.data, (int) rc);
  327. }
  328. return 0;
  329. }
  330. void
  331. ngx_http_lua_inject_resp_header_api(lua_State *L)
  332. {
  333. lua_newtable(L); /* .header */
  334. lua_createtable(L, 0, 2); /* metatable for .header */
  335. lua_pushcfunction(L, ngx_http_lua_ngx_header_get);
  336. lua_setfield(L, -2, "__index");
  337. lua_pushcfunction(L, ngx_http_lua_ngx_header_set);
  338. lua_setfield(L, -2, "__newindex");
  339. lua_setmetatable(L, -2);
  340. lua_setfield(L, -2, "header");
  341. }
  342. void
  343. ngx_http_lua_inject_req_header_api(ngx_log_t *log, lua_State *L)
  344. {
  345. int rc;
  346. lua_pushcfunction(L, ngx_http_lua_ngx_req_header_clear);
  347. lua_setfield(L, -2, "clear_header");
  348. lua_pushcfunction(L, ngx_http_lua_ngx_req_header_set);
  349. lua_setfield(L, -2, "set_header");
  350. lua_pushcfunction(L, ngx_http_lua_ngx_req_get_headers);
  351. lua_setfield(L, -2, "get_headers");
  352. lua_pushlightuserdata(L, &ngx_http_lua_req_get_headers_metatable_key);
  353. lua_createtable(L, 0, 1); /* metatable for ngx.req.get_headers(_, true) */
  354. {
  355. const char buf[] =
  356. "local tb, key = ...\n"
  357. "local new_key = string.gsub(string.lower(key), '_', '-')\n"
  358. "if new_key ~= key then return tb[new_key] else return nil end";
  359. rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1,
  360. "ngx.req.get_headers __index");
  361. }
  362. if (rc != 0) {
  363. ngx_log_error(NGX_LOG_ERR, log, 0,
  364. "failed to load Lua code of the metamethod for "
  365. "ngx.req.get_headers: %i: %s", rc, lua_tostring(L, -1));
  366. lua_pop(L, 3);
  367. return;
  368. }
  369. lua_setfield(L, -2, "__index");
  370. lua_rawset(L, LUA_REGISTRYINDEX);
  371. }