1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation.  You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 //--------------------------------------------------------------------------
18 // http_inspect.cc author Tom Peters <thopeter@cisco.com>
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include "http_inspect.h"
25 
26 #include <cassert>
27 #include <iomanip>
28 #include <sstream>
29 
30 #include "detection/detection_engine.h"
31 #include "detection/detection_util.h"
32 #include "service_inspectors/http2_inspect/http2_dummy_packet.h"
33 #include "service_inspectors/http2_inspect/http2_flow_data.h"
34 #include "log/unified2.h"
35 #include "protocols/packet.h"
36 #include "stream/stream.h"
37 
38 #include "http_common.h"
39 #include "http_context_data.h"
40 #include "http_enum.h"
41 #include "http_js_norm.h"
42 #include "http_msg_body.h"
43 #include "http_msg_body_chunk.h"
44 #include "http_msg_body_cl.h"
45 #include "http_msg_body_h2.h"
46 #include "http_msg_body_old.h"
47 #include "http_msg_header.h"
48 #include "http_msg_request.h"
49 #include "http_msg_status.h"
50 #include "http_msg_trailer.h"
51 #include "http_test_manager.h"
52 
53 using namespace snort;
54 using namespace HttpCommon;
55 using namespace HttpEnums;
56 
GetUnreservedChars(const ByteBitSet & bitset)57 static std::string GetUnreservedChars(const ByteBitSet& bitset)
58 {
59     const ByteBitSet& def_bitset(HttpParaList::UriParam::UriParam::default_unreserved_char);
60     std::string chars;
61 
62     for (unsigned char c = 1; c; ++c)
63         if (def_bitset[c] && !bitset[c])
64             chars += c;
65 
66     return chars;
67 }
68 
GetBadChars(const ByteBitSet & bitset)69 static std::string GetBadChars(const ByteBitSet& bitset)
70 {
71     std::stringstream ss;
72     ss << std::hex;
73 
74     for (unsigned i = 0; i < bitset.size(); ++i)
75         if (bitset[i])
76             ss << " 0x" << std::setw(2) << std::setfill('0') << i;
77 
78     auto str = ss.str();
79     if ( !str.empty() )
80         str.erase(0, 1);
81 
82     return str;
83 }
84 
85 
GetXFFHeaders(const StrCode * header_list)86 static std::string GetXFFHeaders(const StrCode *header_list)
87 {
88     std::string hdr_list;
89     for (int idx = 0; header_list[idx].code; idx++)
90     {
91         hdr_list += header_list[idx].name;
92         hdr_list += " ";
93     }
94 
95     // Remove the trailing whitespace, if any
96     if (hdr_list.length())
97     {
98         hdr_list.pop_back();
99     }
100     return hdr_list;
101 }
102 
HttpInspect(const HttpParaList * params_)103 HttpInspect::HttpInspect(const HttpParaList* params_) :
104     params(params_),
105     xtra_trueip_id(Stream::reg_xtra_data_cb(get_xtra_trueip)),
106     xtra_uri_id(Stream::reg_xtra_data_cb(get_xtra_uri)),
107     xtra_host_id(Stream::reg_xtra_data_cb(get_xtra_host)),
108     xtra_jsnorm_id(Stream::reg_xtra_data_cb(get_xtra_jsnorm))
109 {
110 #ifdef REG_TEST
111     if (params->test_input)
112     {
113         HttpTestManager::activate_test_input(HttpTestManager::IN_HTTP);
114     }
115     if (params->test_output)
116     {
117         HttpTestManager::activate_test_output(HttpTestManager::IN_HTTP);
118     }
119     if ((params->test_input) || (params->test_output))
120     {
121         HttpTestManager::set_print_amount(params->print_amount);
122         HttpTestManager::set_print_hex(params->print_hex);
123         HttpTestManager::set_show_pegs(params->show_pegs);
124         HttpTestManager::set_show_scan(params->show_scan);
125     }
126 #endif
127 
128     if (params->script_detection)
129     {
130         script_finder = new ScriptFinder(params->script_detection_handle);
131     }
132 }
133 
configure(SnortConfig *)134 bool HttpInspect::configure(SnortConfig* )
135 {
136     params->js_norm_param.js_norm->configure();
137 
138     return true;
139 }
140 
show(const SnortConfig *) const141 void HttpInspect::show(const SnortConfig*) const
142 {
143     assert(params);
144 
145     auto unreserved_chars = GetUnreservedChars(params->uri_param.unreserved_char);
146     auto bad_chars = GetBadChars(params->uri_param.bad_characters);
147     auto xff_headers = GetXFFHeaders(params->xff_headers);
148 
149     std::string js_norm_ident_ignore;
150     for (auto s : params->js_norm_param.ignored_ids)
151         js_norm_ident_ignore += s + " ";
152 
153     ConfigLogger::log_limit("request_depth", params->request_depth, -1LL);
154     ConfigLogger::log_limit("response_depth", params->response_depth, -1LL);
155     ConfigLogger::log_flag("unzip", params->unzip);
156     ConfigLogger::log_flag("normalize_utf", params->normalize_utf);
157     ConfigLogger::log_flag("decompress_pdf", params->decompress_pdf);
158     ConfigLogger::log_flag("decompress_swf", params->decompress_swf);
159     ConfigLogger::log_flag("decompress_zip", params->decompress_zip);
160     ConfigLogger::log_flag("decompress_vba", params->decompress_vba);
161     ConfigLogger::log_flag("script_detection", params->script_detection);
162     ConfigLogger::log_flag("normalize_javascript", params->js_norm_param.normalize_javascript);
163     ConfigLogger::log_value("max_javascript_whitespaces",
164         params->js_norm_param.max_javascript_whitespaces);
165     ConfigLogger::log_value("js_norm_bytes_depth", params->js_norm_param.js_norm_bytes_depth);
166     ConfigLogger::log_value("js_norm_identifier_depth", params->js_norm_param.js_identifier_depth);
167     ConfigLogger::log_value("js_norm_max_tmpl_nest", params->js_norm_param.max_template_nesting);
168     ConfigLogger::log_value("js_norm_max_bracket_depth", params->js_norm_param.max_bracket_depth);
169     ConfigLogger::log_value("js_norm_max_scope_depth", params->js_norm_param.max_scope_depth);
170     if (!js_norm_ident_ignore.empty())
171         ConfigLogger::log_list("js_norm_ident_ignore", js_norm_ident_ignore.c_str());
172     ConfigLogger::log_value("bad_characters", bad_chars.c_str());
173     ConfigLogger::log_value("ignore_unreserved", unreserved_chars.c_str());
174     ConfigLogger::log_flag("percent_u", params->uri_param.percent_u);
175     ConfigLogger::log_flag("utf8", params->uri_param.utf8);
176     ConfigLogger::log_flag("utf8_bare_byte", params->uri_param.utf8_bare_byte);
177     ConfigLogger::log_flag("iis_unicode", params->uri_param.iis_unicode);
178     ConfigLogger::log_value("iis_unicode_map_file", params->uri_param.iis_unicode_map_file.c_str());
179     ConfigLogger::log_value("iis_unicode_code_page", params->uri_param.iis_unicode_code_page);
180     ConfigLogger::log_flag("iis_double_decode", params->uri_param.iis_double_decode);
181     ConfigLogger::log_value("oversize_dir_length", params->uri_param.oversize_dir_length);
182     ConfigLogger::log_flag("backslash_to_slash", params->uri_param.backslash_to_slash);
183     ConfigLogger::log_flag("plus_to_space", params->uri_param.plus_to_space);
184     ConfigLogger::log_flag("simplify_path", params->uri_param.simplify_path);
185     ConfigLogger::log_value("xff_headers", xff_headers.c_str());
186     ConfigLogger::log_flag("request_body_app_detection", params->publish_request_body);
187 }
188 
get_latest_is(const Packet * p)189 InspectSection HttpInspect::get_latest_is(const Packet* p)
190 {
191     HttpMsgSection* current_section = HttpContextData::get_snapshot(p);
192 
193     if (current_section == nullptr)
194         return IS_NONE;
195 
196     // FIXIT-L revisit why we need this check. We should not be getting a current section back
197     // for a raw packet but one of the test cases did exactly that.
198     if (!(p->packet_flags & PKT_PSEUDO))
199         return IS_NONE;
200 
201     return current_section->get_inspection_section();
202 }
203 
get_latest_src(const Packet * p)204 SourceId HttpInspect::get_latest_src(const Packet* p)
205 {
206     HttpMsgSection* current_section = HttpContextData::get_snapshot(p);
207 
208     if (current_section == nullptr)
209         return SRC__NOT_COMPUTE;
210 
211     return current_section->get_source_id();
212 }
213 
get_buf(InspectionBuffer::Type ibt,Packet * p,InspectionBuffer & b)214 bool HttpInspect::get_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
215 {
216     switch (ibt)
217     {
218     case InspectionBuffer::IBT_KEY:
219         return get_buf(HTTP_BUFFER_URI, p, b);
220 
221     case InspectionBuffer::IBT_HEADER:
222         if (get_latest_is(p) == IS_TRAILER)
223             return get_buf(HTTP_BUFFER_TRAILER, p, b);
224         else
225             return get_buf(HTTP_BUFFER_HEADER, p , b);
226 
227     case InspectionBuffer::IBT_BODY:
228         return get_buf(HTTP_BUFFER_CLIENT_BODY, p, b);
229 
230     case InspectionBuffer::IBT_RAW_KEY:
231         return get_buf(HTTP_BUFFER_RAW_URI, p , b);
232 
233     case InspectionBuffer::IBT_RAW_HEADER:
234         if (get_latest_is(p) == IS_TRAILER)
235             return get_buf(HTTP_BUFFER_RAW_TRAILER, p, b);
236         else
237             return get_buf(HTTP_BUFFER_RAW_HEADER, p , b);
238 
239     case InspectionBuffer::IBT_METHOD:
240         return get_buf(HTTP_BUFFER_METHOD, p , b);
241 
242     case InspectionBuffer::IBT_STAT_CODE:
243         return get_buf(HTTP_BUFFER_STAT_CODE, p , b);
244 
245     case InspectionBuffer::IBT_STAT_MSG:
246         return get_buf(HTTP_BUFFER_STAT_MSG, p , b);
247 
248     case InspectionBuffer::IBT_COOKIE:
249         return get_buf(HTTP_BUFFER_COOKIE, p , b);
250 
251     case InspectionBuffer::IBT_VBA:
252         return get_buf(BUFFER_VBA_DATA, p, b);
253 
254     case InspectionBuffer::IBT_JS_DATA:
255         return get_buf(BUFFER_JS_DATA, p, b);
256 
257     default:
258         return false;
259     }
260 }
261 
get_buf(unsigned id,Packet * p,InspectionBuffer & b)262 bool HttpInspect::get_buf(unsigned id, Packet* p, InspectionBuffer& b)
263 {
264     Cursor c;
265     HttpBufferInfo buffer_info(id);
266 
267     const Field& http_buffer = http_get_buf(c, p, buffer_info);
268 
269     if (http_buffer.length() <= 0)
270         return false;
271 
272     b.data = http_buffer.start();
273     b.len = http_buffer.length();
274     return true;
275 }
276 
http_get_buf(Cursor & c,Packet * p,const HttpBufferInfo & buffer_info) const277 const Field& HttpInspect::http_get_buf(Cursor& c, Packet* p,
278     const HttpBufferInfo& buffer_info) const
279 {
280     HttpMsgSection* const current_section = HttpContextData::get_snapshot(p);
281 
282     if (current_section == nullptr)
283         return Field::FIELD_NULL;
284 
285     return current_section->get_classic_buffer(c, buffer_info);
286 }
287 
http_get_num_headers(Packet * p,const HttpBufferInfo & buffer_info) const288 int32_t HttpInspect::http_get_num_headers(Packet* p,
289     const HttpBufferInfo& buffer_info) const
290 {
291     const HttpMsgSection* const current_section = HttpContextData::get_snapshot(p);
292 
293     if (current_section == nullptr)
294         return STAT_NOT_COMPUTE;
295 
296     return current_section->get_num_headers(buffer_info);
297 }
298 
get_fp_buf(InspectionBuffer::Type ibt,Packet * p,InspectionBuffer & b)299 bool HttpInspect::get_fp_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
300 {
301     if (get_latest_is(p) == IS_NONE)
302         return false;
303 
304     // Fast pattern buffers only supplied at specific times
305     switch (ibt)
306     {
307     case InspectionBuffer::IBT_KEY:
308     case InspectionBuffer::IBT_RAW_KEY:
309         // Many rules targeting POST feature http_uri fast pattern with http_client_body. We
310         // accept the performance hit of rerunning http_uri fast pattern with request body message
311         // sections
312         if (get_latest_src(p) != SRC_CLIENT)
313             return false;
314         break;
315     case InspectionBuffer::IBT_HEADER:
316     case InspectionBuffer::IBT_RAW_HEADER:
317         // http_header fast patterns for response bodies limited to first section
318         if ((get_latest_src(p) == SRC_SERVER) && (get_latest_is(p) == IS_BODY))
319             return false;
320         break;
321     case InspectionBuffer::IBT_BODY:
322     case InspectionBuffer::IBT_VBA:
323     case InspectionBuffer::IBT_JS_DATA:
324         if ((get_latest_is(p) != IS_FIRST_BODY) && (get_latest_is(p) != IS_BODY))
325             return false;
326         break;
327     case InspectionBuffer::IBT_METHOD:
328         if ((get_latest_src(p) != SRC_CLIENT) || (get_latest_is(p) == IS_BODY))
329             return false;
330         break;
331     case InspectionBuffer::IBT_STAT_CODE:
332     case InspectionBuffer::IBT_STAT_MSG:
333         if ((get_latest_src(p) != SRC_SERVER) || (get_latest_is(p) != IS_HEADER))
334             return false;
335         break;
336     case InspectionBuffer::IBT_COOKIE:
337         if (get_latest_is(p) != IS_HEADER)
338             return false;
339         break;
340     default:
341         break;
342     }
343     return get_buf(ibt, p, b);
344 }
345 
get_xtra_trueip(Flow * flow,uint8_t ** buf,uint32_t * len,uint32_t * type)346 int HttpInspect::get_xtra_trueip(Flow* flow, uint8_t** buf, uint32_t* len, uint32_t* type)
347 {
348     HttpMsgSection* current_section = HttpContextData::get_snapshot(flow);
349 
350     if (current_section == nullptr)
351         return 0;
352 
353     HttpMsgHeader* const req_header = current_section->get_header(SRC_CLIENT);
354     if (req_header == nullptr)
355         return 0;
356     const Field& true_ip = req_header->get_true_ip_addr();
357     if (true_ip.length() <= 0)
358         return 0;
359 
360     *buf = const_cast<uint8_t*>(true_ip.start());
361     *len = true_ip.length();
362     *type = (*len == 4) ? EVENT_INFO_XFF_IPV4 : EVENT_INFO_XFF_IPV6;
363     return 1;
364 }
365 
get_xtra_uri(Flow * flow,uint8_t ** buf,uint32_t * len,uint32_t * type)366 int HttpInspect::get_xtra_uri(Flow* flow, uint8_t** buf, uint32_t* len, uint32_t* type)
367 {
368     HttpMsgSection* current_section = HttpContextData::get_snapshot(flow);
369 
370     if (current_section == nullptr)
371         return 0;
372 
373     HttpMsgRequest* const request = current_section->get_request();
374     if (request == nullptr)
375         return 0;
376     const Field& uri = request->get_uri();
377     if (uri.length() <= 0)
378         return 0;
379 
380     *buf = const_cast<uint8_t*>(uri.start());
381     *len = uri.length();
382     *type = EVENT_INFO_HTTP_URI;
383 
384     return 1;
385 }
386 
get_xtra_host(Flow * flow,uint8_t ** buf,uint32_t * len,uint32_t * type)387 int HttpInspect::get_xtra_host(Flow* flow, uint8_t** buf, uint32_t* len, uint32_t* type)
388 {
389     HttpMsgSection* current_section = HttpContextData::get_snapshot(flow);
390 
391     if (current_section == nullptr)
392         return 0;
393 
394     HttpMsgHeader* const req_header = current_section->get_header(SRC_CLIENT);
395     if (req_header == nullptr)
396         return 0;
397     const Field& host = req_header->get_header_value_norm(HEAD_HOST);
398     if (host.length() <= 0)
399         return 0;
400 
401     *buf = const_cast<uint8_t*>(host.start());
402     *len = host.length();
403     *type = EVENT_INFO_HTTP_HOSTNAME;
404 
405     return 1;
406 }
407 
408 // The name of this method reflects its legacy purpose. We actually return the normalized data
409 // from a response message body which may include other forms of normalization in addition to
410 // JavaScript normalization. But if you don't turn JavaScript normalization on you get nothing.
get_xtra_jsnorm(Flow * flow,uint8_t ** buf,uint32_t * len,uint32_t * type)411 int HttpInspect::get_xtra_jsnorm(Flow* flow, uint8_t** buf, uint32_t* len, uint32_t* type)
412 {
413     HttpMsgSection* current_section = HttpContextData::get_snapshot(flow);
414 
415     if ((current_section == nullptr) ||
416         (current_section->get_source_id() != SRC_SERVER) ||
417         !current_section->get_params()->js_norm_param.normalize_javascript)
418         return 0;
419 
420     HttpMsgBody* const body = current_section->get_body();
421     if (body == nullptr)
422         return 0;
423     assert((void*)body == (void*)current_section);
424     const Field& detect_data = body->get_detect_data();
425     if (detect_data.length() <= 0)
426         return 0;
427 
428     *buf = const_cast<uint8_t*>(detect_data.start());
429     *len = detect_data.length();
430     *type = EVENT_INFO_JSNORM_DATA;
431 
432     return 1;
433 }
434 
disable_detection(Packet * p)435 void HttpInspect::disable_detection(Packet* p)
436 {
437     HttpFlowData* session_data = http_get_flow_data(p->flow);
438     if (session_data->for_http2)
439         p->disable_inspect = true;
440     else
441     {
442         assert(p->context);
443         DetectionEngine::disable_all(p);
444     }
445 }
446 
http_get_flow_data(const Flow * flow)447 HttpFlowData* HttpInspect::http_get_flow_data(const Flow* flow)
448 {
449     Http2FlowData* h2i_flow_data = nullptr;
450     if (Http2FlowData::inspector_id != 0)
451         h2i_flow_data = (Http2FlowData*)flow->get_flow_data(Http2FlowData::inspector_id);
452     if (h2i_flow_data == nullptr)
453         return (HttpFlowData*)flow->get_flow_data(HttpFlowData::inspector_id);
454     else
455         return h2i_flow_data->get_hi_flow_data();
456 }
457 
http_set_flow_data(Flow * flow,HttpFlowData * flow_data)458 void HttpInspect::http_set_flow_data(Flow* flow, HttpFlowData* flow_data)
459 {
460     // for_http2 set in HttpFlowData constructor after checking for h2i_flow_data
461     if (!flow_data->for_http2)
462         flow->set_flow_data(flow_data);
463     else
464     {
465         Http2FlowData* h2i_flow_data =
466             (Http2FlowData*)flow->get_flow_data(Http2FlowData::inspector_id);
467         assert(h2i_flow_data);
468         h2i_flow_data->set_hi_flow_data(flow_data);
469     }
470 }
471 
eval(Packet * p)472 void HttpInspect::eval(Packet* p)
473 {
474     Profile profile(HttpModule::get_profile_stats());
475 
476     const SourceId source_id = p->is_from_client() ? SRC_CLIENT : SRC_SERVER;
477 
478     HttpFlowData* session_data = http_get_flow_data(p->flow);
479     if (session_data == nullptr)
480     {
481         assert(false);
482         return;
483     }
484 
485     // FIXIT-M Workaround for unexpected eval() calls. Currently asserting when stream_user is in
486     // use due to calls to HttpInspect::eval on the raw stream_user packet
487     if ((session_data->section_type[source_id] == SEC__NOT_COMPUTE) ||
488         (session_data->type_expected[source_id] == SEC_ABORT)       ||
489         (session_data->octets_reassembled[source_id] != p->dsize))
490     {
491         //assert(session_data->type_expected[source_id] != SEC_ABORT);
492         //assert(session_data->section_type[source_id] != SEC__NOT_COMPUTE);
493         //assert(session_data->octets_reassembled[source_id] == p->dsize);
494         session_data->type_expected[source_id] = SEC_ABORT;
495         return;
496     }
497 
498     if (!session_data->for_http2)
499         HttpModule::increment_peg_counts(PEG_TOTAL_BYTES, p->dsize);
500 
501     session_data->octets_reassembled[source_id] = STAT_NOT_PRESENT;
502 
503     // Don't make pkt_data for headers available to detection
504     if ((session_data->section_type[source_id] == SEC_HEADER) ||
505         (session_data->section_type[source_id] == SEC_TRAILER))
506     {
507         p->set_detect_limit(0);
508     }
509 
510     // Limit alt_dsize of message body sections to request/response depth
511     if ((session_data->detect_depth_remaining[source_id] > 0) &&
512         (session_data->detect_depth_remaining[source_id] < p->dsize))
513     {
514         p->set_detect_limit(session_data->detect_depth_remaining[source_id]);
515     }
516 
517     if (!process(p->data, p->dsize, p->flow, source_id, true))
518         disable_detection(p);
519 
520 #ifdef REG_TEST
521     else
522     {
523         if (HttpTestManager::use_test_output(HttpTestManager::IN_HTTP))
524         {
525             fprintf(HttpTestManager::get_output_file(), "Sent to detection %hu octets\n\n",
526                 p->dsize);
527             fflush(HttpTestManager::get_output_file());
528         }
529     }
530 #endif
531 
532     // If current transaction is complete then we are done with it. This is strictly a memory
533     // optimization not necessary for correct operation.
534     if ((source_id == SRC_SERVER) && (session_data->type_expected[SRC_SERVER] == SEC_STATUS) &&
535          session_data->transaction[SRC_SERVER]->final_response())
536     {
537         HttpTransaction::delete_transaction(session_data->transaction[SRC_SERVER], session_data);
538         session_data->transaction[SRC_SERVER] = nullptr;
539     }
540 
541     // Whenever we process a packet we set these flags. If someone asks for an extra data
542     // buffer the JIT code will figure out if we actually have it.
543     SetExtraData(p, xtra_trueip_id);
544     SetExtraData(p, xtra_uri_id);
545     SetExtraData(p, xtra_host_id);
546     SetExtraData(p, xtra_jsnorm_id);
547 }
548 
process(const uint8_t * data,const uint16_t dsize,Flow * const flow,SourceId source_id,bool buf_owner) const549 bool HttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* const flow,
550     SourceId source_id, bool buf_owner) const
551 {
552     HttpMsgSection* current_section;
553     HttpFlowData* session_data = http_get_flow_data(flow);
554 
555     if (!session_data->partial_flush[source_id])
556         HttpModule::increment_peg_counts(PEG_INSPECT);
557     else
558         HttpModule::increment_peg_counts(PEG_PARTIAL_INSPECT);
559 
560     switch (session_data->section_type[source_id])
561     {
562     case SEC_REQUEST:
563         current_section = new HttpMsgRequest(
564             data, dsize, session_data, source_id, buf_owner, flow, params);
565         break;
566     case SEC_STATUS:
567         current_section = new HttpMsgStatus(
568             data, dsize, session_data, source_id, buf_owner, flow, params);
569         break;
570     case SEC_HEADER:
571         current_section = new HttpMsgHeader(
572             data, dsize, session_data, source_id, buf_owner, flow, params);
573         break;
574     case SEC_BODY_CL:
575         current_section = new HttpMsgBodyCl(
576             data, dsize, session_data, source_id, buf_owner, flow, params);
577         break;
578     case SEC_BODY_OLD:
579         current_section = new HttpMsgBodyOld(
580             data, dsize, session_data, source_id, buf_owner, flow, params);
581         break;
582     case SEC_BODY_CHUNK:
583         current_section = new HttpMsgBodyChunk(
584             data, dsize, session_data, source_id, buf_owner, flow, params);
585         break;
586     case SEC_BODY_H2:
587         current_section = new HttpMsgBodyH2(
588             data, dsize, session_data, source_id, buf_owner, flow, params);
589         break;
590     case SEC_TRAILER:
591         current_section = new HttpMsgTrailer(
592             data, dsize, session_data, source_id, buf_owner, flow, params);
593         break;
594     default:
595         assert(false);
596         if (buf_owner)
597         {
598             delete[] data;
599         }
600         return false;
601     }
602 
603     current_section->analyze();
604     current_section->gen_events();
605     if (!session_data->partial_flush[source_id])
606         current_section->update_flow();
607     session_data->section_type[source_id] = SEC__NOT_COMPUTE;
608 
609 #ifdef REG_TEST
610     if (HttpTestManager::use_test_output(HttpTestManager::IN_HTTP))
611     {
612         current_section->print_section(HttpTestManager::get_output_file());
613         fflush(HttpTestManager::get_output_file());
614         if (HttpTestManager::use_test_input(HttpTestManager::IN_HTTP))
615         {
616             printf("Finished processing section from test %" PRIi64 "\n",
617                 HttpTestManager::get_test_number());
618         }
619         fflush(stdout);
620     }
621 #endif
622 
623     current_section->publish();
624     return current_section->detection_required();
625 }
626 
clear(Packet * p)627 void HttpInspect::clear(Packet* p)
628 {
629     Profile profile(HttpModule::get_profile_stats());
630 
631     HttpFlowData* const session_data = http_get_flow_data(p->flow);
632 
633     if (session_data == nullptr)
634     {
635         assert(false);
636         return;
637     }
638 
639     Http2FlowData* h2i_flow_data = nullptr;
640     if (Http2FlowData::inspector_id != 0)
641     {
642         h2i_flow_data = (Http2FlowData*)p->flow->get_flow_data(Http2FlowData::inspector_id);
643     }
644 
645     HttpMsgSection* current_section = nullptr;
646     if (h2i_flow_data != nullptr)
647     {
648         current_section = h2i_flow_data->get_hi_msg_section();
649         assert(current_section != nullptr);
650         h2i_flow_data->set_hi_msg_section(nullptr);
651     }
652     else
653         current_section = HttpContextData::clear_snapshot(p->context);
654 
655     if ( current_section == nullptr )
656     {
657         //assert(false); //FIXIT-M This happens with stream_user
658         return;
659     }
660 
661     current_section->clear();
662     HttpTransaction* current_transaction = current_section->get_transaction();
663 
664     const SourceId source_id = current_section->get_source_id();
665 
666     // FIXIT-M This check may not apply to the transaction attached to the packet
667     // in case of offload.
668     if (session_data->detection_status[source_id] == DET_DEACTIVATING)
669     {
670         if (source_id == SRC_CLIENT)
671         {
672             p->flow->set_to_server_detection(false);
673         }
674         else
675         {
676             p->flow->set_to_client_detection(false);
677         }
678         session_data->detection_status[source_id] = DET_OFF;
679     }
680 
681     current_transaction->garbage_collect();
682     session_data->garbage_collect();
683 
684     if (session_data->cutover_on_clear)
685     {
686         Flow* flow = p->flow;
687         flow->set_service(p, nullptr);
688         flow->free_flow_data(HttpFlowData::inspector_id);
689     }
690 }
691 
692