Skip to content
Snippets Groups Projects
Commit 43537980 authored by Elemer Lelik's avatar Elemer Lelik
Browse files

First version

parent 7ab541c4
No related branches found
No related tags found
No related merge requests found
<?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>
# 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
File added
File added
/******************************************************************************
* 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;
}
}
/******************************************************************************
* 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
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment