diff options
author | erititan | 2017-04-11 09:52:42 +0000 |
---|---|---|
committer | erititan | 2017-04-11 09:52:42 +0000 |
commit | 43537980c3ff570ed565ef92cc1c14bfc2b4639c (patch) | |
tree | 01bfe937c7fa6832946583c9584b6caf09af142f | |
parent | 7ab541c4a31fbb495b5926e25e72cc5c5ade1f62 (diff) | |
download | titan.ProtocolModules.HTTP2-43537980c3ff570ed565ef92cc1c14bfc2b4639c.tar.gz titan.ProtocolModules.HTTP2-43537980c3ff570ed565ef92cc1c14bfc2b4639c.tar.xz titan.ProtocolModules.HTTP2-43537980c3ff570ed565ef92cc1c14bfc2b4639c.zip |
First versionR.1.A
-rw-r--r-- | HTTP2_CNL113851.tpd | 42 | ||||
-rw-r--r-- | README.md | 9 | ||||
-rw-r--r-- | doc/HTTP2_CNL113851_1551.doc | bin | 0 -> 84992 bytes | |||
-rw-r--r-- | doc/HTTP2_CNL113851_PRI.doc | bin | 0 -> 59392 bytes | |||
-rw-r--r-- | src/HTTP2_EncDec.cc | 1928 | ||||
-rw-r--r-- | src/HTTP2_Types.ttcn | 291 |
6 files changed, 2270 insertions, 0 deletions
diff --git a/HTTP2_CNL113851.tpd b/HTTP2_CNL113851.tpd new file mode 100644 index 0000000..a66c8d9 --- /dev/null +++ b/HTTP2_CNL113851.tpd @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2017 Ericsson + + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + + File: HTTP2_CNL113851.tpd + Description: tpd project file + Rev: R1A + Prodnr: CNL 113 851 + + --> +<TITAN_Project_File_Information version="1.0"> + <ProjectName>HTTP2_CNL113851</ProjectName> + <Folders> + <FolderResource projectRelativePath="src" relativeURI="src"/> + </Folders> + <Files> + <FileResource projectRelativePath="src/HTTP2_EncDec.cc" relativeURI="src/HTTP2_EncDec.cc"/> + <FileResource projectRelativePath="src/HTTP2_Types.ttcn" relativeURI="src/HTTP2_Types.ttcn"/> + </Files> + <ActiveConfiguration>Default</ActiveConfiguration> + <Configurations> + <Configuration name="Default"> + <ProjectProperties> + <MakefileSettings> + <generateInternalMakefile>true</generateInternalMakefile> + <GNUMake>true</GNUMake> + <incrementalDependencyRefresh>true</incrementalDependencyRefresh> + <targetExecutable>bin/HTTP2_CNL113851</targetExecutable> + </MakefileSettings> + <LocalBuildSettings> + <workingDirectory>bin</workingDirectory> + </LocalBuildSettings> + </ProjectProperties> + </Configuration> + </Configurations> +</TITAN_Project_File_Information> diff --git a/README.md b/README.md new file mode 100644 index 0000000..d8acd44 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# titan.ProtocolModules.HTTP2 + +Main project page: + +https://projects.eclipse.org/projects/tools.titan + +The source code of the TTCN-3 compiler and executor: + +https://github.com/eclipse/titan.core diff --git a/doc/HTTP2_CNL113851_1551.doc b/doc/HTTP2_CNL113851_1551.doc Binary files differnew file mode 100644 index 0000000..9d532f1 --- /dev/null +++ b/doc/HTTP2_CNL113851_1551.doc diff --git a/doc/HTTP2_CNL113851_PRI.doc b/doc/HTTP2_CNL113851_PRI.doc Binary files differnew file mode 100644 index 0000000..6526631 --- /dev/null +++ b/doc/HTTP2_CNL113851_PRI.doc diff --git a/src/HTTP2_EncDec.cc b/src/HTTP2_EncDec.cc new file mode 100644 index 0000000..df739c8 --- /dev/null +++ b/src/HTTP2_EncDec.cc @@ -0,0 +1,1928 @@ +/****************************************************************************** +* Copyright (c) 2017 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Gabor Szalai - initial implementation and initial documentation +******************************************************************************/ +// +// File: HTTP2_EncDec.cc +// Description: Encoder/decoder function for HTTP2 +// Rev: R1A +// Prodnr: CNL 113 851 + + +#include "HTTP2_Types.hh" +#include <stdint.h> +#include "memory.h" +#include <string.h> +#include <stdio.h> +#include <deque> + +// header compression context classes +class HTTP2_hdr_data{ +public: + CHARSTRING name; + CHARSTRING value; + int size; + + HTTP2_hdr_data(){ + name=""; + value=""; + size=32; + }; + HTTP2_hdr_data(const CHARSTRING& p_name, const CHARSTRING& p_value){ + name=p_name; + value=p_value; + size=32+name.lengthof()+value.lengthof(); + }; + ~HTTP2_hdr_data(){}; + + void set(const CHARSTRING& p_name, const CHARSTRING& p_value){ + name=p_name; + value=p_value; + size=32+name.lengthof()+value.lengthof(); + } + +}; + + +class HTTP2_compression_ctx{ +public: + std::deque<HTTP2_hdr_data*> h_table; + int h_table_size; + int h_table_max_size; + + HTTP2_compression_ctx(){ + h_table_size=0; + h_table_max_size=4096; + }; + HTTP2_compression_ctx(int max_size){ + h_table_size=0; + h_table_max_size=max_size; + }; + + ~HTTP2_compression_ctx(){ + std::deque<HTTP2_hdr_data*>::iterator it = h_table.begin(); + while(it!=h_table.end()){ + delete *it; + it++; + } + }; + + void set_max_size(int new_size){ + while(new_size<h_table_size){ + h_table_size-= h_table.back()->size; + delete h_table.back(); + h_table.pop_back(); + } + h_table_max_size=new_size; + }; + + void add_hdr(const CHARSTRING& p_name, const CHARSTRING& p_value){ + HTTP2_hdr_data *hdata= new HTTP2_hdr_data(p_name,p_value); + h_table.push_front(hdata); + h_table_size+=hdata->size; + while(h_table_max_size<h_table_size){ + h_table_size-= h_table.back()->size; + delete h_table.back(); + h_table.pop_back(); + }; + + }; + + int find(const CHARSTRING& p_name) const { + for(size_t i=0;i<h_table.size();i++){ + if(h_table[i]->name==p_name){ + return i+1; + } + } + return -1; + }; + int find(const CHARSTRING& p_name, const CHARSTRING& p_value) const { + for(size_t i=0;i<h_table.size();i++){ + if( (h_table[i]->name==p_name) && (h_table[i]->value==p_value) ){ + return i+1; + } + } + return -1; + }; + + const HTTP2_hdr_data* operator[](int idx) const{ + if( (idx>0) && (idx<=(int)h_table.size()) ){ + return h_table[idx-1]; + } + return NULL; + }; + +}; + +class HTTP2_compression_ctxs{ +public: + HTTP2_compression_ctx local; + HTTP2_compression_ctx remote; + +}; + +class HTTP2_static_table_class{ +public: + HTTP2_compression_ctx ctx; + HTTP2_static_table_class(){ + ctx.add_hdr("www-authenticate",""); + ctx.add_hdr("via",""); + ctx.add_hdr("vary",""); + ctx.add_hdr("user-agent",""); + ctx.add_hdr("transfer-encoding",""); + ctx.add_hdr("strict-transport-security",""); + ctx.add_hdr("set-cookie",""); + ctx.add_hdr("server",""); + ctx.add_hdr("retry-after",""); + ctx.add_hdr("refresh",""); + ctx.add_hdr("referer",""); + ctx.add_hdr("range",""); + ctx.add_hdr("proxy-authorization",""); + ctx.add_hdr("proxy-authenticate",""); + ctx.add_hdr("max-forwards",""); + ctx.add_hdr("location",""); + ctx.add_hdr("link",""); + ctx.add_hdr("last-modified",""); + ctx.add_hdr("if-unmodified-since",""); + ctx.add_hdr("if-range",""); + ctx.add_hdr("if-none-match",""); + ctx.add_hdr("if-modified-since",""); + ctx.add_hdr("if-match",""); + ctx.add_hdr("host",""); + ctx.add_hdr("from",""); + ctx.add_hdr("expires",""); + ctx.add_hdr("expect",""); + ctx.add_hdr("etag",""); + ctx.add_hdr("date",""); + ctx.add_hdr("cookie",""); + ctx.add_hdr("content-type",""); + ctx.add_hdr("content-range",""); + ctx.add_hdr("content-location",""); + ctx.add_hdr("content-length",""); + ctx.add_hdr("content-language",""); + ctx.add_hdr("content-encoding",""); + ctx.add_hdr("content-disposition",""); + ctx.add_hdr("cache-control",""); + ctx.add_hdr("authorization",""); + ctx.add_hdr("allow",""); + ctx.add_hdr("age",""); + ctx.add_hdr("access-control-allow-origin",""); + ctx.add_hdr("accept",""); + ctx.add_hdr("accept-ranges",""); + ctx.add_hdr("accept-language",""); + ctx.add_hdr("accept-encoding","gzip, deflate"); + ctx.add_hdr("accept-charset",""); + ctx.add_hdr(":status","500"); + ctx.add_hdr(":status","404"); + ctx.add_hdr(":status","400"); + ctx.add_hdr(":status","304"); + ctx.add_hdr(":status","206"); + ctx.add_hdr(":status","204"); + ctx.add_hdr(":status","200"); + ctx.add_hdr(":scheme","https"); + ctx.add_hdr(":scheme","http"); + ctx.add_hdr(":path","/index.html"); + ctx.add_hdr(":path","/"); + ctx.add_hdr(":method","POST"); + ctx.add_hdr(":method","GET"); + ctx.add_hdr(":authority",""); + } +}; + +static const HTTP2_static_table_class HTTP2_static_table=HTTP2_static_table_class(); + +////// Indexed variable int representation functions +// Support max 32 bit unsigned val +// it means the buffer should be at least 6 octet to safely store the max value +// with the minimal prefix + +static const unsigned char twoN_minus_one_table[]={ // stores 2^N-1 for N=0..8 +0,1,3,7,15,31,63,127,255 +}; + +// return the number of used octets +static int encode_integer(unsigned char* buff, + const uint32_t val, + const int prefix_len, + const unsigned char filler){ // only the filler bits should be set + int ret_val=0; + if(val< twoN_minus_one_table[prefix_len]){ + // fits in one octet + buff[0]= filler | (val & 0xFF); + ret_val=1; + } else { + uint32_t act_val=val-twoN_minus_one_table[prefix_len]; + buff[0]= filler | ( twoN_minus_one_table[prefix_len] & 0xFF); + ret_val=1; + while(act_val>127){ + buff[ret_val]= 0x80 | (act_val%128); + act_val/=128; + ret_val++; + } + buff[ret_val]= act_val; + ret_val++; + } + return ret_val; +} + +// returns the number of the used octets +static int decode_integer(const unsigned char* buff, + uint32_t& val, + const int prefix_len, + unsigned char& filler){ // only the filler bits will be set + filler = buff[0] & ~twoN_minus_one_table[prefix_len]; + + val = buff[0] & twoN_minus_one_table[prefix_len]; + + int ret_val=0; + if(val==twoN_minus_one_table[prefix_len]){ + // The value is not fit into the prefix_len bits + do { + ret_val++; + val += ( ((uint32_t)(buff[ret_val] & 0x7F)) << (7*ret_val) ); + } while(buff[ret_val] & 0x80); + ret_val++; + } else { + ret_val=1; + } + return ret_val; +} + + + + + +//////////// Huffman tables See RFC7541 + +// Huffman code lengths in bits + +static const int huffman_code_length[]={ + 13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28, + 28, 28, 28, 28, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6, + 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10, + 13, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6, + 15, 5, 6, 5, 6, 5, 6, 6, 6, 5, 7, 7, 6, 6, 6, 5, + 6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, 28, + 20, 22, 20, 20, 22, 22, 22, 23, 22, 23, 23, 23, 23, 23, 24, 23, + 24, 24, 22, 23, 24, 23, 23, 23, 23, 21, 22, 23, 22, 23, 23, 24, + 22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, 24, 21, 22, 23, 23, + 21, 21, 22, 21, 23, 22, 23, 23, 20, 22, 22, 22, 23, 22, 22, 23, + 26, 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27, 26, 24, 25, + 19, 21, 26, 27, 27, 26, 27, 24, 21, 21, 26, 26, 28, 27, 27, 27, + 20, 24, 20, 21, 22, 21, 21, 23, 22, 22, 25, 25, 24, 24, 26, 23, + 26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27, 27, 27, 27, 27, 26, + 30 +}; + +static const unsigned int huffman_code_values[]={ + 0x1ff8, 0x7fffd8, 0xfffffe2, 0xfffffe3, 0xfffffe4, 0xfffffe5, 0xfffffe6, 0xfffffe7, 0xfffffe8, 0xffffea, 0x3ffffffc, 0xfffffe9, 0xfffffea, 0x3ffffffd, 0xfffffeb, 0xfffffec, + 0xfffffed, 0xfffffee, 0xfffffef, 0xffffff0, 0xffffff1, 0xffffff2, 0x3ffffffe, 0xffffff3, 0xffffff4, 0xffffff5, 0xffffff6, 0xffffff7, 0xffffff8, 0xffffff9, 0xffffffa, 0xffffffb, + 0x14, 0x3f8, 0x3f9, 0xffa, 0x1ff9, 0x15, 0xf8, 0x7fa, 0x3fa, 0x3fb, 0xf9, 0x7fb, 0xfa, 0x16, 0x17, 0x18, + 0x0, 0x1, 0x2, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x5c, 0xfb, 0x7ffc, 0x20, 0xffb, 0x3fc, + 0x1ffa, 0x21, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, + 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0xfc, 0x73, 0xfd, 0x1ffb, 0x7fff0, 0x1ffc, 0x3ffc, 0x22, + 0x7ffd, 0x3, 0x23, 0x4, 0x24, 0x5, 0x25, 0x26, 0x27, 0x6, 0x74, 0x75, 0x28, 0x29, 0x2a, 0x7, + 0x2b, 0x76, 0x2c, 0x8, 0x9, 0x2d, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7ffe, 0x7fc, 0x3ffd, 0x1ffd, 0xffffffc, + 0xfffe6, 0x3fffd2, 0xfffe7, 0xfffe8, 0x3fffd3, 0x3fffd4, 0x3fffd5, 0x7fffd9, 0x3fffd6, 0x7fffda, 0x7fffdb, 0x7fffdc, 0x7fffdd, 0x7fffde, 0xffffeb, 0x7fffdf, + 0xffffec, 0xffffed, 0x3fffd7, 0x7fffe0, 0xffffee, 0x7fffe1, 0x7fffe2, 0x7fffe3, 0x7fffe4, 0x1fffdc, 0x3fffd8, 0x7fffe5, 0x3fffd9, 0x7fffe6, 0x7fffe7, 0xffffef, + 0x3fffda, 0x1fffdd, 0xfffe9, 0x3fffdb, 0x3fffdc, 0x7fffe8, 0x7fffe9, 0x1fffde, 0x7fffea, 0x3fffdd, 0x3fffde, 0xfffff0, 0x1fffdf, 0x3fffdf, 0x7fffeb, 0x7fffec, + 0x1fffe0, 0x1fffe1, 0x3fffe0, 0x1fffe2, 0x7fffed, 0x3fffe1, 0x7fffee, 0x7fffef, 0xfffea, 0x3fffe2, 0x3fffe3, 0x3fffe4, 0x7ffff0, 0x3fffe5, 0x3fffe6, 0x7ffff1, + 0x3ffffe0, 0x3ffffe1, 0xfffeb, 0x7fff1, 0x3fffe7, 0x7ffff2, 0x3fffe8, 0x1ffffec, 0x3ffffe2, 0x3ffffe3, 0x3ffffe4, 0x7ffffde, 0x7ffffdf, 0x3ffffe5, 0xfffff1, 0x1ffffed, + 0x7fff2, 0x1fffe3, 0x3ffffe6, 0x7ffffe0, 0x7ffffe1, 0x3ffffe7, 0x7ffffe2, 0xfffff2, 0x1fffe4, 0x1fffe5, 0x3ffffe8, 0x3ffffe9, 0xffffffd, 0x7ffffe3, 0x7ffffe4, 0x7ffffe5, + 0xfffec, 0xfffff3, 0xfffed, 0x1fffe6, 0x3fffe9, 0x1fffe7, 0x1fffe8, 0x7ffff3, 0x3fffea, 0x3fffeb, 0x1ffffee, 0x1ffffef, 0xfffff4, 0xfffff5, 0x3ffffea, 0x7ffff4, + 0x3ffffeb, 0x7ffffe6, 0x3ffffec, 0x3ffffed, 0x7ffffe7, 0x7ffffe8, 0x7ffffe9, 0x7ffffea, 0x7ffffeb, 0xffffffe, 0x7ffffec, 0x7ffffed, 0x7ffffee, 0x7ffffef, 0x7fffff0, 0x3ffffee, + 0x3fffffff +}; + + +// inserts the huffman code of one character into teh buffer +static void put_code2buff(unsigned char* buff, int& bitpos, unsigned char code){ + int code_len = huffman_code_length[code]; + int bitpos_in_octet = bitpos%8; + + // moves to the first bit of the huffman code to the insertion point + int shift= (16-bitpos_in_octet-(code_len%8))%8; + uint64_t ins_val= ((uint64_t)huffman_code_values[code]) << shift; + + + buff+= bitpos/8; + for(int i=((code_len+shift+7)/8)-1;i>=0;i--) { + if(i==0){ + buff[i] |= (ins_val & 0xFF); + } else { + buff[i] = (ins_val & 0xFF); + } + ins_val >>= 8; + } + bitpos+=code_len; +} + +static const unsigned char get_mask_table[]={ +0x80, 0x40, 0x20, 0x10, +0x08, 0x04, 0x02, 0x01 +}; + +static int get_onebit(const unsigned char* buff, int& bitpos){ + if(buff[bitpos/8] & get_mask_table[bitpos%8]){ + bitpos++; + return 1; + } + bitpos++; + return 0; +} + +// return -1 or the char code or the EOF (256) +static int decompress_one_char(const unsigned char* buff, int& bitpos, int length /*in bits*/ ){ + unsigned int huffman_val=0; + + if((bitpos+5)>length){ + while(bitpos<length){ + if(get_onebit(buff,bitpos)!=1) {return -1;} // incomplete code + } + return 256; //EOF + } + + // get the first 5 bit, the minimum code length is 5 + for(int i=0;i<5;i++){ + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + } + // Check the 5 bit codes + // See RFC7541 for magic values + switch(huffman_val){ + case 0x0: + return 48; + case 0x1: + return 49; + case 0x2: + return 50; + case 0x3: + return 97; + case 0x4: + return 99; + case 0x5: + return 101; + case 0x6: + return 105; + case 0x7: + return 111; + case 0x8: + return 115; + case 0x9: + return 116; + } + + if(bitpos==length){ // no more bits + if(huffman_val == 0x1f){ // all bit is 1 + return 256; //EOF + } else { + return -1; // invalid code + } + } + + // 6 bit codes + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + + switch(huffman_val){ + case 0x14: + return 32; + case 0x15: + return 37; + case 0x16: + return 45; + case 0x17: + return 46; + case 0x18: + return 47; + case 0x19: + return 51; + case 0x1a: + return 52; + case 0x1b: + return 53; + case 0x1c: + return 54; + case 0x1d: + return 55; + case 0x1e: + return 56; + case 0x1f: + return 57; + case 0x20: + return 61; + case 0x21: + return 65; + case 0x22: + return 95; + case 0x23: + return 98; + case 0x24: + return 100; + case 0x25: + return 102; + case 0x26: + return 103; + case 0x27: + return 104; + case 0x28: + return 108; + case 0x29: + return 109; + case 0x2a: + return 110; + case 0x2b: + return 112; + case 0x2c: + return 114; + case 0x2d: + return 117; + } + + if(bitpos==length){ // no more bits + if(huffman_val == 0x3f){ // all bit is 1 + return 256; //EOF + } else { + return -1; // invalid code + } + } + + // 7 bit codes + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + switch(huffman_val){ + case 0x5c: + return 58; + case 0x5d: + return 66; + case 0x5e: + return 67; + case 0x5f: + return 68; + case 0x60: + return 69; + case 0x61: + return 70; + case 0x62: + return 71; + case 0x63: + return 72; + case 0x64: + return 73; + case 0x65: + return 74; + case 0x66: + return 75; + case 0x67: + return 76; + case 0x68: + return 77; + case 0x69: + return 78; + case 0x6a: + return 79; + case 0x6b: + return 80; + case 0x6c: + return 81; + case 0x6d: + return 82; + case 0x6e: + return 83; + case 0x6f: + return 84; + case 0x70: + return 85; + case 0x71: + return 86; + case 0x72: + return 87; + case 0x73: + return 89; + case 0x74: + return 106; + case 0x75: + return 107; + case 0x76: + return 113; + case 0x77: + return 118; + case 0x78: + return 119; + case 0x79: + return 120; + case 0x7a: + return 121; + case 0x7b: + return 122; + } + + if(bitpos==length){ // no more bits + if(huffman_val == 0x7f){ // all bit is 1 + return 256; //EOF + } else { + return -1; // invalid code + } + } + + // 8bit codes + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + switch(huffman_val){ + case 0xf8: + return 38; + case 0xf9: + return 42; + case 0xfa: + return 44; + case 0xfb: + return 59; + case 0xfc: + return 88; + case 0xfd: + return 90; + } + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 10bit codes + switch(huffman_val){ + case 0x3f8: + return 33; + case 0x3f9: + return 34; + case 0x3fa: + return 40; + case 0x3fb: + return 41; + case 0x3fc: + return 63; + } + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 11bit codes + switch(huffman_val){ + case 0x7fa: + return 39; + case 0x7fb: + return 43; + case 0x7fc: + return 124; + } + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 12bit codes + + switch(huffman_val){ + case 0xffa: + return 35; + case 0xffb: + return 62; + } + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 13bit codes + + switch(huffman_val){ + case 0x1ff8: + return 0; + case 0x1ff9: + return 36; + case 0x1ffa: + return 64; + case 0x1ffb: + return 91; + case 0x1ffc: + return 93; + case 0x1ffd: + return 126; + } + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 14bit codes + switch(huffman_val){ + case 0x3ffc: + return 94; + case 0x3ffd: + return 125; + } + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 15bit codes + switch(huffman_val){ + case 0x7ffc: + return 60; + case 0x7ffd: + return 96; + case 0x7ffe: + return 123; + } + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 19bit codes + switch(huffman_val){ + case 0x7fff0: + return 92; + case 0x7fff1: + return 195; + case 0x7ff2: + return 208; + } + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 20bit codes + switch(huffman_val){ + case 0xfffe6: + return 128; + case 0xfffe7: + return 130; + case 0xfffe8: + return 131; + case 0xfffe9: + return 162; + case 0xfffea: + return 184; + case 0xfffeb: + return 194; + case 0xfffec: + return 224; + case 0xfffed: + return 226; + } + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 21bit codes + switch(huffman_val){ + case 0x1fffdc: + return 153; + case 0x1fffdd: + return 161; + case 0x1fffde: + return 167; + case 0x1fffdf: + return 172; + case 0x1fffe0: + return 176; + case 0x1fffe1: + return 177; + case 0x1fffe2: + return 179; + case 0x1fffe3: + return 209; + case 0x1fffe4: + return 216; + case 0x1fffe5: + return 217; + case 0x1fffe6: + return 227; + case 0x1fffe7: + return 229; + case 0x1fffe8: + return 230; + } + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 22bit codes + switch(huffman_val){ + case 0x3fffd2: + return 129; + case 0x3fffd3: + return 132; + case 0x3fffd4: + return 133; + case 0x3fffd5: + return 134; + case 0x3fffd6: + return 136; + case 0x3fffd7: + return 146; + case 0x3fffd8: + return 154; + case 0x3fffd9: + return 156; + case 0x3fffda: + return 160; + case 0x3fffdb: + return 163; + case 0x3fffdc: + return 164; + case 0x3fffdd: + return 169; + case 0x3fffde: + return 170; + case 0x3fffdf: + return 173; + case 0x3fffe0: + return 178; + case 0x3fffe1: + return 181; + case 0x3fffe2: + return 185; + case 0x3fffe3: + return 186; + case 0x3fffe4: + return 187; + case 0x3fffe5: + return 189; + case 0x3fffe6: + return 190; + case 0x3fffe7: + return 196; + case 0x3fffe8: + return 198; + case 0x3fffe9: + return 228; + case 0x3fffea: + return 232; + case 0x3fffeb: + return 233; + } + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 23bit codes + switch(huffman_val){ + case 0x7fffd8: + return 1; + case 0x7fffd9: + return 135; + case 0x7fffda: + return 137; + case 0x7fffdb: + return 138; + case 0x7fffdc: + return 139; + case 0x7fffdd: + return 140; + case 0x7fffde: + return 141; + case 0x7fffdf: + return 143; + case 0x7fffe0: + return 147; + case 0x7fffe1: + return 149; + case 0x7fffe2: + return 150; + case 0x7fffe3: + return 151; + case 0x7fffe4: + return 152; + case 0x7fffe5: + return 155; + case 0x7fffe6: + return 157; + case 0x7fffe7: + return 158; + case 0x7fffe8: + return 165; + case 0x7fffe9: + return 166; + case 0x7fffea: + return 168; + case 0x7fffeb: + return 174; + case 0x7fffec: + return 175; + case 0x7fffed: + return 180; + case 0x7fffee: + return 182; + case 0x7fffef: + return 183; + case 0x7ffff0: + return 188; + case 0x7ffff1: + return 191; + case 0x7ffff2: + return 197; + case 0x7ffff3: + return 231; + case 0x7ffff4: + return 239; + } + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 24bit codes + switch(huffman_val){ + case 0xffffea: + return 9; + case 0xffffeb: + return 142; + case 0xffffec: + return 144; + case 0xffffed: + return 145; + case 0xffffee: + return 148; + case 0xffffef: + return 159; + case 0xfffff0: + return 171; + case 0xfffff1: + return 206; + case 0xfffff2: + return 215; + case 0xfffff3: + return 225; + case 0xfffff4: + return 236; + case 0xfffff5: + return 237; + } + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 25bit codes + switch(huffman_val){ + case 0x1ffffec: + return 199; + case 0x1ffffed: + return 207; + case 0x1ffffee: + return 234; + case 0x1ffffef: + return 235; + } + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 26bit codes + switch(huffman_val){ + case 0x3ffffe0: + return 192; + case 0x3ffffe1: + return 193; + case 0x3ffffe2: + return 200; + case 0x3ffffe3: + return 201; + case 0x3ffffe4: + return 202; + case 0x3ffffe5: + return 205; + case 0x3ffffe6: + return 210; + case 0x3ffffe7: + return 213; + case 0x3ffffe8: + return 218; + case 0x3ffffe9: + return 219; + case 0x3ffffea: + return 238; + case 0x3ffffeb: + return 240; + case 0x3ffffec: + return 242; + case 0x3ffffed: + return 243; + case 0x3ffffee: + return 255; + } + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 27bit codes + switch(huffman_val){ + case 0x3ffffde: + return 203; + case 0x3ffffdf: + return 204; + case 0x3ffffe0: + return 211; + case 0x3ffffe1: + return 212; + case 0x3ffffe2: + return 214; + case 0x3ffffe3: + return 221; + case 0x3ffffe4: + return 222; + case 0x3ffffe5: + return 223; + case 0x3ffffe6: + return 241; + case 0x3ffffe7: + return 244; + case 0x3ffffe8: + return 245; + case 0x3ffffe9: + return 246; + case 0x3ffffea: + return 247; + case 0x3ffffeb: + return 248; + case 0x3ffffec: + return 250; + case 0x3ffffed: + return 251; + case 0x3ffffee: + return 252; + case 0x3ffffef: + return 253; + case 0x3fffff0: + return 254; + } + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 28bit codes + switch(huffman_val){ + case 0xfffffe2: + return 2; + case 0xfffffe3: + return 3; + case 0xfffffe4: + return 4; + case 0xfffffe5: + return 5; + case 0xfffffe6: + return 6; + case 0xfffffe7: + return 7; + case 0xfffffe8: + return 8; + case 0xfffffe9: + return 11; + case 0xfffffea: + return 12; + case 0xfffffeb: + return 14; + case 0xfffffec: + return 15; + case 0xfffffed: + return 16; + case 0xfffffee: + return 17; + case 0xfffffef: + return 18; + case 0xffffff0: + return 19; + case 0xffffff1: + return 20; + case 0xffffff2: + return 21; + case 0xffffff3: + return 23; + case 0xffffff4: + return 24; + case 0xffffff5: + return 25; + case 0xffffff6: + return 26; + case 0xffffff7: + return 27; + case 0xffffff8: + return 28; + case 0xffffff9: + return 29; + case 0xffffffa: + return 30; + case 0xffffffb: + return 31; + case 0xffffffc: + return 127; + case 0xffffffd: + return 220; + case 0xffffffe: + return 249; + } + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + + if(bitpos==length){ // no more bits + return -1; // invalid code + } + huffman_val<<=1; + huffman_val+=get_onebit(buff,bitpos); + // 30bit codes + switch(huffman_val){ + case 0x3ffffffc: + return 10; + case 0x3ffffffd: + return 13; + case 0x3ffffffe: + return 22; + case 0x3fffffff: + return 256; + } + +return -1; +} + +static const unsigned char mask_table[]={ +0xff, 0x7f, 0x3f, 0x1f, +0x0f, 0x07, 0x03, 0x01 +}; + +static OCTETSTRING enc_huff(const OCTETSTRING& pl__stream){ + int enc_len=0; + const unsigned char* ptr=(const unsigned char*)pl__stream; + for(int i=0;i<pl__stream.lengthof();i++){ + enc_len+=huffman_code_length[ptr[i]]; + } + enc_len=(enc_len+7)/8; + + unsigned char* res=(unsigned char*)Malloc(enc_len*sizeof(unsigned char)); + memset(res,0,enc_len); + + int bitpos=0; + for(int i=0;i<pl__stream.lengthof();i++){ + put_code2buff(res,bitpos,ptr[i]); + } + + if(bitpos%8){ + res[bitpos/8]|=mask_table[bitpos%8]; + } + OCTETSTRING ret_val=OCTETSTRING(enc_len,res); + Free(res); + return ret_val; +} + +static OCTETSTRING dec_huff(const OCTETSTRING& pl__stream){ + int bitpos=0; + int len=pl__stream.lengthof()*8; + const unsigned char* ptr=(const unsigned char*)pl__stream; + + OCTETSTRING ret_val=OCTETSTRING(0,NULL); + int res=decompress_one_char(ptr,bitpos,len); + while( (res!=-1) && (res!=256) ){ + ret_val = ret_val + int2oct(res,1); + res=decompress_one_char(ptr,bitpos,len); + } + return ret_val; +} + +// Encode the string according to the RFC7541 5.2 +static OCTETSTRING enc_http2_string(const OCTETSTRING& pl__stream, const int use_huffman){ + unsigned char len_field[6]; + + OCTETSTRING str= use_huffman?enc_huff(pl__stream):pl__stream; + + int len_len= encode_integer(len_field,str.lengthof(),7,use_huffman?0x80:0); + + return OCTETSTRING(len_len,len_field) + str; + +} + +static int dec_http2_string(const unsigned char* ptr, int ptr_len, OCTETSTRING& pl__stream){ + uint32_t str_len=0; + unsigned char huff=0; + int len_len=decode_integer(ptr,str_len,7,huff); + ptr+=len_len; + if(ptr_len<len_len+(int)str_len){ + return -1; + } + + pl__stream=huff?dec_huff(OCTETSTRING(str_len,ptr)):OCTETSTRING(str_len,ptr); + return len_len+str_len; +} + +static HTTP2_compression_ctxs* get_ptr(const INTEGER& val){ + return (HTTP2_compression_ctxs*)(val.get_long_long_val()); +} + +static OCTETSTRING HTTP2_encode_one_header(const CHARSTRING& hname, const CHARSTRING& hval, HTTP2_compression_ctx* comp_ctx){ + + // first search in the dynamic table + OCTETSTRING ret_val=OCTETSTRING(0,NULL); + unsigned char int_encode_buff[6]; + + int idx=comp_ctx->find(hname,hval); + int idx_offset=61; // size of the fixed table + + if(idx==-1){ // not found it + // check the fixed table + idx=HTTP2_static_table.ctx.find(hname,hval); + idx_offset=0; + } + int idx_len=0; + if(idx>0){ // found it + idx_len=encode_integer(int_encode_buff,idx+idx_offset,7,0x80); + return OCTETSTRING(idx_len,int_encode_buff); + } + + // not found, lets check for the header name + idx_offset=61; + comp_ctx->find(hname); + if(idx==-1){ // not found it + // check the fixed table + idx=HTTP2_static_table.ctx.find(hname); + idx_offset=0; + } + + int can_be_added=((32+hname.lengthof()+hval.lengthof())>(comp_ctx->h_table_max_size))?0:1; // Do not add if the header size is more than the max table size + + if(idx>0){ // found it + if(can_be_added){ + idx_len=encode_integer(int_encode_buff,idx+idx_offset,6,0x40); + ret_val=OCTETSTRING(idx_len,int_encode_buff); + } else { + idx_len=encode_integer(int_encode_buff,idx+idx_offset,4,0x00); + ret_val=OCTETSTRING(idx_len,int_encode_buff); + } + ret_val=ret_val+enc_http2_string(char2oct(hval),1); + } else { + if(can_be_added){ + idx_len=encode_integer(int_encode_buff,0,6,0x40); + ret_val=OCTETSTRING(idx_len,int_encode_buff); + } else { + idx_len=encode_integer(int_encode_buff,0,4,0x00); + ret_val=OCTETSTRING(idx_len,int_encode_buff); + } + ret_val=ret_val+enc_http2_string(char2oct(hname),1); + ret_val=ret_val+enc_http2_string(char2oct(hval),1); + } + + if(can_be_added){ + comp_ctx->add_hdr(hname,hval); + } + + return ret_val; +} + +static int HTTP2_decode_one_header(const unsigned char* buff, int buff_len, CHARSTRING& hname, CHARSTRING& hval, HTTP2_compression_ctx* comp_ctx){ + if(buff_len<1){ + return -1; //not enough data + } + + int ret_val=0; + uint32_t idx=0; + + if((buff[0] & 0xE0)== 0x20){ // Dynamic Table Size Update + unsigned char filler; + ret_val=decode_integer(buff,idx,5,filler); + if(ret_val>buff_len){ + return -1; + } + + comp_ctx->set_max_size(idx); +//printf("Dynamic Table Size Update %d\r\n", idx); + return ret_val; + + } + + if(buff[0] & 0x80){ // indexed field representation + unsigned char filler; + ret_val=decode_integer(buff,idx,7,filler); +//printf("indexed field representation %d\r\n", idx); + + if(ret_val>buff_len){ + return -1; + } + + if(idx==0){ + // invalid value + return -1; + } + + if(idx<62){ + hname=HTTP2_static_table.ctx[idx]->name; + hval=HTTP2_static_table.ctx[idx]->value; + } else { + idx-=61; + const HTTP2_hdr_data* d=((*comp_ctx)[idx]); + if(d==NULL){ + return -1; + } + hname=d->name; + hval=d->value; + } + return ret_val; + } + + int add_hdr=0; + + if((buff[0] & 0xC0)== 0x40){ // Literal Header Field with Incremental Indexing + add_hdr=1; + unsigned char filler; + ret_val=decode_integer(buff,idx,6,filler); +//printf("Literal Header Field with Incremental Indexing %d\r\n", idx); + } else if(((buff[0] & 0xF0)== 0x10) || ((buff[0] & 0xF0)== 0x00)){ // Literal Header Field without Indexing + unsigned char filler; + ret_val=decode_integer(buff,idx,4,filler); +//printf("Literal Header Field withot Indexing %d %x\r\n", idx,buff[0]); + } else { + // not possible + return -1; + } + if(ret_val>buff_len){ + return -1; + } + + buff+=ret_val; // skip the index + + if(idx!=0){ // indexed header name + if(idx<62){ + hname=HTTP2_static_table.ctx[idx]->name; + } else { + idx-=61; + const HTTP2_hdr_data* d=((*comp_ctx)[idx]); + if(d==NULL){ + return -1; + } + hname=d->name; + } + } else { // new header name + OCTETSTRING str; + int str_len=dec_http2_string(buff,buff_len-ret_val,str); + if(str_len==-1){ + return -1; + } + buff+=str_len; + ret_val+=str_len; + hname=CHARSTRING(str.lengthof(),(const char*)(const unsigned char*)str); + } + + OCTETSTRING str; + int str_len=dec_http2_string(buff,buff_len-ret_val,str); + if(str_len==-1){ + return -1; + } + + buff+=str_len; + ret_val+=str_len; + hval=CHARSTRING(str.lengthof(),(const char*)(const unsigned char*)str); + + if(add_hdr){ + comp_ctx->add_hdr(hname,hval); + } + + return ret_val; + +} +namespace HTTP2__Types { + + +HTTP2__comp__context HTTP2__comp__context__init( const INTEGER& h__table__size__local , + const INTEGER& h__table__size__remote){ + + HTTP2_compression_ctxs* ctx=new HTTP2_compression_ctxs; + ctx->local.set_max_size(h__table__size__local); + ctx->remote.set_max_size(h__table__size__remote); + + HTTP2__comp__context ret_val; + ret_val.internal__id1().set_long_long_val((long long int)ctx); + return ret_val; +} + +void HTTP2__comp__context__free(HTTP2__Types::HTTP2__comp__context& ctx){ + delete get_ptr(ctx.internal__id1()); + ctx.internal__id1()=0; +} + +void HTTP2__comp__context__set__table__size__remote(HTTP2__Types::HTTP2__comp__context& ctx, const INTEGER& new_size){ + HTTP2_compression_ctxs* c=get_ptr(ctx.internal__id1()); + c->remote.set_max_size(new_size); +} + +void HTTP2__comp__context__set__table__size__local(HTTP2__Types::HTTP2__comp__context& ctx, const INTEGER& new_size){ + HTTP2_compression_ctxs* c=get_ptr(ctx.internal__id1()); + c->local.set_max_size(new_size); +} + +OCTETSTRING encode_prio(const HTTP2__Priority__data& p_data){ + return bit2oct(int2bit(p_data.exclusive__flag()?1:0,1)+int2bit(p_data.stream__dependency(),31))+int2oct(p_data.weight(),1); +} + + +OCTETSTRING enc__huff(const OCTETSTRING& pl__stream){ + return enc_huff(pl__stream); +} + +OCTETSTRING dec__huff(const OCTETSTRING& pl__stream){ + return dec_huff(pl__stream); +} + +INTEGER HTTP2__comp__context__encode(HTTP2__comp__context& pl_context, const HTTP2__header__block& pl_hblock, OCTETSTRING& pl_frame_data){ + + HTTP2_compression_ctxs* ctx=get_ptr(pl_context.internal__id1()); + pl_frame_data= OCTETSTRING(0,NULL); + + if(pl_hblock.pseudo__headers().ispresent()){ + if(pl_hblock.pseudo__headers()().method().ispresent()){ + pl_frame_data= pl_frame_data+HTTP2_encode_one_header(":method",pl_hblock.pseudo__headers()().method()(),&ctx->local); + } + if(pl_hblock.pseudo__headers()().authority().ispresent()){ + pl_frame_data= pl_frame_data+HTTP2_encode_one_header(":authority",pl_hblock.pseudo__headers()().authority()(),&ctx->local); + } + if(pl_hblock.pseudo__headers()().scheme().ispresent()){ + pl_frame_data= pl_frame_data+HTTP2_encode_one_header(":scheme",pl_hblock.pseudo__headers()().scheme()(),&ctx->local); + } + if(pl_hblock.pseudo__headers()().path().ispresent()){ + pl_frame_data= pl_frame_data+HTTP2_encode_one_header(":path",pl_hblock.pseudo__headers()().path()(),&ctx->local); + } + if(pl_hblock.pseudo__headers()().status().ispresent()){ + pl_frame_data= pl_frame_data+HTTP2_encode_one_header(":status",int2str(pl_hblock.pseudo__headers()().status()()),&ctx->local); + } + } + + if(pl_hblock.headers().ispresent()){ + for(int i=0;i<pl_hblock.headers()().lengthof();i++){ + pl_frame_data= pl_frame_data+HTTP2_encode_one_header(pl_hblock.headers()()[i].header__name(), + pl_hblock.headers()()[i].header__value().ispresent()?pl_hblock.headers()()[i].header__value()():"",&ctx->local); + } + + } + + return 0; +} + +INTEGER HTTP2__comp__context__decode(HTTP2__Types::HTTP2__comp__context& pl_context, HTTP2__Types::HTTP2__header__block& pl_hblock, const OCTETSTRING& pl_stream){ + + const unsigned char* ptr=(const unsigned char*)pl_stream; + int ptr_len=pl_stream.lengthof(); + HTTP2_compression_ctxs* ctx=get_ptr(pl_context.internal__id1()); + + pl_hblock.pseudo__headers()=OMIT_VALUE; + pl_hblock.headers()=OMIT_VALUE; + + while(ptr_len>0){ + CHARSTRING hname=""; + CHARSTRING hval=""; + int hlen =-1; + hlen=HTTP2_decode_one_header(ptr,ptr_len,hname, hval, &(ctx->remote)); + if(hlen==-1){ + return 1; + } +printf("decoded header len %d %s %s\r\n",hlen,(const char*)hname,(const char*)hval); + if(hname==":method"){ + if(!pl_hblock.pseudo__headers().ispresent()) pl_hblock.pseudo__headers()() = HTTP2__pseudo__headers(OMIT_VALUE,OMIT_VALUE,OMIT_VALUE,OMIT_VALUE,OMIT_VALUE); + pl_hblock.pseudo__headers()().method()=hval; + } else if(hname==":scheme") { + if(!pl_hblock.pseudo__headers().ispresent()) pl_hblock.pseudo__headers()() = HTTP2__pseudo__headers(OMIT_VALUE,OMIT_VALUE,OMIT_VALUE,OMIT_VALUE,OMIT_VALUE); + pl_hblock.pseudo__headers()().scheme()=hval; + } else if(hname==":authority") { + if(!pl_hblock.pseudo__headers().ispresent()) pl_hblock.pseudo__headers()() = HTTP2__pseudo__headers(OMIT_VALUE,OMIT_VALUE,OMIT_VALUE,OMIT_VALUE,OMIT_VALUE); + pl_hblock.pseudo__headers()().authority()=hval; + } else if(hname==":path") { + if(!pl_hblock.pseudo__headers().ispresent()) pl_hblock.pseudo__headers()() = HTTP2__pseudo__headers(OMIT_VALUE,OMIT_VALUE,OMIT_VALUE,OMIT_VALUE,OMIT_VALUE); + pl_hblock.pseudo__headers()().path()=hval; + } else if(hname==":status") { + if(!pl_hblock.pseudo__headers().ispresent()) pl_hblock.pseudo__headers()() = HTTP2__pseudo__headers(OMIT_VALUE,OMIT_VALUE,OMIT_VALUE,OMIT_VALUE,OMIT_VALUE); + pl_hblock.pseudo__headers()().status()=str2int(hval); + } else { + if(!pl_hblock.headers().ispresent()) pl_hblock.headers()() = NULL_VALUE; + pl_hblock.headers()()[pl_hblock.headers()().lengthof()]=HTTP2__header__field(hname,hval); + + } + ptr+=hlen; + ptr_len-=hlen; + + + } + + return 0; +} + +OCTETSTRING f__HTTP2__encode__frame(const HTTP2__Frame& pl__frame){ + + unsigned char flags=0; + + OCTETSTRING ret_val=OCTETSTRING(0,NULL); + + switch(pl__frame.get_selection()){ + case HTTP2__Frame::ALT_data__frame: + if(pl__frame.data__frame().end__stream__flag()){ + flags|=0x01; + } + if(pl__frame.data__frame().padding().ispresent()){ + flags|=0x08; + } + ret_val=int2oct(0,1) // Type: DATA frames (type=0x0) + + int2oct(flags,1) + + int2oct(pl__frame.data__frame().stream__id(),4); + + if(pl__frame.data__frame().padding().ispresent()){ + ret_val=ret_val+int2oct(pl__frame.data__frame().padding()().lengthof(),1); + } + ret_val=ret_val+pl__frame.data__frame().data(); + if(pl__frame.data__frame().padding().ispresent()){ + ret_val=ret_val+pl__frame.data__frame().padding()(); + } + + break; + case HTTP2__Frame::ALT_header__frame: + if(pl__frame.header__frame().end__stream__flag()){ + flags|=0x01; + } + if(pl__frame.header__frame().end__header__flag()){ + flags|=0x04; + } + if(pl__frame.header__frame().padding().ispresent()){ + flags|=0x08; + } + if(pl__frame.header__frame().priority__data().ispresent()){ + flags|=0x20; + } + ret_val=int2oct(0x1,1) // Type: HEADERS frame (type=0x1) + + int2oct(flags,1) + + int2oct(pl__frame.header__frame().stream__id(),4); + + if(pl__frame.header__frame().padding().ispresent()){ + ret_val=ret_val+int2oct(pl__frame.header__frame().padding()().lengthof(),1); + } + + if(pl__frame.header__frame().priority__data().ispresent()){ + ret_val=ret_val+encode_prio(pl__frame.header__frame().priority__data()()); + } + ret_val=ret_val+pl__frame.header__frame().header__block__fragment(); + + if(pl__frame.header__frame().padding().ispresent()){ + ret_val=ret_val+pl__frame.header__frame().padding()(); + } + + + break; + case HTTP2__Frame::ALT_priority__frame: + ret_val=int2oct(0x2,1) // Type: PRIORITY frame (type=0x2) + + int2oct(flags,1) + + int2oct(pl__frame.priority__frame().stream__id(),4); + ret_val=ret_val+encode_prio(pl__frame.priority__frame().priority__data()); + + + break; + case HTTP2__Frame::ALT_rst__frame: + ret_val=int2oct(0x3,1) // Type: RST_STREAM frame (type=0x3) + + int2oct(flags,1) + + int2oct(pl__frame.rst__frame().stream__id(),4) + + int2oct(pl__frame.rst__frame().error__code(),4); + + break; + case HTTP2__Frame::ALT_settings__frame: + if(pl__frame.settings__frame().ack__flag()){ + flags|=0x01; + } + ret_val=int2oct(0x4,1) // Type: SETTINGS frame (type=0x4) + + int2oct(flags,1) + + int2oct(0,4); // The stream identifier for a SETTINGS frame MUST be zero + + if(pl__frame.settings__frame().settings().ispresent()){ + for(int i=0;i<pl__frame.settings__frame().settings()().lengthof();i++){ + ret_val=ret_val+int2oct(pl__frame.settings__frame().settings()()[i].setting__id(),2)+int2oct(pl__frame.settings__frame().settings()()[i].setting__value(),4); + } + } + break; + case HTTP2__Frame::ALT_push__promise__frame: + if(pl__frame.push__promise__frame().end__header__flag()){ + flags|=0x04; + } + if(pl__frame.push__promise__frame().padding().ispresent()){ + flags|=0x08; + } + ret_val=int2oct(0x5,1) // Type: PUSH_PROMISE frame (type=0x5) + + int2oct(flags,1) + + int2oct(pl__frame.push__promise__frame().stream__id(),4); + + if(pl__frame.push__promise__frame().padding().ispresent()){ + ret_val=ret_val+int2oct(pl__frame.push__promise__frame().padding()().lengthof(),1); + } + + ret_val=ret_val+int2oct(pl__frame.push__promise__frame().promised__stream__id(),4) + + pl__frame.push__promise__frame().header__block__fragment(); + + if(pl__frame.header__frame().padding().ispresent()){ + ret_val=ret_val+pl__frame.push__promise__frame().padding()(); + } + + break; + case HTTP2__Frame::ALT_ping__frame: + if(pl__frame.ping__frame().ack__flag()){ + flags|=0x01; + } + ret_val=int2oct(0x6,1) // Type: PING frame (type=0x6) + + int2oct(flags,1) + + int2oct(0,4) // The stream identifier for a PING frame MUST be zero + + pl__frame.ping__frame().opaque__data() ; + + + + break; + case HTTP2__Frame::ALT_goaway__frame: + ret_val=int2oct(0x7,1) // Type: GOAWAY frame (type=0x7) + + int2oct(flags,1) + + int2oct(0,4) // The stream identifier for a GOAWAY frame MUST be zero + + int2oct(pl__frame.goaway__frame().last__stream__id(),4) ; + + int2oct(pl__frame.goaway__frame().error__code(),4) ; + if(pl__frame.goaway__frame().debug__data().ispresent()){ + ret_val=ret_val+pl__frame.goaway__frame().debug__data()(); + } + + break; + case HTTP2__Frame::ALT_window__update__frame: + ret_val=int2oct(0x8,1) // Type: WINDOW_UPDATE frame (type=0x8) + + int2oct(flags,1) + + int2oct(pl__frame.window__update__frame().stream__id(),4) + + int2oct(pl__frame.window__update__frame().window__size__increment(),4); + + break; + case HTTP2__Frame::ALT_continuation__frame: + if(pl__frame.continuation__frame().end__header__flag()){ + flags|=0x04; + } + ret_val=int2oct(0x9,1) // Type: CONTINUATION frame (type=0x9) + + int2oct(flags,1) + + int2oct(pl__frame.continuation__frame().stream__id(),4) + + pl__frame.continuation__frame().header__block__fragment(); + + break; + case HTTP2__Frame::ALT_generic__frame: + ret_val=int2oct(pl__frame.generic__frame().frame__type(),1) + + bit2oct(pl__frame.generic__frame().flags()) + + int2oct(pl__frame.generic__frame().stream__id(),4) + + pl__frame.generic__frame().payload(); + break; + default: + break; + } + + // length: The 9 octets of the frame header are not included in this value + return int2oct(ret_val.lengthof()-6,3) + ret_val; +} + +INTEGER decode_uint32(const unsigned char* ptr){ + return oct2int(OCTETSTRING(4,ptr)); +} +INTEGER decode_uint16(const unsigned char* ptr){ + return oct2int(OCTETSTRING(2,ptr)); +} + +INTEGER decode_uint31(const unsigned char* ptr){ + unsigned int ret_val= (*ptr) & 0x7F; + ret_val<<=8; + ptr++; + ret_val+=*ptr; + ret_val<<=8; + ptr++; + ret_val+=*ptr; + ret_val<<=8; + ptr++; + ret_val+=*ptr; + return ret_val; +} + +void decode_prio_data(const unsigned char* ptr, HTTP2__Priority__data& p_data){ + p_data.exclusive__flag()=((*ptr) & 0x80); + p_data.stream__dependency()=decode_uint31(ptr); + ptr+=4; + p_data.weight()=*ptr; +} + +INTEGER f__HTTP2__decode__frame(const OCTETSTRING& pl__stream, + HTTP2__Frame& pl__frame, + HTTP2__decoder__error__descr& pl__error__descr){ + + pl__error__descr.error__class() = c__connection__no__error__class; + pl__error__descr.error__type() =c__error__code__NO__ERROR; + pl__error__descr.error__text()= "OK"; + + if(pl__stream.lengthof()<9){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__FRAME__SIZE__ERROR; + pl__error__descr.error__text()= "The frame is shorter than the header size"; + return 1; // too short + } + const unsigned char* ptr=(const unsigned char*)pl__stream; + // decode length + int payload_len= *ptr; // payload length + payload_len<<=8; + ptr++; + payload_len+=*ptr; + payload_len<<=8; + ptr++; + payload_len+=*ptr; + ptr++; + if(pl__stream.lengthof()!=(payload_len+9)){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__FRAME__SIZE__ERROR; + pl__error__descr.error__text()= "The payload size not match the packet size"; + return 1; // length field error + } + const unsigned char type=*ptr; + ptr++; + const unsigned char flags=*ptr; + ptr++; + INTEGER stream_id=decode_uint31(ptr); + ptr+=4; + // now the ptr points to frame payload + switch(type){ // type + case 0x0: // Type: DATA frames (type=0x0) + if(flags & 0x8){ // padding + if(payload_len<1){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__FRAME__SIZE__ERROR; + pl__error__descr.error__text()= "DATA frame: missing padding length field"; + return 1; // too short + } + int pl=*ptr; // padding length + if(payload_len<(pl+1)){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__PROTOCOL__ERROR; + pl__error__descr.error__text()= "DATA frame: wrong padding size"; + return 1; // too short + } + ptr++; + pl__frame.data__frame().data()=OCTETSTRING(payload_len-pl-1,ptr); + ptr+=payload_len-pl-1; + pl__frame.data__frame().padding()=OCTETSTRING(pl,ptr); + } else { + pl__frame.data__frame().data()=OCTETSTRING(payload_len,ptr); + pl__frame.data__frame().padding()=OMIT_VALUE; + } + pl__frame.data__frame().stream__id()=stream_id; + pl__frame.data__frame().end__stream__flag()=(flags & 0x1); + + break; + case 0x1: {// Type: HEADERS frame (type=0x1) + int pl=0; // padding length + if(flags & 0x8){ // padding + if(payload_len<1){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__FRAME__SIZE__ERROR; + pl__error__descr.error__text()= "HEADER frame: missing padding length field"; + return 1; // too short + } + pl=*ptr; + ptr++; + payload_len--; + if(payload_len<pl){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__PROTOCOL__ERROR; + pl__error__descr.error__text()= "HEADER frame: wrong padding size"; + return 1; // too short + } + } + if(flags & 0x20){ // PRIORITY + if((payload_len - pl)<5){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__FRAME__SIZE__ERROR; + pl__error__descr.error__text()= "HEADER frame: not enough payload to decode priority data"; + return 1; // too short + } + decode_prio_data(ptr,pl__frame.header__frame().priority__data()()); + ptr+=5; + payload_len-=5; + } else { + pl__frame.header__frame().priority__data()=OMIT_VALUE; + } + pl__frame.header__frame().end__stream__flag()=(flags & 0x1); + pl__frame.header__frame().end__header__flag()=(flags & 0x4); + pl__frame.header__frame().stream__id()=stream_id; + pl__frame.header__frame().header__block__fragment()=OCTETSTRING(payload_len-pl,ptr); + if(flags & 0x8){ // padding + ptr+=(payload_len-pl); + pl__frame.header__frame().padding()=OCTETSTRING(pl,ptr); + } else { + pl__frame.header__frame().padding()=OMIT_VALUE; + } + + } + break; + case 0x2: // Type: PRIORITY frame (type=0x2) + if(payload_len!=5){ + pl__error__descr.error__class() = c__stream__error__class; + pl__error__descr.error__type() =c__error__code__FRAME__SIZE__ERROR; + pl__error__descr.error__text()= "PRIORITY frame: length is not 5 octet"; + return 1; // wrong size + } + decode_prio_data(ptr,pl__frame.priority__frame().priority__data()); + pl__frame.priority__frame().stream__id()=stream_id; + break; + case 0x3: // Type: RST_STREAM frame (type=0x3) + if(payload_len!=4){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__FRAME__SIZE__ERROR; + pl__error__descr.error__text()= " RST_STREAMframe: length is not 4 octet"; + return 1; // wrong size + } + pl__frame.rst__frame().error__code()=decode_uint32(ptr); + pl__frame.rst__frame().stream__id()=stream_id; + break; + case 0x4: // Type: SETTINGS frame (type=0x4) + if(payload_len % 6){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__FRAME__SIZE__ERROR; + pl__error__descr.error__text()= " SETTINGS frame: length is not a multiple of 6 octets"; + return 1; // wrong size + } + if(stream_id!=0){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__PROTOCOL__ERROR; + pl__error__descr.error__text()= " SETTINGS frame: stream id is not 0."; + return 1; // wrong size + } + + pl__frame.settings__frame().settings()=OMIT_VALUE; + {int i=0; + while(payload_len){ + pl__frame.settings__frame().settings()()[i].setting__id()=decode_uint16(ptr); + ptr+=2; + pl__frame.settings__frame().settings()()[i].setting__value()=decode_uint32(ptr); + ptr+=4; + payload_len-=6; + i++; + }} + + pl__frame.settings__frame().ack__flag()=(flags & 0x1); + break; + case 0x5:{ // Type: PUSH_PROMISE frame (type=0x5) + int pl=0; // padding length + if(flags & 0x8){ // padding + if(payload_len<5){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__FRAME__SIZE__ERROR; + pl__error__descr.error__text()= "PUSH_PROMISE frame: missing padding length field or missing promised stream id"; + return 1; // too short + } + pl=*ptr; + ptr++; + payload_len--; + if(payload_len<=(pl+4)){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__PROTOCOL__ERROR; + pl__error__descr.error__text()= "PUSH_PROMISE frame: wrong padding size"; + return 1; // too short + } + + } else { + if(payload_len<4){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__FRAME__SIZE__ERROR; + pl__error__descr.error__text()= "PUSH_PROMISE frame: missing promised stream id"; + return 1; // too short + } + } + pl__frame.push__promise__frame().promised__stream__id()=decode_uint31(ptr); + ptr+=4; + payload_len-=4; + + pl__frame.push__promise__frame().header__block__fragment()=OCTETSTRING(payload_len-pl,ptr); + if(flags & 0x8){ // padding + ptr+=(payload_len-pl); + pl__frame.push__promise__frame().padding()=OCTETSTRING(pl,ptr); + } else { + pl__frame.push__promise__frame().padding()=OMIT_VALUE; + } + pl__frame.push__promise__frame().end__header__flag()=(flags & 0x4); + + pl__frame.push__promise__frame().stream__id()=stream_id; + } + break; + case 0x6: // Type: PING frame (type=0x6) + if(payload_len !=8){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__FRAME__SIZE__ERROR; + pl__error__descr.error__text()= "PING frame: length is not 8 octets"; + return 1; // wrong size + } + if(stream_id!=0){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__PROTOCOL__ERROR; + pl__error__descr.error__text()= "PING frame: stream id is not 0."; + return 1; // wrong size + } + pl__frame.ping__frame().opaque__data()=OCTETSTRING(8,ptr); + pl__frame.ping__frame().ack__flag()=(flags & 0x1); + break; + case 0x7: // Type: GOAWAY frame (type=0x7) + if(payload_len <8){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__FRAME__SIZE__ERROR; + pl__error__descr.error__text()= "GOAWAY frame: length is less than 8 octets"; + return 1; // wrong size + } + if(stream_id!=0){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__PROTOCOL__ERROR; + pl__error__descr.error__text()= "GOAWAY frame: stream id is not 0."; + return 1; // wrong size + } + pl__frame.goaway__frame().last__stream__id()=decode_uint31(ptr); + ptr+=4; + payload_len-=4; + pl__frame.goaway__frame().error__code()=decode_uint32(ptr); + ptr+=4; + payload_len-=4; + if(payload_len>0){ + pl__frame.goaway__frame().debug__data()=OCTETSTRING(payload_len,ptr); + } else { + pl__frame.goaway__frame().debug__data()=OMIT_VALUE; + } + break; + case 0x8: // Type: WINDOW_UPDATE frame (type=0x8) + if(payload_len !=4){ + pl__error__descr.error__class() = c__connection__error__class; + pl__error__descr.error__type() =c__error__code__FRAME__SIZE__ERROR; + pl__error__descr.error__text()= "WINDOW_UPDATE frame: length is not 4 octets"; + return 1; // wrong size + } + pl__frame.window__update__frame().window__size__increment()=decode_uint32(ptr); + pl__frame.window__update__frame().stream__id()=stream_id; + break; + case 0x9: // Type: CONTINUATION frame (type=0x9) + pl__frame.continuation__frame().header__block__fragment()=OCTETSTRING(payload_len,ptr); + pl__frame.continuation__frame().stream__id()=stream_id; + pl__frame.continuation__frame().end__header__flag()=(flags & 0x4); + break; + default: // unknown frame + pl__frame.generic__frame().frame__type()=type; + pl__frame.generic__frame().flags()= int2bit(flags,8); + pl__frame.generic__frame().stream__id()=stream_id; + pl__frame.generic__frame().payload()=OCTETSTRING(payload_len,ptr); + break; + } + + return 0; +} + +} + diff --git a/src/HTTP2_Types.ttcn b/src/HTTP2_Types.ttcn new file mode 100644 index 0000000..8af8071 --- /dev/null +++ b/src/HTTP2_Types.ttcn @@ -0,0 +1,291 @@ +/****************************************************************************** +* Copyright (c) 2017 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Gabor Szalai - initial implementation and initial documentation +******************************************************************************/ +// +// File: HTTP2_Types.ttcn +// Description: Functions and types for HTTP2 +// Rev: R1A +// Prodnr: CNL 113 851 +module HTTP2_Types{ + +external function f_HTTP2_encode_frame(in HTTP2_Frame pl_frame) return octetstring +with { + extension "prototype(convert)" +} + +// return values: +// 1 - decoding failed +// 0 - OK +// +// The pl_error_descr contains the description of the error + + +external function f_HTTP2_decode_frame(in octetstring pl_stream, + out HTTP2_Frame pl_frame, + out HTTP2_decoder_error_descr pl_error_descr) return integer + +// Message dissector function for IPL4 test port +type record of integer HTTP2_ro_integer + +function f_HTTP2_msglen( + in octetstring stream, + inout HTTP2_ro_integer args +) return integer { + var integer pl_len:=lengthof(stream) + if(pl_len<3){ + return -1; + } + if(pl_len<lengthof(HTTP2_connection_preface)){ + if(substr(HTTP2_connection_preface,0,pl_len)==stream ){ + return -1 + } + } else { + if(HTTP2_connection_preface==substr(stream,0,lengthof(HTTP2_connection_preface))){ + return lengthof(HTTP2_connection_preface) + } + + } + return oct2int(substr(stream,0,3))+9 +} + +const octetstring HTTP2_connection_preface:='505249202a20485454502f322e300d0a0d0a534d0d0a0d0a'O + +// Error classes +const integer c_connection_no_error_class := 0 +const integer c_connection_error_class := 1 +const integer c_stream_error_class := 2 + +// Error codes +const integer c_error_code_NO_ERROR:= 0 +const integer c_error_code_PROTOCOL_ERROR := 1 +const integer c_error_code_INTERNAL_ERROR :=2 +const integer c_error_code_FLOW_CONTROL_ERROR := 3 +const integer c_error_code_SETTINGS_TIMEOUT := 4 +const integer c_error_code_STREAM_CLOSED := 5 +const integer c_error_code_FRAME_SIZE_ERROR := 6 +const integer c_error_code_REFUSED_STREAM := 7 +const integer c_error_code_CANCEL := 8 +const integer c_error_code_COMPRESSION_ERROR := 9 +const integer c_error_code_CONNECT_ERROR := 10 +const integer c_error_code_ENHANCE_YOUR_CALM := 11 +const integer c_error_code_INADEQUATE_SECURITY := 12 +const integer c_error_code_HTTP_1_1_REQUIRED := 13 + +// Settings parameters +const integer c_SETTINGS_HEADER_TABLE_SIZE := 1 +const integer c_SETTINGS_ENABLE_PUSH := 2 +const integer c_SETTINGS_MAX_CONCURRENT_STREAMS := 3 +const integer c_SETTINGS_INITIAL_WINDOW_SIZE := 4 +const integer c_SETTINGS_MAX_FRAME_SIZE := 5 +const integer c_SETTINGS_MAX_HEADER_LIST_SIZE := 6 + +type record HTTP2_decoder_error_descr{ + integer error_class, + integer error_type, + charstring error_text +} + +// HTTP/2 Frame definition +// The length field handled automatically +type union HTTP2_Frame { + HTTP2_Data_frame data_frame, + HTTP2_Header_frame header_frame, + HTTP2_Priority_frame priority_frame, + HTTP2_RST_Stream_frame rst_frame, + HTTP2_Settings_frame settings_frame, + HTTP2_Push_Promise_frame push_promise_frame, + HTTP2_Ping_frame ping_frame, + HTTP2_Goaway_frame goaway_frame, + HTTP2_Window_Update_frame window_update_frame, + HTTP2_Continuation_frame continuation_frame, + HTTP2_Generic_frame generic_frame +} + +// Data Frame definition +// The padding flag are handled automatically +type record HTTP2_Data_frame{ + integer stream_id, + boolean end_stream_flag, + octetstring data, + octetstring padding optional +} + +// Header Frame definition +// The padding flag are handled automatically +// The priority flag are handled automatically +type record HTTP2_Header_frame{ + integer stream_id, + boolean end_stream_flag, + boolean end_header_flag, + HTTP2_Priority_data priority_data optional, + octetstring header_block_fragment, + octetstring padding optional +} + +type record HTTP2_Priority_data{ + boolean exclusive_flag, + integer stream_dependency, + integer weight +} + +type record HTTP2_Priority_frame{ + integer stream_id, + HTTP2_Priority_data priority_data +} + +type record HTTP2_RST_Stream_frame { + integer stream_id, + integer error_code +} + +type record HTTP2_Setting_data{ + integer setting_id, + integer setting_value +} + +type record of HTTP2_Setting_data HTTP2_Setting_list + +// Always use 0 stream +type record HTTP2_Settings_frame{ + boolean ack_flag, + HTTP2_Setting_list settings optional +} + +// The padding flag are handled automatically +type record HTTP2_Push_Promise_frame{ + integer stream_id, + boolean end_header_flag, + integer promised_stream_id, + octetstring header_block_fragment, + octetstring padding optional +} + + +// Always use 0 stream +type record HTTP2_Ping_frame{ + boolean ack_flag, + octetstring opaque_data length(8) +} + +// Always use 0 stream +type record HTTP2_Goaway_frame{ + integer last_stream_id, + integer error_code, + octetstring debug_data optional +} + +type record HTTP2_Window_Update_frame{ + integer stream_id, + integer window_size_increment +} + +type record HTTP2_Continuation_frame{ + integer stream_id, + boolean end_header_flag, + octetstring header_block_fragment +} + +// Use it to send/receive non-defined or errornous frame +// Only the length calculated by the encoder +type record HTTP2_Generic_frame{ + integer frame_type, + bitstring flags length(8), + integer stream_id, + octetstring payload +} + + +// HTTP2 request/response and header definitions +// RFC7540 8.1.2.1 +// Note: the encoder doesn't enforces validity +// of the specified pseudo header field combination + +type record HTTP2_pseudo_headers{ + charstring method optional, + charstring scheme optional, + charstring authority optional, + charstring path optional, + integer status optional +} + +type record HTTP2_header_field{ + charstring header_name, + charstring header_value optional +} + +type record of HTTP2_header_field HTTP2_header_list + +// This type should be used for request/response headers +type record HTTP2_header_block { + HTTP2_pseudo_headers pseudo_headers optional, + HTTP2_header_list headers optional +} + + +// Header compression releated type definitions +// For each connection (not streams) a separate +// compression context should be used. + +// Never touch the fields of the HTTP2_comp_context +// Don't even think about it !!!!! + +// 1. Create the context with function: +// HTTP2_comp_context_init + +// 2. Every header block should be encoded/decoded with the functions: +// HTTP2_comp_context_encode +// HTTP2_comp_context_decode +// in the exactly the same order as the header blocks are sent or received +// in order to maintain the header compression context + +// 3. Delete the context with +// HTTP2_comp_context_free +// Please note: non freed context leads to memory leak!!!! + +// Creates a new header compression context +external function HTTP2_comp_context_init(in integer h_table_size_local:=4096, // The initial size of the header table + in integer h_table_size_remote:=4096 + ) return HTTP2_comp_context + +// Retur value: +// 0 - OK +// otherwise - error code +external function HTTP2_comp_context_encode(inout HTTP2_comp_context pl_context, + in HTTP2_header_block pl_hblock, + out octetstring pl_frame_data) return integer + +// Retur value: +// 0 - OK +// otherwise - error code +external function HTTP2_comp_context_decode(inout HTTP2_comp_context pl_context, + out HTTP2_header_block pl_hblock, + in octetstring pl_frame_data) return integer + + +// Free and release the header compression context +external function HTTP2_comp_context_free(inout HTTP2_comp_context pl_context) + + +// Set header table size +external function HTTP2_comp_context_set_table_size_remote(inout HTTP2_comp_context pl_context, + in integer h_table_size) + +external function HTTP2_comp_context_set_table_size_local(inout HTTP2_comp_context pl_context, + in integer h_table_size) + +//**************************************************// +// DO NOT TOUCH THE FIELDS OF THE HTTP2_comp_context +//**************************************************// +type record HTTP2_comp_context{ + integer internal_id1 +} + + +} |