]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add rlm_rest xlat back as an async expansion
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 19 Jan 2018 02:01:24 +0000 (19:01 -0700)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 19 Jan 2018 02:01:50 +0000 (19:01 -0700)
It sends requests at least... More work needed to call the resume function properly

src/modules/rlm_rest/rest.c
src/modules/rlm_rest/rest.h
src/modules/rlm_rest/rlm_rest.c

index 6557fba7950559b6632c35aec94f7a767d390edc..04d0652e15e136b1b824f077100ab1c53e045ad8 100644 (file)
@@ -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, '/');
index 0cf845f1ba0ee0d36af8a5799c353ca8f9dd5c41..f47e48c6f6735e9d70cefea107ed0e275cafb8bb 100644 (file)
@@ -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
  */
index 565ef9893d7aa8a02500c75a44f08e4cd35a52b6..c6198895f6f352d185c02d259186befb5f0c0372 100644 (file)
@@ -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;
 }