diff options
author | Reyk Floeter <reyk@esdenera.com> | 2014-07-13 01:15:01 +0200 |
---|---|---|
committer | Reyk Floeter <reyk@esdenera.com> | 2014-07-13 01:15:01 +0200 |
commit | 6d196c9daa83925cc04f8019c1c0065317f6efdf (patch) | |
tree | 484726f0f6df8ff02e9cb1943ee35d8711417dd6 /httpd.c | |
parent | 9edde19e282ba13de068a4dc7e717152aaae77b8 (diff) | |
download | httpd-6d196c9daa83925cc04f8019c1c0065317f6efdf.tar.gz httpd-6d196c9daa83925cc04f8019c1c0065317f6efdf.zip |
Simple file serving
Diffstat (limited to 'httpd.c')
-rw-r--r-- | httpd.c | 209 |
1 files changed, 209 insertions, 0 deletions
@@ -526,3 +526,212 @@ accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen, } return (ret); } + +struct kv * +kv_add(struct kvtree *keys, char *key, char *value) +{ + struct kv *kv, *oldkv; + + if (key == NULL) + return (NULL); + if ((kv = calloc(1, sizeof(*kv))) == NULL) + return (NULL); + if ((kv->kv_key = strdup(key)) == NULL) { + free(kv); + return (NULL); + } + if (value != NULL && + (kv->kv_value = strdup(value)) == NULL) { + free(kv->kv_key); + free(kv); + return (NULL); + } + TAILQ_INIT(&kv->kv_children); + + if ((oldkv = RB_INSERT(kvtree, keys, kv)) != NULL) { + TAILQ_INSERT_TAIL(&oldkv->kv_children, kv, kv_entry); + kv->kv_parent = oldkv; + } + + return (kv); +} + +int +kv_set(struct kv *kv, char *fmt, ...) +{ + va_list ap; + char *value = NULL; + struct kv *ckv; + + va_start(ap, fmt); + if (vasprintf(&value, fmt, ap) == -1) + return (-1); + va_end(ap); + + /* Remove all children */ + while ((ckv = TAILQ_FIRST(&kv->kv_children)) != NULL) { + TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry); + kv_free(ckv); + free(ckv); + } + + /* Set the new value */ + if (kv->kv_value != NULL) + free(kv->kv_value); + kv->kv_value = value; + + return (0); +} + +int +kv_setkey(struct kv *kv, char *fmt, ...) +{ + va_list ap; + char *key = NULL; + + va_start(ap, fmt); + if (vasprintf(&key, fmt, ap) == -1) + return (-1); + va_end(ap); + + if (kv->kv_key != NULL) + free(kv->kv_key); + kv->kv_key = key; + + return (0); +} + +void +kv_delete(struct kvtree *keys, struct kv *kv) +{ + struct kv *ckv; + + RB_REMOVE(kvtree, keys, kv); + + /* Remove all children */ + while ((ckv = TAILQ_FIRST(&kv->kv_children)) != NULL) { + TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry); + kv_free(ckv); + free(ckv); + } + + kv_free(kv); + free(kv); +} + +struct kv * +kv_extend(struct kvtree *keys, struct kv *kv, char *value) +{ + char *newvalue; + + if (kv == NULL) { + return (NULL); + } else if (kv->kv_value != NULL) { + if (asprintf(&newvalue, "%s%s", kv->kv_value, value) == -1) + return (NULL); + + free(kv->kv_value); + kv->kv_value = newvalue; + } else if ((kv->kv_value = strdup(value)) == NULL) + return (NULL); + + return (kv); +} + +void +kv_purge(struct kvtree *keys) +{ + struct kv *kv; + + while ((kv = RB_MIN(kvtree, keys)) != NULL) + kv_delete(keys, kv); +} + +void +kv_free(struct kv *kv) +{ + if (kv->kv_type == KEY_TYPE_NONE) + return; + if (kv->kv_key != NULL) { + free(kv->kv_key); + } + kv->kv_key = NULL; + if (kv->kv_value != NULL) { + free(kv->kv_value); + } + kv->kv_value = NULL; + memset(kv, 0, sizeof(*kv)); +} + +struct kv * +kv_inherit(struct kv *dst, struct kv *src) +{ + memset(dst, 0, sizeof(*dst)); + memcpy(dst, src, sizeof(*dst)); + TAILQ_INIT(&dst->kv_children); + + if (src->kv_key != NULL) { + if ((dst->kv_key = strdup(src->kv_key)) == NULL) { + kv_free(dst); + return (NULL); + } + } + if (src->kv_value != NULL) { + if ((dst->kv_value = strdup(src->kv_value)) == NULL) { + kv_free(dst); + return (NULL); + } + } + + return (dst); +} + +int +kv_log(struct evbuffer *log, struct kv *kv) +{ + char *msg; + + if (log == NULL) + return (0); + if (asprintf(&msg, " [%s%s%s]", + kv->kv_key == NULL ? "(unknown)" : kv->kv_key, + kv->kv_value == NULL ? "" : ": ", + kv->kv_value == NULL ? "" : kv->kv_value) == -1) + return (-1); + if (evbuffer_add(log, msg, strlen(msg)) == -1) { + free(msg); + return (-1); + } + free(msg); + + return (0); +} + +struct kv * +kv_find(struct kvtree *keys, struct kv *kv) +{ + struct kv *match; + const char *key; + + if (kv->kv_flags & KV_FLAG_GLOBBING) { + /* Test header key using shell globbing rules */ + key = kv->kv_key == NULL ? "" : kv->kv_key; + RB_FOREACH(match, kvtree, keys) { + if (fnmatch(key, match->kv_key, FNM_CASEFOLD) == 0) + break; + } + } else { + /* Fast tree-based lookup only works without globbing */ + match = RB_FIND(kvtree, keys, kv); + } + + return (match); +} + +int +kv_cmp(struct kv *a, struct kv *b) +{ + return (strcasecmp(a->kv_key, b->kv_key)); +} + +RB_GENERATE(kvtree, kv, kv_node, kv_cmp); |