1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
3 #include "proxy.h"
4
mcplib_response_elapsed(lua_State * L)5 int mcplib_response_elapsed(lua_State *L) {
6 mcp_resp_t *r = luaL_checkudata(L, -1, "mcp.response");
7 lua_pushinteger(L, r->elapsed);
8 return 1;
9 }
10
11 // resp:ok()
mcplib_response_ok(lua_State * L)12 int mcplib_response_ok(lua_State *L) {
13 mcp_resp_t *r = luaL_checkudata(L, -1, "mcp.response");
14
15 if (r->status == MCMC_OK) {
16 lua_pushboolean(L, 1);
17 } else {
18 lua_pushboolean(L, 0);
19 }
20
21 return 1;
22 }
23
mcplib_response_hit(lua_State * L)24 int mcplib_response_hit(lua_State *L) {
25 mcp_resp_t *r = luaL_checkudata(L, -1, "mcp.response");
26
27 if (r->status == MCMC_OK && r->resp.code != MCMC_CODE_END) {
28 lua_pushboolean(L, 1);
29 } else {
30 lua_pushboolean(L, 0);
31 }
32
33 return 1;
34 }
35
36 // Caller needs to discern if a vlen is 0 because of a failed response or an
37 // OK response that was actually zero. So we always return an integer value
38 // here.
mcplib_response_vlen(lua_State * L)39 int mcplib_response_vlen(lua_State *L) {
40 mcp_resp_t *r = luaL_checkudata(L, -1, "mcp.response");
41
42 // We do remove the "\r\n" from the value length, so if you're actually
43 // processing the value nothing breaks.
44 if (r->resp.vlen >= 2) {
45 lua_pushinteger(L, r->resp.vlen-2);
46 } else {
47 lua_pushinteger(L, 0);
48 }
49
50 return 1;
51 }
52
53 // Refer to MCMC_CODE_* defines.
mcplib_response_code(lua_State * L)54 int mcplib_response_code(lua_State *L) {
55 mcp_resp_t *r = luaL_checkudata(L, -1, "mcp.response");
56
57 lua_pushinteger(L, r->resp.code);
58
59 return 1;
60 }
61
62 // Get the unparsed response line for handling in lua.
mcplib_response_line(lua_State * L)63 int mcplib_response_line(lua_State *L) {
64 mcp_resp_t *r = luaL_checkudata(L, -1, "mcp.response");
65
66 if (r->resp.rline != NULL) {
67 lua_pushlstring(L, r->resp.rline, r->resp.rlen);
68 } else {
69 lua_pushnil(L);
70 }
71
72 return 1;
73 }
74
mcplib_response_flag_blank(lua_State * L)75 int mcplib_response_flag_blank(lua_State *L) {
76 mcp_resp_t *r = luaL_checkudata(L, 1, "mcp.response");
77 mcmc_resp_t reresp;
78 size_t len = 0;
79 const char *flagstr = luaL_checklstring(L, 2, &len);
80
81 if (len != 1) {
82 proxy_lua_error(L, "request: meta flag must be a single character");
83 return 0;
84 }
85 if (flagstr[0] < 65 || flagstr[0] > 122) {
86 proxy_lua_error(L, "request: invalid flag, must be A-Z,a-z");
87 return 0;
88 }
89
90 mcmc_parse_buf(r->buf, r->blen, &reresp);
91
92 if (reresp.type == MCMC_RESP_META) {
93 // r->resp.rline is the start of the meta line... rlen is the length.
94 // we cast away the const and do evil here.
95 char *pos = (char *) reresp.rline;
96 size_t rlen = reresp.rlen;
97
98 char *end = pos + rlen;
99 char flag = flagstr[0];
100
101 while (pos != end) {
102 // either flag is at the start of the line or it has a space
103 // immediately before it.
104 if (*pos == flag && (pos == reresp.rline || *(pos-1) == ' ')) {
105 while (pos != end && !isspace(*pos)) {
106 *pos = ' ';
107 pos++;
108 }
109 lua_pushboolean(L, 1); // found and blanked.
110 return 1;
111 } else {
112 pos++;
113 }
114 }
115
116 // TODO: blank out r->tok?
117 }
118 lua_pushboolean(L, 0); // not found or not done.
119 return 1;
120 }
121
mcp_response_cleanup(LIBEVENT_THREAD * t,mcp_resp_t * r)122 void mcp_response_cleanup(LIBEVENT_THREAD *t, mcp_resp_t *r) {
123 // On error/similar we might be holding the read buffer.
124 // If the buf is handed off to mc_resp for return, this pointer is NULL
125 if (r->buf != NULL) {
126 pthread_mutex_lock(&t->proxy_limit_lock);
127 t->proxy_buffer_memory_used -= r->blen + r->extra;
128 pthread_mutex_unlock(&t->proxy_limit_lock);
129
130 free(r->buf);
131 r->buf = NULL;
132 }
133 r->tok.ntokens = 0;
134
135 // release our temporary mc_resp sub-object.
136 if (r->cresp != NULL) {
137 mc_resp *cresp = r->cresp;
138 assert(r->thread != NULL);
139 if (cresp->item) {
140 item_remove(cresp->item);
141 cresp->item = NULL;
142 }
143 resp_free(r->thread, cresp);
144 r->cresp = NULL;
145 }
146 }
147
mcplib_response_gc(lua_State * L)148 int mcplib_response_gc(lua_State *L) {
149 LIBEVENT_THREAD *t = PROXY_GET_THR(L);
150 mcp_resp_t *r = luaL_checkudata(L, -1, "mcp.response");
151 mcp_response_cleanup(t, r);
152
153 return 0;
154 }
155
156 // Note that this can be called multiple times for a single object, as opposed
157 // to _gc. The cleanup routine is armored against repeat accesses by NULL'ing
158 // th efields it checks.
mcplib_response_close(lua_State * L)159 int mcplib_response_close(lua_State *L) {
160 LIBEVENT_THREAD *t = PROXY_GET_THR(L);
161 mcp_resp_t *r = luaL_checkudata(L, 1, "mcp.response");
162 mcp_response_cleanup(t, r);
163
164 return 0;
165 }
166
167
168