Skip to content

Commit

Permalink
rest: Add xlat argument for headers
Browse files Browse the repository at this point in the history
  • Loading branch information
arr2036 committed Nov 28, 2024
1 parent bc22359 commit 6b4e486
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 52 deletions.
87 changes: 45 additions & 42 deletions src/modules/rlm_rest/rest.c
Original file line number Diff line number Diff line change
Expand Up @@ -1691,6 +1691,41 @@ static int rest_request_config_body(module_ctx_t const *mctx, rlm_rest_section_t
return -1;
}

/** Adds an additional header to a handle to use in the next reques
*
* @param[in] request Current request.
* @param[in] randle used for the next request.
* @param[in] header to add.
* @param[in] validate whether to perform basic checks on the header
* @return
* - 0 on success.
* - -1 on failure.
*/
int rest_request_config_add_header(request_t *request, fr_curl_io_request_t *randle, char const *header, bool validate)
{
rlm_rest_curl_context_t *ctx = talloc_get_type_abort(randle->uctx, rlm_rest_curl_context_t);
struct curl_slist *headers;

if (validate && !strchr(header, ':')) {
RWDEBUG("Invalid HTTP header \"%s\" must be in format '<attribute>: <value>'. Skipping...",
header);
return -1;
}

RINDENT();
RDEBUG3("%s", header);
REXDENT();

headers = curl_slist_append(ctx->headers, header);
if (unlikely(!headers)) {
REDEBUG("Failed to add header \"%s\"", header);
return -1;
}
ctx->headers = headers;

return 0;
}

/** Configures request curlopts.
*
* Configures libcurl handle setting various curlopts for things like local
Expand Down Expand Up @@ -1776,19 +1811,10 @@ int rest_request_config(module_ctx_t const *mctx, rlm_rest_section_t const *sect
*/
RDEBUG3("Adding custom headers:");
snprintf(buffer, sizeof(buffer), "X-FreeRADIUS-Section: %s", section->name);

RINDENT();
RDEBUG3("%s", buffer);
REXDENT();
ctx->headers = curl_slist_append(ctx->headers, buffer);
if (!ctx->headers) goto error_header;
if (unlikely(rest_request_config_add_header(request, randle, buffer, false) < 0)) return -1;

snprintf(buffer, sizeof(buffer), "X-FreeRADIUS-Server: %s", cf_section_name2(unlang_call_current(request)));
RINDENT();
RDEBUG3("%s", buffer);
REXDENT();
ctx->headers = curl_slist_append(ctx->headers, buffer);
if (!ctx->headers) goto error_header;
if (unlikely(rest_request_config_add_header(request, randle, buffer, false) < 0)) return -1;

/*
* Add in the section headers
Expand All @@ -1797,11 +1823,7 @@ int rest_request_config(module_ctx_t const *mctx, rlm_rest_section_t const *sect
size_t len = talloc_array_length(call_env->request.header), i;
for (i = 0; i < len; i++) {
fr_value_box_list_foreach(&call_env->request.header[i], header) {
RINDENT();
RDEBUG3("%pV", header);
REXDENT();

ctx->headers = curl_slist_append(ctx->headers, header->vb_strvalue);
if (unlikely(rest_request_config_add_header(request, randle, header->vb_strvalue, true) < 0)) return -1;
}
}
}
Expand All @@ -1811,23 +1833,13 @@ int rest_request_config(module_ctx_t const *mctx, rlm_rest_section_t const *sect
*/
{
fr_pair_t *header;
fr_dcursor_t headers;
fr_dcursor_t header_cursor;

for (header = fr_pair_dcursor_by_da_init(&headers, &request->control_pairs, attr_rest_http_header);
for (header = fr_pair_dcursor_by_da_init(&header_cursor, &request->control_pairs, attr_rest_http_header);
header;
header = fr_dcursor_current(&headers)) {
header = fr_dcursor_remove(&headers);
if (!strchr(header->vp_strvalue, ':')) {
RWDEBUG("Invalid HTTP header \"%s\" must be in format '<attribute>: <value>'. Skipping...",
header->vp_strvalue);
talloc_free(header);
continue;
}
RINDENT();
RDEBUG3("%pV", &header->data);
REXDENT();

ctx->headers = curl_slist_append(ctx->headers, header->vp_strvalue);
header = fr_dcursor_current(&header_cursor)) {
header = fr_dcursor_remove(&header_cursor);
if (unlikely(rest_request_config_add_header(request, randle, header->vp_strvalue, true) < 0)) return -1;

/*
* Set content-type based on a corresponding REST-HTTP-Header attribute, if provided.
Expand Down Expand Up @@ -1855,12 +1867,7 @@ int rest_request_config(module_ctx_t const *mctx, rlm_rest_section_t const *sect
if (type != REST_HTTP_BODY_NONE) {
char const *content_type = fr_table_str_by_value(http_content_type_table, type, section->request.body_str);
snprintf(buffer, sizeof(buffer), "Content-Type: %s", content_type);
ctx->headers = curl_slist_append(ctx->headers, buffer);
if (!ctx->headers) {
error_header:
REDEBUG("Failed creating header");
return -1;
}
if (unlikely(rest_request_config_add_header(request, randle, content_type, false) < 0)) return -1;

RDEBUG3("Request body content-type will be \"%s\"", content_type);
}
Expand Down Expand Up @@ -1973,11 +1980,7 @@ do {\
if (section->request.chunk > 0) {
ctx->request.chunk = section->request.chunk;

ctx->headers = curl_slist_append(ctx->headers, "Expect:");
if (!ctx->headers) goto error_header;

ctx->headers = curl_slist_append(ctx->headers, "Transfer-Encoding: chunked");
if (!ctx->headers) goto error_header;
if (unlikely(rest_request_config_add_header(request, randle, "Transfer-Encoding: chunked", false) < 0)) return -1;
}

break;
Expand Down
4 changes: 4 additions & 0 deletions src/modules/rlm_rest/rest.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,10 @@ void *rest_mod_conn_create(TALLOC_CTX *ctx, void *instance, fr_time_delta_t time
/*
* Request processing API
*/

int rest_request_config_add_header(request_t *request, fr_curl_io_request_t *randle,
char const *header, bool validate) CC_HINT(nonnull(1,2,3));

int rest_request_config(module_ctx_t const *mctx, rlm_rest_section_t const *section,
request_t *request, fr_curl_io_request_t *randle, http_method_t method,
http_body_type_t type,
Expand Down
28 changes: 18 additions & 10 deletions src/modules/rlm_rest/rlm_rest.c
Original file line number Diff line number Diff line change
Expand Up @@ -497,17 +497,18 @@ static xlat_action_t rest_xlat_resume(TALLOC_CTX *ctx, fr_dcursor_t *out,
}

static xlat_arg_parser_t const rest_xlat_args[] = {
{ .required = true, .single = true, .type = FR_TYPE_STRING },
{ .required = true, .safe_for = CURL_URI_SAFE_FOR, .type = FR_TYPE_STRING },
{ .concat = true, .type = FR_TYPE_STRING },
{ .required = true, .single = true, .type = FR_TYPE_STRING }, /* HTTP Method */
{ .required = true, .safe_for = CURL_URI_SAFE_FOR, .type = FR_TYPE_STRING }, /* URL */
{ .concat = true, .type = FR_TYPE_STRING }, /* Data */
{ .type = FR_TYPE_STRING }, /* Headers */
XLAT_ARG_PARSER_TERMINATOR
};

/** Simple xlat to read text data from a URL
*
* Example:
@verbatim
%rest(POST, http://example.com/, "{ \"key\": \"value\" }")
%rest(POST, http://example.com/, "{ \"key\": \"value\" }", [<headers>])
@endverbatim
*
* @ingroup xlat_functions
Expand All @@ -526,12 +527,13 @@ static xlat_action_t rest_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out,
fr_value_box_t *method_vb;
fr_value_box_t *uri_vb;
fr_value_box_t *data_vb;
fr_value_box_t *header_vb;

/* There are no configurable parameters other than the URI */
rlm_rest_xlat_rctx_t *rctx;
rlm_rest_section_t *section;

XLAT_ARGS(in, &method_vb, &uri_vb, &data_vb);
XLAT_ARGS(in, &method_vb, &uri_vb, &data_vb, &header_vb);

MEM(rctx = talloc(request, rlm_rest_xlat_rctx_t));
section = &rctx->section;
Expand Down Expand Up @@ -591,6 +593,16 @@ static xlat_action_t rest_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out,
section->request.method_str : fr_table_str_by_value(http_method_table, section->request.method, NULL),
uri_vb);

if (header_vb) {
fr_value_box_list_foreach(&header_vb->vb_group, header) {
if (unlikely(rest_request_config_add_header(request, randle, header->vb_strvalue, true) < 0)) {
error_release:
rest_slab_release(randle);
goto error;
}
}
}

/*
* Configure various CURL options, and initialise the read/write
* context data.
Expand All @@ -601,11 +613,7 @@ static xlat_action_t rest_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out,
section, request, randle, section->request.method,
section->request.body,
uri_vb->vb_strvalue, data_vb ? data_vb->vb_strvalue : NULL);
if (ret < 0) {
error_release:
rest_slab_release(randle);
goto error;
}
if (ret < 0) goto error_release;

/*
* Send the CURL request, pre-parse headers, aggregate incoming
Expand Down

0 comments on commit 6b4e486

Please sign in to comment.