From: Arran Cudbard-Bell Date: Fri, 19 Jan 2018 02:01:24 +0000 (-0700) Subject: Add rlm_rest xlat back as an async expansion X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c80a4ee44c8bc7fc0404f10dfd4968af7fb3faea;p=thirdparty%2Ffreeradius-server.git Add rlm_rest xlat back as an async expansion It sends requests at least... More work needed to call the resume function properly --- diff --git a/src/modules/rlm_rest/rest.c b/src/modules/rlm_rest/rest.c index 6557fba7950..04d0652e15e 100644 --- a/src/modules/rlm_rest/rest.c +++ b/src/modules/rlm_rest/rest.c @@ -2304,7 +2304,7 @@ ssize_t rest_uri_build(char **out, rlm_rest_t const *inst, REQUEST *request, cha p = strchr(p, ':'); if (!p || (*++p != '/') || (*++p != '/')) { malformed: - REDEBUG("Error URI is malformed, can't find start of path"); + REDEBUG("Error URI \"%s\" is malformed, can't find start of path", uri); return -1; } p = strchr(p + 1, '/'); @@ -2377,7 +2377,7 @@ ssize_t rest_uri_host_unescape(char **out, rlm_rest_t const *inst, REQUEST *requ p = strchr(p, ':'); if (!p || (*++p != '/') || (*++p != '/')) { malformed: - REDEBUG("Error URI is malformed, can't find start of path"); + REDEBUG("URI \"%s\" is malformed, can't find start of path", uri); return -1; } p = strchr(p + 1, '/'); diff --git a/src/modules/rlm_rest/rest.h b/src/modules/rlm_rest/rest.h index 0cf845f1ba0..f47e48c6f67 100644 --- a/src/modules/rlm_rest/rest.h +++ b/src/modules/rlm_rest/rest.h @@ -172,6 +172,14 @@ typedef struct { //!< we think there are. } rlm_rest_thread_t; +/** Wrapper around the module thread stuct for individual xlats + * + */ +typedef struct { + rlm_rest_t const *inst; //!< Instance of rlm_rest. + rlm_rest_thread_t *t; //!< rlm_rest thread instance. +} rest_xlat_thread_inst_t; + /* * States for stream based attribute encoders */ diff --git a/src/modules/rlm_rest/rlm_rest.c b/src/modules/rlm_rest/rlm_rest.c index 565ef9893d7..c6198895f6f 100644 --- a/src/modules/rlm_rest/rlm_rest.c +++ b/src/modules/rlm_rest/rlm_rest.c @@ -170,35 +170,125 @@ static int rlm_rest_perform(rlm_rest_t const *instance, rlm_rest_thread_t *threa return 0; } -#if 0 +/** Stores the state of a yielded xlat + * + */ +typedef struct { + rlm_rest_section_t section; //!< Our mutated section config. + rlm_rest_handle_t *handle; //!< curl easy handle servicing our request. +} rlm_rest_xlat_rctx_t; + +static xlat_action_t rest_xlat_resume(TALLOC_CTX *ctx, fr_cursor_t *out, + REQUEST *request, UNUSED void const *xlat_inst, void *xlat_thread_inst, + UNUSED fr_cursor_t *in, void *rctx) +{ + rest_xlat_thread_inst_t *xti = talloc_get_type_abort(xlat_thread_inst, rest_xlat_thread_inst_t); + rlm_rest_t const *mod_inst = xti->inst; + rlm_rest_thread_t *t = xti->t; + + rlm_rest_xlat_rctx_t *our_rctx = talloc_get_type_abort(rctx, rlm_rest_xlat_rctx_t); + int hcode; + ssize_t len; + char const *body; + xlat_action_t xa = XLAT_ACTION_DONE; + + rlm_rest_handle_t *handle = our_rctx->handle; + rlm_rest_section_t *section = &our_rctx->section; + + if (section->tls_extract_cert_attrs) rest_response_certinfo(mod_inst, section, + request, handle); + + if (rlm_rest_status_update(request, handle) < 0) { + xa = XLAT_ACTION_FAIL; + goto finish; + } + + hcode = rest_get_handle_code(handle); + switch (hcode) { + case 404: + case 410: + case 403: + case 401: + { + xa = XLAT_ACTION_FAIL; +error: + rest_response_error(request, handle); + goto finish; + } + case 204: + goto finish; + + default: + /* + * Attempt to parse content if there was any. + */ + if ((hcode >= 200) && (hcode < 300)) { + break; + } else if (hcode < 500) { + xa = XLAT_ACTION_FAIL; + goto error; + } else { + xa = XLAT_ACTION_FAIL; + goto error; + } + } + + len = rest_get_handle_data(&body, handle); + if (len > 0) { + fr_value_box_t *vb; + + MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_STRING, NULL, true)); + fr_value_box_bstrndup(vb, vb, NULL, body, len, true); + fr_cursor_insert(out, vb); + } + +finish: + rest_request_cleanup(mod_inst, handle); + + fr_pool_connection_release(t->pool, request, handle); + + talloc_free(our_rctx); + + return xa; +} + /* * Simple xlat to read text data from a URL */ -static ssize_t rest_xlat(UNUSED TALLOC_CTX *ctx, char **out, UNUSED size_t outlen, - void const *mod_inst, UNUSED void const *xlat_inst, - REQUEST *request, char const *fmt) +static xlat_action_t rest_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_cursor_t *out, + REQUEST *request, UNUSED void const *xlat_inst, void *xlat_thread_inst, + fr_cursor_t *in) { - rlm_rest_t const *inst = mod_inst; - rlm_rest_handle_t *handle = NULL; - ssize_t len; - int ret; - char *uri = NULL; - char const *p = fmt, *q; - http_method_t method; - void *thread = NULL; + rest_xlat_thread_inst_t *xti = talloc_get_type_abort(xlat_thread_inst, rest_xlat_thread_inst_t); + rlm_rest_t const *mod_inst = xti->inst; + rlm_rest_thread_t *t = xti->t; - rad_assert(*out == NULL); + rlm_rest_handle_t *handle = NULL; + ssize_t len; + int ret; + char *uri = NULL; + char const *p = NULL, *q; + http_method_t method; + fr_value_box_t *head; /* There are no configurable parameters other than the URI */ - rlm_rest_section_t *section; + rlm_rest_xlat_rctx_t *rctx; + rlm_rest_section_t *section; + + head = fr_cursor_head(in); + if (head->type != FR_TYPE_STRING) { + REDEBUG("rest xlat only accepts string inputs"); + return XLAT_ACTION_FAIL; + } + p = head->vb_strvalue; + + MEM(rctx = talloc(request, rlm_rest_xlat_rctx_t)); + section = &rctx->section; /* * Section gets modified, so we need our own copy. */ - MEM(section = talloc(request, rlm_rest_section_t)); - memcpy(section, &inst->xlat, sizeof(*section)); - - rad_assert(fmt); + memcpy(&rctx->section, &mod_inst->xlat, sizeof(*section)); RDEBUG("Expanding URI components"); @@ -221,7 +311,7 @@ static ssize_t rest_xlat(UNUSED TALLOC_CTX *ctx, char **out, UNUSED size_t outle */ if ((*q == ' ') && (q != p)) { section->method = HTTP_METHOD_CUSTOM; - MEM(section->method_str = talloc_bstrndup(section, p, q - p)); + MEM(section->method_str = talloc_bstrndup(rctx, p, q - p)); p = q; } else { section->method = HTTP_METHOD_GET; @@ -233,11 +323,8 @@ static ssize_t rest_xlat(UNUSED TALLOC_CTX *ctx, char **out, UNUSED size_t outle */ while (isspace(*p) && p++); -#if 0 handle = fr_pool_connection_get(t->pool, request); - if (!handle) return -1; -#endif /* * Unescape parts of xlat'd URI, this allows REST servers to be specified by @@ -247,6 +334,7 @@ static ssize_t rest_xlat(UNUSED TALLOC_CTX *ctx, char **out, UNUSED size_t outle if (len <= 0) { error: rest_request_cleanup(mod_inst, handle); + fr_pool_connection_release(t->pool, request, handle); talloc_free(section); return -1; @@ -272,7 +360,7 @@ static ssize_t rest_xlat(UNUSED TALLOC_CTX *ctx, char **out, UNUSED size_t outle * * @todo We could extract the User-Name and password from the URL string. */ - ret = rest_request_config(mod_inst, thread, section, request, + ret = rest_request_config(mod_inst, t, section, request, handle, section->method, section->body, uri, NULL, NULL); talloc_free(uri); if (ret < 0) goto error; @@ -283,77 +371,12 @@ static ssize_t rest_xlat(UNUSED TALLOC_CTX *ctx, char **out, UNUSED size_t outle * * @fixme need to pass in thread to all xlat functions */ - ret = rest_io_request_enqueue(NULL, request, handle); + ret = rest_io_request_enqueue(t, request, handle); if (ret < 0) goto error; - return 0; /* FIXME XLAT YIELD */ + return unlang_xlat_yield(request, rest_xlat_resume, NULL, rctx); } -static ssize_t rest_xlat_resume(UNUSED TALLOC_CTX *ctx, char **out, UNUSED size_t outlen, - void const *mod_inst, UNUSED void const *xlat_inst, - REQUEST *request, UNUSED char const *fmt) -{ - rlm_rest_t const *inst = mod_inst; - rlm_rest_handle_t *handle = NULL; /* FIXME POPULATE FROM REQUEST */ - int hcode; - ssize_t len, slen = 0; - char const *body; - rlm_rest_section_t *section = NULL; /* FIXME POPULATE FROM REQUEST */ - - if (section->tls_extract_cert_attrs) rest_response_certinfo(mod_inst, section, request, handle); - - if (rlm_rest_status_update(request, handle) < 0) { - rcode = RLM_MODULE_FAIL; - goto finish; - } - - hcode = rest_get_handle_code(handle); - switch (hcode) { - case 404: - case 410: - case 403: - case 401: - { - slen = -1; -error: - rest_response_error(request, handle); - goto finish; - } - case 204: - goto finish; - - default: - /* - * Attempt to parse content if there was any. - */ - if ((hcode >= 200) && (hcode < 300)) { - break; - } else if (hcode < 500) { - slen = -2; - goto error; - } else { - slen = -1; - goto error; - } - } - - len = rest_get_handle_data(&body, handle); - if (len > 0) { - *out = talloc_bstrndup(request, body, len); - slen = len; - } - -finish: - rest_request_cleanup(mod_inst, handle); - - fr_pool_connection_release(t->pool, request, handle); - - talloc_free(section); - - return slen; -} -#endif - static rlm_rcode_t mod_authorize_result(REQUEST *request, void *instance, void *thread, void *ctx) { rlm_rest_t const *inst = instance; @@ -883,6 +906,28 @@ static int parse_sub_section(rlm_rest_t *inst, CONF_SECTION *parent, CONF_PARSER return 0; } +/** Resolves and caches the module's thread instance for use by a specific xlat instance + * + * @param[in] xlat_inst UNUSED. + * @param[in] xlat_thread_inst pre-allocated structure to hold pointer to module's + * thread instance. + * @param[in] exp UNUSED. + * @param[in] uctx Module's global instance. Used to lookup thread + * specific instance. + * @return 0. + */ +static int mod_xlat_thread_instantiate(UNUSED void *xlat_inst, void *xlat_thread_inst, + UNUSED xlat_exp_t const *exp, void *uctx) +{ + rlm_rest_t *inst = talloc_get_type_abort(uctx, rlm_rest_t); + rest_xlat_thread_inst_t *xt = xlat_thread_inst; + + xt->inst = inst; + xt->t = talloc_get_type_abort(module_thread_instance_by_data(inst), rlm_rest_thread_t); + + return 0; +} + /** Create a thread specific multihandle * * Easy handles representing requests are added to the curl multihandle @@ -985,12 +1030,10 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf) inst->xlat_name = cf_section_name2(conf); if (!inst->xlat_name) inst->xlat_name = cf_section_name1(conf); -#if 0 - /* - * Register the rest xlat function - */ - xlat_register(inst, inst->xlat_name, rest_xlat, rest_uri_escape, NULL, 0, 0, false); -#endif + xlat_async_register(inst, inst->xlat_name, rest_xlat, + NULL, 0, NULL, + mod_xlat_thread_instantiate, sizeof(rest_xlat_thread_inst_t), NULL, + inst); return 0; }