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.
21 call_user(struct conn *c, struct shttpd_arg *arg, shttpd_callback_t func)
24 arg->state = c->loc.chan.emb.state;
25 arg->out.buf = io_space(&c->loc.io);
26 arg->out.len = io_space_len(&c->loc.io);
27 arg->out.num_bytes = 0;
28 arg->in.buf = io_data(&c->rem.io);;
29 arg->in.len = io_data_len(&c->rem.io);
30 arg->in.num_bytes = 0;
34 io_inc_head(&c->loc.io, arg->out.num_bytes);
35 io_inc_tail(&c->rem.io, arg->in.num_bytes);
36 c->loc.chan.emb.state = arg->state; /* Save state */
39 * If callback finished output, that means it did all cleanup.
40 * If the connection is terminated unexpectedly, we canna call
41 * the callback via the stream close() method from disconnect.
42 * However, if cleanup is already done, we set close() method to
43 * NULL, to prevent the call from disconnect().
46 if (arg->flags & SHTTPD_END_OF_OUTPUT)
47 c->loc.flags &= ~FLAG_DONT_CLOSE;
49 c->loc.flags |= FLAG_DONT_CLOSE;
53 do_embedded(struct stream *stream, void *buf, size_t len)
55 struct shttpd_arg arg;
56 buf = NULL; len = 0; /* Squash warnings */
58 arg.user_data = stream->conn->loc.chan.emb.data;
61 call_user(stream->conn, &arg, (shttpd_callback_t)
62 stream->conn->loc.chan.emb.func.v_func);
68 close_embedded(struct stream *stream)
70 struct shttpd_arg arg;
71 struct conn *c = stream->conn;
73 arg.flags = SHTTPD_CONNECTION_ERROR;
74 arg.user_data = c->loc.chan.emb.data;
77 * Do not call the user function if SHTTPD_END_OF_OUTPUT was set,
78 * i.e. the callback already terminated correctly
80 if (stream->flags & FLAG_DONT_CLOSE)
81 call_user(stream->conn, &arg, (shttpd_callback_t)
82 c->loc.chan.emb.func.v_func);
86 shttpd_printf(struct shttpd_arg *arg, const char *fmt, ...)
88 struct conn *c = arg->priv;
89 struct io *io = &c->loc.io;
90 char *buf = arg->out.buf + arg->out.num_bytes;
91 int buflen = arg->out.len - arg->out.num_bytes, len = 0;
94 assert(buf <= io->buf + io->size);
98 len = vsnprintf(buf, buflen, fmt, ap);
101 if (len < 0 || len > buflen)
103 arg->out.num_bytes += len;
110 shttpd_get_header(struct shttpd_arg *arg, const char *header_name)
112 struct conn *c = arg->priv;
117 e = c->request + c->rem.headers_len;
118 len = strlen(header_name);
121 if ((s = strchr(p, '\n')) != NULL)
122 s[s[-1] == '\r' ? -1 : 0] = '\0';
123 if (my_strncasecmp(header_name, p, len) == 0)
124 return (p + len + 2);
133 shttpd_get_env(struct shttpd_arg *arg, const char *env_name)
135 struct conn *c = arg->priv;
138 if (strcmp(env_name, "REQUEST_METHOD") == 0) {
139 return (known_http_methods[c->method].ptr);
140 } else if (strcmp(env_name, "REQUEST_URI") == 0) {
142 } else if (strcmp(env_name, "QUERY_STRING") == 0) {
144 } else if (strcmp(env_name, "REMOTE_USER") == 0) {
145 vec = &c->ch.user.v_vec;
147 ((char *) vec->ptr)[vec->len] = '\0';
150 } else if (strcmp(env_name, "REMOTE_ADDR") == 0) {
151 return (inet_ntoa(c->sa.u.sin.sin_addr));/* FIXME NOT MT safe */
158 shttpd_get_http_version(struct shttpd_arg *arg, unsigned long *major, unsigned long *minor)
160 struct conn *c = arg->priv;
162 *major = c->major_version;
163 *minor = c->minor_version;
167 shttpd_register_uri(struct shttpd_ctx *ctx,
168 const char *uri, shttpd_callback_t callback, void *data)
170 struct registered_uri *e;
172 if ((e = malloc(sizeof(*e))) != NULL) {
173 e->uri = my_strdup(uri);
174 e->callback.v_func = (void (*)(void)) callback;
175 e->callback_data = data;
176 LL_TAIL(&ctx->registered_uris, &e->link);
182 shttpd_init2(const char *config_file, char *names[], char *values[], size_t n)
186 for (i = 0; i < n; i++)
187 set_option(names[i], values[i]);
189 return (init_ctx(config_file, 0, NULL));
194 shttpd_protect_uri(struct shttpd_ctx *ctx, const char *uri, const char *file)
196 struct uri_auth *auth;
198 if ((auth = malloc(sizeof(*auth))) != NULL) {
199 auth->uri = my_strdup(uri);
200 auth->file_name = my_strdup(file);
201 auth->uri_len = strlen(uri);
202 LL_ADD(&ctx->uri_auths, &auth->link);
207 shttpd_get_var(const char *var, const char *buf, int buf_len,
208 char *value, int value_len)
210 const char *p, *e, *s;
213 var_len = strlen(var);
214 e = buf + buf_len - var_len;
216 /* buf is "var1=val1&var2=val2...". Find variable first */
217 for (p = buf; p < e; p++)
218 if (!my_strncasecmp(var, p, var_len) && p[var_len] == '=') {
220 /* Found. Shift to variable value */
224 /* Find where the value ends */
225 if ((s = memchr(p, '&', e - p)) == NULL)
228 /* Copy value into the buffer, decoding it */
229 url_decode(p, s - p, value, value_len);
238 match_regexp(const char *regexp, const char *text)
241 return (*text == '\0');
245 if (match_regexp(regexp + 1, text))
247 } while (*text++ != '\0');
249 if (*text != '\0' && *regexp == *text)
250 return (match_regexp(regexp + 1, text + 1));
255 struct registered_uri *
256 is_registered_uri(struct shttpd_ctx *ctx, const char *uri)
259 struct registered_uri *reg_uri;
261 LL_FOREACH(&ctx->registered_uris, lp) {
262 reg_uri = LL_ENTRY(lp, struct registered_uri, link);
263 if (match_regexp(reg_uri->uri, uri))
271 setup_embedded_stream(struct conn *c, union variant func, void *data)
273 c->loc.chan.emb.state = NULL;
274 c->loc.chan.emb.func = func;
275 c->loc.chan.emb.data = data;
276 c->loc.io_class = &io_embedded;
277 c->loc.flags |= FLAG_R | FLAG_W |FLAG_ALWAYS_READY;
281 shttpd_handle_error(struct shttpd_ctx *ctx, int code,
282 shttpd_callback_t func, void *data)
284 struct error_handler *e;
286 if ((e = malloc(sizeof(*e))) != NULL) {
288 e->callback.v_func = (void (*)(void)) func;
289 e->callback_data = data;
290 LL_TAIL(&ctx->error_handlers, &e->link);
294 const struct io_class io_embedded = {
297 (int (*)(struct stream *, const void *, size_t)) do_embedded,
301 #endif /* EMBEDDED */