Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

in_http: add support for form/url_encoded payloads. #6960

Merged
merged 4 commits into from
Jul 20, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 144 additions & 1 deletion plugins/in_http/http_prot.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,52 @@
#include "http.h"
#include "http_conn.h"

#define HTTP_CONTENT_JSON 0
#define HTTP_CONTENT_JSON 0
#define HTTP_CONTENT_URLENCODED 1

static inline char hex2nibble(char c)
{
if ((c >= 0x30) && (c <= '9')) {
return c - 0x30;
}
// 0x30-0x39 are digits, 0x41-0x46 A-F,
// so there is a gap at 0x40
if ((c >= 'A') && (c <= 'F')) {
return (c - 'A') + 10;
}
if ((c >= 'a') && (c <= 'f')) {
return (c - 'a') + 10;
}
return 0;
}

static int sds_uri_decode(flb_sds_t s)
{
char buf[1024];
char *optr;
char *iptr;


for (optr = buf, iptr = s; iptr < s + flb_sds_len(s) && optr-buf < sizeof(buf); iptr++) {
if (*iptr == '%') {
if (iptr+2 > (s + flb_sds_len(s))) {
return -1;
}
*optr++ = hex2nibble(*(iptr+1)) << 4 | hex2nibble(*(iptr+2));
iptr+=2;
} else if (*iptr == '+') {
*optr++ = ' ';
} else {
*optr++ = *iptr;
}
}

memcpy(s, buf, optr-buf);
s[optr-buf] = '\0';
flb_sds_len_set(s, (optr-buf));

return 0;
}

static int send_response(struct http_conn *conn, int http_status, char *message)
{
Expand Down Expand Up @@ -289,6 +334,97 @@ static ssize_t parse_payload_json(struct flb_http *ctx, flb_sds_t tag,
return 0;
}

static ssize_t parse_payload_urlencoded(struct flb_http *ctx, flb_sds_t tag,
char *payload, size_t size)
{
struct mk_list *kvs;
struct mk_list *head = NULL;
struct flb_split_entry *cur = NULL;
char **keys = NULL;
char **vals = NULL;
char *sep;
char *start;
int idx = 0;
int ret = -1;
msgpack_packer pck;
msgpack_sbuffer sbuf;


/* initialize buffers */
msgpack_sbuffer_init(&sbuf);
msgpack_packer_init(&pck, &sbuf, msgpack_sbuffer_write);

kvs = flb_utils_split(payload, '&', -1 );
if (kvs == NULL) {
goto split_error;
}

keys = flb_calloc(mk_list_size(kvs), sizeof(char *));
if (keys == NULL) {
goto keys_calloc_error;
}

vals = flb_calloc(mk_list_size(kvs), sizeof(char *));
if (vals == NULL) {
goto vals_calloc_error;
}

mk_list_foreach(head, kvs) {
cur = mk_list_entry(head, struct flb_split_entry, _head);
if (cur->value[0] == '\n') {
start = &cur->value[1];
} else {
start = cur->value;
}
sep = strchr(start, '=');
if (sep == NULL) {
vals[idx] = NULL;
continue;
}
*sep++ = '\0';

keys[idx] = flb_sds_create_len(start, strlen(start));
vals[idx] = flb_sds_create_len(sep, strlen(sep));

flb_sds_trim(keys[idx]);
flb_sds_trim(vals[idx]);
idx++;
}

msgpack_pack_map(&pck, mk_list_size(kvs));
for (idx = 0; idx < mk_list_size(kvs); idx++) {
msgpack_pack_str(&pck, flb_sds_len(keys[idx]));
msgpack_pack_str_body(&pck, keys[idx], flb_sds_len(keys[idx]));

if (sds_uri_decode(vals[idx]) != 0) {
goto decode_error;
} else {
msgpack_pack_str(&pck, flb_sds_len(vals[idx]));
msgpack_pack_str_body(&pck, vals[idx], strlen(vals[idx]));
}
}

ret = process_pack(ctx, tag, sbuf.data, sbuf.size);

decode_error:
for (idx = 0; idx < mk_list_size(kvs); idx++) {
if (keys[idx]) {
flb_sds_destroy(keys[idx]);
}
if (vals[idx]) {
flb_sds_destroy(vals[idx]);
}
}
flb_free(vals);
vals_calloc_error:
flb_free(keys);
keys_calloc_error:
flb_utils_split_free(kvs);
split_error:
msgpack_sbuffer_destroy(&sbuf);
return ret;
}

static int process_payload(struct flb_http *ctx, struct http_conn *conn,
flb_sds_t tag,
struct mk_http_session *session,
Expand All @@ -308,6 +444,11 @@ static int process_payload(struct flb_http *ctx, struct http_conn *conn,
type = HTTP_CONTENT_JSON;
}

if (header->val.len == 33 &&
strncasecmp(header->val.data, "application/x-www-form-urlencoded", 33) == 0) {
type = HTTP_CONTENT_URLENCODED;
}

if (type == -1) {
send_response(conn, 400, "error: invalid 'Content-Type'\n");
return -1;
Expand All @@ -320,6 +461,8 @@ static int process_payload(struct flb_http *ctx, struct http_conn *conn,

if (type == HTTP_CONTENT_JSON) {
parse_payload_json(ctx, tag, request->data.data, request->data.len);
} else if (type == HTTP_CONTENT_URLENCODED) {
parse_payload_urlencoded(ctx, tag, request->data.data, request->data.len);
}

return 0;
Expand Down