From 95e830cc22676de8cbb3253be8a47cb757591521 Mon Sep 17 00:00:00 2001 From: "Rodriguez,German J" Date: Thu, 12 Mar 2020 13:48:48 -0500 Subject: [PATCH] omhttp: Adding multiple http headers capability --- contrib/omhttp/omhttp.c | 50 +++++++++++++++++++++++++++++ tests/Makefile.am | 6 +++- tests/omhttp-httpheaderkey.sh | 44 +++++++++++++++++++++++++ tests/omhttp-multiplehttpheaders.sh | 46 ++++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100755 tests/omhttp-httpheaderkey.sh create mode 100755 tests/omhttp-multiplehttpheaders.sh diff --git a/contrib/omhttp/omhttp.c b/contrib/omhttp/omhttp.c index 433b28fed..e518ab962 100644 --- a/contrib/omhttp/omhttp.c +++ b/contrib/omhttp/omhttp.c @@ -119,6 +119,8 @@ typedef struct instanceConf_s { uchar *httpheaderkey; uchar *httpheadervalue; uchar *headerBuf; + uchar **httpHeaders; + int nHttpHeaders; uchar *restPath; uchar *checkPath; uchar *tplName; @@ -189,6 +191,7 @@ static struct cnfparamdescr actpdescr[] = { { "httpcontenttype", eCmdHdlrGetWord, 0 }, { "httpheaderkey", eCmdHdlrGetWord, 0 }, { "httpheadervalue", eCmdHdlrString, 0 }, + { "httpheaders", eCmdHdlrArray, 0 }, { "uid", eCmdHdlrGetWord, 0 }, { "pwd", eCmdHdlrGetWord, 0 }, { "restpath", eCmdHdlrGetWord, 0 }, @@ -299,6 +302,11 @@ CODESTARTfreeInstance free(pData->headerContentTypeBuf); free(pData->httpheaderkey); free(pData->httpheadervalue); + for(i = 0 ; i < pData->nHttpHeaders ; ++i) { + free((void*) pData->httpHeaders[i]); + } + free(pData->httpHeaders); + pData->nHttpHeaders = 0; free(pData->pwd); free(pData->authBuf); free(pData->headerBuf); @@ -351,6 +359,10 @@ CODESTARTdbgPrintInstInfo (uchar*)"(not configured)" : pData->httpheaderkey); dbgprintf("\thttpheadervalue='%s'\n", pData->httpheadervalue == NULL ? (uchar*)"(not configured)" : pData->httpheadervalue); + dbgprintf("\thttpHeaders=["); + for(i = 0 ; i < pData->nHttpHeaders ; ++i) + dbgprintf("\t%s\n",pData->httpHeaders[i]); + dbgprintf("\t]\n"); dbgprintf("\tpwd=(%sconfigured)\n", pData->pwd == NULL ? "not " : ""); dbgprintf("\trest path='%s'\n", pData->restPath); dbgprintf("\tcheck path='%s'\n", pData->checkPath); @@ -1029,6 +1041,11 @@ buildCurlHeaders(wrkrInstanceData_t *pWrkrData, sbool contentEncodeGzip) CHKmalloc(slist); } + for (int k = 0 ; k < pWrkrData->pData->nHttpHeaders; k++) { + slist = curl_slist_append(slist, (char *)pWrkrData->pData->httpHeaders[k]); + CHKmalloc(slist); + } + // When sending more than 1Kb, libcurl automatically sends an Except: 100-Continue header // and will wait 1s for a response, could make this configurable but for now disable slist = curl_slist_append(slist, HTTP_HEADER_EXPECT_EMPTY); @@ -1656,9 +1673,17 @@ curlSetup(wrkrInstanceData_t *const pWrkrData) } else { slist = curl_slist_append(slist, HTTP_HEADER_CONTENT_JSON); } + if (pWrkrData->pData->headerBuf != NULL) { slist = curl_slist_append(slist, (char *)pWrkrData->pData->headerBuf); + CHKmalloc(slist); } + + for (int k = 0 ; k < pWrkrData->pData->nHttpHeaders; k++) { + slist = curl_slist_append(slist, (char *)pWrkrData->pData->httpHeaders[k]); + CHKmalloc(slist); + } + // When sending more than 1Kb, libcurl automatically sends an Except: 100-Continue header // and will wait 1s for a response, could make this configurable but for now disable slist = curl_slist_append(slist, HTTP_HEADER_EXPECT_EMPTY); @@ -1705,6 +1730,8 @@ setInstParamDefaults(instanceData *const pData) pData->headerContentTypeBuf = NULL; pData->httpheaderkey = NULL; pData->httpheadervalue = NULL; + pData->httpHeaders = NULL; + pData->nHttpHeaders = 0; pData->pwd = NULL; pData->authBuf = NULL; pData->restPath = NULL; @@ -1735,6 +1762,20 @@ setInstParamDefaults(instanceData *const pData) pData->retryRuleset = NULL; } +static rsRetVal +checkHeaderParam(char *const param) +{ + DEFiRet; + char *val = strstr(param, ":"); + if(val == NULL) { + LogError(0, RS_RET_PARAM_ERROR, "missing ':' delimiter in " + "parameter '%s'", param); + ABORT_FINALIZE(RS_RET_PARAM_ERROR); + } +finalize_it: + RETiRet; +} + BEGINnewActInst struct cnfparamvals *pvals; char* serverParam = NULL; @@ -1772,6 +1813,14 @@ CODESTARTnewActInst pData->httpheaderkey = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); } else if(!strcmp(actpblk.descr[i].name, "httpheadervalue")) { pData->httpheadervalue = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "httpheaders")) { + pData->nHttpHeaders = pvals[i].val.d.ar->nmemb; + CHKmalloc(pData->httpHeaders = malloc(sizeof(uchar *) * pvals[i].val.d.ar->nmemb )); + for(int j = 0 ; j < pvals[i].val.d.ar->nmemb ; ++j) { + char *cstr = es_str2cstr(pvals[i].val.d.ar->arr[j], NULL); + CHKiRet(checkHeaderParam(cstr)); + pData->httpHeaders[j] = (uchar *)cstr; + } } else if(!strcmp(actpblk.descr[i].name, "pwd")) { pData->pwd = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); } else if(!strcmp(actpblk.descr[i].name, "restpath")) { @@ -1896,6 +1945,7 @@ CODESTARTnewActInst if (pData->httpcontenttype != NULL) CHKiRet(computeApiHeader((char*) "Content-Type", (char*) pData->httpcontenttype, &pData->headerContentTypeBuf)); + if (pData->httpheaderkey != NULL) CHKiRet(computeApiHeader((char*) pData->httpheaderkey, (char*) pData->httpheadervalue, &pData->headerBuf)); diff --git a/tests/Makefile.am b/tests/Makefile.am index 0ac6215ef..5cb7570c0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -844,7 +844,9 @@ TESTS += \ omhttp-batch-lokirest-retry.sh \ omhttp-batch-lokirest.sh \ omhttp-batch-newline.sh \ - omhttp-retry.sh + omhttp-retry.sh \ + omhttp-httpheaderkey.sh \ + omhttp-multiplehttpheaders.sh if HAVE_VALGRIND TESTS += \ omhttp-auth-vg.sh \ @@ -2112,6 +2114,8 @@ EXTRA_DIST= \ omhttp-batch-lokirest.sh \ omhttp-batch-newline.sh \ omhttp-retry.sh \ + omhttp-httpheaderkey.sh \ + omhttp-multiplehttpheaders.sh \ omhttp-auth-vg.sh \ omhttp-basic-vg.sh \ omhttp-batch-jsonarray-compress-vg.sh \ diff --git a/tests/omhttp-httpheaderkey.sh b/tests/omhttp-httpheaderkey.sh new file mode 100755 index 000000000..fb266cf66 --- /dev/null +++ b/tests/omhttp-httpheaderkey.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# This file is part of the rsyslog project, released under ASL 2.0 + +# Starting actual testbench +. ${srcdir:=.}/diag.sh init + +export NUMMESSAGES=1000 + +port="$(get_free_port)" +omhttp_start_server $port + +generate_conf +add_conf ' +template(name="tpl" type="string" + string="{\"msgnum\":\"%msg:F,58:2%\"}") + +module(load="../contrib/omhttp/.libs/omhttp") + +if $msg contains "msgnum:" then + action( + # Payload + name="my_http_action" + type="omhttp" + errorfile="'$RSYSLOG_DYNNAME/omhttp.error.log'" + template="tpl" + httpheaderkey="X-Insert-Key" + httpheadervalue="dummy-value" + server="localhost" + serverport="'$port'" + restpath="my/endpoint" + batch="off" + + # Auth + usehttps="off" + ) +' +startup +injectmsg +shutdown_when_empty +wait_shutdown +omhttp_get_data $port my/endpoint +omhttp_stop_server +seq_check +exit_test diff --git a/tests/omhttp-multiplehttpheaders.sh b/tests/omhttp-multiplehttpheaders.sh new file mode 100755 index 000000000..c24d73834 --- /dev/null +++ b/tests/omhttp-multiplehttpheaders.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# This file is part of the rsyslog project, released under ASL 2.0 + +# Starting actual testbench +. ${srcdir:=.}/diag.sh init + +export NUMMESSAGES=1000 + +port="$(get_free_port)" +omhttp_start_server $port + +generate_conf +add_conf ' +template(name="tpl" type="string" + string="{\"msgnum\":\"%msg:F,58:2%\"}") + +module(load="../contrib/omhttp/.libs/omhttp") + +if $msg contains "msgnum:" then + action( + # Payload + name="my_http_action" + type="omhttp" + errorfile="'$RSYSLOG_DYNNAME/omhttp.error.log'" + template="tpl" + httpheaders=[ + "X-Insert-Key: dummy-value", + "X-Event-Source: logs" + ] + server="localhost" + serverport="'$port'" + restpath="my/endpoint" + batch="off" + + # Auth + usehttps="off" + ) +' +startup +injectmsg +shutdown_when_empty +wait_shutdown +omhttp_get_data $port my/endpoint +omhttp_stop_server +seq_check +exit_test