Commit 55f07dff authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

https: also fold incoming HTTP/2 field headers

parent 5a4d4002
...@@ -428,86 +428,93 @@ struct vlc_h2_frame *vlc_http_msg_h2_frame(const struct vlc_http_msg *m, ...@@ -428,86 +428,93 @@ struct vlc_h2_frame *vlc_http_msg_h2_frame(const struct vlc_http_msg *m,
return f; return f;
} }
static int vlc_h2_header_special(const char *name)
{
/* NOTE: HPACK always returns lower-case names, so strcmp() is fine. */
static const char special_names[5][16] = {
":status", ":method", ":scheme", ":authority", ":path"
};
for (unsigned i = 0; i < 5; i++)
if (!strcmp(special_names[i], name))
return i;
return -1;
}
struct vlc_http_msg *vlc_http_msg_h2_headers(unsigned n, char *hdrs[][2]) struct vlc_http_msg *vlc_http_msg_h2_headers(unsigned n, char *hdrs[][2])
{ {
struct vlc_http_msg *m = vlc_http_resp_create(0); struct vlc_http_msg *m = vlc_http_resp_create(0);
if (unlikely(m == NULL)) if (unlikely(m == NULL))
return NULL; return NULL;
m->headers = malloc(n * sizeof (char *[2]));
if (unlikely(m->headers == NULL))
goto error;
char *special_caption[5] = { NULL, NULL, NULL, NULL, NULL };
char *special[5] = { NULL, NULL, NULL, NULL, NULL };
for (unsigned i = 0; i < n; i++) for (unsigned i = 0; i < n; i++)
{ {
char *name = hdrs[i][0]; const char *name = hdrs[i][0];
char *value = hdrs[i][1]; const char *value = hdrs[i][1];
int idx = vlc_h2_header_special(name);
if (idx >= 0) /* NOTE: HPACK always returns lower-case names, so strcmp() is fine. */
if (!strcmp(name, ":status"))
{ {
if (special[idx] != NULL) char *end;
goto error; /* Duplicate special header! */ unsigned long status = strtoul(value, &end, 10);
special_caption[idx] = name; if (m->status != 0 || status > 999 || *end != '\0')
special[idx] = value; goto error; /* Not a three decimal digits status! */
m->status = status;
continue; continue;
} }
m->headers[m->count][0] = name; if (!strcmp(name, ":method"))
m->headers[m->count][1] = value; {
m->count++; if (m->method != NULL)
} goto error;
if (special[0] != NULL) m->method = strdup(value);
{ /* HTTP response */ if (unlikely(m->method == NULL))
char *end; goto error;
unsigned long status = strtoul(special[0], &end, 10);
if (status > 999 || *end != '\0') m->status = -1; /* this is a request */
goto error; /* Not a three decimal digits status! */ continue;
}
free(special[0]); if (!strcmp(name, ":scheme"))
m->status = status; {
} if (m->scheme != NULL)
else goto error;
m->status = -1; /* HTTP request */
m->method = special[1]; m->scheme = strdup(value);
m->scheme = special[2]; if (unlikely(m->scheme == NULL))
m->authority = special[3]; goto error;
m->path = special[4]; continue;
}
for (unsigned i = 0; i < 5; i++) if (!strcmp(name, ":authority"))
free(special_caption[i]); {
if (m->authority != NULL)
goto error;
return m; m->authority = strdup(value);
if (unlikely(m->authority == NULL))
goto error;
continue;
}
if (!strcmp(name, ":path"))
{
if (m->path != NULL)
goto error;
m->path = strdup(value);
if (unlikely(m->path == NULL))
goto error;
continue;
}
if (vlc_http_msg_add_header(m, name, "%s", value))
goto error;
}
if ((m->status < 0) == (m->method == NULL))
{ /* Must be either a request or response. Not both, not neither. */
error: error:
free(m->headers); vlc_http_msg_destroy(m);
free(m); m = NULL;
}
for (unsigned i = 0; i < n; i++) for (unsigned i = 0; i < n; i++)
{ {
free(hdrs[i][0]); free(hdrs[i][0]);
free(hdrs[i][1]); free(hdrs[i][1]);
} }
return NULL; return m;
} }
/* Header helpers */ /* Header helpers */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment