#include /* Should these be "namespaced" under evapp_util. * Or perhaps, should they be in a evapp_util struct? */ bool parse_cookie(evapp_ctx *ctx, struct evkeyvalq *data) { const char *header = NULL; char *cookie = NULL, *semi = NULL; struct evhttp_request *request = evapp_request(ctx); if (!request || !ctx || !data) return false; // get everything up to first semi colon header = evhttp_find_header(request->input_headers, "Cookie"); if (!header) // XXX: should this return a count instead? return false; cookie = strdup(header); semi = index(cookie, ';'); if (semi) *semi = '\0'; // pass to evkeyval_from_query if (!parse_query(cookie, strlen(cookie), false, true, NULL, data)) { free(cookie); return false; } free(cookie); return true; } bool set_cookie(evapp_ctx *ctx, struct evkeyvalq *data, const char *path, const char *domain, size_t lifetime, bool secure) { struct evbuffer *cookie = NULL; char *real_path, date[51]; struct evkeyval *keyval; struct tm tm; time_t t; struct evhttp_request *request = evapp_request(ctx); if (!data) return false; if (!ctx || !request) return false; cookie = evbuffer_new(); if (!cookie) return false; // we use : since browser don't like & even though : is banned! wtf! TAILQ_FOREACH(keyval, data, next) { evbuffer_add_printf(cookie, "%s=%s:", keyval->key, keyval->value); } t = time(NULL) + lifetime; gmtime_r(&t, &tm); /* Add the expires in the future. Let evhttp stamp the date */ if (strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S GMT", &tm) != 0) { evbuffer_add_printf(cookie, "; expires=%s", date); } /* If no path, use the current as the default */ if (!path) { char *end; real_path = strdup(request->uri); if (!real_path) { evbuffer_free(cookie); return false; } end = index(real_path, '?'); if (!end) *end = '\0'; evbuffer_add_printf(cookie, "; path=%s", real_path); free(real_path); } else { evbuffer_add_printf(cookie, "; path=%s", path); } /* Only set domain values on real names and not local host names */ if (domain) { evbuffer_add_printf(cookie, "; domain=.%s", domain); } else { const char *host_header = evhttp_find_header(request->input_headers, "host"); if (host_header) { char *host_only = strdup(host_header); char *colon = NULL; if (!host_only) { evbuffer_free(cookie); return false; } colon = index(host_only, ':'); if (colon) *colon = '\0'; // XXX: bad for falsified domains. App should check early against // "allowed" domains and stop the request then. // (Falsified host header could get a cookie to evil.org instead of // the correct place.) /* Note, don't set the domain if the host is short/local */ if (index(host_only, '.')) evbuffer_add_printf(cookie, "; domain=.%s", host_only); free(host_only); // Hopefully this will work with the edge cases. } else if (evapp_get_default_domain(ctx)) { evbuffer_add_printf(cookie, "; domain=.%s", evapp_get_default_domain(ctx)); } } if (secure) evbuffer_add_printf(cookie, "; secure"); evhttp_add_header(request->output_headers, "Set-Cookie", (char *)EVBUFFER_DATA(cookie)); evbuffer_free(cookie); return true; }