diff --git a/conf/kore.conf.example b/conf/kore.conf.example index a642ddb..8b56b8d 100644 --- 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 index 517512f..2b66b18 100755 --- 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 index 6d117a9..7b79a5a 100755 --- 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 index 3c313e4..acc630d 100755 --- 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 index 1de0c73..76c6ef9 100644 --- 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 index f428733..4d29274 100644 --- 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 index 068f7e1..1194339 100644 --- 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 index a14ce0e..93caf46 100644 --- 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 index 6a6a6eb..51fe81f 100644 --- 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 index 2805bf5..1908e42 100644 --- 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;