X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=libs%2Fshttpd%2Fio_emb.c;fp=libs%2Fshttpd%2Fio_emb.c;h=42cd5c5e9be74cb611f781e6f3b13319396b5bae;hb=d8ccfe2b3944adf07d35534459cdda19d15217c8;hp=0000000000000000000000000000000000000000;hpb=21f835f30b4e092c847bf4569a00995774f7330e;p=fms.git diff --git a/libs/shttpd/io_emb.c b/libs/shttpd/io_emb.c new file mode 100644 index 0000000..42cd5c5 --- /dev/null +++ b/libs/shttpd/io_emb.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2004-2005 Sergey Lyubka + * All rights reserved + * + * "THE BEER-WARE LICENSE" (Revision 42): + * Sergey Lyubka wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. + */ + +#include "defs.h" + +#if defined(EMBEDDED) +const char * +shttpd_version(void) +{ + return (VERSION); +} + +static void +call_user(struct conn *c, struct shttpd_arg *arg, shttpd_callback_t func) +{ + arg->priv = c; + arg->state = c->loc.chan.emb.state; + arg->out.buf = io_space(&c->loc.io); + arg->out.len = io_space_len(&c->loc.io); + arg->out.num_bytes = 0; + arg->in.buf = io_data(&c->rem.io);; + arg->in.len = io_data_len(&c->rem.io); + arg->in.num_bytes = 0; + + func(arg); + + io_inc_head(&c->loc.io, arg->out.num_bytes); + io_inc_tail(&c->rem.io, arg->in.num_bytes); + c->loc.chan.emb.state = arg->state; /* Save state */ + + /* + * If callback finished output, that means it did all cleanup. + * If the connection is terminated unexpectedly, we canna call + * the callback via the stream close() method from disconnect. + * However, if cleanup is already done, we set close() method to + * NULL, to prevent the call from disconnect(). + */ + + if (arg->flags & SHTTPD_END_OF_OUTPUT) + c->loc.flags &= ~FLAG_DONT_CLOSE; + else + c->loc.flags |= FLAG_DONT_CLOSE; +} + +static int +do_embedded(struct stream *stream, void *buf, size_t len) +{ + struct shttpd_arg arg; + buf = NULL; len = 0; /* Squash warnings */ + + arg.user_data = stream->conn->loc.chan.emb.data; + arg.flags = 0; + + call_user(stream->conn, &arg, (shttpd_callback_t) + stream->conn->loc.chan.emb.func.v_func); + + return (0); +} + +static void +close_embedded(struct stream *stream) +{ + struct shttpd_arg arg; + struct conn *c = stream->conn; + + arg.flags = SHTTPD_CONNECTION_ERROR; + arg.user_data = c->loc.chan.emb.data; + + /* + * Do not call the user function if SHTTPD_END_OF_OUTPUT was set, + * i.e. the callback already terminated correctly + */ + if (stream->flags & FLAG_DONT_CLOSE) + call_user(stream->conn, &arg, (shttpd_callback_t) + c->loc.chan.emb.func.v_func); +} + +size_t +shttpd_printf(struct shttpd_arg *arg, const char *fmt, ...) +{ + struct conn *c = arg->priv; + struct io *io = &c->loc.io; + char *buf = arg->out.buf + arg->out.num_bytes; + int buflen = arg->out.len - arg->out.num_bytes, len = 0; + va_list ap; + + assert(buf <= io->buf + io->size); + + if (buflen > 0) { + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + + if (len < 0 || len > buflen) + len = buflen; + arg->out.num_bytes += len; + } + + return (len); +} + +const char * +shttpd_get_header(struct shttpd_arg *arg, const char *header_name) +{ + struct conn *c = arg->priv; + char *p, *s, *e; + size_t len; + + p = c->headers; + e = c->request + c->rem.headers_len; + len = strlen(header_name); + + while (p < e) { + if ((s = strchr(p, '\n')) != NULL) + s[s[-1] == '\r' ? -1 : 0] = '\0'; + if (my_strncasecmp(header_name, p, len) == 0) + return (p + len + 2); + + p += strlen(p) + 1; + } + + return (NULL); +} + +const char * +shttpd_get_env(struct shttpd_arg *arg, const char *env_name) +{ + struct conn *c = arg->priv; + struct vec *vec; + + if (strcmp(env_name, "REQUEST_METHOD") == 0) { + return (known_http_methods[c->method].ptr); + } else if (strcmp(env_name, "REQUEST_URI") == 0) { + return (c->uri); + } else if (strcmp(env_name, "QUERY_STRING") == 0) { + return (c->query); + } else if (strcmp(env_name, "REMOTE_USER") == 0) { + vec = &c->ch.user.v_vec; + if (vec->len > 0) { + ((char *) vec->ptr)[vec->len] = '\0'; + return (vec->ptr); + } + } else if (strcmp(env_name, "REMOTE_ADDR") == 0) { + return (inet_ntoa(c->sa.u.sin.sin_addr));/* FIXME NOT MT safe */ + } + + return (NULL); +} + +void +shttpd_get_http_version(struct shttpd_arg *arg, unsigned long *major, unsigned long *minor) +{ + struct conn *c = arg->priv; + + *major = c->major_version; + *minor = c->minor_version; +} + +void +shttpd_register_uri(struct shttpd_ctx *ctx, + const char *uri, shttpd_callback_t callback, void *data) +{ + struct registered_uri *e; + + if ((e = malloc(sizeof(*e))) != NULL) { + e->uri = my_strdup(uri); + e->callback.v_func = (void (*)(void)) callback; + e->callback_data = data; + LL_TAIL(&ctx->registered_uris, &e->link); + } +} + +#if 0 +struct shttpd_ctx * +shttpd_init2(const char *config_file, char *names[], char *values[], size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) + set_option(names[i], values[i]); + + return (init_ctx(config_file, 0, NULL)); +} +#endif + +void +shttpd_protect_uri(struct shttpd_ctx *ctx, const char *uri, const char *file) +{ + struct uri_auth *auth; + + if ((auth = malloc(sizeof(*auth))) != NULL) { + auth->uri = my_strdup(uri); + auth->file_name = my_strdup(file); + auth->uri_len = strlen(uri); + LL_ADD(&ctx->uri_auths, &auth->link); + } +} + +int +shttpd_get_var(const char *var, const char *buf, int buf_len, + char *value, int value_len) +{ + const char *p, *e, *s; + size_t var_len; + + var_len = strlen(var); + e = buf + buf_len - var_len; + + /* buf is "var1=val1&var2=val2...". Find variable first */ + for (p = buf; p < e; p++) + if (!my_strncasecmp(var, p, var_len) && p[var_len] == '=') { + + /* Found. Shift to variable value */ + e = buf + buf_len; + p += var_len + 1; + + /* Find where the value ends */ + if ((s = memchr(p, '&', e - p)) == NULL) + s = e; + + /* Copy value into the buffer, decoding it */ + url_decode(p, s - p, value, value_len); + + return (1); + } + + return (0); +} + +static int +match_regexp(const char *regexp, const char *text) +{ + if (*regexp == '\0') + return (*text == '\0'); + + if (*regexp == '*') + do { + if (match_regexp(regexp + 1, text)) + return (1); + } while (*text++ != '\0'); + + if (*text != '\0' && *regexp == *text) + return (match_regexp(regexp + 1, text + 1)); + + return (0); +} + +struct registered_uri * +is_registered_uri(struct shttpd_ctx *ctx, const char *uri) +{ + struct llhead *lp; + struct registered_uri *reg_uri; + + LL_FOREACH(&ctx->registered_uris, lp) { + reg_uri = LL_ENTRY(lp, struct registered_uri, link); + if (match_regexp(reg_uri->uri, uri)) + return (reg_uri); + } + + return (NULL); +} + +void +setup_embedded_stream(struct conn *c, union variant func, void *data) +{ + c->loc.chan.emb.state = NULL; + c->loc.chan.emb.func = func; + c->loc.chan.emb.data = data; + c->loc.io_class = &io_embedded; + c->loc.flags |= FLAG_R | FLAG_W |FLAG_ALWAYS_READY; +} + +void +shttpd_handle_error(struct shttpd_ctx *ctx, int code, + shttpd_callback_t func, void *data) +{ + struct error_handler *e; + + if ((e = malloc(sizeof(*e))) != NULL) { + e->code = code; + e->callback.v_func = (void (*)(void)) func; + e->callback_data = data; + LL_TAIL(&ctx->error_handlers, &e->link); + } +} + +const struct io_class io_embedded = { + "embedded", + do_embedded, + (int (*)(struct stream *, const void *, size_t)) do_embedded, + close_embedded +}; + +#endif /* EMBEDDED */