/*
 * HTTP ACLs declaration
 *
 * Copyright 2000-2018 Willy Tarreau <w@1wt.eu>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 *
 */

#include <sys/types.h>

#include <ctype.h>
#include <string.h>
#include <time.h>

#include <haproxy/acl.h>
#include <haproxy/api.h>
#include <haproxy/arg.h>
#include <haproxy/auth.h>
#include <haproxy/chunk.h>
#include <haproxy/http.h>
#include <haproxy/pattern.h>
#include <haproxy/pool.h>
#include <haproxy/tools.h>
#include <haproxy/version.h>


/* We use the pre-parsed method if it is known, and store its number as an
 * integer. If it is unknown, we use the pointer and the length.
 */
static int pat_parse_meth(const char *text, struct pattern *pattern, int mflags, char **err)
{
	int len, meth;

	len  = strlen(text);
	meth = find_http_meth(text, len);

	pattern->val.i = meth;
	if (meth == HTTP_METH_OTHER) {
		pattern->ptr.str = (char *)text;
		pattern->len = len;
	}
	else {
		pattern->ptr.str = NULL;
		pattern->len = 0;
	}
	return 1;
}

/* See above how the method is stored in the global pattern */
static struct pattern *pat_match_meth(struct sample *smp, struct pattern_expr *expr, int fill)
{
	int icase;
	struct pattern_list *lst;
	struct pattern *pattern;

	list_for_each_entry(lst, &expr->patterns, list) {
		pattern = &lst->pat;

		/* well-known method */
		if (pattern->val.i != HTTP_METH_OTHER) {
			if (smp->data.u.meth.meth == pattern->val.i)
				return pattern;
			else
				continue;
		}

		/* Other method, we must compare the strings */
		if (pattern->len != smp->data.u.meth.str.data)
			continue;

		icase = expr->mflags & PAT_MF_IGNORE_CASE;
		if ((icase && strncasecmp(pattern->ptr.str, smp->data.u.meth.str.area, smp->data.u.meth.str.data) == 0) ||
		    (!icase && strncmp(pattern->ptr.str, smp->data.u.meth.str.area, smp->data.u.meth.str.data) == 0))
			return pattern;
	}
	return NULL;
}

/************************************************************************/
/*          All supported ACL keywords must be declared here.           */
/************************************************************************/

/* Note: must not be declared <const> as its list will be overwritten.
 * Please take care of keeping this list alphabetically sorted.
 */
static struct acl_kw_list acl_kws = {ILH, {
	{ "base",            "base",     PAT_MATCH_STR },
	{ "base_beg",        "base",     PAT_MATCH_BEG },
	{ "base_dir",        "base",     PAT_MATCH_DIR },
	{ "base_dom",        "base",     PAT_MATCH_DOM },
	{ "base_end",        "base",     PAT_MATCH_END },
	{ "base_len",        "base",     PAT_MATCH_LEN },
	{ "base_reg",        "base",     PAT_MATCH_REG },
	{ "base_sub",        "base",     PAT_MATCH_SUB },

	{ "cook",            "req.cook", PAT_MATCH_STR },
	{ "cook_beg",        "req.cook", PAT_MATCH_BEG },
	{ "cook_dir",        "req.cook", PAT_MATCH_DIR },
	{ "cook_dom",        "req.cook", PAT_MATCH_DOM },
	{ "cook_end",        "req.cook", PAT_MATCH_END },
	{ "cook_len",        "req.cook", PAT_MATCH_LEN },
	{ "cook_reg",        "req.cook", PAT_MATCH_REG },
	{ "cook_sub",        "req.cook", PAT_MATCH_SUB },

	{ "hdr",             "req.hdr",  PAT_MATCH_STR },
	{ "hdr_beg",         "req.hdr",  PAT_MATCH_BEG },
	{ "hdr_dir",         "req.hdr",  PAT_MATCH_DIR },
	{ "hdr_dom",         "req.hdr",  PAT_MATCH_DOM },
	{ "hdr_end",         "req.hdr",  PAT_MATCH_END },
	{ "hdr_len",         "req.hdr",  PAT_MATCH_LEN },
	{ "hdr_reg",         "req.hdr",  PAT_MATCH_REG },
	{ "hdr_sub",         "req.hdr",  PAT_MATCH_SUB },

	/* these two declarations uses strings with list storage (in place
	 * of tree storage). The basic match is PAT_MATCH_STR, but the indexation
	 * and delete functions are relative to the list management. The parse
	 * and match method are related to the corresponding fetch methods. This
	 * is very particular ACL declaration mode.
	 */
	{ "http_auth_group", NULL,       PAT_MATCH_STR, NULL,  pat_idx_list_str, pat_del_list_ptr, NULL, pat_match_auth },
	{ "method",          NULL,       PAT_MATCH_STR, pat_parse_meth, pat_idx_list_str, pat_del_list_ptr, NULL, pat_match_meth },

	{ "path",            "path",     PAT_MATCH_STR },
	{ "path_beg",        "path",     PAT_MATCH_BEG },
	{ "path_dir",        "path",     PAT_MATCH_DIR },
	{ "path_dom",        "path",     PAT_MATCH_DOM },
	{ "path_end",        "path",     PAT_MATCH_END },
	{ "path_len",        "path",     PAT_MATCH_LEN },
	{ "path_reg",        "path",     PAT_MATCH_REG },
	{ "path_sub",        "path",     PAT_MATCH_SUB },

	{ "req_ver",         "req.ver",  PAT_MATCH_STR },
	{ "resp_ver",        "res.ver",  PAT_MATCH_STR },

	{ "scook",           "res.cook", PAT_MATCH_STR },
	{ "scook_beg",       "res.cook", PAT_MATCH_BEG },
	{ "scook_dir",       "res.cook", PAT_MATCH_DIR },
	{ "scook_dom",       "res.cook", PAT_MATCH_DOM },
	{ "scook_end",       "res.cook", PAT_MATCH_END },
	{ "scook_len",       "res.cook", PAT_MATCH_LEN },
	{ "scook_reg",       "res.cook", PAT_MATCH_REG },
	{ "scook_sub",       "res.cook", PAT_MATCH_SUB },

	{ "shdr",            "res.hdr",  PAT_MATCH_STR },
	{ "shdr_beg",        "res.hdr",  PAT_MATCH_BEG },
	{ "shdr_dir",        "res.hdr",  PAT_MATCH_DIR },
	{ "shdr_dom",        "res.hdr",  PAT_MATCH_DOM },
	{ "shdr_end",        "res.hdr",  PAT_MATCH_END },
	{ "shdr_len",        "res.hdr",  PAT_MATCH_LEN },
	{ "shdr_reg",        "res.hdr",  PAT_MATCH_REG },
	{ "shdr_sub",        "res.hdr",  PAT_MATCH_SUB },

	{ "url",             "url",      PAT_MATCH_STR },
	{ "url_beg",         "url",      PAT_MATCH_BEG },
	{ "url_dir",         "url",      PAT_MATCH_DIR },
	{ "url_dom",         "url",      PAT_MATCH_DOM },
	{ "url_end",         "url",      PAT_MATCH_END },
	{ "url_len",         "url",      PAT_MATCH_LEN },
	{ "url_reg",         "url",      PAT_MATCH_REG },
	{ "url_sub",         "url",      PAT_MATCH_SUB },

	{ "urlp",            "urlp",     PAT_MATCH_STR },
	{ "urlp_beg",        "urlp",     PAT_MATCH_BEG },
	{ "urlp_dir",        "urlp",     PAT_MATCH_DIR },
	{ "urlp_dom",        "urlp",     PAT_MATCH_DOM },
	{ "urlp_end",        "urlp",     PAT_MATCH_END },
	{ "urlp_len",        "urlp",     PAT_MATCH_LEN },
	{ "urlp_reg",        "urlp",     PAT_MATCH_REG },
	{ "urlp_sub",        "urlp",     PAT_MATCH_SUB },

	{ /* END */ },
}};

INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);

/*
 * Local variables:
 *  c-indent-level: 8
 *  c-basic-offset: 8
 * End:
 */
