summaryrefslogtreecommitdiff
path: root/httpd.c
diff options
context:
space:
mode:
authorReyk Floeter <reyk@esdenera.com>2014-07-13 01:15:01 +0200
committerReyk Floeter <reyk@esdenera.com>2014-07-13 01:15:01 +0200
commit6d196c9daa83925cc04f8019c1c0065317f6efdf (patch)
tree484726f0f6df8ff02e9cb1943ee35d8711417dd6 /httpd.c
parent9edde19e282ba13de068a4dc7e717152aaae77b8 (diff)
downloadhttpd-6d196c9daa83925cc04f8019c1c0065317f6efdf.tar.gz
httpd-6d196c9daa83925cc04f8019c1c0065317f6efdf.zip
Simple file serving
Diffstat (limited to 'httpd.c')
-rw-r--r--httpd.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/httpd.c b/httpd.c
index 5f9c17d..32ed5ef 100644
--- a/httpd.c
+++ b/httpd.c
@@ -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);