示例#1
0
/** uses/modifies wrk->tmp_str */
static void try_append_file(liVRequest *vr, GString **curbuf, const gchar *filename, gboolean encode_html) {
	GString *f = vr->wrk->tmp_str;
	g_string_truncate(f, 0);
	g_string_append_len(f, GSTR_LEN(vr->physical.path));
	li_path_append_slash(f);
	g_string_append(f, filename);

	if (!encode_html) {
		int fd;
		struct stat st;

		while (-1 == (fd = open(f->str, O_RDONLY))) {
			if (errno == EINTR)
				continue;
			return; /* failed to open, ignore */
		}
		if (-1 == fstat(fd, &st)) {
			close(fd);
			return; /* failed to open, ignore */
		}
		if (st.st_size > MAX_INCLUDE_FILE_SIZE) {
			close(fd);
			return; /* file too big, ignore */
		}

		/* flush current buffer and append file */
		li_chunkqueue_append_string(vr->direct_out, *curbuf);
		*curbuf = g_string_sized_new(4*1024-1);
		li_chunkqueue_append_file_fd(vr->direct_out, NULL, 0, st.st_size, fd);
	} else {
		GError *error = NULL;
		gchar *contents;
		gsize length;

		if (!g_file_get_contents(f->str, &contents, &length, &error)) {
			g_error_free(error);
			return; /* ignore errors */
		}
		if (length > MAX_INCLUDE_FILE_SIZE) {
			g_free(contents);
			return; /* file too big, ignore */
		}

		g_string_append_len(*curbuf, CONST_STR_LEN("<pre>"));
		li_string_encode_append(contents, *curbuf, LI_ENCODING_HTML);
		g_string_append_len(*curbuf, CONST_STR_LEN("</pre>"));
		g_free(contents);
	}
}
static liHandlerResult cache_etag_filter_hit(liVRequest *vr, liFilter *f) {
	cache_etag_file *cfile = (cache_etag_file*) f->param;
	UNUSED(vr);

	if (!cfile) return LI_HANDLER_GO_ON;

	if (!f->out->is_closed) li_chunkqueue_append_file_fd(f->out, NULL, 0, cfile->hit_length, cfile->hit_fd);
	cfile->hit_fd = -1;
	cache_etag_file_free(cfile);
	f->param = NULL;

	f->out->is_closed = TRUE;

	return LI_HANDLER_GO_ON;
}
示例#3
0
static int _lua_chunkqueue_add_file(lua_State *L, gboolean tempfile) {
	liChunkQueue *cq;
	const char *filename;
	GString g_filename;
	size_t len;
	struct stat st;
	int fd, err;
	goffset start, length;

	luaL_checkany(L, 2);
	cq = li_lua_get_chunkqueue(L, 1);
	if (cq == NULL) return 0;
	if (!lua_isstring(L, 2)) {
		lua_pushliteral(L, "chunkqueue:add expects filename as first parameter");
		lua_error(L);

		return -1;
	}

	filename = lua_tolstring(L, 2, &len);
	g_filename = li_const_gstring(filename, len);
	if (LI_HANDLER_GO_ON != li_stat_cache_get_sync(NULL, &g_filename, &st, &err, &fd)) {
		lua_pushliteral(L, "chunkqueue:add couldn't open file: ");
		lua_pushvalue(L, 2);
		lua_concat(L, 2);
		lua_error(L);

		return -1;
	}

	start = 0;
	length = st.st_size;

	if (lua_gettop(L) >= 3) {
		if (!lua_isnumber(L, 3)) {
			lua_pushliteral(L, "chunkqueue:add expects number (or nothing) as second parameter");
			lua_error(L);

			close(fd);
			return -1;
		}

		start = lua_tonumber(L, 3);
	}
	if (lua_gettop(L) >= 4) {
		if (!lua_isnumber(L, 4)) {
			lua_pushliteral(L, "chunkqueue:add expects number (or nothing) as third parameter");
			lua_error(L);

			close(fd);
			return -1;
		}

		length = lua_tonumber(L, 3);
	}

	if (start < 0 || start >= st.st_size || length < 0 || start + length > st.st_size) {
		lua_pushliteral(L, "chunkqueue:add: Invalid start/length values");
		lua_error(L);

		close(fd);
		return -1;
	}

	if (tempfile) {
		li_chunkqueue_append_tempfile_fd(cq, g_string_new_len(filename, len), start, length, fd);
	} else {
		li_chunkqueue_append_file_fd(cq, NULL, start, length, fd);
	}

	return 0;
}
示例#4
0
static liHandlerResult cache_etag_handle(liVRequest *vr, gpointer param, gpointer *context) {
	cache_etag_context *ctx = (cache_etag_context*) param;
	cache_etag_file *cfile = (cache_etag_file*) *context;
	GList *etag_entry;
	liHttpHeader *etag;
	struct stat st;
	GString *tmp_str = vr->wrk->tmp_str;
	liHandlerResult res;
	int err, fd;

	if (!cfile) {
		if (vr->request.http_method != LI_HTTP_METHOD_GET) return LI_HANDLER_GO_ON;

		LI_VREQUEST_WAIT_FOR_RESPONSE_HEADERS(vr);

		if (vr->response.http_status != 200) return LI_HANDLER_GO_ON;

		/* Don't cache static files if filter list is empty */
		if (NULL == vr->filters_out_first && vr->backend_source->out->is_closed && 0 == vr->backend_source->out->mem_usage)
			return LI_HANDLER_GO_ON;

		etag_entry = li_http_header_find_first(vr->response.headers, CONST_STR_LEN("etag"));
		if (!etag_entry) return LI_HANDLER_GO_ON; /* no etag -> no caching */
		if (li_http_header_find_next(etag_entry, CONST_STR_LEN("etag"))) {
			VR_ERROR(vr, "%s", "duplicate etag header in response, will not cache it");
			return LI_HANDLER_GO_ON;
		}
		etag = (liHttpHeader*) etag_entry->data;

		cfile = cache_etag_file_create(createFileName(vr, ctx->path, etag));
		*context = cfile;
	}

	res = li_stat_cache_get(vr, cfile->filename, &st, &err, &fd);
	if (res == LI_HANDLER_WAIT_FOR_EVENT)
		return res;

	if (res == LI_HANDLER_GO_ON) {
		liFilter *f;
		if (!S_ISREG(st.st_mode)) {
			VR_ERROR(vr, "Unexpected file type for cache file '%s' (mode %o)", cfile->filename->str, (unsigned int) st.st_mode);
			close(fd);
			return LI_HANDLER_GO_ON; /* no caching */
		}
		cfile->hit_fd = fd;
#ifdef FD_CLOEXEC
		fcntl(cfile->hit_fd, F_SETFD, FD_CLOEXEC);
#endif
		if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
			VR_DEBUG(vr, "cache hit for '%s'", vr->request.uri.path->str);
		}
		cfile->hit_length = st.st_size;
		g_string_truncate(tmp_str, 0);
		li_string_append_int(tmp_str, st.st_size);
		li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Length"), GSTR_LEN(tmp_str));
		f = li_vrequest_add_filter_out(vr, cache_etag_filter_hit, NULL, NULL, NULL);
		if (NULL != f) {
			li_chunkqueue_append_file_fd(f->out, NULL, 0, cfile->hit_length, cfile->hit_fd);
			f->out->is_closed = TRUE;
			cfile->hit_fd = -1;
		}
		cache_etag_file_free(cfile);

		*context = NULL;
		return LI_HANDLER_GO_ON;
	}

	if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
		VR_DEBUG(vr, "cache miss for '%s'", vr->request.uri.path->str);
	}

	if (!cache_etag_file_start(vr, cfile)) {
		cache_etag_file_free(cfile);
		*context = NULL;
		return LI_HANDLER_GO_ON; /* no caching */
	}

	li_vrequest_add_filter_out(vr, cache_etag_filter_miss, cache_etag_filter_free, NULL, cfile);
	*context = NULL;

	return LI_HANDLER_GO_ON;
}