diff --git a/README.lwsws.md b/README.lwsws.md index d47e6ea1a..b56ea487e 100644 --- a/README.lwsws.md +++ b/README.lwsws.md @@ -295,6 +295,14 @@ options are given, the content is marked uncacheable. } +4) You can also define a list of additional mimetypes per-mount + + "extra-mimetypes": { + ".zip": "application/zip", + ".doc": "text/evil" + } + + Plugins ------- diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index bb364683f..a692d096c 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -1391,6 +1391,7 @@ struct lws_http_mount { const char *def; /* default target, eg, "index.html" */ const struct lws_protocol_vhost_options *cgienv; + const struct lws_protocol_vhost_options *extra_mimetypes; int cgi_timeout; int cache_max_age; diff --git a/lib/server.c b/lib/server.c index a3b512a3e..94a028068 100644 --- a/lib/server.c +++ b/lib/server.c @@ -192,9 +192,14 @@ lws_select_vhost(struct lws_context *context, int port, const char *servername) return NULL; } -static const char * get_mimetype(const char *file) +static const char * +get_mimetype(const char *file, const struct lws_http_mount *m) { int n = strlen(file); + const struct lws_protocol_vhost_options *pvo = NULL; + + if (m) + pvo = m->extra_mimetypes; if (n < 5) return NULL; @@ -238,10 +243,19 @@ static const char * get_mimetype(const char *file) if (!strcmp(&file[n - 4], ".xml")) return "application/xml"; + while (pvo) { + if (!strcmp(&file[n - strlen(pvo->name)], pvo->name)) + return pvo->value; + + pvo = pvo->next; + } + return NULL; } -int lws_http_serve(struct lws *wsi, char *uri, const char *origin) +static int +lws_http_serve(struct lws *wsi, char *uri, const char *origin, + const struct lws_http_mount *m) { const char *mimetype; #ifndef _WIN32_WCE @@ -329,7 +343,7 @@ int lws_http_serve(struct lws *wsi, char *uri, const char *origin) return -1; #endif - mimetype = get_mimetype(path); + mimetype = get_mimetype(path, m); if (!mimetype) { lwsl_err("unknown mimetype for %s", path); goto bail; @@ -745,7 +759,7 @@ lws_http_action(struct lws *wsi) wsi->cache_revalidate = hit->cache_revalidate; wsi->cache_intermediaries = hit->cache_intermediaries; - n = lws_http_serve(wsi, s, hit->origin); + n = lws_http_serve(wsi, s, hit->origin, hit); if (n) { /* * lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL); diff --git a/lwsws/conf.c b/lwsws/conf.c index 6ce8ef030..736739737 100644 --- a/lwsws/conf.c +++ b/lwsws/conf.c @@ -60,6 +60,7 @@ static const char * const paths_vhosts[] = { "vhosts[].mounts[].cache-reuse", "vhosts[].mounts[].cache-revalidate", "vhosts[].mounts[].cache-intermediaries", + "vhosts[].mounts[].extra-mimetypes.*", "vhosts[].ws-protocols[].*.*", "vhosts[].ws-protocols[].*", "vhosts[].ws-protocols[]", @@ -90,6 +91,7 @@ enum lejp_vhost_paths { LEJPVP_MOUNT_CACHE_REUSE, LEJPVP_MOUNT_CACHE_REVALIDATE, LEJPVP_MOUNT_CACHE_INTERMEDIARIES, + LEJPVP_MOUNT_EXTRA_MIMETYPES, LEJPVP_PROTOCOL_NAME_OPT, LEJPVP_PROTOCOL_NAME, LEJPVP_PROTOCOL, @@ -110,11 +112,13 @@ struct jpargs { struct lws_http_mount *head, *last; struct lws_protocol_vhost_options *pvo; + struct lws_protocol_vhost_options *pvo_em; struct lws_http_mount m; const char **plugin_dirs; int count_plugin_dirs; unsigned int enable_client_ssl:1; + unsigned int fresh_mount:1; }; static void * @@ -234,8 +238,10 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason) } if (reason == LEJPCB_OBJECT_START && - ctx->path_match == LEJPVP_MOUNTS + 1) + ctx->path_match == LEJPVP_MOUNTS + 1) { + a->fresh_mount = 1; memset(&a->m, 0, sizeof(a->m)); + } /* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */ if (reason == LEJPCB_OBJECT_START && @@ -248,7 +254,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason) a->pvo->next = a->info->pvo; a->info->pvo = a->pvo; a->pvo->name = a->p; - lwsl_err("adding %s\n", a->p); + lwsl_notice(" adding protocol %s\n", a->p); a->p += n; a->pvo->value = a->p; a->pvo->options = NULL; @@ -298,10 +304,14 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason) "callback://" }; + if (!a->fresh_mount) + return 0; + if (!a->m.mountpoint || !a->m.origin) { lwsl_err("mountpoint and origin required\n"); return 1; } + lwsl_debug("adding mount %s\n", a->m.mountpoint); m = lwsws_align(a); memcpy(m, &a->m, sizeof(*m)); if (a->last) @@ -325,6 +335,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason) a->head = m; a->last = m; + a->fresh_mount = 0; } /* we only match on the prepared path strings */ @@ -434,9 +445,23 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason) a->p += n; pvo->value = a->p; pvo->options = NULL; - a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf); - *(a->p)++ = '\0'; break; + + case LEJPVP_MOUNT_EXTRA_MIMETYPES: + a->pvo_em = lwsws_align(a); + a->p += sizeof(*a->pvo_em); + + n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p); + /* ie, enable this protocol, no options yet */ + a->pvo_em->next = a->m.extra_mimetypes; + a->m.extra_mimetypes = a->pvo_em; + a->pvo_em->name = a->p; + lwsl_notice(" adding extra-mimetypes %s -> %s\n", a->p, ctx->buf); + a->p += n; + a->pvo_em->value = a->p; + a->pvo_em->options = NULL; + break; + case LEJPVP_ENABLE_CLIENT_SSL: a->enable_client_ssl = arg_to_bool(ctx->buf); return 0; diff --git a/test-server/test-server-v2.0.c b/test-server/test-server-v2.0.c index e1442d56a..b66a84e2d 100644 --- a/test-server/test-server-v2.0.c +++ b/test-server/test-server-v2.0.c @@ -81,6 +81,7 @@ static const struct lws_http_mount mount_post = { "protocol-post-demo", /* handler */ NULL, /* default filename if none given */ NULL, + NULL, 0, 0, 0, @@ -102,6 +103,7 @@ static const struct lws_http_mount mount = { LOCAL_RESOURCE_PATH, /* where to go on the filesystem for that */ "test.html", /* default filename if none given */ NULL, + NULL, 0, 0, 0,