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");
*/
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;
*/
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
if (len <= 0) {
error:
rest_request_cleanup(mod_inst, handle);
+ fr_pool_connection_release(t->pool, request, handle);
talloc_free(section);
return -1;
*
* @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;
*
* @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;
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
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;
}