Ejemplo n.º 1
0
static liHandlerResult redirect(liVRequest *vr, gpointer param, gpointer *context) {
	guint i;
	redirect_rule *rule;
	redirect_data *rd = param;
	gboolean debug = _OPTION(vr, rd->p, 0).boolean;
	GString *dest = vr->wrk->tmp_str;

	UNUSED(context);

	if (li_vrequest_is_handled(vr)) return LI_HANDLER_GO_ON;

	for (i = 0; i < rd->rules->len; i++) {
		rule = &g_array_index(rd->rules, redirect_rule, i);

		if (redirect_internal(vr, dest, rule)) {
			/* regex matched */
			if (debug) {
				VR_DEBUG(vr, "redirect: \"%s\"", dest->str);
			}

			if (!li_vrequest_handle_direct(vr)) return LI_HANDLER_ERROR;

			vr->response.http_status = 301;
			li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Location"), GSTR_LEN(dest));

			/* stop at first matching regex */
			return LI_HANDLER_GO_ON;
		}
	}

	return LI_HANDLER_GO_ON;
}
Ejemplo n.º 2
0
static int lua_vrequest_handle_direct(lua_State *L) {
	liVRequest *vr;
	vr = li_lua_get_vrequest(L, 1);

	lua_pushboolean(L, li_vrequest_handle_direct(vr));

	return 1;
}
Ejemplo n.º 3
0
static liHandlerResult auth_handle_deny(liVRequest *vr, gpointer param, gpointer *context) {
	liPlugin *p = param;
	UNUSED(context);

	if (!li_vrequest_handle_direct(vr)) {
		if (_OPTION(vr, p, 0).boolean || CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
			VR_DEBUG(vr, "skipping auth.deny as request is already handled with current status %i", vr->response.http_status);
		}
		return LI_HANDLER_GO_ON;
	}

	vr->response.http_status = 403;

	return LI_HANDLER_GO_ON;
}
Ejemplo n.º 4
0
static liHandlerResult mc_handle_lookup(liVRequest *vr, gpointer param, gpointer *context) {
	memcached_ctx *ctx = param;
	memcache_request *req = *context;

	if (req) {
		static const GString default_mime_str = { CONST_STR_LEN("application/octet-stream"), 0 };

		liBuffer *buf = req->buffer;
		const GString *mime_str;

		if (NULL != req->req) return LI_HANDLER_WAIT_FOR_EVENT; /* not done yet */

		g_slice_free(memcache_request, req);
		*context = NULL;

		if (NULL == buf) {
			/* miss */
			if (ctx->act_miss) li_action_enter(vr, ctx->act_miss);
			return LI_HANDLER_GO_ON;
		}

		if (!li_vrequest_handle_direct(vr)) {
			if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
				VR_DEBUG(vr, "%s", "memcached.lookup: request already handled");
			}
			li_buffer_release(buf);
			return LI_HANDLER_GO_ON;
		}

		if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
			VR_DEBUG(vr, "%s", "memcached.lookup: key found, handling request");
		}

		li_chunkqueue_append_buffer(vr->direct_out, buf);

		vr->response.http_status = 200;

		mime_str = li_mimetype_get(vr, vr->request.uri.path);
		if (!mime_str) mime_str = &default_mime_str;
		li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Type"), GSTR_LEN(mime_str));

		/* hit */
		if (ctx->act_found) li_action_enter(vr, ctx->act_found);
		return LI_HANDLER_GO_ON;
	} else {
		liMemcachedCon *con;
		GError *err = NULL;

		if (li_vrequest_is_handled(vr)) {
			if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
				VR_DEBUG(vr, "%s", "memcached.lookup: request already handled");
			}
			return LI_HANDLER_GO_ON;
		}

		con = mc_ctx_prepare(ctx, vr->wrk);
		mc_ctx_build_key(vr->wrk->tmp_str, ctx, vr);

		if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
			VR_DEBUG(vr, "memcached.lookup: looking up key '%s'", vr->wrk->tmp_str->str);
		}

		req = g_slice_new0(memcache_request);
		req->req = li_memcached_get(con, vr->wrk->tmp_str, memcache_callback, req, &err);

		if (NULL == req->req) {
			if (NULL != err) {
				if (LI_MEMCACHED_DISABLED != err->code) {
					VR_ERROR(vr, "memcached.lookup: get failed: %s", err->message);
				}
				g_clear_error(&err);
			} else {
				VR_ERROR(vr, "memcached.lookup: get failed: %s", "Unkown error");
			}
			g_slice_free(memcache_request, req);

			/* miss */
			if (ctx->act_miss) li_action_enter(vr, ctx->act_miss);

			return LI_HANDLER_GO_ON;
		}
		req->vr = vr;

		*context = req;

		return LI_HANDLER_WAIT_FOR_EVENT;
	}
}
Ejemplo n.º 5
0
static liHandlerResult dirlist(liVRequest *vr, gpointer param, gpointer *context) {
	GString *listing;
	liStatCacheEntry *sce;
	dirlist_data *dd;

	UNUSED(context);

	switch (vr->request.http_method) {
	case LI_HTTP_METHOD_GET:
	case LI_HTTP_METHOD_HEAD:
		break;
	default:
		return LI_HANDLER_GO_ON;
	}

	if (li_vrequest_is_handled(vr)) return LI_HANDLER_GO_ON;

	if (vr->physical.path->len == 0) return LI_HANDLER_GO_ON;

	switch (li_stat_cache_get_dirlist(vr, vr->physical.path, &sce)) {
	case LI_HANDLER_GO_ON: break;
	case LI_HANDLER_WAIT_FOR_EVENT: return LI_HANDLER_WAIT_FOR_EVENT;
	default: return LI_HANDLER_ERROR;
	}

	dd = param;

	if (sce->data.failed) {
		/* stat failed */
		int e = sce->data.err;

		li_stat_cache_entry_release(vr, sce);

		switch (e) {
		case ENOENT:
		case ENOTDIR:
			return LI_HANDLER_GO_ON;
		case EACCES:
			if (!li_vrequest_handle_direct(vr)) return LI_HANDLER_ERROR;
			vr->response.http_status = 403;
			return LI_HANDLER_GO_ON;
		default:
			VR_ERROR(vr, "stat('%s') failed: %s", sce->data.path->str, g_strerror(sce->data.err));
			return LI_HANDLER_ERROR;
		}
	} else if (!S_ISDIR(sce->data.st.st_mode)) {
		li_stat_cache_entry_release(vr, sce);
		return LI_HANDLER_GO_ON;
	} else if (vr->request.uri.path->len == 0 || vr->request.uri.path->str[vr->request.uri.path->len-1] != '/') {
		li_stat_cache_entry_release(vr, sce);
		li_vrequest_redirect_directory(vr);
		return LI_HANDLER_GO_ON;
	} else {
		/* everything ok, we have the directory listing */
		gboolean cachable;
		guint i, j;
		liStatCacheEntryData *sced;
		GString *mime_str, *encoded;
		GArray *directories, *files;
		gchar sizebuf[sizeof("999.9K")+1];
		gchar datebuf[sizeof("2005-Jan-01 22:23:24")+1];
		guint datebuflen;
		struct tm tm;
		gboolean hide;

		if (!li_vrequest_handle_direct(vr)) {
			li_stat_cache_entry_release(vr, sce);
			return LI_HANDLER_ERROR;
		}
		vr->response.http_status = 200;

		if (dd->debug)
			VR_DEBUG(vr, "dirlist for \"%s\", %u entries", sce->data.path->str, sce->dirlist->len);

		li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Type"), GSTR_LEN(dd->content_type));
		li_etag_set_header(vr, &sce->data.st, &cachable);
		if (cachable) {
			vr->response.http_status = 304;
			li_stat_cache_entry_release(vr, sce);
			return LI_HANDLER_GO_ON;
		}

		/* temporary string for encoded names */
		encoded = g_string_sized_new(64-1);

		/* seperate directories from other files */
		directories = g_array_sized_new(FALSE, FALSE, sizeof(guint), 16);
		files = g_array_sized_new(FALSE, FALSE, sizeof(guint), sce->dirlist->len);
		for (i = 0; i < sce->dirlist->len; i++) {
			sced = &g_array_index(sce->dirlist, liStatCacheEntryData, i);
			hide = FALSE;

			/* ingore entries where the stat() failed */
			if (sced->failed)
				continue;

			if (dd->hide_dotfiles && sced->path->str[0] == '.')
				continue;

			if (dd->hide_tildefiles && sced->path->str[sced->path->len-1] == '~')
				continue;

			for (j = 0; j < dd->exclude_suffix->len; j++) {
				if (li_string_suffix(sced->path, GSTR_LEN((GString*)g_ptr_array_index(dd->exclude_suffix, j)))) {
					hide = TRUE;
					break;
				}
			}

			if (hide)
				continue;

			for (j = 0; j < dd->exclude_prefix->len; j++) {
				if (li_string_prefix(sced->path, GSTR_LEN((GString*)g_ptr_array_index(dd->exclude_prefix, j)))) {
					hide = TRUE;
					break;
				}
			}

			if (hide)
				continue;

			if (S_ISDIR(sced->st.st_mode)) {
				if (dd->hide_directories) continue;
				g_array_append_val(directories, i);
			} else {
				if ((dd->include_header || dd->hide_header) && g_str_equal(sced->path, "HEADER.txt")) {
					if (dd->hide_header) continue;
				} else if ((dd->include_readme || dd->hide_readme) && g_str_equal(sced->path, "README.txt")) {
					if (dd->hide_readme) continue;
				}
				g_array_append_val(files, i);
			}
		}

		listing = g_string_sized_new(4*1024-1);
		g_string_append_printf(listing, html_header_start, vr->request.uri.path->str);

		if (dd->css) {
			/* custom css */
			g_string_append_len(listing, CONST_STR_LEN("		<link rel=\"stylesheet\" type=\"text/css\" href=\""));
			g_string_append_len(listing, GSTR_LEN(dd->css));
			g_string_append_len(listing, CONST_STR_LEN("\" />\n"));
		} else {
			/* default css */
			g_string_append_len(listing, CONST_STR_LEN(html_css));
		}
		g_string_append_len(listing, CONST_STR_LEN(html_header_end));

		try_append_file(vr, &listing, "HEADER.txt", dd->encode_header);

		g_string_append_printf(listing, html_table_start, vr->request.uri.path->str);

		if (0 != strcmp("/", vr->request.uri.path->str)) {
			g_string_append_printf(listing, html_table_row, '0', "../",
				"Parent Directory", (gint64)0, "", (gint64)0, "-", "Directory");
		}

		/* list directories */
		if (!dd->hide_directories) {
			for (i = 0; i < directories->len; i++) {
				sced = &g_array_index(sce->dirlist, liStatCacheEntryData, g_array_index(directories, guint, i));

				localtime_r(&(sced->st.st_mtime), &tm);
				datebuflen = strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
				datebuf[datebuflen] = '\0';

				g_string_append_len(listing, CONST_STR_LEN("				<tr group=\"1\"><td><a href=\""));
				li_string_encode(sced->path->str, encoded, LI_ENCODING_URI);
				g_string_append_len(listing, GSTR_LEN(encoded));
				g_string_append_len(listing, CONST_STR_LEN("/\">"));
				li_string_encode(sced->path->str, encoded, LI_ENCODING_HTML);
				g_string_append_len(listing, GSTR_LEN(encoded));
				g_string_append_len(listing, CONST_STR_LEN("</a></td><td class=\"modified\" val=\""));
				li_string_append_int(listing, sced->st.st_mtime);
				g_string_append_len(listing, CONST_STR_LEN("\">"));
				g_string_append_len(listing, datebuf, datebuflen);
				g_string_append_len(listing, CONST_STR_LEN("</td>"
					"<td class=\"size\" val=\"0\">-</td>"
					"<td class=\"type\">Directory</td></tr>\n"));
			}
		}

		/*g_string_append_len(listing, CONST_STR_LEN("<tr><td colspan=\"4\">&nbsp;</td></tr>\n"));*/

		/* list files */
		for (i = 0; i < files->len; i++) {
			sced = &g_array_index(sce->dirlist, liStatCacheEntryData, g_array_index(files, guint, i));
			mime_str = li_mimetype_get(vr, sced->path);

			localtime_r(&(sced->st.st_mtime), &tm);
			datebuflen = strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
			datebuf[datebuflen] = '\0';

			dirlist_format_size(sizebuf, sced->st.st_size);

			g_string_append_len(listing, CONST_STR_LEN("				<tr group=\"2\"><td><a href=\""));
			li_string_encode(sced->path->str, encoded, LI_ENCODING_URI);
			g_string_append_len(listing, GSTR_LEN(encoded));
			g_string_append_len(listing, CONST_STR_LEN("\">"));
			li_string_encode(sced->path->str, encoded, LI_ENCODING_HTML);
			g_string_append_len(listing, GSTR_LEN(encoded));
			g_string_append_len(listing, CONST_STR_LEN(
				"</a></td>"
				"<td class=\"modified\" val=\""));
			li_string_append_int(listing, sced->st.st_mtime);
			g_string_append_len(listing, CONST_STR_LEN("\">"));
			g_string_append_len(listing, datebuf, datebuflen);
			g_string_append_len(listing, CONST_STR_LEN("</td><td class=\"size\" val=\""));
			li_string_append_int(listing, sced->st.st_size);
			g_string_append_len(listing, CONST_STR_LEN("\">"));
			g_string_append(listing, sizebuf);
			g_string_append_len(listing, CONST_STR_LEN("</td><td class=\"type\">"));
			if (mime_str) {
				g_string_append_len(listing, GSTR_LEN(mime_str));
			} else {
				g_string_append_len(listing, CONST_STR_LEN("application/octet-stream"));
			}
			g_string_append_len(listing, CONST_STR_LEN("</td></tr>\n"));

			/*
			g_string_append_printf(listing, html_table_row,
				sced->path->str, sced->path->str,
				(gint64)sced->st.st_mtime, datebuf,
				sced->st.st_size, sizebuf,
				mime_str ? mime_str->str : "application/octet-stream");
			*/
		}

		g_string_append_len(listing, CONST_STR_LEN(html_table_end));

		try_append_file(vr, &listing, "README.txt", dd->encode_readme);

		if (dd->include_sort) {
			g_string_append_len(listing, CONST_STR_LEN(javascript_sort));
		}

		g_string_append_printf(listing, html_footer, CORE_OPTIONPTR(LI_CORE_OPTION_SERVER_TAG).string->str);

		li_chunkqueue_append_string(vr->direct_out, listing);
		g_string_free(encoded, TRUE);
		g_array_free(directories, TRUE);
		g_array_free(files, TRUE);
	}

	li_stat_cache_entry_release(vr, sce);

	return LI_HANDLER_GO_ON;
}
Ejemplo n.º 6
0
/* the CollectCallback */
static void progress_collect_cb(gpointer cbdata, gpointer fdata, GPtrArray *result, gboolean complete) {
	guint i;
	GString *output;
	mod_progress_node *node = NULL;
	mod_progress_job *job = fdata;
	liVRequest *vr = job->vr;
	gboolean debug = job->debug;
	mod_progress_format format = job->format;

	UNUSED(cbdata);

	if (complete) {
		/* clear context so it doesn't get cleaned up anymore */
		*(job->context) = NULL;

		for (i = 0; i < result->len; i++) {
			node = g_ptr_array_index(result, i);
			if (node)
				break;
		}

		output = g_string_sized_new(128);

		/* send mime-type. there seems to be no standard for javascript... using the most commong */
		li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("application/x-javascript"));

		if (format == PROGRESS_FORMAT_LEGACY) {
			g_string_append_len(output, CONST_STR_LEN("new Object("));
		} else if (format == PROGRESS_FORMAT_JSONP) {
			gchar *val;
			guint len;

			if (li_querystring_find(vr->request.uri.query, CONST_STR_LEN("X-Progress-Callback"), &val, &len)) {
				/* X-Progress-Callback specified, need to check for xss */
				gchar *c;

				for (c = val; c != val+len; c++) {
					if ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') || (*c >= '0' && *c <= '9') || *c == '.' || *c == '_')
						continue;
					break;
				}

				/* was there a bad char? */
				if (c != val+len) {
					g_string_append_len(output, CONST_STR_LEN("progress("));
				} else {
					g_string_append_len(output,val, len);
					g_string_append_c(output, '(');
				}
			} else {
				g_string_append_len(output, CONST_STR_LEN("progress("));
			}
		}

		if (!node) {
			/* progress id not known */
			if (debug)
				VR_DEBUG(vr, "progress.show: progress id \"%s\" unknown", job->id);
			
			g_string_append_len(output, CONST_STR_LEN("{\"state\": \"unknown\"}"));
		} else {
			if (debug)
				VR_DEBUG(vr, "progress.show: progress id \"%s\" found", job->id);

			if (node->vr) {
				/* still in progress */
				g_string_append_printf(output,
					"{\"state\": \"running\", \"received\": %"G_GUINT64_FORMAT", \"sent\": %"G_GUINT64_FORMAT", \"request_size\": %"G_GUINT64_FORMAT", \"response_size\": %"G_GUINT64_FORMAT"}",
					node->bytes_in, node->bytes_out, node->request_size, node->response_size
				);
			} else if (node->status_code == 200) {
				/* done, success */
				g_string_append_printf(output,
					"{\"state\": \"done\", \"received\": %"G_GUINT64_FORMAT", \"sent\": %"G_GUINT64_FORMAT", \"request_size\": %"G_GUINT64_FORMAT", \"response_size\": %"G_GUINT64_FORMAT"}",
					node->bytes_in, node->bytes_out, node->request_size, node->response_size
				);
			} else {
				/* done, error */
				g_string_append_printf(output,
					"{\"state\": \"error\", \"status\": %d}",
					node->status_code
				);
			}
		}

		if (format == PROGRESS_FORMAT_LEGACY || format == PROGRESS_FORMAT_JSONP) {
			g_string_append_c(output, ')');
		}

		vr->response.http_status = 200;
		li_chunkqueue_append_string(vr->out, output);
		li_vrequest_handle_direct(vr);
		li_vrequest_joblist_append(vr);
	}

	/* free results */
	for (i = 0; i < result->len; i++) {
		if (g_ptr_array_index(result, i))
			g_slice_free(mod_progress_node, g_ptr_array_index(result, i));
	}

	g_free(job->id);
	g_slice_free(mod_progress_job, job);
}
Ejemplo n.º 7
0
static liHandlerResult auth_basic(liVRequest *vr, gpointer param, gpointer *context) {
	liHttpHeader *hdr;
	gboolean auth_ok = FALSE;
	AuthBasicData *bdata = param;
	gboolean debug = _OPTION(vr, bdata->p, 0).boolean;

	UNUSED(context);

	if (li_vrequest_is_handled(vr)) {
		if (debug || CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
			VR_DEBUG(vr, "skipping auth.basic as request is already handled with current status %i", vr->response.http_status);
		}
		return LI_HANDLER_GO_ON;
	}

	/* check for Authorization header */
	hdr = li_http_header_lookup(vr->request.headers, CONST_STR_LEN("Authorization"));

	if (!hdr || !g_str_has_prefix(LI_HEADER_VALUE(hdr), "Basic ")) {
		if (debug) {
			VR_DEBUG(vr, "requesting authorization from client for realm \"%s\"", bdata->realm->str);
		}
	} else {
		gchar *decoded, *username = NULL, *password;
		size_t len;
		/* auth_info contains username:password encoded in base64 */
		if (NULL != (decoded = (gchar*)g_base64_decode(LI_HEADER_VALUE(hdr) + sizeof("Basic ") - 1, &len))) {
			/* bogus data? */
			if (NULL != (password = strchr(decoded, ':'))) {
				*password = '******';
				password++;
				username = decoded;
			} else {
				g_free(decoded);
			}
		}

		if (!username) {
			if (debug) {
				VR_DEBUG(vr, "couldn't parse authorization info from client for realm \"%s\"", bdata->realm->str);
			}
		} else {
			GString user = li_const_gstring(username, password - username - 1);
			GString pass = li_const_gstring(password, len - (password - username));
			if (bdata->backend(vr, &user, &pass, bdata, debug)) {
				auth_ok = TRUE;

				li_environment_set(&vr->env, CONST_STR_LEN("REMOTE_USER"), username, password - username - 1);
				li_environment_set(&vr->env, CONST_STR_LEN("AUTH_TYPE"), CONST_STR_LEN("Basic"));
			} else {
				if (debug) {
					VR_DEBUG(vr, "wrong authorization info from client on realm \"%s\" (user: \"%s\")", bdata->realm->str, username);
				}
			}
			g_free(decoded);
		}
	}

	g_string_truncate(vr->wrk->tmp_str, 0);
	g_string_append_len(vr->wrk->tmp_str, CONST_STR_LEN("Basic realm=\""));
	g_string_append_len(vr->wrk->tmp_str, GSTR_LEN(bdata->realm));
	g_string_append_c(vr->wrk->tmp_str, '"');
	/* generate header always */

	if (!auth_ok) {
		li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("WWW-Authenticate"), GSTR_LEN(vr->wrk->tmp_str));

		/* we already checked for handled */
		if (!li_vrequest_handle_direct(vr))
			return LI_HANDLER_ERROR;

		vr->response.http_status = 401;
		return LI_HANDLER_GO_ON;
	} else {
		/* lets hope browser just ignore the header if status is not 401
		 * but this way it is easier to use a later "auth.deny;"
		 */
		li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("WWW-Authenticate"), GSTR_LEN(vr->wrk->tmp_str));
	}

	if (debug) {
		VR_DEBUG(vr, "client authorization successful for realm \"%s\"", bdata->realm->str);
	}

	return LI_HANDLER_GO_ON;
}
Ejemplo n.º 8
0
static liHandlerResult mod_limit_action_handle(liVRequest *vr, gpointer param, gpointer *context) {
	gboolean limit_reached = FALSE;
	mod_limit_context *ctx = (mod_limit_context*) param;
	GPtrArray *arr = g_ptr_array_index(vr->plugin_ctx, ctx->plugin->id);
	gint cons;
	mod_limit_req_ip_data *rid;
	liSocketAddress *remote_addr = &vr->coninfo->remote_addr;
	gpointer addr;
	guint32 bits;

	UNUSED(context);

	if (li_vrequest_is_handled(vr)) {
		VR_DEBUG(vr, "%s", "mod_limit: already have a content handler - ignoring limits. Put limit.* before content handlers such as 'static', 'fastcgi' or 'proxy'");
		return LI_HANDLER_GO_ON;
	}

	/* IPv4 or IPv6? */
	switch (remote_addr->addr->plain.sa_family) {
	case AF_INET:
		addr = &remote_addr->addr->ipv4.sin_addr.s_addr;
		bits = 32;
		break;
	case AF_INET6:
		addr = &remote_addr->addr->ipv6.sin6_addr.s6_addr;
		bits = 128;
		break;
	default:
		if (ctx->type == ML_TYPE_CON_IP || ctx->type == ML_TYPE_REQ_IP) {
			VR_DEBUG(vr, "%s", "mod_limit only supports ipv4 or ipv6 clients");
			return LI_HANDLER_ERROR;
		}
		addr = NULL;
		bits = 0;
	}

	if (!arr) {
		/* request is not in any context yet, create new array */
		arr = g_ptr_array_sized_new(2);
		g_ptr_array_index(vr->plugin_ctx, ctx->plugin->id) = arr;
	}

	switch (ctx->type) {
	case ML_TYPE_CON:
#ifdef GLIB_VERSION_2_30
		/* since 2.30 g_atomic_int_add does the same as g_atomic_int_exchange_and_add,
		 * before it didn't return the old value. this fixes the deprecation warning. */
		if (g_atomic_int_add(&ctx->pool.con, 1) > ctx->limit) {
			g_atomic_int_add(&ctx->pool.con, -1);
			limit_reached = TRUE;
			VR_DEBUG(vr, "limit.con: limit reached (%d active connections)", ctx->limit);
		}
#else
		if (g_atomic_int_exchange_and_add(&ctx->pool.con, 1) > ctx->limit) {
			g_atomic_int_add(&ctx->pool.con, -1);
			limit_reached = TRUE;
			VR_DEBUG(vr, "limit.con: limit reached (%d active connections)", ctx->limit);
		}
#endif
		break;
	case ML_TYPE_CON_IP:
		g_mutex_lock(ctx->mutex);
		cons = GPOINTER_TO_INT(li_radixtree_lookup_exact(ctx->pool.con_ip, addr, bits));
		if (cons < ctx->limit) {
			li_radixtree_insert(ctx->pool.con_ip, addr, bits, GINT_TO_POINTER(cons+1));
		} else {
			limit_reached = TRUE;
			VR_DEBUG(vr, "limit.con_ip: limit reached (%d active connections)", ctx->limit);
		}
		g_mutex_unlock(ctx->mutex);
		break;
	case ML_TYPE_REQ:
		g_mutex_lock(ctx->mutex);
		if (li_cur_ts(vr->wrk) - ctx->pool.req.ts > 1.0) {
			/* reset pool */
			ctx->pool.req.ts = li_cur_ts(vr->wrk);
			ctx->pool.req.num = 1;
		} else {
			ctx->pool.req.num++;
			if (ctx->pool.req.num > ctx->limit) {
				limit_reached = TRUE;
				VR_DEBUG(vr, "limit.req: limit reached (%d req/s)", ctx->limit);
			}
		}
		g_mutex_unlock(ctx->mutex);
		break;
	case ML_TYPE_REQ_IP:
		g_mutex_lock(ctx->mutex);
		rid = li_radixtree_lookup_exact(ctx->pool.req_ip, addr, bits);
		if (!rid) {
			/* IP not known */
			rid = g_slice_new0(mod_limit_req_ip_data);
			rid->requests = 1;
			rid->ip = li_sockaddr_dup(*remote_addr);
			rid->ctx = ctx;
			rid->timeout_elem.data = rid;
			li_radixtree_insert(ctx->pool.req_ip, addr, bits, rid);
			li_waitqueue_push(&(((mod_limit_data*)ctx->plugin->data)->timeout_queues[vr->wrk->ndx]), &rid->timeout_elem);
		} else if (rid->requests < ctx->limit) {
			rid->requests++;
		} else {
			limit_reached = TRUE;
			VR_DEBUG(vr, "limit.req_ip: limit reached (%d req/s)", ctx->limit);
		}
		g_mutex_unlock(ctx->mutex);
		break;
	}

	if (limit_reached) {
		/* limit reached, we either execute the defined action or return a 503 error page */
		if (ctx->action_limit_reached) {
			/* execute action */
			li_action_enter(vr, ctx->action_limit_reached);
		} else {
			/* return 503 error page */
			if (!li_vrequest_handle_direct(vr)) {
				return LI_HANDLER_ERROR;
			}

			vr->response.http_status = 503;
		}
	} else {
		g_ptr_array_add(arr, ctx);
		g_atomic_int_inc(&ctx->refcount);
	}

	return LI_HANDLER_GO_ON;
}
Ejemplo n.º 9
0
/* closes connection after response */
static void bad_request(liConnection *con, int status) {
	con->info.keep_alive = FALSE;
	con->mainvr->response.http_status = status;
	li_vrequest_handle_direct(con->mainvr);
}
Ejemplo n.º 10
0
static liHandlerResult flv(liVRequest *vr, gpointer param, gpointer *context) {
    gchar *start;
    guint len;
    goffset pos;
    liHandlerResult res;
    gboolean cachable;
    struct stat st;
    int err;
    int fd = -1;

    UNUSED(context);
    UNUSED(param);

    if (li_vrequest_is_handled(vr))
        return LI_HANDLER_GO_ON;

    res = li_stat_cache_get(vr, vr->physical.path, &st, &err, &fd);

    if (res == LI_HANDLER_WAIT_FOR_EVENT)
        return res;

    if (res == LI_HANDLER_ERROR) {
        /* open or fstat failed */

        if (fd != -1)
            close(fd);

        if (!li_vrequest_handle_direct(vr))
            return LI_HANDLER_ERROR;

        switch (err) {
        case ENOENT:
        case ENOTDIR:
            vr->response.http_status = 404;
            return LI_HANDLER_GO_ON;
        case EACCES:
            vr->response.http_status = 403;
            return LI_HANDLER_GO_ON;
        default:
            VR_ERROR(vr, "stat() or open() for '%s' failed: %s", vr->physical.path->str, g_strerror(err));
            return LI_HANDLER_ERROR;
        }
    } else if (S_ISDIR(st.st_mode)) {
        if (fd != -1)
            close(fd);

        return LI_HANDLER_GO_ON;
    } else if (!S_ISREG(st.st_mode)) {
        if (fd != -1)
            close(fd);

        if (!li_vrequest_handle_direct(vr))
            return LI_HANDLER_ERROR;

        vr->response.http_status = 403;
    } else {
        liChunkFile *cf;

#ifdef FD_CLOEXEC
        fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif

        if (!li_vrequest_handle_direct(vr)) {
            close(fd);
            return LI_HANDLER_ERROR;
        }

        if (li_querystring_find(vr->request.uri.query, CONST_STR_LEN("start"), &start, &len)) {
            guint i;
            pos = 0;

            for (i = 0; i < len; i++) {
                if (start[i] >= '0' && start[i] <= '9') {
                    pos *= 10;
                    pos += start[i] - '0';
                }
            }
        } else {
            pos = 0;
        }

        li_etag_set_header(vr, &st, &cachable);
        if (cachable) {
            vr->response.http_status = 304;
            close(fd);
            return LI_HANDLER_GO_ON;
        }


        vr->response.http_status = 200;
        li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/x-flv"));

        if (pos < 0 || pos > st.st_size)
            pos = 0;

        if (pos != 0)
            li_chunkqueue_append_mem(vr->direct_out, CONST_STR_LEN("FLV\x1\x1\0\0\0\x9\0\0\0\x9"));

        cf = li_chunkfile_new(NULL, fd, FALSE);
        li_chunkqueue_append_chunkfile(vr->direct_out, cf, pos, st.st_size - pos);
        li_chunkfile_release(cf);
    }

    return LI_HANDLER_GO_ON;
}