2
* Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
5
* "THE BEER-WARE LICENSE" (Revision 42):
6
* Sergey Lyubka wrote this file. As long as you retain this notice you
7
* can do whatever you want with this stuff. If we meet some day, and you think
8
* this stuff is worth it, you can buy me a beer in return.
20
call_user(struct conn *c, struct shttpd_arg *arg, shttpd_callback_t func)
23
arg->state = c->loc.chan.emb.state;
24
arg->out.buf = io_space(&c->loc.io);
25
arg->out.len = io_space_len(&c->loc.io);
26
arg->out.num_bytes = 0;
27
arg->in.buf = io_data(&c->rem.io);;
28
arg->in.len = io_data_len(&c->rem.io);
29
arg->in.num_bytes = 0;
31
if (io_data_len(&c->rem.io) >= c->rem.io.size)
32
arg->flags |= SHTTPD_POST_BUFFER_FULL;
34
if (c->rem.content_len > 0 && c->rem.io.total < c->rem.content_len)
35
arg->flags |= SHTTPD_MORE_POST_DATA;
39
io_inc_head(&c->loc.io, arg->out.num_bytes);
40
io_inc_tail(&c->rem.io, arg->in.num_bytes);
41
c->loc.chan.emb.state = arg->state; /* Save state */
44
* If callback finished output, that means it did all cleanup.
45
* If the connection is terminated unexpectedly, we canna call
46
* the callback via the stream close() method from disconnect.
47
* However, if cleanup is already done, we set close() method to
48
* NULL, to prevent the call from disconnect().
51
if (arg->flags & SHTTPD_END_OF_OUTPUT)
52
c->loc.flags &= ~FLAG_DONT_CLOSE;
54
c->loc.flags |= FLAG_DONT_CLOSE;
56
if (arg->flags & SHTTPD_SUSPEND)
57
c->loc.flags |= FLAG_SUSPEND;
61
do_embedded(struct stream *stream, void *buf, size_t len)
63
struct shttpd_arg arg;
64
buf = NULL; len = 0; /* Squash warnings */
66
arg.user_data = stream->conn->loc.chan.emb.data;
69
call_user(stream->conn, &arg, (shttpd_callback_t)
70
stream->conn->loc.chan.emb.func.v_func);
76
close_embedded(struct stream *stream)
78
struct shttpd_arg arg;
79
struct conn *c = stream->conn;
81
arg.flags = SHTTPD_CONNECTION_ERROR;
82
arg.user_data = c->loc.chan.emb.data;
85
* Do not call the user function if SHTTPD_END_OF_OUTPUT was set,
86
* i.e. the callback already terminated correctly
88
if (stream->flags & FLAG_DONT_CLOSE)
89
call_user(stream->conn, &arg, (shttpd_callback_t)
90
c->loc.chan.emb.func.v_func);
94
shttpd_printf(struct shttpd_arg *arg, const char *fmt, ...)
96
char *buf = arg->out.buf + arg->out.num_bytes;
97
int buflen = arg->out.len - arg->out.num_bytes, len = 0;
102
len = vsnprintf(buf, buflen, fmt, ap);
105
if (len < 0 || len > buflen)
107
arg->out.num_bytes += len;
114
shttpd_get_header(struct shttpd_arg *arg, const char *header_name)
116
struct conn *c = arg->priv;
121
e = c->request + c->rem.headers_len;
122
len = strlen(header_name);
125
if ((s = strchr(p, '\n')) != NULL)
126
s[s[-1] == '\r' ? -1 : 0] = '\0';
127
if (my_strncasecmp(header_name, p, len) == 0)
128
return (p + len + 2);
137
shttpd_get_env(struct shttpd_arg *arg, const char *env_name)
139
struct conn *c = arg->priv;
142
if (strcmp(env_name, "REQUEST_METHOD") == 0) {
143
return (known_http_methods[c->method].ptr);
144
} else if (strcmp(env_name, "REQUEST_URI") == 0) {
146
} else if (strcmp(env_name, "QUERY_STRING") == 0) {
148
} else if (strcmp(env_name, "REMOTE_USER") == 0) {
149
vec = &c->ch.user.v_vec;
151
((char *) vec->ptr)[vec->len] = '\0';
154
} else if (strcmp(env_name, "REMOTE_ADDR") == 0) {
155
return (inet_ntoa(c->sa.u.sin.sin_addr));/* FIXME NOT MT safe */
162
shttpd_get_http_version(struct shttpd_arg *arg, unsigned long *major, unsigned long *minor)
164
struct conn *c = arg->priv;
166
*major = c->major_version;
167
*minor = c->minor_version;
171
shttpd_register_uri(struct shttpd_ctx *ctx,
172
const char *uri, shttpd_callback_t callback, void *data)
174
struct registered_uri *e;
176
if ((e = malloc(sizeof(*e))) != NULL) {
177
e->uri = my_strdup(uri);
178
e->callback.v_func = (void (*)(void)) callback;
179
e->callback_data = data;
180
LL_TAIL(&ctx->registered_uris, &e->link);
185
shttpd_get_var(const char *var, const char *buf, int buf_len,
186
char *value, int value_len)
188
const char *p, *e, *s;
191
var_len = strlen(var);
192
e = buf + buf_len; /* End of QUERY_STRING buffer */
194
/* buf is "var1=val1&var2=val2...". Find variable first */
195
for (p = buf; p + var_len < e; p++)
196
if ((p == buf || p[-1] == '&') &&
198
!my_strncasecmp(var, p, var_len)) {
200
/* Point 'p' to var value, 's' to the end of value */
202
if ((s = memchr(p, '&', e - p)) == NULL)
205
/* URL-decode value. Return result length */
206
return (url_decode(p, s - p, value, value_len));
213
match_regexp(const char *regexp, const char *text)
216
return (*text == '\0');
220
if (match_regexp(regexp + 1, text))
222
} while (*text++ != '\0');
224
if (*text != '\0' && *regexp == *text)
225
return (match_regexp(regexp + 1, text + 1));
230
struct registered_uri *
231
is_registered_uri(struct shttpd_ctx *ctx, const char *uri)
234
struct registered_uri *reg_uri;
236
LL_FOREACH(&ctx->registered_uris, lp) {
237
reg_uri = LL_ENTRY(lp, struct registered_uri, link);
238
if (match_regexp(reg_uri->uri, uri))
246
setup_embedded_stream(struct conn *c, union variant func, void *data)
248
c->loc.chan.emb.state = NULL;
249
c->loc.chan.emb.func = func;
250
c->loc.chan.emb.data = data;
251
c->loc.io_class = &io_embedded;
252
c->loc.flags |= FLAG_R | FLAG_W |FLAG_ALWAYS_READY;
256
shttpd_handle_error(struct shttpd_ctx *ctx, int code,
257
shttpd_callback_t func, void *data)
259
struct error_handler *e;
261
if ((e = malloc(sizeof(*e))) != NULL) {
263
e->callback.v_func = (void (*)(void)) func;
264
e->callback_data = data;
265
LL_TAIL(&ctx->error_handlers, &e->link);
270
shttpd_wakeup(const void *priv)
272
const struct conn *conn = priv;
273
char buf[sizeof(int) + sizeof(void *)];
274
int cmd = CTL_WAKEUP;
277
conn->flags &= ~SHTTPD_SUSPEND;
279
(void) memcpy(buf, &cmd, sizeof(cmd));
280
(void) memcpy(buf + sizeof(cmd), conn, sizeof(conn));
282
(void) send(conn->worker->ctl[1], buf, sizeof(buf), 0);
285
const struct io_class io_embedded = {
288
(int (*)(struct stream *, const void *, size_t)) do_embedded,