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