kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

commit 31d14d028a078626df9acff54a13ed6530f80bd6
parent d783a1d22dc69dd0a2dcb0a4c53babe671f628b7
Author: Joris Vink <joris@coders.se>
Date:   Mon, 26 Dec 2016 23:37:05 +0100

add compile-time configurable mime types.

these types are used for the new builtin asset_serve_* functions.

must be defined in conf/build.conf.

Diffstat:
includes/http.h | 2+-
src/cli.c | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
src/http.c | 3++-
3 files changed, 72 insertions(+), 4 deletions(-)

diff --git a/includes/http.h b/includes/http.h @@ -223,7 +223,7 @@ void http_process_request(struct http_request *); ssize_t http_body_read(struct http_request *, void *, size_t); void http_response(struct http_request *, int, const void *, size_t); void http_serveable(struct http_request *, const void *, - size_t, const char *); + size_t, const char *, const char *); void http_response_stream(struct http_request *, int, void *, size_t, int (*cb)(struct netbuf *), void *); int http_request_header(struct http_request *, diff --git a/src/cli.c b/src/cli.c @@ -66,6 +66,14 @@ #define BUILD_C 1 #define BUILD_CXX 2 +struct mime_type { + char *ext; + char *type; + TAILQ_ENTRY(mime_type) list; +}; + +TAILQ_HEAD(mime_list, mime_type); + struct buildopt { char *name; char *kore_source; @@ -145,6 +153,7 @@ static void cli_buildopt_kore_source(struct buildopt *, const char *); static void cli_buildopt_kore_flavor(struct buildopt *, const char *); +static void cli_buildopt_mime(struct buildopt *, const char *); static void cli_flavor_load(void); static void cli_flavor_change(const char *); @@ -193,7 +202,7 @@ static const char *http_serveable_function = "asset_serve_%s_%s(struct http_request *req)\n" "{\n" " http_serveable(req, asset_%s_%s, asset_len_%s_%s,\n" - " asset_sha1_%s_%s);\n" + " asset_sha1_%s_%s, \"%s\");\n" " return (KORE_RESULT_OK);\n" "}\n"; @@ -247,6 +256,11 @@ static const char *build_data = "cxxflags=-Wall -Wmissing-declarations -Wshadow\n" "cxxflags=-Wpointer-arith -Wcast-qual -Wsign-compare\n" "\n" + "# Mime types for assets served via the builtin asset_serve_*\n" + "#mime_add=txt:text/plain; charset=utf-8\n" + "#mime_add=png:image/png\n" + "#mime_add=html:text/html; charset=utf-8\n" + "\n" "dev {\n" " # These flags are added to the shared ones when\n" " # you build the \"dev\" flavor.\n" @@ -280,6 +294,7 @@ static char *rootdir = NULL; static char *compiler_c = "gcc"; static char *compiler_cpp = "g++"; static char *compiler_ld = "gcc"; +static struct mime_list mime_types; static struct cfile_list source_files; static struct buildopt_list build_options; static int source_files_count; @@ -450,6 +465,7 @@ cli_build(int argc, char **argv) cxx_files_count = 0; TAILQ_INIT(&source_files); TAILQ_INIT(&build_options); + TAILQ_INIT(&mime_types); (void)cli_vasprintf(&src_path, "%s/src", rootdir); (void)cli_vasprintf(&assets_path, "%s/assets", rootdir); @@ -781,6 +797,8 @@ cli_build_asset(char *fpath, struct dirent *dp) SHA_CTX sctx; off_t off; void *base; + struct mime_type *mime; + const char *mime_type; int in, out, i, len; u_int8_t *d, digest[SHA_DIGEST_LENGTH]; char *cpath, *ext, *opath, *p, *name; @@ -868,6 +886,17 @@ cli_build_asset(char *fpath, struct dirent *dp) cli_fatal("failed to convert SHA1 digest to hex"); } + mime = NULL; + TAILQ_FOREACH(mime, &mime_types, list) { + if (!strcasecmp(mime->ext, ext)) + break; + } + + if (mime != NULL) + mime_type = mime->type; + else + mime_type = "text/plain"; + /* Add the meta data. */ cli_file_writef(out, "};\n\n"); cli_file_writef(out, "u_int32_t asset_len_%s_%s = %" PRIu32 ";\n", @@ -878,7 +907,7 @@ cli_build_asset(char *fpath, struct dirent *dp) "const char *asset_sha1_%s_%s = \"\\\"%s\\\"\";\n", name, ext, hash); cli_file_writef(out, http_serveable_function, name, ext, - name, ext, name, ext, name, ext, name, ext); + name, ext, name, ext, name, ext, name, ext, mime_type); /* Write the file symbols into assets.h so they can be used. */ cli_write_asset(name, ext); @@ -1334,6 +1363,8 @@ parse_option: cli_buildopt_kore_source(bopt, t); } else if (!strcasecmp(p, "kore_flavor")) { cli_buildopt_kore_flavor(bopt, t); + } else if (!strcasecmp(p, "mime_add")) { + cli_buildopt_mime(bopt, t); } else { printf("ignoring unknown option '%s'\n", p); } @@ -1388,6 +1419,7 @@ static void cli_buildopt_cleanup(void) { struct buildopt *bopt, *next; + struct mime_type *mime, *mnext; for (bopt = TAILQ_FIRST(&build_options); bopt != NULL; bopt = next) { next = TAILQ_NEXT(bopt, list); @@ -1405,6 +1437,14 @@ cli_buildopt_cleanup(void) kore_free(bopt->kore_flavor); kore_free(bopt); } + + for (mime = TAILQ_FIRST(&mime_types); mime != NULL; mime = mnext) { + mnext = TAILQ_NEXT(mime, list); + TAILQ_REMOVE(&mime_types, mime, list); + kore_free(mime->type); + kore_free(mime->ext); + kore_free(mime); + } } static void @@ -1486,6 +1526,33 @@ cli_buildopt_kore_flavor(struct buildopt *bopt, const char *string) } static void +cli_buildopt_mime(struct buildopt *bopt, const char *ext) +{ + struct mime_type *mime; + char *type; + + if (bopt == NULL) + bopt = cli_buildopt_default(); + else + cli_fatal("mime_add only supported in global context"); + + if ((type = strchr(ext, ':')) == NULL) + cli_fatal("no type given in %s", ext); + + *(type)++ = '\0'; + TAILQ_FOREACH(mime, &mime_types, list) { + if (!strcmp(mime->ext, ext)) + cli_fatal("duplicate extension %s found", ext); + } + + mime = kore_malloc(sizeof(*mime)); + mime->ext = kore_strdup(ext); + mime->type = kore_strdup(type); + + TAILQ_INSERT_TAIL(&mime_types, mime, list); +} + +static void cli_build_flags_common(struct kore_buf* buf) { kore_buf_appendf(buf, diff --git a/src/http.c b/src/http.c @@ -483,7 +483,7 @@ http_request_free(struct http_request *req) void http_serveable(struct http_request *req, const void *data, size_t len, - const char *etag) + const char *etag, const char *type) { char *match; @@ -501,6 +501,7 @@ http_serveable(struct http_request *req, const void *data, size_t len, } http_response_header(req, "etag", etag); + http_response_header(req, "content-type", type); http_response(req, HTTP_STATUS_OK, data, len); }