blob: 13014a857433ff832b759cb542705274423cd629 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2017-2019 Ericsson AB
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
* Contributors:
* Gabor Szalai - initial implementation and initial documentation
******************************************************************************/
//
// File: HTTP2_EncDec.cc
// Description: Encoder/decoder function for HTTP2
// Rev: R1D
// 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-1)) );
} 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 void http2_debug_log(const char *fmt, ...) {
TTCN_Logger::begin_event(TTCN_DEBUG);
TTCN_Logger::log_event("HTTP2 protocol module debug: ");
va_list args;
va_start(args, fmt);
TTCN_Logger::log_event_va_list(fmt, args);
va_end(args);
TTCN_Logger::end_event();
}
static int HTTP2_decode_one_header(const unsigned char* buff, int buff_len, CHARSTRING& hname, CHARSTRING& hval, HTTP2_compression_ctx* comp_ctx, bool debug_enabled){
if(debug_enabled){http2_debug_log("HTTP2_decode_one_header called");}
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);
if(debug_enabled){http2_debug_log("Dynamic Table Size Update %d", idx);}
return ret_val;
}
if(buff[0] & 0x80){ // indexed field representation
unsigned char filler;
ret_val=decode_integer(buff,idx,7,filler);
if(debug_enabled){http2_debug_log("Indexed field representation %d", 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);
if(debug_enabled){http2_debug_log("Literal Header Field with Incremental Indexing %d", 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);
if(debug_enabled){http2_debug_log("Literal Header Field without Incremental Indexing %d", idx);}
} 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 BOOLEAN& pl_enable_debug){
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),pl_enable_debug);
if(hlen==-1){
if(pl_enable_debug){http2_debug_log("decoded header len %d",hlen);}
return 1;
}
if(pl_enable_debug){http2_debug_log("decoded header len %d %s %s",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;
}
}