view static.c @ 1046:36c1bd8ea8db

static: use filename from uri_info instead of from the client The uri_info filename does *not* have the prefix. This didn't matter when blahgd was hosted at / URI prefix, but makes a big difference with other prefixes (e.g., /blahg/). Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Thu, 13 Aug 2020 10:55:04 -0400
parents e719679a8439
children 1b24215e4f1e
line wrap: on
line source

/*
 * Copyright (c) 2015-2020 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <jeffpc/error.h>

#include "static.h"
#include "utils.h"

/* must include trailing '/' */
#define URI_PREFIX	"/"

struct uri_info {
	const char *uri;
	const char *content_type;	/* required for URI_STATIC */
	enum uri_type type;
};

static const struct uri_info safe_uris[] = {
	{ "",			NULL,		URI_DYNAMIC, },
	{ "bug.png",		"image/png",	URI_STATIC,  },
	{ "favicon.ico",	"image/png",	URI_STATIC,  },
	{ "style.css",		"text/css",	URI_STATIC,  },
	{ "wiki.png",		"image/png",	URI_STATIC,  },
};

static const struct uri_info *get_uri_info(const char *path)
{
	int i;

	if (!path)
		return NULL;

	if (hasdotdot(path))
		return NULL;

	/* all URIs must start with the proper prefix */
	if (strncmp(URI_PREFIX, path, strlen(URI_PREFIX)))
		return NULL;

	/* strip the prefix from the uri */
	path += strlen(URI_PREFIX);

	for (i = 0; i < ARRAY_LEN(safe_uris); i++) {
		if (!strcmp(safe_uris[i].uri, path))
			return &safe_uris[i];
	}

	return NULL;
}

enum uri_type get_uri_type(struct str *path)
{
	const struct uri_info *info;

	info = get_uri_info(str_cstr(path));

	str_putref(path);

	return info ? info->type : URI_BAD;
}

int blahg_static(struct req *req)
{
	char path[FILENAME_MAX];
	const struct uri_info *info;
	struct str *uri_str;
	const char *uri;

	uri_str = nvl_lookup_str(req->scgi->request.headers, SCGI_DOCUMENT_URI);
	ASSERT(!IS_ERR(uri_str));

	uri = str_cstr(uri_str);

	info = get_uri_info(uri);
	ASSERT(info);

	snprintf(path, sizeof(path), "%s/static/%s", str_cstr(config.theme_dir),
		 info->uri);

	str_putref(uri_str);

	/*
	 * We assume that the URI (minus the URI prefix) is relative to the
	 * theme's static subdir.  Since we have a whitelist of allowed
	 * URIs, we are safe from file system traversal issues.
	 */
	req->scgi->response.body = read_file_len(path,
						 &req->scgi->response.bodylen);

	if (IS_ERR(req->scgi->response.body))
		return R404(req, NULL);

	req_head(req, "Content-Type", info->content_type);

	return 0;
}