1
0
mirror of https://github.com/stefanocasazza/ULib.git synced 2025-09-28 19:05:55 +08:00
ULib/tests/ulib/http2/hencode.cpp
stefanocasazza cee99c923d sync
2018-06-24 19:41:10 +02:00

412 lines
11 KiB
C++

// hencode.cpp
#include <ulib/utility/http2.h>
#undef PACKAGE
#define PACKAGE "hencode"
#define U_OPTIONS \
"purpose 'simple HPACK encoder'\n" \
"option e expect-error 1 '<ERR>' ''\n" \
"option l table-limit 1 '' ''\n" \
"option t table-size 1 'Default table size: 4096' ''\n"
#include <ulib/application.h>
#define U_ENCODE_INT_DUMP(a,b,c,d) \
U_INTERNAL_DUMP("hpackEncodeInt("#a","#b","#c"): %s", u_memoryDump(buffer,buf,UHTTP2::hpackEncodeInt(buf,a,b,c)-buf)) \
U_INTERNAL_ASSERT_EQUALS(u_get_unalignedp32(buf),d)
class Application : public UApplication {
public:
Application()
{
U_TRACE(5, "Application::Application()")
}
~Application()
{
U_TRACE(5, "Application::~Application()")
}
static void TST_encode(const UString& content)
{
U_TRACE(5, "Application::TST_encode(%V)", content.rep)
U_INTERNAL_ASSERT_EQUALS(UHTTP2::isHeaderName(U_CONSTANT_TO_PARAM("name:")), false)
const char* ptr;
char buffer[4096];
unsigned char* dst;
UString token, name, value;
uint8_t prefix_max = 0x00, pattern = 0x00;
UVector<UString> vline(content,'\n'), vtoken;
uint32_t i, l, n = vline.size(), num, cnt = 0, idx, index;
bool bvalue_is_indexed = false, binsert_dynamic_table = false;
UHTTP2::HpackHeaderTableEntry* entry;
UHTTP2::HpackDynamicTable* dyntbl = &(UHTTP2::pConnection->odyntbl);
for (i = 0; i < n; ++i)
{
U_INTERNAL_ASSERT_EQUALS(bvalue_is_indexed, false)
U_INTERNAL_ASSERT_EQUALS(binsert_dynamic_table, false)
name.clear();
value.clear();
token = vline[i];
U_INTERNAL_DUMP("vline[%u] = %V", i, token.rep)
vtoken.clear();
num = vtoken.split(vline[i], ' ');
start: token = vtoken[0];
U_INTERNAL_DUMP("token = %V", token.rep)
if (num == 1)
{
if (token.equal(U_CONSTANT_TO_PARAM("send")))
{
U_INTERNAL_ASSERT_MAJOR(cnt, 0)
cnt = 0;
}
else if (token.equal(U_CONSTANT_TO_PARAM("push")))
{
U_INTERNAL_ASSERT_MAJOR(cnt, 0)
cnt = 0;
}
else if (token.equal(U_CONSTANT_TO_PARAM("trim")))
{
U_INTERNAL_ASSERT_EQUALS(cnt, 0)
}
continue;
}
dst = (unsigned char*)(ptr = buffer);
if (token.equal(U_CONSTANT_TO_PARAM("resize")))
{
U_INTERNAL_ASSERT_EQUALS(cnt, 0)
uint32_t val[4096], i0 = i;
val[0] = vtoken[1].strtoul();
U_INTERNAL_DUMP("val[0] = %u", val[0])
l = 0;
while ((i+1) < n &&
(vtoken.clear(), (num = vtoken.split(vline[++i], ' '))) == 2 &&
vtoken[0].equal(U_CONSTANT_TO_PARAM("resize")))
{
val[++l] = vtoken[1].strtoul();
U_DUMP("val[%u] = %u vline[%u] = %V", l, val[l], i, vline[i].rep)
}
U_INTERNAL_DUMP("i = %u i0 = %u l = %u", i, i0, l)
if (l <= 1)
{
dst = UHTTP2::setHpackOutputDynTblCapacity(dst, val[0]);
if (l == 1) dst = UHTTP2::setHpackOutputDynTblCapacity(dst, val[1]);
}
else
{
dst = UHTTP2::setHpackOutputDynTblCapacity(dst, val[l-1]);
dst = UHTTP2::setHpackOutputDynTblCapacity(dst, val[l]);
}
cout.write(ptr, dst-(unsigned char*)ptr);
if (i > i0) goto start;
continue;
}
if (token.equal(U_CONSTANT_TO_PARAM("update")))
{
idx = vtoken[1].strtoul();
U_INTERNAL_DUMP("idx = %u dyntbl->hpack_max_capacity = %u", idx, dyntbl->hpack_max_capacity)
if (idx < dyntbl->hpack_max_capacity)
{
dst = UHTTP2::setHpackOutputDynTblCapacity(dst, idx);
cout.write(ptr, dst-(unsigned char*)ptr);
}
continue;
}
++cnt;
if (token.equal(U_CONSTANT_TO_PARAM("indexed")))
{
U_INTERNAL_ASSERT_EQUALS(num, 2)
// indexed 6
pattern = 0x80;
prefix_max = (1<<7)-1;
bvalue_is_indexed = true;
idx = vtoken[1].strtoul();
goto check2;
}
if (token.equal(U_CONSTANT_TO_PARAM("dynamic")))
{
U_INTERNAL_ASSERT(num >= 5)
// dynamic idx 55 huf foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1
pattern = 0x40;
prefix_max = (1<<6)-1;
binsert_dynamic_table = true;
}
else if (token.equal(U_CONSTANT_TO_PARAM("never")))
{
U_INTERNAL_ASSERT(num >= 5)
// never idx 99999 str value
pattern = 0x10;
prefix_max = (1<<4)-1;
}
else if (token.equal(U_CONSTANT_TO_PARAM("literal")))
{
U_INTERNAL_ASSERT(num >= 5)
// literal idx 4 str /sample/path
pattern = 0x00;
prefix_max = (1<<4)-1;
}
else
{
U_ERROR("Unknown token");
}
value = vtoken[4];
for (l = 5; l < num; ++l) value += ' ' + vtoken[l];
if (vtoken[1].equal(U_CONSTANT_TO_PARAM("idx")) == false)
{
// not-existing name
U_INTERNAL_ASSERT_EQUALS(bvalue_is_indexed, false)
dst = UHTTP2::hpackEncodeInt(dst, 0, prefix_max, pattern);
if (UHTTP2::isHeaderName((name = vtoken[2])) == false)
{
UHTTP2::hpack_errno = -7; // A invalid header name or value character was coded
return;
}
dst = UHTTP2::hpackEncodeString(dst, name, vtoken[1].equal(U_CONSTANT_TO_PARAM("huf")));
if (UHTTP2::isHpackError()) return;
dst = UHTTP2::hpackEncodeString(dst, value, vtoken[3].equal(U_CONSTANT_TO_PARAM("huf")));
if (UHTTP2::isHpackError()) return;
cout.write(ptr, dst-(unsigned char*)ptr);
if (binsert_dynamic_table)
{
binsert_dynamic_table = false;
UHTTP2::addHpackDynTblEntry(dyntbl, name.copy(), value.copy());
}
continue;
}
idx = vtoken[2].strtoul();
check2: U_INTERNAL_DUMP("idx = %u", idx)
if (idx == 0 ||
idx > 4096)
{
idx_err: UHTTP2::hpack_errno = -4; // The decoded or specified index is out of range
return;
}
dst = UHTTP2::hpackEncodeInt(dst, idx, prefix_max, pattern);
if (idx >= HTTP2_HEADER_TABLE_OFFSET)
{
index = idx - HTTP2_HEADER_TABLE_OFFSET;
U_INTERNAL_DUMP("index = %d dyntbl->num_entries = %u bvalue_is_indexed = %b binsert_dynamic_table = %b", index, dyntbl->num_entries, bvalue_is_indexed, binsert_dynamic_table)
if (index >= dyntbl->num_entries) goto idx_err;
bvalue_is_indexed = false;
if (binsert_dynamic_table)
{
binsert_dynamic_table = false;
dst = UHTTP2::hpackEncodeString(dst, value, vtoken[3].equal(U_CONSTANT_TO_PARAM("huf")));
if (UHTTP2::isHpackError()) return;
entry = UHTTP2::getHpackDynTblEntry(dyntbl, index);
if (entry == 0) return;
name._assign(entry->name);
UHTTP2::evictHpackDynTblEntry(dyntbl, entry);
UHTTP2::addHpackDynTblEntry(dyntbl, name, value.copy());
}
cout.write(ptr, dst-(unsigned char*)ptr);
continue;
}
// existing name
U_INTERNAL_DUMP("idx = %u bvalue_is_indexed = %b binsert_dynamic_table = %b", idx, bvalue_is_indexed, binsert_dynamic_table)
if (bvalue_is_indexed) bvalue_is_indexed = false;
else
{
dst = UHTTP2::hpackEncodeString(dst, value, vtoken[3].equal(U_CONSTANT_TO_PARAM("huf")));
if (UHTTP2::isHpackError()) return;
}
cout.write(ptr, dst-(unsigned char*)ptr);
if (binsert_dynamic_table)
{
binsert_dynamic_table = false;
entry = UHTTP2::hpack_static_table + idx-1;
name._assign(entry->name);
U_INTERNAL_DUMP("name = %V value = %V", name.rep, value.rep)
UHTTP2::addHpackDynTblEntry(dyntbl, name, value.copy());
}
U_INTERNAL_DUMP("num_entries = %u entry_capacity = %u entry_start_index = %u hpack_size = %u hpack_capacity = %u hpack_max_capacity = %u",
dyntbl->num_entries, dyntbl->entry_capacity, dyntbl->entry_start_index, dyntbl->hpack_size, dyntbl->hpack_capacity, dyntbl->hpack_max_capacity)
}
}
void run(int argc, char* argv[], char* env[])
{
U_TRACE(5, "Application::run(%d,%p,%p)", argc, argv, env)
UApplication::run(argc, argv, env);
char buffer[256];
/*
unsigned char buf[32];
U_ENCODE_INT_DUMP( 8,(1<<7)-1,0x80, U_MULTICHAR_CONSTANT16(0x88,0x00))
U_ENCODE_INT_DUMP( 8,(1<<4)-1,0x00, U_MULTICHAR_CONSTANT16(0x08,0x00))
U_ENCODE_INT_DUMP(62,(1<<6)-1,0x40, U_MULTICHAR_CONSTANT16(0x7e,0x00))
U_ENCODE_INT_DUMP(54,(1<<6)-1,0x40, U_MULTICHAR_CONSTANT16(0x76,0x00))
return;
*/
// manage input
UString x(U_CAPACITY);
UServices::readEOF(STDIN_FILENO, x);
if (x.empty()) U_ERROR("cannot read data from <stdin>");
// manage options
int exp = 0;
UHTTP2::btest = true;
UHTTP2::ctor();
if (UApplication::isOptions())
{
UString tmp = opt['t'];
if (tmp)
{
UHTTP2::pConnection->idyntbl.hpack_capacity =
UHTTP2::pConnection->idyntbl.hpack_max_capacity =
UHTTP2::pConnection->odyntbl.hpack_capacity =
UHTTP2::pConnection->odyntbl.hpack_max_capacity = tmp.strtoul();
}
tmp = opt['e'];
if (tmp)
{
for (int i = 0; i < 11; ++i)
{
if (tmp.equal(UHTTP2::hpack_error[i].str, 3))
{
exp = UHTTP2::hpack_error[i].value;
goto next;
}
}
U_ERROR("Unknown error");
}
}
next: TST_encode(x);
U_INTERNAL_DUMP("UHTTP2::hpack_errno = %d exp = %d", UHTTP2::hpack_errno, exp)
if (UHTTP2::hpack_errno != exp) UApplication::exit_value = 1;
if (UHTTP2::hpack_errno) cerr.write(buffer, u__snprintf(buffer, sizeof(buffer), U_CONSTANT_TO_PARAM("main: hpack result: %s (%d)\n"), UHTTP2::hpack_strerror(), UHTTP2::hpack_errno));
else
{
cout.flush();
(void) U_SYSCALL(dup2, "%d,%d", 3, STDOUT_FILENO);
cout.write(U_CONSTANT_TO_PARAM("Dynamic Table (after decoding):"));
UHTTP2::printHpackOutputDynTable();
}
}
private:
#ifndef U_COVERITY_FALSE_POSITIVE
U_DISALLOW_COPY_AND_ASSIGN(Application)
#endif
};
U_MAIN