Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions lib/nghttp3_conv.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ const uint8_t *nghttp3_get_varint(int64_t *dest, const uint8_t *p) {
}
}

int64_t nghttp3_get_varint_fb(const uint8_t *p) { return *p & 0x3f; }

size_t nghttp3_get_varintlen(const uint8_t *p) {
return (size_t)(1u << (*p >> 6));
}
Expand Down
6 changes: 0 additions & 6 deletions lib/nghttp3_conv.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,6 @@ STIN uint16_t ntohs(uint16_t netshort) {
*/
const uint8_t *nghttp3_get_varint(int64_t *dest, const uint8_t *p);

/*
* nghttp3_get_varint_fb reads first byte of encoded variable-length
* integer from |p|.
*/
int64_t nghttp3_get_varint_fb(const uint8_t *p);

/*
* nghttp3_get_varintlen returns the required number of bytes to read
* variable-length integer starting at |p|.
Expand Down
33 changes: 18 additions & 15 deletions lib/nghttp3_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,42 +181,45 @@ void nghttp3_stream_read_state_reset(nghttp3_stream_read_state *rstate) {
nghttp3_ssize nghttp3_read_varint(nghttp3_varint_read_state *rvint,
const uint8_t *begin, const uint8_t *end,
int fin) {
const uint8_t *orig_begin = begin;
size_t len;
size_t len, vlen;
uint8_t *p;

assert(begin != end);

if (rvint->left == 0) {
assert(rvint->acc == 0);

len = nghttp3_get_varintlen(begin);
if (len <= (size_t)(end - begin)) {
vlen = nghttp3_get_varintlen(begin);
len = nghttp3_min_size(vlen, (size_t)(end - begin));
if (vlen <= len) {
nghttp3_get_varint(&rvint->acc, begin);
return (nghttp3_ssize)len;
return (nghttp3_ssize)vlen;
}

if (fin) {
return NGHTTP3_ERR_INVALID_ARGUMENT;
}

rvint->acc = nghttp3_get_varint_fb(begin++);
rvint->left = len - 1;
}
p = (uint8_t *)&rvint->acc + (sizeof(rvint->acc) - vlen);
memcpy(p, begin, len);
*p &= 0x3f;
rvint->left = vlen - len;

len = nghttp3_min_size(rvint->left, (size_t)(end - begin));
end = begin + len;

for (; begin != end;) {
rvint->acc = (rvint->acc << 8) + *begin++;
return (nghttp3_ssize)len;
}

len = nghttp3_min_size(rvint->left, (size_t)(end - begin));
p = (uint8_t *)&rvint->acc + (sizeof(rvint->acc) - rvint->left);
memcpy(p, begin, len);
rvint->left -= len;

if (fin && rvint->left) {
if (rvint->left == 0) {
rvint->acc = (int64_t)nghttp3_ntohl64((uint64_t)rvint->acc);
} else if (fin) {
return NGHTTP3_ERR_INVALID_ARGUMENT;
}

return (nghttp3_ssize)(begin - orig_begin);
return (nghttp3_ssize)len;
}

int nghttp3_stream_frq_add(nghttp3_stream *stream,
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ set(main_SOURCES
main.c
nghttp3_qpack_test.c
nghttp3_conn_test.c
nghttp3_stream_test.c
nghttp3_tnode_test.c
nghttp3_http_test.c
nghttp3_conv_test.c
Expand Down
2 changes: 2 additions & 0 deletions tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ OBJECTS = \
main.c \
nghttp3_qpack_test.c \
nghttp3_conn_test.c \
nghttp3_stream_test.c \
nghttp3_tnode_test.c \
nghttp3_http_test.c \
nghttp3_conv_test.c \
Expand All @@ -38,6 +39,7 @@ OBJECTS = \
HFILES = \
nghttp3_qpack_test.h \
nghttp3_conn_test.h \
nghttp3_stream_test.h \
nghttp3_tnode_test.h \
nghttp3_http_test.h \
nghttp3_conv_test.h \
Expand Down
3 changes: 2 additions & 1 deletion tests/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,14 @@
/* include test cases' include files here */
#include "nghttp3_qpack_test.h"
#include "nghttp3_conn_test.h"
#include "nghttp3_stream_test.h"
#include "nghttp3_tnode_test.h"
#include "nghttp3_http_test.h"
#include "nghttp3_conv_test.h"

int main(int argc, char **argv) {
const MunitSuite suites[] = {
qpack_suite, conn_suite, tnode_suite, http_suite, {0},
qpack_suite, conn_suite, stream_suite, tnode_suite, http_suite, {0},
};
const MunitSuite suite = {
.prefix = "",
Expand Down
181 changes: 181 additions & 0 deletions tests/nghttp3_stream_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
* nghttp3
*
* Copyright (c) 2025 nghttp3 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "nghttp3_stream_test.h"

#include <stdio.h>
#include <assert.h>

#include "nghttp3_stream.h"
#include "nghttp3_test_helper.h"

static const MunitTest tests[] = {
munit_void_test(test_nghttp3_read_varint),
munit_test_end(),
};

const MunitSuite stream_suite = {
.prefix = "/stream",
.tests = tests,
};

void test_nghttp3_read_varint(void) {
nghttp3_varint_read_state rvint;
nghttp3_ssize nread;

{
/* 1 byte integer */
const uint8_t input[] = {0x3f};

nghttp3_varint_read_state_reset(&rvint);

nread =
nghttp3_read_varint(&rvint, input, input + sizeof(input), /* fin = */ 0);

assert_ptrdiff(1, ==, nread);
assert_size(0, ==, rvint.left);
assert_int64(63, ==, rvint.acc);
}

{
/* 1 byte integer with fin */
const uint8_t input[] = {0x3f};

nghttp3_varint_read_state_reset(&rvint);

nread =
nghttp3_read_varint(&rvint, input, input + sizeof(input), /* fin = */ 1);

assert_ptrdiff((nghttp3_ssize)sizeof(input), ==, nread);
assert_size(0, ==, rvint.left);
assert_int64(63, ==, rvint.acc);
}

{
/* 4 bytes integer */
const uint8_t input[] = {0xad, 0xa5, 0xcb, 0x03};

nghttp3_varint_read_state_reset(&rvint);

nread =
nghttp3_read_varint(&rvint, input, input + sizeof(input), /* fin = */ 0);

assert_ptrdiff((nghttp3_ssize)sizeof(input), ==, nread);
assert_size(0, ==, rvint.left);
assert_int64(0x2d << 24 | 0xa5 << 16 | 0xcb << 8 | 0x03, ==, rvint.acc);
}

{
/* 4 bytes integer but incomplete */
const uint8_t input[] = {0xad, 0xa5, 0xcb, 0x03};

nghttp3_varint_read_state_reset(&rvint);

nread = nghttp3_read_varint(&rvint, input, input + sizeof(input) - 1,
/* fin = */ 0);

assert_ptrdiff((nghttp3_ssize)(sizeof(input) - 1), ==, nread);
assert_size(1, ==, rvint.left);

nread = nghttp3_read_varint(&rvint, input + sizeof(input) - 1,
input + sizeof(input), /* fin = */ 1);

assert_ptrdiff(1, ==, nread);
assert_size(0, ==, rvint.left);
assert_int64(0x2d << 24 | 0xa5 << 16 | 0xcb << 8 | 0x03, ==, rvint.acc);
}

{
/* 4 bytes integer prematurely ended by fin */
const uint8_t input[] = {0xad, 0xa5, 0xcb};

nghttp3_varint_read_state_reset(&rvint);

nread =
nghttp3_read_varint(&rvint, input, input + sizeof(input), /* fin = */ 1);

assert_ptrdiff(NGHTTP3_ERR_INVALID_ARGUMENT, ==, nread);
}

{
/* 4 bytes integer prematurely ended by fin in the second input */
const uint8_t input[] = {0xad, 0xa5, 0xcb};

nghttp3_varint_read_state_reset(&rvint);

nread = nghttp3_read_varint(&rvint, input, input + (sizeof(input) - 1),
/* fin = */ 0);

assert_ptrdiff((nghttp3_ssize)(sizeof(input) - 1), ==, nread);
assert_size(2, ==, rvint.left);

nread = nghttp3_read_varint(&rvint, input + (sizeof(input) - 1),
input + sizeof(input),
/* fin = */ 1);

assert_ptrdiff(NGHTTP3_ERR_INVALID_ARGUMENT, ==, nread);
}

{
/* 4 bytes integer + extra byte */
const uint8_t input[] = {0xad, 0xa5, 0xcb, 0x03, 0xff};

nghttp3_varint_read_state_reset(&rvint);

nread =
nghttp3_read_varint(&rvint, input, input + sizeof(input), /* fin = */ 0);

assert_ptrdiff((nghttp3_ssize)(sizeof(input) - 1), ==, nread);
assert_size(0, ==, rvint.left);
assert_int64(0x2d << 24 | 0xa5 << 16 | 0xcb << 8 | 0x03, ==, rvint.acc);
}

{
/* 8 bytes integer */
const uint8_t input[] = {0xed, 0xa5, 0xcb, 0x03, 0x90, 0xfc, 0x13, 0xd8};

nghttp3_varint_read_state_reset(&rvint);

nread =
nghttp3_read_varint(&rvint, input, input + sizeof(input), /* fin = */ 0);

assert_ptrdiff((nghttp3_ssize)sizeof(input), ==, nread);
assert_size(0, ==, rvint.left);
assert_int64(0x2dll << 56 | 0xa5ll << 48 | 0xcbll << 40 | 0x03ll << 32 |
0x90ll << 24 | 0xfcll << 16 | 0x13ll << 8 | 0xd8ll,
==, rvint.acc);
}

{
/* 8 bytes integer prematurely ended by fin at the first byte */
const uint8_t input[] = {0xed};

nghttp3_varint_read_state_reset(&rvint);

nread =
nghttp3_read_varint(&rvint, input, input + sizeof(input), /* fin = */ 1);

assert_ptrdiff(NGHTTP3_ERR_INVALID_ARGUMENT, ==, nread);
}
}
40 changes: 40 additions & 0 deletions tests/nghttp3_stream_test.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* nghttp3
*
* Copyright (c) 2025 nghttp3 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP3_STREAM_TEST_H
#define NGHTTP3_STREAM_TEST_H

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* defined(HAVE_CONFIG_H) */

#define MUNIT_ENABLE_ASSERT_ALIASES

#include "munit.h"

extern const MunitSuite stream_suite;

munit_void_test_decl(test_nghttp3_read_varint)

#endif /* !defined(NGHTTP3_STREAM_TEST_H) */
Loading