kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

commit b95b623e72329bd2800654e78eea1e39422dc8ab
parent 915b8e1d3cc477aa357c29c95715591c08321a3a
Author: Joris Vink <joris@coders.se>
Date:   Tue, 16 Jan 2018 18:47:50 +0100

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.

Diffstat:
conf/kore.conf.example | 10++++++++++
examples/integers/conf/integers.conf | 3++-
examples/ktunnel/conf/ktunnel.conf | 2+-
examples/parameters/conf/parameters.conf | 2+-
examples/python/conf/python.conf | 4++--
examples/tasks/conf/tasks.conf | 2+-
includes/http.h | 5++++-
includes/kore.h | 3+++
src/config.c | 35+++++++++++++++++++++++++++--------
src/http.c | 19++++++++++++-------
10 files changed, 63 insertions(+), 22 deletions(-)

diff --git a/conf/kore.conf.example b/conf/kore.conf.example @@ -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 { diff --git a/examples/integers/conf/integers.conf b/examples/integers/conf/integers.conf @@ -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 } } diff --git a/examples/ktunnel/conf/ktunnel.conf b/examples/ktunnel/conf/ktunnel.conf @@ -18,7 +18,7 @@ domain * { static /connect open_connection - params get /connect { + params qs:get /connect { validate host v_host validate port v_port } diff --git a/examples/parameters/conf/parameters.conf b/examples/parameters/conf/parameters.conf @@ -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 } diff --git a/examples/python/conf/python.conf b/examples/python/conf/python.conf @@ -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 } } diff --git a/examples/tasks/conf/tasks.conf b/examples/tasks/conf/tasks.conf @@ -19,7 +19,7 @@ domain * { static / page_handler static /post_back post_back - params get / { + params qs:get / { validate user v_user } diff --git a/includes/http.h b/includes/http.h @@ -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 *); diff --git a/includes/kore.h b/includes/kore.h @@ -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; diff --git a/src/config.c b/src/config.c @@ -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]); diff --git a/src/http.c b/src/http.c @@ -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;