@@ -10,7 +10,7 @@ using namespace analyzer::mitrecnd;
1010
1111/* *
1212 * HTTP2_Stream::UncompressedOutput : public analyzer::OutputHandler
13- *
13+ *
1414 * Description: The output handler type used by the zip decompression api.
1515 *
1616 */
@@ -43,10 +43,11 @@ HTTP2_HalfStream::HTTP2_HalfStream(HTTP2_Analyzer* analyzer, uint32_t stream_id,
4343 this ->peerStreamEnded = false ;
4444 this ->zip = nullptr ;
4545 this ->send_size = true ;
46-
4746 this ->data_size = 0 ;
4847 this ->contentLength = 0 ;
4948 this ->contentEncodingId = DATA_ENCODING_IDENTITY;
49+ this ->brotli = nullptr ;
50+ this ->brotli_buffer = nullptr ;
5051}
5152
5253HTTP2_HalfStream::~HTTP2_HalfStream ()
@@ -55,6 +56,14 @@ HTTP2_HalfStream::~HTTP2_HalfStream()
5556 zip->Done ();
5657 delete zip;
5758 }
59+
60+ if (this ->brotli != nullptr ) {
61+ BrotliDecoderDestroyInstance (this ->brotli );
62+ }
63+
64+ if (this ->brotli_buffer != nullptr ) {
65+ delete this ->brotli_buffer ;
66+ }
5867}
5968
6069bool HTTP2_HalfStream::processHeaders (uint8_t ** headerBlockFragmentPtr, uint32_t & len,
@@ -146,14 +155,14 @@ void HTTP2_HalfStream::extractDataInfoHeaders(std::string& name, std::string& va
146155}
147156
148157void HTTP2_HalfStream::SubmitData (int len, const char * buf){
149-
158+
150159 // if partial data
151160 if ((this ->send_size && this ->contentLength > 0 && len < this ->contentLength )
152161 || !this ->send_size ) {
153162 file_mgr->DataIn (reinterpret_cast <const u_char*>(buf), len, this ->dataOffset ,
154163 this ->analyzer ->GetAnalyzerTag (), this ->analyzer ->Conn (),
155164 this ->isOrig , this ->precomputed_file_id );
156-
165+
157166 this ->dataOffset += len;
158167 }
159168 else {
@@ -165,14 +174,14 @@ void HTTP2_HalfStream::SubmitData(int len, const char* buf){
165174
166175void HTTP2_HalfStream::EndofData (void )
167176{
168- // If a unique file identifier has been created then use it, otherwise
177+ // If a unique file identifier has been created then use it, otherwise
169178 // relay to the file manager all information it needs to uniquely identify
170179 // the message.
171180 if (!this ->precomputed_file_id .empty ()) {
172181 file_mgr->EndOfFile (this ->precomputed_file_id );
173182 } else {
174183 file_mgr->EndOfFile (this ->analyzer ->GetAnalyzerTag (),
175- this ->analyzer ->Conn (),
184+ this ->analyzer ->Conn (),
176185 this ->isOrig );
177186 }
178187}
@@ -188,11 +197,15 @@ void HTTP2_HalfStream::DeliverBody(int len, const char* data, int trailing_CRLF)
188197 break ;
189198 case DATA_ENCODING_BROTLI:
190199 if (this ->dataBlockCnt == 1 ) { // Begin Entity
191- this ->brotli = BrotliDecoderCreateInstance (0 , 0 , 0 );
200+ this ->brotli = BrotliDecoderCreateInstance (0 , 0 , 0 );
201+ this ->brotli_buffer = new uint8_t [BROTLI_BUFFER_SIZE];
192202 }
193203 translateBrotliBody (len, data);
194204 if (trailing_CRLF) { // End Entity
205+ delete this ->brotli_buffer ;
206+ this ->brotli_buffer = nullptr ;
195207 BrotliDecoderDestroyInstance (this ->brotli );
208+ this ->brotli = nullptr ;
196209 }
197210 break ;
198211 case DATA_ENCODING_AES128GCM: // AES encrypted with 128 bit Key in Galois/Counter Mode
@@ -220,7 +233,7 @@ void HTTP2_HalfStream::translateZipBody(int len, const char* data, int method)
220233{
221234 if (!zip){
222235 // We don't care about the direction here.
223- zip = new zip::ZIP_Analyzer (this ->analyzer ->Conn (), false ,
236+ zip = new zip::ZIP_Analyzer (this ->analyzer ->Conn (), false ,
224237 (zip::ZIP_Analyzer::Method) method);
225238 zip->SetOutputHandler (new UncompressedOutput (this ));
226239 }
@@ -230,21 +243,55 @@ void HTTP2_HalfStream::translateZipBody(int len, const char* data, int method)
230243void HTTP2_HalfStream::translateBrotliBody (int len, const char * data)
231244{
232245 BrotliDecoderResult result;
233- size_t total_out = 0 ;
246+ bool repeat;
247+ size_t bytes_decompressed;
234248 size_t available_in = len;
235249 const uint8_t * next_in = (const uint8_t *) data;
236- size_t available_out = MAX_FRAME_SIZE;
237- uint8_t *next_out = this ->brotli_buffer ;
238250
239- result = BrotliDecoderDecompressStream (this ->brotli ,
240- &available_in,
241- &next_in,
242- &available_out,
243- &next_out,
244- &total_out);
245- if (result == BROTLI_DECODER_RESULT_SUCCESS) {
246- DeliverBodyClear ((int )available_out, (const char *)this ->brotli_buffer , false );
247- }
251+ do {
252+ repeat = false ;
253+ size_t available_out = BROTLI_BUFFER_SIZE;
254+ uint8_t *next_out = this ->brotli_buffer ;
255+
256+ result = BrotliDecoderDecompressStream (
257+ this ->brotli , &available_in, &next_in,
258+ &available_out, &next_out, NULL );
259+
260+ bytes_decompressed = BROTLI_BUFFER_SIZE - available_out;
261+
262+ if (result == BROTLI_DECODER_RESULT_SUCCESS
263+ && available_in > 0 ) {
264+ this ->analyzer ->Weird (" Unexpected left-over bytes in brotli decompression" );
265+ }
266+
267+ switch (result) {
268+ case BROTLI_DECODER_RESULT_ERROR:
269+ {
270+ BrotliDecoderErrorCode code = BrotliDecoderGetErrorCode (this ->brotli );
271+ const char * error_string = BrotliDecoderErrorString (code);
272+ reporter->Error (" Brotli decoder error: %s" , error_string);
273+ break ;
274+ }
275+ case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
276+ // Set repeat so this sequence continues until all output data
277+ // is extracted
278+ repeat = true ;
279+ // Don't break -- let this fall through to the below case(s)
280+ case BROTLI_DECODER_RESULT_SUCCESS:
281+ case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
282+ {
283+ if (bytes_decompressed > 0 ) {
284+ DeliverBodyClear ((int )bytes_decompressed,
285+ (const char *)this ->brotli_buffer , false );
286+ }
287+ break ;
288+ }
289+ default :
290+ // Unexpected/undocumented result
291+ reporter->Warning (" Brotli decoder returned unexpected result" );
292+ break ;
293+ }
294+ } while (repeat);
248295}
249296
250297void HTTP2_HalfStream::processData (HTTP2_Data_Frame* data)
@@ -292,10 +339,10 @@ void HTTP2_OrigStream::handleFrame(HTTP2_Frame* frame)
292339 this ->Open_State (frame);
293340 break ;
294341 case HTTP2_STREAM_STATE_HALF_CLOSED:
295- this ->Open_State (frame);
342+ this ->Open_State (frame);
296343 break ;
297344 case HTTP2_STREAM_STATE_CLOSED:
298- this ->Closed_State (frame);
345+ this ->Closed_State (frame);
299346 break ;
300347 default :
301348 break ;
@@ -364,7 +411,7 @@ void HTTP2_OrigStream::ProcessHeaderBlock(HTTP2_Header_Frame_Base* header)
364411 if (name[0 ] == ' :' ) {
365412 // Determine if this is one of the Pseudo Headers
366413 if (name == " :authority" ) {
367- std::string token = value.substr (value.find (" @" ) + 1 , std::string::npos);
414+ std::string token = value.substr (value.find (" @" ) + 1 , std::string::npos);
368415 this ->request_host = token.substr (0 , token.find (" :" ));
369416 this ->request_authority = value;
370417 }
@@ -392,9 +439,9 @@ void HTTP2_OrigStream::ProcessHeaderBlock(HTTP2_Header_Frame_Base* header)
392439 this ->analyzer ->HTTP2_Header (this ->isOrig , this ->id , name, value);
393440 }
394441
395- // Retrieve the header info on a per header basis so that
396- // persistent header storage is only necessary if http2_all_headers
397- // is hooked.
442+ // Retrieve the header info on a per header basis so that
443+ // persistent header storage is only necessary if http2_all_headers
444+ // is hooked.
398445 extractDataInfoHeaders (name, value);
399446
400447 // Cache off if http2_all_headers is hooked.
@@ -448,12 +495,12 @@ void HTTP2_OrigStream::Idle_State(HTTP2_Frame* frame)
448495 if (http2_content_type) {
449496 if (this ->contentType .empty ()) {
450497 this ->contentType = " text/plain" ;
451- }
498+ }
452499 this ->analyzer ->HTTP2_ContentType (this ->isOrig , this ->id , this ->contentType );
453500 }
454501
455502 // Advanced the state to 'open'
456- this ->state = HTTP2_STREAM_STATE_OPEN;
503+ this ->state = HTTP2_STREAM_STATE_OPEN;
457504 } else { // expect continuation frames
458505
459506 }
@@ -463,7 +510,7 @@ void HTTP2_OrigStream::Idle_State(HTTP2_Frame* frame)
463510 // Advance the state and do some book-keeping
464511 this ->state = HTTP2_STREAM_STATE_HALF_CLOSED;
465512 this ->handleEndStream ();
466- }
513+ }
467514 break ;
468515 }
469516 case NGHTTP2_DATA:
@@ -569,10 +616,10 @@ void HTTP2_RespStream::handleFrame(HTTP2_Frame* frame)
569616 this ->Open_State (frame);
570617 break ;
571618 case HTTP2_STREAM_STATE_HALF_CLOSED:
572- this ->Open_State (frame);
619+ this ->Open_State (frame);
573620 break ;
574621 case HTTP2_STREAM_STATE_CLOSED:
575- this ->Closed_State (frame);
622+ this ->Closed_State (frame);
576623 break ;
577624 default :
578625 break ;
@@ -647,9 +694,9 @@ void HTTP2_RespStream::ProcessHeaderBlock(HTTP2_Header_Frame_Base* header)
647694 this ->analyzer ->HTTP2_Header (this ->isOrig , this ->id , name, value);
648695 }
649696
650- // Retrieve the header info on a per header basis so that
651- // persistent header storage is only necessary if http2_all_headers
652- // is hooked.
697+ // Retrieve the header info on a per header basis so that
698+ // persistent header storage is only necessary if http2_all_headers
699+ // is hooked.
653700 extractDataInfoHeaders (name, value);
654701
655702 // Cache off if http2_all_headers is hooked.
@@ -693,15 +740,15 @@ void HTTP2_RespStream::Idle_State(HTTP2_Frame* frame)
693740 this ->hlist .flushHeaders ();
694741 }
695742
696- this ->state = HTTP2_STREAM_STATE_OPEN;
743+ this ->state = HTTP2_STREAM_STATE_OPEN;
697744 } else { // expect continuation frames
698745
699746 }
700747
701748 if (header->isEndStream ()){
702749 this ->state = HTTP2_STREAM_STATE_HALF_CLOSED;
703750 this ->handleEndStream ();
704- }
751+ }
705752 break ;
706753 }
707754 case NGHTTP2_DATA:
@@ -781,7 +828,7 @@ void HTTP2_RespStream::Closed_State(HTTP2_Frame* frame)
781828}
782829
783830HTTP2_Stream::HTTP2_Stream (HTTP2_Analyzer* analyzer, uint32_t stream_id, nghttp2_hd_inflater* inflaters[2 ])
784- {
831+ {
785832 this ->id = stream_id;
786833 this ->inflaters [0 ] = inflaters[0 ];
787834 this ->inflaters [1 ] = inflaters[1 ];
@@ -826,9 +873,9 @@ bool HTTP2_Stream::handleFrame(HTTP2_Frame* f, bool orig) {
826873
827874 if (f->getType () == NGHTTP2_RST_STREAM){
828875 // TODO FIXME how to handle a rst stream frame
829- // -- spec specifies rst frame sender must be able to accept frames
830- // already in transit also priority frames can still be sent after a
831- // reset can either keep stream allocated to allow for processing of
876+ // -- spec specifies rst frame sender must be able to accept frames
877+ // already in transit also priority frames can still be sent after a
878+ // reset can either keep stream allocated to allow for processing of
832879 // frames after reset or ignore further frames
833880 this ->streamReset = true ;
834881 this ->streamResetter = orig;
0 commit comments