Skip to content

Commit

Permalink
fabrics: Unescape URI elements
Browse files Browse the repository at this point in the history
This adds support for unescaping percent-encoded URI parts.

Signed-off-by: Tomas Bzatek <[email protected]>
  • Loading branch information
tbzatek authored and igaw committed May 15, 2024
1 parent 0d55a40 commit 1ec2432
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 9 deletions.
47 changes: 38 additions & 9 deletions src/nvme/fabrics.c
Original file line number Diff line number Diff line change
Expand Up @@ -1704,12 +1704,41 @@ int nvmf_register_ctrl(nvme_ctrl_t c, enum nvmf_dim_tas tas, __u32 *result)
return nvmf_dim(c, tas, NVMF_TRTYPE_TCP, nvme_get_adrfam(c), "", NULL, result);
}

#define IS_XDIGIT(c) ((c >= '0' && c <= '9') || \
(c >= 'A' && c <= 'F') || \
(c >= 'a' && c <= 'f'))
#define XDIGIT_VAL(c) ((c >= '0' && c <= '9') ? c - '0' : ( \
(c >= 'A' && c <= 'F') ? c - 'A' + 10 : c - 'a' + 10))

/* returns newly allocated string */
static char *unescape_uri(const char *str, int len)
{
char *dst;
int l;
int i, j;

l = len > 0 ? len : strlen(str);
dst = malloc(l + 1);
for (i = 0, j = 0; i < l; i++, j++) {
if (str[i] == '%' && i + 2 < l &&
IS_XDIGIT(str[i + 1]) && IS_XDIGIT(str[i + 2])) {
dst[j] = (XDIGIT_VAL(str[i + 1]) << 4) +
XDIGIT_VAL(str[i + 2]);
i += 2;
} else
dst[j] = str[i];
}
dst[j] = '\0';
return dst;
}

struct nvme_fabrics_uri *nvme_parse_uri(const char *str)
{
struct nvme_fabrics_uri *uri;
_cleanup_free_ char *scheme = NULL;
_cleanup_free_ char *authority = NULL;
_cleanup_free_ char *path = NULL;
_cleanup_free_ char *h = NULL;
const char *host;
int i;

Expand All @@ -1726,8 +1755,6 @@ struct nvme_fabrics_uri *nvme_parse_uri(const char *str)
* -CONTROLLER PORT]/NQN.2014-08.ORG.NVMEXPRESS.DISCOVERY/<NID>
*/

/* TODO: unescape? */

uri = calloc(1, sizeof(struct nvme_fabrics_uri));
if (!uri)
return NULL;
Expand All @@ -1750,20 +1777,22 @@ struct nvme_fabrics_uri *nvme_parse_uri(const char *str)
host = strrchr(authority, '@');
if (host) {
host++;
uri->userinfo = strndup(authority, host - authority);
uri->userinfo = unescape_uri(authority, host - authority);
} else
host = authority;

/* try matching IPv6 address first */
if (sscanf(host, "[%m[^]]]:%d",
&uri->host, &uri->port) < 1)
&uri->host, &uri->port) < 1) {
/* treat it as IPv4/hostname */
if (sscanf(host, "%m[^:]:%d",
&uri->host, &uri->port) < 1) {
&h, &uri->port) < 1) {
nvme_free_uri(uri);
errno = EINVAL;
return NULL;
}
uri->host = unescape_uri(h, 0);
}

/* split path into elements */
if (path) {
Expand All @@ -1772,13 +1801,13 @@ struct nvme_fabrics_uri *nvme_parse_uri(const char *str)
/* separate the fragment */
e = strrchr(path, '#');
if (e) {
uri->fragment = strdup(e + 1);
uri->fragment = unescape_uri(e + 1, 0);
*e = '\0';
}
/* separate the query string */
e = strrchr(path, '?');
if (e) {
uri->query = strdup(e + 1);
uri->query = unescape_uri(e + 1, 0);
*e = '\0';
}

Expand All @@ -1791,11 +1820,11 @@ struct nvme_fabrics_uri *nvme_parse_uri(const char *str)
i = 0;
elem = strtok_r(path, "/", &e);
if (elem)
uri->path_segments[i++] = strdup(elem);
uri->path_segments[i++] = unescape_uri(elem, 0);
while (elem && strlen(elem)) {
elem = strtok_r(NULL, "/", &e);
if (elem)
uri->path_segments[i++] = strdup(elem);
uri->path_segments[i++] = unescape_uri(elem, 0);
}
}

Expand Down
13 changes: 13 additions & 0 deletions test/uriparser.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,19 @@ static struct test_data test_data[] = {
"nvme", "aa:bb::cc", .proto = "rdma", .port = 12345,
.user = "u[aa:bb::cc]", .path = { "p1", "x" },
.query = "q=val", .frag = "fr" },
{ "nvme://ex%5Cmp%3Ae", "nvme", "ex\\mp:e" },
{ "nvme://ex%5Cmp%3Ae.com/", "nvme", "ex\\mp:e.com" },
{ "nvme://u%24er@ex%5Cmp%3Ae.com/", "nvme", "ex\\mp:e.com",
.user = "u$er" },
{ "nvme+tcp://ex%5Cmp%3Ae.com:1234",
"nvme", "ex\\mp:e.com", .proto = "tcp", .port = 1234 },
{ "nvme+tcp://ex%5Cmp%3Ae.com:1234/p1/ex%3Camp%3Ele/p3",
"nvme", "ex\\mp:e.com", .proto = "tcp", .port = 1234,
.path = { "p1", "ex<amp>le", "p3", NULL } },
{ "nvme+tcp://ex%5Cmp%3Ae.com:1234/p1/%3C%3E/p3?q%5E%24ry#fr%26gm%23nt",
"nvme", "ex\\mp:e.com", .proto = "tcp", .port = 1234,
.path = { "p1", "<>", "p3", NULL }, .query = "q^$ry",
.frag = "fr&gm#nt" },
};

const char *test_data_bad[] = {
Expand Down

0 comments on commit 1ec2432

Please sign in to comment.