@@ -428,55 +428,66 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr,
428428}
429429
430430apr_status_t modsecurity_request_body_to_stream (modsec_rec * msr ,const char * buffer ,int buflen ,char * * error_msg ) {
431- char * stream_input_body = NULL ;
432- char * data = NULL ;
433- int first_pkt = 0 ;
431+ apr_size_t allocate_length = 0 ;
432+ char * allocated = NULL ;
434433
435- if (msr -> stream_input_data == NULL ) {
436- msr -> stream_input_data = (char * )calloc (sizeof (char ),msr -> stream_input_length + 1 );
437- first_pkt = 1 ;
438- }
439- else {
440-
441- data = (char * )malloc (msr -> stream_input_length + 1 - buflen );
434+ if (msr -> stream_input_data == NULL ) {
435+ // Is the request body length known beforehand? (requests that are not Transfer-Encoding: chunked)
436+ if (msr -> request_content_length > 0 ) {
437+ // Use min of Content-Length and SecRequestBodyLimit
438+ allocate_length = min (msr -> request_content_length ,msr -> txcfg -> reqbody_limit );
439+ }
440+ else {
441+ // We don't know how this request is going to be, so hope for just buflen to begin with (requests that are Transfer-Encoding: chunked)
442+ allocate_length = buflen ;
443+ }
442444
443- if (data == NULL )
445+ allocated = (char * )calloc (allocate_length ,sizeof (char ));
446+ if (allocated ) {
447+ msr -> stream_input_data = allocated ;
448+ msr -> stream_input_allocated_length = allocate_length ;
449+ }
450+ else {
451+ * error_msg = apr_psprintf (
452+ msr -> mp ,
453+ "Unable to allocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes." ,
454+ allocate_length );
444455return -1 ;
445-
446- memset (data ,0 ,msr -> stream_input_length + 1 - buflen );
447- memcpy (data ,msr -> stream_input_data ,msr -> stream_input_length - buflen );
448-
449- stream_input_body = (char * )realloc (msr -> stream_input_data ,msr -> stream_input_length + 1 );
450-
451- msr -> stream_input_data = (char * )stream_input_body ;
452- }
453-
454- if (msr -> stream_input_data == NULL ) {
455- if (data ) {
456- free (data );
457- data = NULL ;
458456 }
459- * error_msg = apr_psprintf (msr -> mp ,"Unable to allocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes." ,
460- msr -> stream_input_length + 1 );
461- return -1 ;
462457 }
458+ else {
459+ // Do we need to expand the space we have previously allocated?
460+ if ((msr -> stream_input_length + buflen )> msr -> stream_input_allocated_length ) {
463461
464- memset (msr -> stream_input_data ,0 ,msr -> stream_input_length + 1 );
462+ // If this becomes a hotspot again, consider increasing by some percent extra each time, for fewer reallocs
463+ allocate_length = msr -> stream_input_length + buflen ;
465464
466- if (first_pkt ) {
467- memcpy (msr -> stream_input_data ,buffer ,msr -> stream_input_length );
468- }else {
469- memcpy (msr -> stream_input_data ,data ,msr -> stream_input_length - buflen );
470- memcpy (msr -> stream_input_data + (msr -> stream_input_length - buflen ),buffer ,buflen );
465+ allocated = (char * )realloc (msr -> stream_input_data ,allocate_length );
466+ if (allocated ) {
467+ msr -> stream_input_data = allocated ;
468+ msr -> stream_input_allocated_length = allocate_length ;
469+ }
470+ else {
471+ * error_msg = apr_psprintf (
472+ msr -> mp ,
473+ "Unable to reallocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes." ,
474+ allocate_length );
475+ free (msr -> stream_input_data );
476+ msr -> stream_input_data = NULL ;
477+ msr -> stream_input_length = 0 ;
478+ msr -> stream_input_allocated_length = 0 ;
479+ return -1 ;
480+ }
481+ }
471482 }
472483
473- if (data ) {
474- free (data );
475- data = NULL ;
476- }
484+ // Append buffer to msr->stream_input_data
485+ memcpy (msr -> stream_input_data + msr -> stream_input_length ,buffer ,buflen );
486+ msr -> stream_input_length += buflen ;
477487
478488return 1 ;
479489}
490+
480491/**
481492 * Replace a bunch of chunks holding a request body with a single large chunk.
482493 */