| /****************************************************************************** |
| * 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; |
| } |
| |
| } |
| |