Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc
Commits
7b645ddc
Commit
7b645ddc
authored
Mar 06, 2015
by
Rémi Denis-Courmont
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
HPACK Header Compression HTTP/2 minimalistic encoder
parent
870d437c
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
305 additions
and
2 deletions
+305
-2
modules/access/http/Makefile.am
modules/access/http/Makefile.am
+4
-2
modules/access/http/hpack.h
modules/access/http/hpack.h
+5
-0
modules/access/http/hpackenc.c
modules/access/http/hpackenc.c
+296
-0
No files found.
modules/access/http/Makefile.am
View file @
7b645ddc
hpack_test_SOURCES
=
access/http/hpack.c access/http/hpack.h
hpack_test_SOURCES
=
access/http/hpack.c access/http/hpack.h
hpack_test_CFLAGS
=
-DDEC_TEST
hpack_test_CFLAGS
=
-DDEC_TEST
check_PROGRAMS
+=
hpack_test
hpackenc_test_SOURCES
=
$(hpack_test_SOURCES)
access/http/hpackenc.c
TESTS
+=
hpack_test
hpackenc_test_CFLAGS
=
-DENC_TEST
check_PROGRAMS
+=
hpack_test hpackenc_test
TESTS
+=
hpack_test hpackenc_test
modules/access/http/hpack.h
View file @
7b645ddc
...
@@ -25,3 +25,8 @@ void hpack_decode_destroy(struct hpack_decoder *);
...
@@ -25,3 +25,8 @@ void hpack_decode_destroy(struct hpack_decoder *);
int
hpack_decode
(
struct
hpack_decoder
*
dec
,
const
uint8_t
*
data
,
int
hpack_decode
(
struct
hpack_decoder
*
dec
,
const
uint8_t
*
data
,
size_t
length
,
char
*
headers
[][
2
],
unsigned
max
);
size_t
length
,
char
*
headers
[][
2
],
unsigned
max
);
size_t
hpack_encode_hdr_neverindex
(
uint8_t
*
restrict
buf
,
size_t
size
,
const
char
*
name
,
const
char
*
value
);
size_t
hpack_encode
(
uint8_t
*
restrict
buf
,
size_t
size
,
const
char
*
const
headers
[][
2
],
unsigned
count
);
modules/access/http/hpackenc.c
0 → 100644
View file @
7b645ddc
/*****************************************************************************
* hpack.c: HPACK Header Compression for HTTP/2 encoder
*****************************************************************************
* Copyright (C) 2015 Rémi Denis-Courmont
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef ENC_TEST
# undef NDEBUG
#endif
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include "hpack.h"
/*
* This is curently the simplest possible HPACK compressor: it does not
* compress anything and is stateless.
* TODO:
* - use static Huffman compression when useful,
* - use header names and values from the static HPACK table,
* - become stateful and let the caller specify the indexed flag,
* - let caller specify the never-indexed flag.
*/
static
size_t
hpack_encode_int
(
uint8_t
*
restrict
buf
,
size_t
size
,
uintmax_t
value
,
unsigned
n
)
{
assert
(
n
>=
1
&&
n
<=
8
);
unsigned
mask
=
(
1
<<
n
)
-
1
;
size_t
ret
=
1
;
if
(
value
<
mask
)
{
if
(
size
>
0
)
buf
[
0
]
|=
value
;
return
1
;
}
if
(
size
>
0
)
*
(
buf
++
)
|=
mask
;
value
-=
mask
;
while
(
value
>=
128
)
{
if
(
ret
++
<
size
)
*
(
buf
++
)
=
0x80
|
(
value
&
0x7F
);
value
>>=
7
;
}
if
(
ret
++
<
size
)
*
(
buf
++
)
=
value
;
return
ret
;
}
static
size_t
hpack_encode_str_raw
(
uint8_t
*
restrict
buf
,
size_t
size
,
const
char
*
str
)
{
size_t
len
=
strlen
(
str
);
if
(
size
>
0
)
*
buf
=
0
;
size_t
ret
=
hpack_encode_int
(
buf
,
size
,
len
,
7
);
if
(
ret
<
size
)
{
buf
+=
ret
;
size
-=
ret
;
memcpy
(
buf
,
str
,
(
len
<=
size
)
?
len
:
size
);
}
ret
+=
len
;
return
ret
;
}
static
size_t
hpack_encode_str_raw_lower
(
uint8_t
*
restrict
buf
,
size_t
size
,
const
char
*
str
)
{
size_t
len
=
strlen
(
str
);
if
(
size
>
0
)
*
buf
=
0
;
size_t
ret
=
hpack_encode_int
(
buf
,
size
,
len
,
7
);
if
(
ret
<
size
)
{
buf
+=
ret
;
size
-=
ret
;
for
(
size_t
i
=
0
;
i
<
len
&&
i
<
size
;
i
++
)
if
(
str
[
i
]
<
'A'
||
str
[
i
]
>
'Z'
)
buf
[
i
]
=
str
[
i
];
else
buf
[
i
]
=
str
[
i
]
-
'A'
+
'a'
;
}
ret
+=
len
;
return
ret
;
}
size_t
hpack_encode_hdr_neverindex
(
uint8_t
*
restrict
buf
,
size_t
size
,
const
char
*
name
,
const
char
*
value
)
{
size_t
ret
=
1
,
val
;
if
(
size
>
0
)
{
*
(
buf
++
)
=
0x10
;
size
--
;
}
val
=
hpack_encode_str_raw_lower
(
buf
,
size
,
name
);
if
(
size
>=
val
)
{
buf
+=
val
;
size
-=
val
;
}
else
size
=
0
;
ret
+=
val
;
val
=
hpack_encode_str_raw
(
buf
,
size
,
value
);
if
(
size
>=
val
)
{
buf
+=
val
;
size
-=
val
;
}
else
size
=
0
;
ret
+=
val
;
return
ret
;
}
size_t
hpack_encode
(
uint8_t
*
restrict
buf
,
size_t
size
,
const
char
*
const
headers
[][
2
],
unsigned
count
)
{
size_t
ret
=
0
;
while
(
count
>
0
)
{
size_t
val
=
hpack_encode_hdr_neverindex
(
buf
,
size
,
headers
[
0
][
0
],
headers
[
0
][
1
]);
if
(
size
>=
val
)
{
buf
+=
val
;
size
-=
val
;
}
else
size
=
0
;
ret
+=
val
;
headers
++
;
count
--
;
}
return
ret
;
}
/*** Test cases ***/
#ifdef ENC_TEST
# include <stdarg.h>
# include <stdlib.h>
# include <stdio.h>
static
void
test_integer
(
unsigned
n
,
uintmax_t
value
)
{
uint8_t
buf
[
3
];
size_t
ret
;
for
(
unsigned
i
=
0
;
i
<
3
;
i
++
)
{
ret
=
hpack_encode_int
(
buf
,
sizeof
(
buf
),
value
,
n
);
assert
(
ret
>
0
);
}
}
static
void
test_integers
(
void
)
{
test_integer
(
5
,
10
);
test_integer
(
5
,
1337
);
test_integer
(
8
,
42
);
}
static
void
test_lowercase
(
const
char
*
str
)
{
char
c
;
while
((
c
=
*
(
str
++
))
!=
'\0'
)
assert
(
c
<
'A'
||
c
>
'Z'
);
}
static
void
test_block
(
const
char
*
name
,
...)
{
const
char
*
headers
[
16
][
2
];
unsigned
count
=
0
;
va_list
ap
;
va_start
(
ap
,
name
);
while
(
name
!=
NULL
)
{
headers
[
count
][
0
]
=
name
;
headers
[
count
][
1
]
=
va_arg
(
ap
,
const
char
*
);
name
=
va_arg
(
ap
,
const
char
*
);
count
++
;
}
va_end
(
ap
);
printf
(
" %u header(s):
\n
"
,
count
);
uint8_t
buf
[
1024
];
size_t
length
=
hpack_encode
(
NULL
,
0
,
headers
,
count
);
for
(
size_t
i
=
0
;
i
<
sizeof
(
buf
);
i
++
)
assert
(
hpack_encode
(
buf
,
i
,
headers
,
count
)
==
length
);
memset
(
buf
,
0xAA
,
sizeof
(
buf
));
assert
(
hpack_encode
(
buf
,
length
,
headers
,
count
)
==
length
);
char
*
eheaders
[
16
][
2
];
struct
hpack_decoder
*
dec
=
hpack_decode_init
(
4096
);
assert
(
dec
!=
NULL
);
int
ecount
=
hpack_decode
(
dec
,
buf
,
length
,
eheaders
,
16
);
assert
((
unsigned
)
ecount
==
count
);
hpack_decode_destroy
(
dec
);
for
(
unsigned
i
=
0
;
i
<
count
;
i
++
)
{
printf
(
" %s: %s
\n
"
,
eheaders
[
i
][
0
],
eheaders
[
i
][
1
]);
test_lowercase
(
eheaders
[
i
][
0
]);
assert
(
!
strcasecmp
(
eheaders
[
i
][
0
],
headers
[
i
][
0
]));
assert
(
!
strcmp
(
eheaders
[
i
][
1
],
headers
[
i
][
1
]));
free
(
eheaders
[
i
][
1
]);
free
(
eheaders
[
i
][
0
]);
}
}
static
void
test_reqs
(
void
)
{
test_block
(
NULL
);
test_block
(
":method"
,
"GET"
,
":scheme"
,
"http"
,
":path"
,
"/"
,
":authority"
,
"www.example.com"
,
NULL
);
test_block
(
":method"
,
"GET"
,
":scheme"
,
"http"
,
":path"
,
"/"
,
":authority"
,
"www.example.com"
,
"Cache-Control"
,
"no-cache"
,
NULL
);
test_block
(
":method"
,
"GET"
,
":scheme"
,
"https"
,
":path"
,
"/index.html"
,
":authority"
,
"www.example.com"
,
"custom-key"
,
"custom-value"
,
NULL
);
}
static
void
test_resps
(
void
)
{
test_block
(
":status"
,
"302"
,
"Cache-Control"
,
"private"
,
"Date"
,
"Mon, 21 Oct 2013 20:13:21 GMT"
,
"Location"
,
"https://www.example.com"
,
NULL
);
test_block
(
":status"
,
"307"
,
"Cache-Control"
,
"private"
,
"Date"
,
"Mon, 21 Oct 2013 20:13:21 GMT"
,
"Location"
,
"https://www.example.com"
,
NULL
);
test_block
(
":status"
,
"200"
,
"Cache-Control"
,
"private"
,
"Date"
,
"Mon, 21 Oct 2013 20:13:22 GMT"
,
"Location"
,
"https://www.example.com"
,
"Content-Encoding"
,
"gzip"
,
"Set-Cookie"
,
"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; "
"max-age=3600; version=1"
,
NULL
);
}
int
main
(
void
)
{
test_integers
();
test_reqs
();
test_resps
();
}
#endif
/* TEST */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment