1 /* Copyright (C) 2020 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 use super::http2::{
19     HTTP2Event, HTTP2Frame, HTTP2FrameTypeData, HTTP2State, HTTP2Transaction, HTTP2TransactionState,
20 };
21 use super::parser;
22 use crate::core::{STREAM_TOCLIENT, STREAM_TOSERVER};
23 use std::ffi::CStr;
24 use std::mem::transmute;
25 use std::str::FromStr;
26 
http2_tx_has_frametype( tx: &mut HTTP2Transaction, direction: u8, value: u8, ) -> std::os::raw::c_int27 fn http2_tx_has_frametype(
28     tx: &mut HTTP2Transaction, direction: u8, value: u8,
29 ) -> std::os::raw::c_int {
30     if direction & STREAM_TOSERVER != 0 {
31         for i in 0..tx.frames_ts.len() {
32             if tx.frames_ts[i].header.ftype as u8 == value {
33                 return 1;
34             }
35         }
36     } else {
37         for i in 0..tx.frames_tc.len() {
38             if tx.frames_tc[i].header.ftype as u8 == value {
39                 return 1;
40             }
41         }
42     }
43     return 0;
44 }
45 
46 #[no_mangle]
rs_http2_tx_has_frametype( tx: *mut std::os::raw::c_void, direction: u8, value: u8, ) -> std::os::raw::c_int47 pub extern "C" fn rs_http2_tx_has_frametype(
48     tx: *mut std::os::raw::c_void, direction: u8, value: u8,
49 ) -> std::os::raw::c_int {
50     let tx = cast_pointer!(tx, HTTP2Transaction);
51     return http2_tx_has_frametype(tx, direction, value);
52 }
53 
54 #[no_mangle]
rs_http2_parse_frametype( str: *const std::os::raw::c_char, ) -> std::os::raw::c_int55 pub unsafe extern "C" fn rs_http2_parse_frametype(
56     str: *const std::os::raw::c_char,
57 ) -> std::os::raw::c_int {
58     let ft_name: &CStr = CStr::from_ptr(str); //unsafe
59     if let Ok(s) = ft_name.to_str() {
60         if let Ok(x) = parser::HTTP2FrameType::from_str(s) {
61             return x as i32;
62         }
63     }
64     return -1;
65 }
66 
http2_tx_has_errorcode( tx: &mut HTTP2Transaction, direction: u8, code: u32, ) -> std::os::raw::c_int67 fn http2_tx_has_errorcode(
68     tx: &mut HTTP2Transaction, direction: u8, code: u32,
69 ) -> std::os::raw::c_int {
70     if direction & STREAM_TOSERVER != 0 {
71         for i in 0..tx.frames_ts.len() {
72             match tx.frames_ts[i].data {
73                 HTTP2FrameTypeData::GOAWAY(goaway) => {
74                     if goaway.errorcode == code {
75                         return 1;
76                     }
77                 }
78                 HTTP2FrameTypeData::RSTSTREAM(rst) => {
79                     if rst.errorcode == code {
80                         return 1;
81                     }
82                 }
83                 _ => {}
84             }
85         }
86     } else {
87         for i in 0..tx.frames_tc.len() {
88             match tx.frames_tc[i].data {
89                 HTTP2FrameTypeData::GOAWAY(goaway) => {
90                     if goaway.errorcode as u32 == code {
91                         return 1;
92                     }
93                 }
94                 HTTP2FrameTypeData::RSTSTREAM(rst) => {
95                     if rst.errorcode as u32 == code {
96                         return 1;
97                     }
98                 }
99                 _ => {}
100             }
101         }
102     }
103     return 0;
104 }
105 
106 #[no_mangle]
rs_http2_tx_has_errorcode( tx: *mut std::os::raw::c_void, direction: u8, code: u32, ) -> std::os::raw::c_int107 pub extern "C" fn rs_http2_tx_has_errorcode(
108     tx: *mut std::os::raw::c_void, direction: u8, code: u32,
109 ) -> std::os::raw::c_int {
110     let tx = cast_pointer!(tx, HTTP2Transaction);
111     return http2_tx_has_errorcode(tx, direction, code);
112 }
113 
114 #[no_mangle]
rs_http2_parse_errorcode( str: *const std::os::raw::c_char, ) -> std::os::raw::c_int115 pub unsafe extern "C" fn rs_http2_parse_errorcode(
116     str: *const std::os::raw::c_char,
117 ) -> std::os::raw::c_int {
118     let ft_name: &CStr = CStr::from_ptr(str); //unsafe
119     if let Ok(s) = ft_name.to_str() {
120         if let Ok(x) = parser::HTTP2ErrorCode::from_str(s) {
121             return x as i32;
122         }
123     }
124     return -1;
125 }
126 
http2_tx_get_next_priority( tx: &mut HTTP2Transaction, direction: u8, nb: u32, ) -> std::os::raw::c_int127 fn http2_tx_get_next_priority(
128     tx: &mut HTTP2Transaction, direction: u8, nb: u32,
129 ) -> std::os::raw::c_int {
130     let mut pos = 0 as u32;
131     if direction & STREAM_TOSERVER != 0 {
132         for i in 0..tx.frames_ts.len() {
133             match &tx.frames_ts[i].data {
134                 HTTP2FrameTypeData::PRIORITY(prio) => {
135                     if pos == nb {
136                         return prio.weight as i32;
137                     } else {
138                         pos = pos + 1;
139                     }
140                 }
141                 HTTP2FrameTypeData::HEADERS(hd) => {
142                     if let Some(prio) = hd.priority {
143                         if pos == nb {
144                             return prio.weight as i32;
145                         } else {
146                             pos = pos + 1;
147                         }
148                     }
149                 }
150                 _ => {}
151             }
152         }
153     } else {
154         for i in 0..tx.frames_tc.len() {
155             match &tx.frames_tc[i].data {
156                 HTTP2FrameTypeData::PRIORITY(prio) => {
157                     if pos == nb {
158                         return prio.weight as i32;
159                     } else {
160                         pos = pos + 1;
161                     }
162                 }
163                 HTTP2FrameTypeData::HEADERS(hd) => {
164                     if let Some(prio) = hd.priority {
165                         if pos == nb {
166                             return prio.weight as i32;
167                         } else {
168                             pos = pos + 1;
169                         }
170                     }
171                 }
172                 _ => {}
173             }
174         }
175     }
176     return -1;
177 }
178 
179 #[no_mangle]
rs_http2_tx_get_next_priority( tx: *mut std::os::raw::c_void, direction: u8, nb: u32, ) -> std::os::raw::c_int180 pub extern "C" fn rs_http2_tx_get_next_priority(
181     tx: *mut std::os::raw::c_void, direction: u8, nb: u32,
182 ) -> std::os::raw::c_int {
183     let tx = cast_pointer!(tx, HTTP2Transaction);
184     return http2_tx_get_next_priority(tx, direction, nb);
185 }
186 
http2_tx_get_next_window( tx: &mut HTTP2Transaction, direction: u8, nb: u32, ) -> std::os::raw::c_int187 fn http2_tx_get_next_window(
188     tx: &mut HTTP2Transaction, direction: u8, nb: u32,
189 ) -> std::os::raw::c_int {
190     let mut pos = 0 as u32;
191     if direction & STREAM_TOSERVER != 0 {
192         for i in 0..tx.frames_ts.len() {
193             match tx.frames_ts[i].data {
194                 HTTP2FrameTypeData::WINDOWUPDATE(wu) => {
195                     if pos == nb {
196                         return wu.sizeinc as i32;
197                     } else {
198                         pos = pos + 1;
199                     }
200                 }
201                 _ => {}
202             }
203         }
204     } else {
205         for i in 0..tx.frames_tc.len() {
206             match tx.frames_tc[i].data {
207                 HTTP2FrameTypeData::WINDOWUPDATE(wu) => {
208                     if pos == nb {
209                         return wu.sizeinc as i32;
210                     } else {
211                         pos = pos + 1;
212                     }
213                 }
214                 _ => {}
215             }
216         }
217     }
218     return -1;
219 }
220 
221 #[no_mangle]
rs_http2_tx_get_next_window( tx: *mut std::os::raw::c_void, direction: u8, nb: u32, ) -> std::os::raw::c_int222 pub extern "C" fn rs_http2_tx_get_next_window(
223     tx: *mut std::os::raw::c_void, direction: u8, nb: u32,
224 ) -> std::os::raw::c_int {
225     let tx = cast_pointer!(tx, HTTP2Transaction);
226     return http2_tx_get_next_window(tx, direction, nb);
227 }
228 
229 #[no_mangle]
rs_http2_parse_settingsid( str: *const std::os::raw::c_char, ) -> std::os::raw::c_int230 pub unsafe extern "C" fn rs_http2_parse_settingsid(
231     str: *const std::os::raw::c_char,
232 ) -> std::os::raw::c_int {
233     let ft_name: &CStr = CStr::from_ptr(str); //unsafe
234     if let Ok(s) = ft_name.to_str() {
235         if let Ok(x) = parser::HTTP2SettingsId::from_str(s) {
236             return x as i32;
237         }
238     }
239     return -1;
240 }
241 
242 #[no_mangle]
rs_http2_detect_settingsctx_parse( str: *const std::os::raw::c_char, ) -> *mut std::os::raw::c_void243 pub unsafe extern "C" fn rs_http2_detect_settingsctx_parse(
244     str: *const std::os::raw::c_char,
245 ) -> *mut std::os::raw::c_void {
246     let ft_name: &CStr = CStr::from_ptr(str); //unsafe
247     if let Ok(s) = ft_name.to_str() {
248         if let Ok((_, ctx)) = parser::http2_parse_settingsctx(s) {
249             let boxed = Box::new(ctx);
250             return transmute(boxed); //unsafe
251         }
252     }
253     return std::ptr::null_mut();
254 }
255 
256 #[no_mangle]
rs_http2_detect_settingsctx_free(ctx: *mut std::os::raw::c_void)257 pub unsafe extern "C" fn rs_http2_detect_settingsctx_free(ctx: *mut std::os::raw::c_void) {
258     // Just unbox...
259     let _ctx: Box<parser::DetectHTTP2settingsSigCtx> = transmute(ctx);
260 }
261 
http2_detect_settings_match( set: &[parser::HTTP2FrameSettings], ctx: &parser::DetectHTTP2settingsSigCtx, ) -> std::os::raw::c_int262 fn http2_detect_settings_match(
263     set: &[parser::HTTP2FrameSettings], ctx: &parser::DetectHTTP2settingsSigCtx,
264 ) -> std::os::raw::c_int {
265     for i in 0..set.len() {
266         if set[i].id == ctx.id {
267             match &ctx.value {
268                 None => {
269                     return 1;
270                 }
271                 Some(x) => match x.mode {
272                     parser::DetectUintMode::DetectUintModeEqual => {
273                         if set[i].value == x.value {
274                             return 1;
275                         }
276                     }
277                     parser::DetectUintMode::DetectUintModeLt => {
278                         if set[i].value <= x.value {
279                             return 1;
280                         }
281                     }
282                     parser::DetectUintMode::DetectUintModeGt => {
283                         if set[i].value >= x.value {
284                             return 1;
285                         }
286                     }
287                     parser::DetectUintMode::DetectUintModeRange => {
288                         if set[i].value <= x.value && set[i].value >= x.valrange {
289                             return 1;
290                         }
291                     }
292                 },
293             }
294         }
295     }
296     return 0;
297 }
298 
http2_detect_settingsctx_match( ctx: &mut parser::DetectHTTP2settingsSigCtx, tx: &mut HTTP2Transaction, direction: u8, ) -> std::os::raw::c_int299 fn http2_detect_settingsctx_match(
300     ctx: &mut parser::DetectHTTP2settingsSigCtx, tx: &mut HTTP2Transaction, direction: u8,
301 ) -> std::os::raw::c_int {
302     if direction & STREAM_TOSERVER != 0 {
303         for i in 0..tx.frames_ts.len() {
304             match &tx.frames_ts[i].data {
305                 HTTP2FrameTypeData::SETTINGS(set) => {
306                     if http2_detect_settings_match(&set, ctx) != 0 {
307                         return 1;
308                     }
309                 }
310                 _ => {}
311             }
312         }
313     } else {
314         for i in 0..tx.frames_tc.len() {
315             match &tx.frames_tc[i].data {
316                 HTTP2FrameTypeData::SETTINGS(set) => {
317                     if http2_detect_settings_match(&set, ctx) != 0 {
318                         return 1;
319                     }
320                 }
321                 _ => {}
322             }
323         }
324     }
325     return 0;
326 }
327 
328 #[no_mangle]
rs_http2_detect_settingsctx_match( ctx: *const std::os::raw::c_void, tx: *mut std::os::raw::c_void, direction: u8, ) -> std::os::raw::c_int329 pub extern "C" fn rs_http2_detect_settingsctx_match(
330     ctx: *const std::os::raw::c_void, tx: *mut std::os::raw::c_void, direction: u8,
331 ) -> std::os::raw::c_int {
332     let ctx = cast_pointer!(ctx, parser::DetectHTTP2settingsSigCtx);
333     let tx = cast_pointer!(tx, HTTP2Transaction);
334     return http2_detect_settingsctx_match(ctx, tx, direction);
335 }
336 
337 #[no_mangle]
rs_detect_u64_parse( str: *const std::os::raw::c_char, ) -> *mut std::os::raw::c_void338 pub unsafe extern "C" fn rs_detect_u64_parse(
339     str: *const std::os::raw::c_char,
340 ) -> *mut std::os::raw::c_void {
341     let ft_name: &CStr = CStr::from_ptr(str); //unsafe
342     if let Ok(s) = ft_name.to_str() {
343         if let Ok((_, ctx)) = parser::detect_parse_u64(s) {
344             let boxed = Box::new(ctx);
345             return transmute(boxed); //unsafe
346         }
347     }
348     return std::ptr::null_mut();
349 }
350 
351 #[no_mangle]
rs_detect_u64_free(ctx: *mut std::os::raw::c_void)352 pub unsafe extern "C" fn rs_detect_u64_free(ctx: *mut std::os::raw::c_void) {
353     // Just unbox...
354     let _ctx: Box<parser::DetectU64Data> = transmute(ctx);
355 }
356 
http2_detect_sizeupdate_match( blocks: &[parser::HTTP2FrameHeaderBlock], ctx: &parser::DetectU64Data, ) -> std::os::raw::c_int357 fn http2_detect_sizeupdate_match(
358     blocks: &[parser::HTTP2FrameHeaderBlock], ctx: &parser::DetectU64Data,
359 ) -> std::os::raw::c_int {
360     for block in blocks.iter() {
361         match ctx.mode {
362             parser::DetectUintMode::DetectUintModeEqual => {
363                 if block.sizeupdate == ctx.value
364                     && block.error == parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate
365                 {
366                     return 1;
367                 }
368             }
369             parser::DetectUintMode::DetectUintModeLt => {
370                 if block.sizeupdate <= ctx.value
371                     && block.error == parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate
372                 {
373                     return 1;
374                 }
375             }
376             parser::DetectUintMode::DetectUintModeGt => {
377                 if block.sizeupdate >= ctx.value
378                     && block.error == parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate
379                 {
380                     return 1;
381                 }
382             }
383             parser::DetectUintMode::DetectUintModeRange => {
384                 if block.sizeupdate <= ctx.value
385                     && block.sizeupdate >= ctx.valrange
386                     && block.error == parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate
387                 {
388                     return 1;
389                 }
390             }
391         }
392     }
393     return 0;
394 }
395 
http2_header_blocks(frame: &HTTP2Frame) -> Option<&[parser::HTTP2FrameHeaderBlock]>396 fn http2_header_blocks(frame: &HTTP2Frame) -> Option<&[parser::HTTP2FrameHeaderBlock]> {
397     match &frame.data {
398         HTTP2FrameTypeData::HEADERS(hd) => {
399             return Some(&hd.blocks);
400         }
401         HTTP2FrameTypeData::CONTINUATION(hd) => {
402             return Some(&hd.blocks);
403         }
404         HTTP2FrameTypeData::PUSHPROMISE(hd) => {
405             return Some(&hd.blocks);
406         }
407         _ => {}
408     }
409     return None;
410 }
411 
http2_detect_sizeupdatectx_match( ctx: &mut parser::DetectU64Data, tx: &mut HTTP2Transaction, direction: u8, ) -> std::os::raw::c_int412 fn http2_detect_sizeupdatectx_match(
413     ctx: &mut parser::DetectU64Data, tx: &mut HTTP2Transaction, direction: u8,
414 ) -> std::os::raw::c_int {
415     if direction & STREAM_TOSERVER != 0 {
416         for i in 0..tx.frames_ts.len() {
417             if let Some(blocks) = http2_header_blocks(&tx.frames_ts[i]) {
418                 if http2_detect_sizeupdate_match(blocks, ctx) != 0 {
419                     return 1;
420                 }
421             }
422         }
423     } else {
424         for i in 0..tx.frames_tc.len() {
425             if let Some(blocks) = http2_header_blocks(&tx.frames_tc[i]) {
426                 if http2_detect_sizeupdate_match(blocks, ctx) != 0 {
427                     return 1;
428                 }
429             }
430         }
431     }
432     return 0;
433 }
434 
435 #[no_mangle]
rs_http2_detect_sizeupdatectx_match( ctx: *const std::os::raw::c_void, tx: *mut std::os::raw::c_void, direction: u8, ) -> std::os::raw::c_int436 pub extern "C" fn rs_http2_detect_sizeupdatectx_match(
437     ctx: *const std::os::raw::c_void, tx: *mut std::os::raw::c_void, direction: u8,
438 ) -> std::os::raw::c_int {
439     let ctx = cast_pointer!(ctx, parser::DetectU64Data);
440     let tx = cast_pointer!(tx, HTTP2Transaction);
441     return http2_detect_sizeupdatectx_match(ctx, tx, direction);
442 }
443 
444 //TODOask better syntax between rs_http2_tx_get_header_name in argument
445 // and rs_http2_detect_sizeupdatectx_match explicitly casting
446 #[no_mangle]
rs_http2_tx_get_header_name( tx: &mut HTTP2Transaction, direction: u8, nb: u32, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8447 pub unsafe extern "C" fn rs_http2_tx_get_header_name(
448     tx: &mut HTTP2Transaction, direction: u8, nb: u32, buffer: *mut *const u8, buffer_len: *mut u32,
449 ) -> u8 {
450     let mut pos = 0 as u32;
451     if direction & STREAM_TOSERVER != 0 {
452         for i in 0..tx.frames_ts.len() {
453             if let Some(blocks) = http2_header_blocks(&tx.frames_ts[i]) {
454                 if nb < pos + blocks.len() as u32 {
455                     let value = &blocks[(nb - pos) as usize].name;
456                     *buffer = value.as_ptr(); //unsafe
457                     *buffer_len = value.len() as u32;
458                     return 1;
459                 } else {
460                     pos = pos + blocks.len() as u32;
461                 }
462             }
463         }
464     } else {
465         for i in 0..tx.frames_tc.len() {
466             if let Some(blocks) = http2_header_blocks(&tx.frames_tc[i]) {
467                 if nb < pos + blocks.len() as u32 {
468                     let value = &blocks[(nb - pos) as usize].name;
469                     *buffer = value.as_ptr(); //unsafe
470                     *buffer_len = value.len() as u32;
471                     return 1;
472                 } else {
473                     pos = pos + blocks.len() as u32;
474                 }
475             }
476         }
477     }
478     return 0;
479 }
480 
http2_frames_get_header_firstvalue<'a>( tx: &'a mut HTTP2Transaction, direction: u8, name: &str, ) -> Result<&'a [u8], ()>481 fn http2_frames_get_header_firstvalue<'a>(
482     tx: &'a mut HTTP2Transaction, direction: u8, name: &str,
483 ) -> Result<&'a [u8], ()> {
484     let frames = if direction == STREAM_TOSERVER {
485         &tx.frames_ts
486     } else {
487         &tx.frames_tc
488     };
489     for i in 0..frames.len() {
490         if let Some(blocks) = http2_header_blocks(&frames[i]) {
491             for block in blocks.iter() {
492                 if block.name == name.as_bytes().to_vec() {
493                     return Ok(&block.value);
494                 }
495             }
496         }
497     }
498     return Err(());
499 }
500 
http2_frames_get_header_value<'a>( tx: &'a mut HTTP2Transaction, direction: u8, name: &str, ) -> Result<&'a [u8], ()>501 fn http2_frames_get_header_value<'a>(
502     tx: &'a mut HTTP2Transaction, direction: u8, name: &str,
503 ) -> Result<&'a [u8], ()> {
504     let mut found = 0;
505     let mut vec = Vec::new();
506     let mut single: Result<&[u8], ()> = Err(());
507     let frames = if direction == STREAM_TOSERVER {
508         &tx.frames_ts
509     } else {
510         &tx.frames_tc
511     };
512     for i in 0..frames.len() {
513         if let Some(blocks) = http2_header_blocks(&frames[i]) {
514             for block in blocks.iter() {
515                 if block.name == name.as_bytes().to_vec() {
516                     if found == 0 {
517                         single = Ok(&block.value);
518                         found = 1;
519                     } else if found == 1 {
520                         if let Ok(s) = single {
521                             vec.extend_from_slice(s);
522                         }
523                         vec.extend_from_slice(&[b',', b' ']);
524                         vec.extend_from_slice(&block.value);
525                         found = 2;
526                     } else {
527                         vec.extend_from_slice(&[b',', b' ']);
528                         vec.extend_from_slice(&block.value);
529                     }
530                 }
531             }
532         }
533     }
534     if found == 0 {
535         return Err(());
536     } else if found == 1 {
537         return single;
538     } else {
539         tx.escaped.push(vec);
540         let idx = tx.escaped.len() - 1;
541         let value = &tx.escaped[idx];
542         return Ok(&value);
543     }
544 }
545 
546 #[no_mangle]
rs_http2_tx_get_uri( tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8547 pub unsafe extern "C" fn rs_http2_tx_get_uri(
548     tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32,
549 ) -> u8 {
550     if let Ok(value) = http2_frames_get_header_firstvalue(tx, STREAM_TOSERVER, ":path") {
551         *buffer = value.as_ptr(); //unsafe
552         *buffer_len = value.len() as u32;
553         return 1;
554     }
555     return 0;
556 }
557 
558 #[no_mangle]
rs_http2_tx_get_method( tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8559 pub unsafe extern "C" fn rs_http2_tx_get_method(
560     tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32,
561 ) -> u8 {
562     if let Ok(value) = http2_frames_get_header_firstvalue(tx, STREAM_TOSERVER, ":method") {
563         *buffer = value.as_ptr(); //unsafe
564         *buffer_len = value.len() as u32;
565         return 1;
566     }
567     return 0;
568 }
569 
570 #[no_mangle]
rs_http2_tx_get_host( tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8571 pub unsafe extern "C" fn rs_http2_tx_get_host(
572     tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32,
573 ) -> u8 {
574     if let Ok(value) = http2_frames_get_header_value(tx, STREAM_TOSERVER, ":authority") {
575         *buffer = value.as_ptr(); //unsafe
576         *buffer_len = value.len() as u32;
577         return 1;
578     }
579     return 0;
580 }
581 
http2_lower(value: &[u8]) -> Option<Vec<u8>>582 fn http2_lower(value: &[u8]) -> Option<Vec<u8>> {
583     for i in 0..value.len() {
584         if value[i].is_ascii_uppercase() {
585             // we got at least one upper character, need to transform
586             let mut vec: Vec<u8> = Vec::with_capacity(value.len());
587             vec.extend_from_slice(value);
588             for j in i..vec.len() {
589                 vec[j].make_ascii_lowercase();
590             }
591             return Some(vec);
592         }
593     }
594     return None;
595 }
596 
597 // returns a tuple with the value and its size
http2_normalize_host(value: &[u8]) -> (Option<Vec<u8>>, usize)598 fn http2_normalize_host(value: &[u8]) -> (Option<Vec<u8>>, usize) {
599     match value.iter().position(|&x| x == ':' as u8) {
600         Some(i) => {
601             return (http2_lower(&value[..i]), i);
602         }
603         None => {
604             return (http2_lower(value), value.len());
605         }
606     }
607 }
608 
609 #[no_mangle]
rs_http2_tx_get_host_norm( tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8610 pub unsafe extern "C" fn rs_http2_tx_get_host_norm(
611     tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32,
612 ) -> u8 {
613     if let Ok(value) = http2_frames_get_header_value(tx, STREAM_TOSERVER, ":authority") {
614         let r = http2_normalize_host(value);
615         // r is a tuple with the value and its size
616         // this is useful when we only take a substring (before the port)
617         match r.0 {
618             Some(normval) => {
619                 // In case we needed some normalization,
620                 // the transaction needs to take ownership of this normalized host
621                 tx.escaped.push(normval);
622                 let idx = tx.escaped.len() - 1;
623                 let resvalue = &tx.escaped[idx];
624                 *buffer = resvalue.as_ptr(); //unsafe
625                 *buffer_len = r.1 as u32;
626                 return 1;
627             }
628             None => {
629                 *buffer = value.as_ptr(); //unsafe
630                 *buffer_len = r.1 as u32;
631                 return 1;
632             }
633         }
634     }
635     return 0;
636 }
637 
638 #[no_mangle]
rs_http2_tx_get_useragent( tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8639 pub unsafe extern "C" fn rs_http2_tx_get_useragent(
640     tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32,
641 ) -> u8 {
642     if let Ok(value) = http2_frames_get_header_value(tx, STREAM_TOSERVER, "user-agent") {
643         *buffer = value.as_ptr(); //unsafe
644         *buffer_len = value.len() as u32;
645         return 1;
646     }
647     return 0;
648 }
649 
650 #[no_mangle]
rs_http2_tx_get_status( tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8651 pub unsafe extern "C" fn rs_http2_tx_get_status(
652     tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32,
653 ) -> u8 {
654     if let Ok(value) = http2_frames_get_header_firstvalue(tx, STREAM_TOCLIENT, ":status") {
655         *buffer = value.as_ptr(); //unsafe
656         *buffer_len = value.len() as u32;
657         return 1;
658     }
659     return 0;
660 }
661 
662 #[no_mangle]
rs_http2_tx_get_cookie( tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8663 pub unsafe extern "C" fn rs_http2_tx_get_cookie(
664     tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32,
665 ) -> u8 {
666     if direction == STREAM_TOSERVER {
667         if let Ok(value) = http2_frames_get_header_value(tx, STREAM_TOSERVER, "cookie") {
668             *buffer = value.as_ptr(); //unsafe
669             *buffer_len = value.len() as u32;
670             return 1;
671         }
672     } else {
673         if let Ok(value) = http2_frames_get_header_value(tx, STREAM_TOCLIENT, "set-cookie") {
674             *buffer = value.as_ptr(); //unsafe
675             *buffer_len = value.len() as u32;
676             return 1;
677         }
678     }
679     return 0;
680 }
681 
682 #[no_mangle]
rs_http2_tx_get_header_value( tx: &mut HTTP2Transaction, direction: u8, strname: *const std::os::raw::c_char, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8683 pub unsafe extern "C" fn rs_http2_tx_get_header_value(
684     tx: &mut HTTP2Transaction, direction: u8, strname: *const std::os::raw::c_char,
685     buffer: *mut *const u8, buffer_len: *mut u32,
686 ) -> u8 {
687     let hname: &CStr = CStr::from_ptr(strname); //unsafe
688     if let Ok(s) = hname.to_str() {
689         if let Ok(value) = http2_frames_get_header_value(tx, direction, &s.to_lowercase()) {
690             *buffer = value.as_ptr(); //unsafe
691             *buffer_len = value.len() as u32;
692             return 1;
693         }
694     }
695     return 0;
696 }
697 
http2_escape_header(blocks: &[parser::HTTP2FrameHeaderBlock], i: u32) -> Vec<u8>698 fn http2_escape_header(blocks: &[parser::HTTP2FrameHeaderBlock], i: u32) -> Vec<u8> {
699     //minimum size + 2 for escapes
700     let normalsize = blocks[i as usize].value.len() + 2 + blocks[i as usize].name.len() + 2;
701     let mut vec = Vec::with_capacity(normalsize);
702     for j in 0..blocks[i as usize].name.len() {
703         vec.push(blocks[i as usize].name[j]);
704         if blocks[i as usize].name[j] == ':' as u8 {
705             vec.push(':' as u8);
706         }
707     }
708     vec.extend_from_slice(&[b':', b' ']);
709     for j in 0..blocks[i as usize].value.len() {
710         vec.push(blocks[i as usize].value[j]);
711         if blocks[i as usize].value[j] == ':' as u8 {
712             vec.push(':' as u8);
713         }
714     }
715     return vec;
716 }
717 
718 #[no_mangle]
rs_http2_tx_get_header_names( tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8719 pub unsafe extern "C" fn rs_http2_tx_get_header_names(
720     tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32,
721 ) -> u8 {
722     let mut vec = vec![b'\r', b'\n'];
723     let frames = if direction & STREAM_TOSERVER != 0 {
724         &tx.frames_ts
725     } else {
726         &tx.frames_tc
727     };
728     for i in 0..frames.len() {
729         if let Some(blocks) = http2_header_blocks(&frames[i]) {
730             for block in blocks.iter() {
731                 // we do not escape linefeeds in headers names
732                 vec.extend_from_slice(&block.name);
733                 vec.extend_from_slice(&[b'\r', b'\n']);
734             }
735         }
736     }
737     if vec.len() > 2 {
738         vec.extend_from_slice(&[b'\r', b'\n']);
739         tx.escaped.push(vec);
740         let idx = tx.escaped.len() - 1;
741         let value = &tx.escaped[idx];
742         *buffer = value.as_ptr(); //unsafe
743         *buffer_len = value.len() as u32;
744         return 1;
745     }
746     return 0;
747 }
748 
http2_header_iscookie(direction: u8, hname: &[u8]) -> bool749 fn http2_header_iscookie(direction: u8, hname: &[u8]) -> bool {
750     if let Ok(s) = std::str::from_utf8(hname) {
751         if direction & STREAM_TOSERVER != 0 {
752             if s.to_lowercase() == "cookie" {
753                 return true;
754             }
755         } else {
756             if s.to_lowercase() == "set-cookie" {
757                 return true;
758             }
759         }
760     }
761     return false;
762 }
763 
http2_header_trimspaces(value: &[u8]) -> &[u8]764 fn http2_header_trimspaces(value: &[u8]) -> &[u8] {
765     let mut start = 0;
766     let mut end = value.len();
767     while start < value.len() {
768         if value[start] == b' ' || value[start] == b'\t' {
769             start += 1;
770         } else {
771             break;
772         }
773     }
774     while end > start {
775         if value[end - 1] == b' ' || value[end - 1] == b'\t' {
776             end -= 1;
777         } else {
778             break;
779         }
780     }
781     return &value[start..end];
782 }
783 
784 #[no_mangle]
rs_http2_tx_get_headers( tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8785 pub unsafe extern "C" fn rs_http2_tx_get_headers(
786     tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32,
787 ) -> u8 {
788     let mut vec = Vec::new();
789     let frames = if direction & STREAM_TOSERVER != 0 {
790         &tx.frames_ts
791     } else {
792         &tx.frames_tc
793     };
794     for i in 0..frames.len() {
795         if let Some(blocks) = http2_header_blocks(&frames[i]) {
796             for block in blocks.iter() {
797                 if !http2_header_iscookie(direction, &block.name) {
798                     // we do not escape linefeeds nor : in headers names
799                     vec.extend_from_slice(&block.name);
800                     vec.extend_from_slice(&[b':', b' ']);
801                     vec.extend_from_slice(http2_header_trimspaces(&block.value));
802                     vec.extend_from_slice(&[b'\r', b'\n']);
803                 }
804             }
805         }
806     }
807     if vec.len() > 0 {
808         tx.escaped.push(vec);
809         let idx = tx.escaped.len() - 1;
810         let value = &tx.escaped[idx];
811         *buffer = value.as_ptr(); //unsafe
812         *buffer_len = value.len() as u32;
813         return 1;
814     }
815     return 0;
816 }
817 
818 #[no_mangle]
rs_http2_tx_get_headers_raw( tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8819 pub unsafe extern "C" fn rs_http2_tx_get_headers_raw(
820     tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32,
821 ) -> u8 {
822     let mut vec = Vec::new();
823     let frames = if direction & STREAM_TOSERVER != 0 {
824         &tx.frames_ts
825     } else {
826         &tx.frames_tc
827     };
828     for i in 0..frames.len() {
829         if let Some(blocks) = http2_header_blocks(&frames[i]) {
830             for block in blocks.iter() {
831                 // we do not escape linefeeds nor : in headers names
832                 vec.extend_from_slice(&block.name);
833                 vec.extend_from_slice(&[b':', b' ']);
834                 vec.extend_from_slice(&block.value);
835                 vec.extend_from_slice(&[b'\r', b'\n']);
836             }
837         }
838     }
839     if vec.len() > 0 {
840         tx.escaped.push(vec);
841         let idx = tx.escaped.len() - 1;
842         let value = &tx.escaped[idx];
843         *buffer = value.as_ptr(); //unsafe
844         *buffer_len = value.len() as u32;
845         return 1;
846     }
847     return 0;
848 }
849 
850 #[no_mangle]
rs_http2_tx_get_header( tx: &mut HTTP2Transaction, direction: u8, nb: u32, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8851 pub unsafe extern "C" fn rs_http2_tx_get_header(
852     tx: &mut HTTP2Transaction, direction: u8, nb: u32, buffer: *mut *const u8, buffer_len: *mut u32,
853 ) -> u8 {
854     let mut pos = 0 as u32;
855     if direction & STREAM_TOSERVER != 0 {
856         for i in 0..tx.frames_ts.len() {
857             if let Some(blocks) = http2_header_blocks(&tx.frames_ts[i]) {
858                 if nb < pos + blocks.len() as u32 {
859                     let ehdr = http2_escape_header(&blocks, nb - pos);
860                     tx.escaped.push(ehdr);
861                     let idx = tx.escaped.len() - 1;
862                     let value = &tx.escaped[idx];
863                     *buffer = value.as_ptr(); //unsafe
864                     *buffer_len = value.len() as u32;
865                     return 1;
866                 } else {
867                     pos = pos + blocks.len() as u32;
868                 }
869             }
870         }
871     } else {
872         for i in 0..tx.frames_tc.len() {
873             if let Some(blocks) = http2_header_blocks(&tx.frames_tc[i]) {
874                 if nb < pos + blocks.len() as u32 {
875                     let ehdr = http2_escape_header(&blocks, nb - pos);
876                     tx.escaped.push(ehdr);
877                     let idx = tx.escaped.len() - 1;
878                     let value = &tx.escaped[idx];
879                     *buffer = value.as_ptr(); //unsafe
880                     *buffer_len = value.len() as u32;
881                     return 1;
882                 } else {
883                     pos = pos + blocks.len() as u32;
884                 }
885             }
886         }
887     }
888 
889     return 0;
890 }
891 
http2_tx_set_header(state: &mut HTTP2State, name: &[u8], input: &[u8])892 fn http2_tx_set_header(state: &mut HTTP2State, name: &[u8], input: &[u8]) {
893     let head = parser::HTTP2FrameHeader {
894         length: 0,
895         ftype: parser::HTTP2FrameType::HEADERS as u8,
896         flags: 0,
897         reserved: 0,
898         stream_id: 1,
899     };
900     let mut blocks = Vec::new();
901     let b = parser::HTTP2FrameHeaderBlock {
902         name: name.to_vec(),
903         value: input.to_vec(),
904         error: parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
905         sizeupdate: 0,
906     };
907     blocks.push(b);
908     let hs = parser::HTTP2FrameHeaders {
909         padlength: None,
910         priority: None,
911         blocks: blocks,
912     };
913     let txdata = HTTP2FrameTypeData::HEADERS(hs);
914     let tx = state.find_or_create_tx(&head, &txdata, STREAM_TOSERVER);
915     tx.frames_ts.push(HTTP2Frame {
916         header: head,
917         data: txdata,
918     });
919     //we do not expect more data from client
920     tx.state = HTTP2TransactionState::HTTP2StateHalfClosedClient;
921 }
922 
923 #[no_mangle]
rs_http2_tx_set_method( state: &mut HTTP2State, buffer: *const u8, buffer_len: u32, )924 pub extern "C" fn rs_http2_tx_set_method(
925     state: &mut HTTP2State, buffer: *const u8, buffer_len: u32,
926 ) {
927     let slice = build_slice!(buffer, buffer_len as usize);
928     http2_tx_set_header(state, ":method".as_bytes(), slice)
929 }
930 
931 #[no_mangle]
rs_http2_tx_set_uri(state: &mut HTTP2State, buffer: *const u8, buffer_len: u32)932 pub extern "C" fn rs_http2_tx_set_uri(state: &mut HTTP2State, buffer: *const u8, buffer_len: u32) {
933     let slice = build_slice!(buffer, buffer_len as usize);
934     http2_tx_set_header(state, ":path".as_bytes(), slice)
935 }
936 
937 #[derive(Debug, PartialEq)]
938 pub enum Http2Base64Error {
939     InvalidBase64,
940 }
941 
942 impl std::error::Error for Http2Base64Error {}
943 
944 impl std::fmt::Display for Http2Base64Error {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result945     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
946         write!(f, "invalid base64")
947     }
948 }
949 
http2_base64_map(input: u8) -> Result<u8, Http2Base64Error>950 fn http2_base64_map(input: u8) -> Result<u8, Http2Base64Error> {
951     match input {
952         43 => Ok(62),  // +
953         47 => Ok(63),  // /
954         48 => Ok(52),  // 0
955         49 => Ok(53),  // 1
956         50 => Ok(54),  // 2
957         51 => Ok(55),  // 3
958         52 => Ok(56),  // 4
959         53 => Ok(57),  // 5
960         54 => Ok(58),  // 6
961         55 => Ok(59),  // 7
962         56 => Ok(60),  // 8
963         57 => Ok(61),  // 9
964         65 => Ok(0),   // A
965         66 => Ok(1),   // B
966         67 => Ok(2),   // C
967         68 => Ok(3),   // D
968         69 => Ok(4),   // E
969         70 => Ok(5),   // F
970         71 => Ok(6),   // G
971         72 => Ok(7),   // H
972         73 => Ok(8),   // I
973         74 => Ok(9),   // J
974         75 => Ok(10),  // K
975         76 => Ok(11),  // L
976         77 => Ok(12),  // M
977         78 => Ok(13),  // N
978         79 => Ok(14),  // O
979         80 => Ok(15),  // P
980         81 => Ok(16),  // Q
981         82 => Ok(17),  // R
982         83 => Ok(18),  // S
983         84 => Ok(19),  // T
984         85 => Ok(20),  // U
985         86 => Ok(21),  // V
986         87 => Ok(22),  // W
987         88 => Ok(23),  // X
988         89 => Ok(24),  // Y
989         90 => Ok(25),  // Z
990         97 => Ok(26),  // a
991         98 => Ok(27),  // b
992         99 => Ok(28),  // c
993         100 => Ok(29), // d
994         101 => Ok(30), // e
995         102 => Ok(31), // f
996         103 => Ok(32), // g
997         104 => Ok(33), // h
998         105 => Ok(34), // i
999         106 => Ok(35), // j
1000         107 => Ok(36), // k
1001         108 => Ok(37), // l
1002         109 => Ok(38), // m
1003         110 => Ok(39), // n
1004         111 => Ok(40), // o
1005         112 => Ok(41), // p
1006         113 => Ok(42), // q
1007         114 => Ok(43), // r
1008         115 => Ok(44), // s
1009         116 => Ok(45), // t
1010         117 => Ok(46), // u
1011         118 => Ok(47), // v
1012         119 => Ok(48), // w
1013         120 => Ok(49), // x
1014         121 => Ok(50), // y
1015         122 => Ok(51), // z
1016         _ => Err(Http2Base64Error::InvalidBase64),
1017     }
1018 }
1019 
http2_decode_base64(input: &[u8]) -> Result<Vec<u8>, Http2Base64Error>1020 fn http2_decode_base64(input: &[u8]) -> Result<Vec<u8>, Http2Base64Error> {
1021     if input.len() % 4 != 0 {
1022         return Err(Http2Base64Error::InvalidBase64);
1023     }
1024     let mut r = vec![0; (input.len() * 3) / 4];
1025     for i in 0..input.len() / 4 {
1026         let i1 = http2_base64_map(input[4 * i])?;
1027         let i2 = http2_base64_map(input[4 * i + 1])?;
1028         let i3 = http2_base64_map(input[4 * i + 2])?;
1029         let i4 = http2_base64_map(input[4 * i + 3])?;
1030         r[3 * i] = (i1 << 2) | (i2 >> 4);
1031         r[3 * i + 1] = (i2 << 4) | (i3 >> 2);
1032         r[3 * i + 2] = (i3 << 6) | i4;
1033     }
1034     return Ok(r);
1035 }
1036 
http2_tx_set_settings(state: &mut HTTP2State, input: &[u8])1037 fn http2_tx_set_settings(state: &mut HTTP2State, input: &[u8]) {
1038     match http2_decode_base64(input) {
1039         Ok(dec) => {
1040             if dec.len() % 6 != 0 {
1041                 state.set_event(HTTP2Event::InvalidHTTP1Settings);
1042             }
1043 
1044             let head = parser::HTTP2FrameHeader {
1045                 length: dec.len() as u32,
1046                 ftype: parser::HTTP2FrameType::SETTINGS as u8,
1047                 flags: 0,
1048                 reserved: 0,
1049                 stream_id: 0,
1050             };
1051 
1052             match parser::http2_parse_frame_settings(&dec) {
1053                 Ok((_, set)) => {
1054                     let txdata = HTTP2FrameTypeData::SETTINGS(set);
1055                     let tx = state.find_or_create_tx(&head, &txdata, STREAM_TOSERVER);
1056                     tx.frames_ts.push(HTTP2Frame {
1057                         header: head,
1058                         data: txdata,
1059                     });
1060                 }
1061                 Err(_) => {
1062                     state.set_event(HTTP2Event::InvalidHTTP1Settings);
1063                 }
1064             }
1065         }
1066         Err(_) => {
1067             state.set_event(HTTP2Event::InvalidHTTP1Settings);
1068         }
1069     }
1070 }
1071 
http2_caseinsensitive_cmp(s1: &[u8], s2: &str) -> bool1072 fn http2_caseinsensitive_cmp(s1: &[u8], s2: &str) -> bool {
1073     if let Ok(s) = std::str::from_utf8(s1) {
1074         return s.to_lowercase() == s2;
1075     }
1076     return false;
1077 }
1078 
1079 #[no_mangle]
rs_http2_tx_add_header( state: &mut HTTP2State, name: *const u8, name_len: u32, value: *const u8, value_len: u32, )1080 pub extern "C" fn rs_http2_tx_add_header(
1081     state: &mut HTTP2State, name: *const u8, name_len: u32, value: *const u8, value_len: u32,
1082 ) {
1083     let slice_name = build_slice!(name, name_len as usize);
1084     let slice_value = build_slice!(value, value_len as usize);
1085     if slice_name == "HTTP2-Settings".as_bytes() {
1086         http2_tx_set_settings(state, slice_value)
1087     } else if http2_caseinsensitive_cmp(slice_name, "host") {
1088         http2_tx_set_header(state, ":authority".as_bytes(), slice_value)
1089     } else {
1090         http2_tx_set_header(state, slice_name, slice_value)
1091     }
1092 }
1093 
1094 #[cfg(test)]
1095 mod tests {
1096 
1097     use super::*;
1098 
1099     #[test]
test_http2_normalize_host()1100     fn test_http2_normalize_host() {
1101         let buf0 = "aBC.com:1234".as_bytes();
1102         let r0 = http2_normalize_host(buf0);
1103         match r0.0 {
1104             Some(r) => {
1105                 assert_eq!(r, "abc.com".as_bytes().to_vec());
1106             }
1107             None => {
1108                 panic!("Result should not have been None");
1109             }
1110         }
1111         let buf1 = "oisf.net".as_bytes();
1112         let r1 = http2_normalize_host(buf1);
1113         match r1.0 {
1114             Some(r) => {
1115                 panic!("Result should not have been None, not {:?}", r);
1116             }
1117             None => {}
1118         }
1119         assert_eq!(r1.1, "oisf.net".len());
1120         let buf2 = "localhost:3000".as_bytes();
1121         let r2 = http2_normalize_host(buf2);
1122         match r2.0 {
1123             Some(r) => {
1124                 panic!("Result should not have been None, not {:?}", r);
1125             }
1126             None => {}
1127         }
1128         assert_eq!(r2.1, "localhost".len());
1129     }
1130 
1131     #[test]
test_http2_header_trimspaces()1132     fn test_http2_header_trimspaces() {
1133         let buf0 = "nospaces".as_bytes();
1134         let r0 = http2_header_trimspaces(buf0);
1135         assert_eq!(r0, "nospaces".as_bytes());
1136         let buf1 = " spaces\t".as_bytes();
1137         let r1 = http2_header_trimspaces(buf1);
1138         assert_eq!(r1, "spaces".as_bytes());
1139         let buf2 = " \t".as_bytes();
1140         let r2 = http2_header_trimspaces(buf2);
1141         assert_eq!(r2, "".as_bytes());
1142     }
1143 
1144     #[test]
test_http2_frames_get_header_value()1145     fn test_http2_frames_get_header_value() {
1146         let mut tx = HTTP2Transaction::new();
1147         let head = parser::HTTP2FrameHeader {
1148             length: 0,
1149             ftype: parser::HTTP2FrameType::HEADERS as u8,
1150             flags: 0,
1151             reserved: 0,
1152             stream_id: 1,
1153         };
1154         let mut blocks = Vec::new();
1155         let b = parser::HTTP2FrameHeaderBlock {
1156             name: "Host".as_bytes().to_vec(),
1157             value: "abc.com".as_bytes().to_vec(),
1158             error: parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
1159             sizeupdate: 0,
1160         };
1161         blocks.push(b);
1162         let b2 = parser::HTTP2FrameHeaderBlock {
1163             name: "Host".as_bytes().to_vec(),
1164             value: "efg.net".as_bytes().to_vec(),
1165             error: parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess,
1166             sizeupdate: 0,
1167         };
1168         blocks.push(b2);
1169         let hs = parser::HTTP2FrameHeaders {
1170             padlength: None,
1171             priority: None,
1172             blocks: blocks,
1173         };
1174         let txdata = HTTP2FrameTypeData::HEADERS(hs);
1175         tx.frames_ts.push(HTTP2Frame {
1176             header: head,
1177             data: txdata,
1178         });
1179         match http2_frames_get_header_value(&mut tx, STREAM_TOSERVER, "Host") {
1180             Ok(x) => {
1181                 assert_eq!(x, "abc.com, efg.net".as_bytes());
1182             }
1183             Err(e) => {
1184                 panic!("Result should not have been an error: {:?}", e);
1185             }
1186         }
1187     }
1188 }
1189