diff --git a/src/url.c b/src/url.c index 4e5910d0..ddcce91c 100644 --- a/src/url.c +++ b/src/url.c @@ -15,6 +15,7 @@ #include "util.h" #include +#include #include "mem.h" @@ -46,6 +47,42 @@ _parsePort(int *port, const char *sport) return s; } +static natsStatus _decodeAndDup(char **decoded, const char *encoded) +{ + size_t len = strlen(encoded); + const char *p = encoded; + const char *e = encoded + len; + char *d; + + *decoded = NATS_MALLOC(len + 1); + if (*decoded == NULL) + { + return nats_setDefaultError(NATS_NO_MEMORY); + } + d = *decoded; + for (; p < e; p++) + { + if (*p != '%') + { + *d++ = *p; + continue; + } + + if (e - p < 3 || (!isxdigit(*(p + 1)) || !isxdigit(*(p + 2)))) + { + NATS_FREE(*decoded); + *decoded = NULL; + return nats_setError(NATS_ERR, "invalid percent encoding in URL: %s", encoded); + } + + char buf[3] = {p[1], p[2], '\0'}; + *d++ = (char)strtol(buf, NULL, 16); + p += 2; + } + *d = '\0'; + return NATS_OK; +} + natsStatus natsUrl_Create(natsUrl **newUrl, const char *urlStr) { @@ -166,9 +203,9 @@ natsUrl_Create(natsUrl **newUrl, const char *urlStr) DUP_STRING(s, url->host, host); if (user != NULL) - IF_OK_DUP_STRING(s, url->username, user); + IFOK(s, _decodeAndDup(&url->username, user)); if (pwd != NULL) - IF_OK_DUP_STRING(s, url->password, pwd); + IFOK(s, _decodeAndDup(&url->password, pwd)); if ((s == NATS_OK) && nats_asprintf(&url->fullUrl, "%s://%s%s%s%s%s:%d%s%s", scheme, userval, usep, pwdval, hsep, host, url->port, pathsep, pathval) < 0) diff --git a/test/test.c b/test/test.c index 71f2a5b9..a2c89803 100644 --- a/test/test.c +++ b/test/test.c @@ -1764,6 +1764,36 @@ test_natsUrl(void) natsUrl_Destroy(u); u = NULL; + test("'tcp://%4C%65v%00ignored:p%77d%00ignoredalso@localhost':"); + s = natsUrl_Create(&u, "tcp://%4C%65v%00ignored:p%77d%00ignoredalso@localhost"); + testCond((s == NATS_OK) + && (u != NULL) + && (u->host != NULL) + && (strcmp(u->host, "localhost") == 0) + && (u->username != NULL) + && (strcmp(u->username, "Lev") == 0) + && (u->password != NULL) + && (strcmp(u->password, "pwd") == 0) + && (u->port == 4222)); + natsUrl_Destroy(u); + u = NULL; + + test("'tcp://%4C%65v:p%77d@localhost':"); + s = natsUrl_Create(&u, "tcp://%4C%65v:p%77d@localhost"); + testCond((s == NATS_OK) && (u != NULL) && (u->host != NULL) && (strcmp(u->host, "localhost") == 0) && (u->username != NULL) && (strcmp(u->username, "Lev") == 0) && (u->password != NULL) && (strcmp(u->password, "pwd") == 0) && (u->port == 4222)); + natsUrl_Destroy(u); + u = NULL; + + test("'tcp://%4c%65v:p%@localhost':"); + s = natsUrl_Create(&u, "tcp://%4c%65v:p%@localhost"); + testCond((s == NATS_ERR) && (u == NULL) && (strstr(nats_GetLastError(NULL), "invalid percent encoding in URL: p%") != NULL)); + nats_clearLastError(); + + test("'tcp://%4H%65v:p%@localhost':"); + s = natsUrl_Create(&u, "tcp://%4H%65v:p%@localhost"); + testCond((s == NATS_ERR) && (u == NULL) && (strstr(nats_GetLastError(NULL), "invalid percent encoding in URL: %4H%65v") != NULL)); + nats_clearLastError(); + test("'tcp://localhost: 4222':"); s = natsUrl_Create(&u, "tcp://localhost: 4222"); testCond((s == NATS_INVALID_ARG)