Commit 750d5ebc authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

https: simplify HTTP/2 headers parsing

parent cb1f0492
...@@ -113,7 +113,8 @@ static int vlc_h2_stream_fatal(struct vlc_h2_stream *s, uint_fast32_t code) ...@@ -113,7 +113,8 @@ static int vlc_h2_stream_fatal(struct vlc_h2_stream *s, uint_fast32_t code)
} }
/** Reports received stream headers */ /** Reports received stream headers */
static void vlc_h2_stream_headers(void *ctx, unsigned count, char *hdrs[][2]) static void vlc_h2_stream_headers(void *ctx, unsigned count,
const char *const hdrs[][2])
{ {
struct vlc_h2_stream *s = ctx; struct vlc_h2_stream *s = ctx;
......
...@@ -522,41 +522,46 @@ static int vlc_h2_parse_headers_end(struct vlc_h2_parser *p) ...@@ -522,41 +522,46 @@ static int vlc_h2_parse_headers_end(struct vlc_h2_parser *p)
char *headers[VLC_H2_MAX_HEADERS][2]; char *headers[VLC_H2_MAX_HEADERS][2];
/* TODO: limit total decompressed size of the headers list */ /* TODO: limit total decompressed size of the headers list */
int val = hpack_decode(p->headers.decoder, p->headers.buf, p->headers.len, int n = hpack_decode(p->headers.decoder, p->headers.buf, p->headers.len,
headers, VLC_H2_MAX_HEADERS); headers, VLC_H2_MAX_HEADERS);
if (val > VLC_H2_MAX_HEADERS) if (n > VLC_H2_MAX_HEADERS)
{ {
for (unsigned i = 0; i < VLC_H2_MAX_HEADERS; i++) for (unsigned i = 0; i < VLC_H2_MAX_HEADERS; i++)
{ {
free(headers[i][0]); free(headers[i][0]);
free(headers[i][1]); free(headers[i][1]);
} }
val = -1; n = -1;
} }
if (val < 0) if (n < 0)
return vlc_h2_parse_error(p, VLC_H2_COMPRESSION_ERROR); return vlc_h2_parse_error(p, VLC_H2_COMPRESSION_ERROR);
void *s = vlc_h2_stream_lookup(p, p->headers.sid); void *s = vlc_h2_stream_lookup(p, p->headers.sid);
int val = 0;
if (s != NULL) if (s != NULL)
{ {
p->cbs->stream_headers(s, val, headers); const char *ch[n ? n : 1][2];
val = 0;
for (int i = 0; i < n; i++)
ch[i][0] = headers[i][0], ch[i][1] = headers[i][1];
p->cbs->stream_headers(s, n, ch);
if (p->headers.eos) if (p->headers.eos)
p->cbs->stream_end(s); p->cbs->stream_end(s);
} }
else else
{
for (int i = 0; i < val; i++)
{
free(headers[i][0]);
free(headers[i][1]);
}
/* NOTE: The specification implies that the error should be sent for /* NOTE: The specification implies that the error should be sent for
* the first header frame. But we actually want to receive the whole * the first header frame. But we actually want to receive the whole
* fragmented headers block, to preserve the HPACK decoder state. * fragmented headers block, to preserve the HPACK decoder state.
* So we send the error at the last header frame instead. */ * So we send the error at the last header frame instead. */
val = vlc_h2_stream_error(p, p->headers.sid, VLC_H2_REFUSED_STREAM); val = vlc_h2_stream_error(p, p->headers.sid, VLC_H2_REFUSED_STREAM);
for (int i = 0; i < n; i++)
{
free(headers[i][0]);
free(headers[i][1]);
} }
p->parser = vlc_h2_parse_generic; p->parser = vlc_h2_parse_generic;
......
...@@ -106,7 +106,8 @@ struct vlc_h2_parser_cbs ...@@ -106,7 +106,8 @@ struct vlc_h2_parser_cbs
void *(*stream_lookup)(void *ctx, uint_fast32_t id); void *(*stream_lookup)(void *ctx, uint_fast32_t id);
int (*stream_error)(void *ctx, uint_fast32_t id, uint_fast32_t code); int (*stream_error)(void *ctx, uint_fast32_t id, uint_fast32_t code);
void (*stream_headers)(void *ctx, unsigned count, char *headers[][2]); void (*stream_headers)(void *ctx, unsigned count,
const char *const headers[][2]);
int (*stream_data)(void *ctx, struct vlc_h2_frame *f); int (*stream_data)(void *ctx, struct vlc_h2_frame *f);
void (*stream_end)(void *ctx); void (*stream_end)(void *ctx);
int (*stream_reset)(void *ctx, uint_fast32_t code); int (*stream_reset)(void *ctx, uint_fast32_t code);
......
...@@ -142,7 +142,8 @@ static const unsigned resp_hdrc = sizeof (resp_hdrv) / sizeof (resp_hdrv[0]); ...@@ -142,7 +142,8 @@ static const unsigned resp_hdrc = sizeof (resp_hdrv) / sizeof (resp_hdrv[0]);
static unsigned stream_header_tables; static unsigned stream_header_tables;
static void vlc_h2_stream_headers(void *ctx, unsigned count, char *hdrs[][2]) static void vlc_h2_stream_headers(void *ctx, unsigned count,
const char *const hdrs[][2])
{ {
assert(ctx == &stream_cookie); assert(ctx == &stream_cookie);
assert(count == resp_hdrc); assert(count == resp_hdrc);
...@@ -151,8 +152,6 @@ static void vlc_h2_stream_headers(void *ctx, unsigned count, char *hdrs[][2]) ...@@ -151,8 +152,6 @@ static void vlc_h2_stream_headers(void *ctx, unsigned count, char *hdrs[][2])
{ {
assert(!strcmp(hdrs[i][0], resp_hdrv[i][0])); assert(!strcmp(hdrs[i][0], resp_hdrv[i][0]));
assert(!strcmp(hdrs[i][1], resp_hdrv[i][1])); assert(!strcmp(hdrs[i][1], resp_hdrv[i][1]));
free(hdrs[i][1]);
free(hdrs[i][0]);
} }
stream_header_tables++; stream_header_tables++;
......
...@@ -427,7 +427,8 @@ struct vlc_h2_frame *vlc_http_msg_h2_frame(const struct vlc_http_msg *m, ...@@ -427,7 +427,8 @@ struct vlc_h2_frame *vlc_http_msg_h2_frame(const struct vlc_http_msg *m,
return f; return f;
} }
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,
const char *const 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))
...@@ -507,12 +508,6 @@ error: ...@@ -507,12 +508,6 @@ error:
vlc_http_msg_destroy(m); vlc_http_msg_destroy(m);
m = NULL; m = NULL;
} }
for (unsigned i = 0; i < n; i++)
{
free(hdrs[i][0]);
free(hdrs[i][1]);
}
return m; return m;
} }
......
...@@ -257,4 +257,5 @@ struct vlc_h2_frame; ...@@ -257,4 +257,5 @@ struct vlc_h2_frame;
struct vlc_h2_frame *vlc_http_msg_h2_frame(const struct vlc_http_msg *m, struct vlc_h2_frame *vlc_http_msg_h2_frame(const struct vlc_http_msg *m,
uint_fast32_t stream_id, bool eos); uint_fast32_t stream_id, bool eos);
struct vlc_http_msg *vlc_http_msg_h2_headers(unsigned n, char *hdrs[][2]); struct vlc_http_msg *vlc_http_msg_h2_headers(unsigned count,
const char *const headers[][2]);
...@@ -255,10 +255,10 @@ int main(void) ...@@ -255,10 +255,10 @@ int main(void)
vlc_http_msg_destroy(m); vlc_http_msg_destroy(m);
char *bad1[][2] = { const char *bad1[][2] = {
{ strdup(":status"), strdup("200") }, { ":status", "200" },
{ strdup(":status"), strdup("200") }, { ":status", "200" },
{ strdup("Server"), strdup("BigBad/1.0") }, { "Server", "BigBad/1.0" },
}; };
m = vlc_http_msg_h2_headers(3, bad1); m = vlc_http_msg_h2_headers(3, bad1);
...@@ -288,12 +288,12 @@ vlc_h2_frame_headers(uint_fast32_t id, uint_fast32_t mtu, bool eos, ...@@ -288,12 +288,12 @@ vlc_h2_frame_headers(uint_fast32_t id, uint_fast32_t mtu, bool eos,
assert(mtu == VLC_H2_DEFAULT_MAX_FRAME); assert(mtu == VLC_H2_DEFAULT_MAX_FRAME);
assert(eos); assert(eos);
char *headers[VLC_H2_MAX_HEADERS][2]; const char *headers[VLC_H2_MAX_HEADERS][2];
for (unsigned i = 0; i < count; i++) for (unsigned i = 0; i < count; i++)
{ {
headers[i][0] = strdup(tab[i][0]); headers[i][0] = tab[i][0];
headers[i][1] = strdup(tab[i][1]); headers[i][1] = tab[i][1];
} }
m = vlc_http_msg_h2_headers(count, headers); m = vlc_http_msg_h2_headers(count, headers);
......
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