Allow param blocks to be marked as "querystring"

Before params get would mean querystring and anything else
would just count toward a www-encoded body.

Now you can prefix the params block with "qs" indicating that
those configured parameters are allowed to occur in the query
string regardless of the method used.

This means you can do something like:

params qs:post /uri {
	...
}

to specify what the allowed parameters are in the querystring for
a POST request towards /uri.

inspired by and properly fixes #205.
This commit is contained in:
Joris Vink 2018-01-16 18:47:50 +01:00
parent 915b8e1d3c
commit b95b623e72
10 changed files with 63 additions and 22 deletions

View File

@ -246,6 +246,16 @@ domain localhost {
validate arg1 v_example
validate id v_number
}
# Configure a params block for allowed parameters in the
# querystring when performing a POST against /params-test.
# You do this by prefixing the method with the qs: marker.
# In the param blocks below we allow the parameter "post_id"
# in the querystring validated by v_number when a POST is
# done against the supplied URL.
params qs:post /params-test {
validate post_id v_number
}
}
#domain domain.com {

View File

@ -15,7 +15,8 @@ domain * {
certkey cert/key.pem
static / page
params get / {
# allowed parameters in the query string for GETs
params qs:get / {
validate id v_id
}
}

View File

@ -18,7 +18,7 @@ domain * {
static /connect open_connection
params get /connect {
params qs:get /connect {
validate host v_host
validate port v_port
}

View File

@ -21,7 +21,7 @@ domain * {
# If you would want to declare parameters available
# to the page handler for POST, swap the 'get' setting
# to 'post' instead, Kore takes care of the rest.
params get / {
params qs:get / {
# Validate the id parameter with the v_id validator.
validate id v_id
}

View File

@ -44,14 +44,14 @@ domain * {
#
# On the native page handler, use a python validator.
#
params get /c {
params qs:get /c {
validate id v_p_id
}
#
# On the python page handler, use a native validator.
#
params get / {
params qs:get / {
validate id v_id
}
}

View File

@ -19,7 +19,7 @@ domain * {
static / page_handler
static /post_back post_back
params get / {
params qs:get / {
validate user v_user
}

View File

@ -26,6 +26,9 @@
extern "C" {
#endif
/* Keep the http_populate_get symbol around. */
#define http_populate_get http_populate_qs
#define HTTP_KEEPALIVE_TIME 20
#define HTTP_HSTS_ENABLE 31536000
#define HTTP_HEADER_MAX_LEN 4096
@ -282,7 +285,7 @@ void *http_state_create(struct http_request *, size_t);
int http_argument_urldecode(char *);
int http_header_recv(struct netbuf *);
void http_populate_get(struct http_request *);
void http_populate_qs(struct http_request *);
void http_populate_post(struct http_request *);
void http_populate_multipart_form(struct http_request *);
void http_populate_cookies(struct http_request *);

View File

@ -255,8 +255,11 @@ LIST_HEAD(listener_head, listener);
#if !defined(KORE_NO_HTTP)
#define KORE_PARAMS_QUERY_STRING 0x0001
struct kore_handler_params {
char *name;
int flags;
u_int8_t method;
struct kore_validator *validator;

View File

@ -178,6 +178,7 @@ char *config_file = NULL;
#if !defined(KORE_NO_HTTP)
static u_int8_t current_method = 0;
static int current_flags = 0;
static struct kore_auth *current_auth = NULL;
static struct kore_module_handle *current_handler = NULL;
#endif
@ -240,6 +241,8 @@ kore_parse_config_file(const char *fpath)
#if !defined(KORE_NO_HTTP)
if (!strcmp(p, "}") && current_handler != NULL) {
lineno++;
current_flags = 0;
current_method = 0;
current_handler = NULL;
continue;
}
@ -734,7 +737,7 @@ static int
configure_params(char *options)
{
struct kore_module_handle *hdlr;
char *argv[3];
char *method, *argv[3];
if (current_domain == NULL) {
printf("params not used in domain context\n");
@ -750,21 +753,36 @@ configure_params(char *options)
if (argv[1] == NULL)
return (KORE_RESULT_ERROR);
if (!strcasecmp(argv[0], "post")) {
if ((method = strchr(argv[0], ':')) != NULL) {
*(method)++ = '\0';
if (!strcasecmp(argv[0], "qs")) {
current_flags = KORE_PARAMS_QUERY_STRING;
} else {
printf("unknown prefix '%s' for '%s'\n",
argv[0], argv[1]);
return (KORE_RESULT_ERROR);
}
} else {
method = argv[0];
}
if (!strcasecmp(method, "post")) {
current_method = HTTP_METHOD_POST;
} else if (!strcasecmp(argv[0], "get")) {
} else if (!strcasecmp(method, "get")) {
current_method = HTTP_METHOD_GET;
} else if (!strcasecmp(argv[0], "put")) {
/* Let params get /foo {} imply qs:get automatically. */
current_flags |= KORE_PARAMS_QUERY_STRING;
} else if (!strcasecmp(method, "put")) {
current_method = HTTP_METHOD_PUT;
} else if (!strcasecmp(argv[0], "delete")) {
} else if (!strcasecmp(method, "delete")) {
current_method = HTTP_METHOD_DELETE;
} else if (!strcasecmp(argv[0], "head")) {
} else if (!strcasecmp(method, "head")) {
current_method = HTTP_METHOD_HEAD;
} else if (!strcasecmp(argv[0], "patch")) {
} else if (!strcasecmp(method, "patch")) {
current_method = HTTP_METHOD_PATCH;
} else {
printf("unknown method: %s in params block for %s\n",
argv[0], argv[1]);
method, argv[1]);
return (KORE_RESULT_ERROR);
}
@ -806,6 +824,7 @@ configure_validate(char *options)
p = kore_malloc(sizeof(*p));
p->validator = val;
p->flags = current_flags;
p->method = current_method;
p->name = kore_strdup(argv[0]);

View File

@ -44,7 +44,7 @@
static int http_body_recv(struct netbuf *);
static void http_error_response(struct connection *, int);
static void http_write_response_cookie(struct http_cookie *);
static void http_argument_add(struct http_request *, char *, char *);
static void http_argument_add(struct http_request *, char *, char *, int);
static void http_response_normal(struct http_request *,
struct connection *, int, const void *, size_t);
static void multipart_add_field(struct http_request *, struct kore_buf *,
@ -1124,7 +1124,7 @@ http_populate_post(struct http_request *req)
for (i = 0; i < v; i++) {
kore_split_string(args[i], "=", val, 3);
if (val[0] != NULL && val[1] != NULL)
http_argument_add(req, val[0], val[1]);
http_argument_add(req, val[0], val[1], 0);
}
out:
@ -1133,12 +1133,12 @@ out:
}
void
http_populate_get(struct http_request *req)
http_populate_qs(struct http_request *req)
{
int i, v;
char *query, *args[HTTP_MAX_QUERY_ARGS], *val[3];
if (req->method != HTTP_METHOD_GET || req->query_string == NULL)
if (req->query_string == NULL)
return;
query = kore_strdup(req->query_string);
@ -1146,7 +1146,7 @@ http_populate_get(struct http_request *req)
for (i = 0; i < v; i++) {
kore_split_string(args[i], "=", val, 3);
if (val[0] != NULL && val[1] != NULL)
http_argument_add(req, val[0], val[1]);
http_argument_add(req, val[0], val[1], 1);
}
kore_free(query);
@ -1496,7 +1496,7 @@ multipart_add_field(struct http_request *req, struct kore_buf *in,
data->offset -= 2;
string = kore_buf_stringify(data, NULL);
http_argument_add(req, name, string);
http_argument_add(req, name, string, 0);
kore_buf_free(data);
}
@ -1527,7 +1527,7 @@ multipart_file_add(struct http_request *req, struct kore_buf *in,
}
static void
http_argument_add(struct http_request *req, char *name, char *value)
http_argument_add(struct http_request *req, char *name, char *value, int qs)
{
struct http_arg *q;
struct kore_handler_params *p;
@ -1535,6 +1535,11 @@ http_argument_add(struct http_request *req, char *name, char *value)
http_argument_urldecode(name);
TAILQ_FOREACH(p, &(req->hdlr->params), list) {
if (qs == 1 && !(p->flags & KORE_PARAMS_QUERY_STRING))
continue;
if (qs == 0 && (p->flags & KORE_PARAMS_QUERY_STRING))
continue;
if (p->method != req->method)
continue;