Skip to content

Commit 86adee1

Browse files
committed
Preallocate memory when SecStreamInBodyInspection is on. 20x speed improvement for 10mb upload. Also simplified modsecurity_request_body_to_stream.
1 parent b878ece commit 86adee1

File tree

5 files changed

+53
-44
lines changed

5 files changed

+53
-44
lines changed

apache2/apache2_io.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,6 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) {
281281
}
282282

283283
if (msr->txcfg->stream_inbody_inspection == 1) {
284-
msr->stream_input_length+=buflen;
285284
modsecurity_request_body_to_stream(msr, buf, buflen, error_msg);
286285
}
287286

apache2/modsecurity.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ struct modsec_rec {
287287
unsigned int resbody_contains_html;
288288

289289
apr_size_t stream_input_length;
290+
apr_size_t stream_input_allocated_length;
290291
char *stream_input_data;
291292
apr_size_t stream_output_length;
292293
char *stream_output_data;

apache2/msc_reqbody.c

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -428,55 +428,62 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr,
428428
}
429429

430430
apr_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;
432+
char* allocated;
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 is known beforehand? (requests that are not Transfer-Encoding: chunked)
436+
if (msr->request_content_length > 0) {
437+
allocate = msr->request_content_length;
438+
}
439+
else {
440+
// 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)
441+
allocate = buflen;
442+
}
442443

443-
if(data == NULL)
444+
allocated = (char*) calloc(allocate, sizeof(char));
445+
if (allocated) {
446+
msr->stream_input_data = allocated;
447+
msr->stream_input_allocated_length = allocate;
448+
}
449+
else {
450+
*error_msg = apr_psprintf(
451+
msr->mp,
452+
"Unable to allocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes.",
453+
allocate);
444454
return -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;
458455
}
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;
462456
}
457+
else {
458+
// Do we need to expand the space we have previously allocated?
459+
if ((msr->stream_input_length + buflen) > msr->stream_input_allocated_length) {
463460

464-
memset(msr->stream_input_data, 0, msr->stream_input_length+1);
461+
// If this becomes a hotspot again, consider increasing by some percent extra each time, for fewer reallocs
462+
allocate = msr->stream_input_length + buflen;
465463

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);
464+
allocated = (char*) realloc(msr->stream_input_data, allocate);
465+
if (allocated) {
466+
msr->stream_input_data = allocated;
467+
msr->stream_input_allocated_length = allocate;
468+
}
469+
else {
470+
*error_msg = apr_psprintf(
471+
msr->mp,
472+
"Unable to reallocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes.",
473+
allocate);
474+
free(msr->stream_input_data);
475+
return -1;
476+
}
477+
}
471478
}
472479

473-
if(data) {
474-
free(data);
475-
data = NULL;
476-
}
480+
// Append buffer to msr->stream_input_data
481+
memcpy(msr->stream_input_data + msr->stream_input_length, buffer, buflen);
482+
msr->stream_input_length += buflen;
477483

478484
return 1;
479485
}
486+
480487
/**
481488
* Replace a bunch of chunks holding a request body with a single large chunk.
482489
*/
@@ -884,15 +891,15 @@ apr_status_t modsecurity_request_body_clear(modsec_rec *msr, char **error_msg) {
884891

885892
if (msr->msc_reqbody_filename != NULL) {
886893
if (keep_body) {
887-
/* Move request body (which is a file) to the storage area. */
888-
const char *put_filename = NULL;
889-
const char *put_basename = NULL;
890-
891894
if (strcmp(msr->txcfg->upload_dir, msr->txcfg->tmp_dir) == 0) {
892895
msr_log(msr, 4, "Not moving file to identical location.");
893896
goto nullify;
894897
}
895898

899+
/* Move request body (which is a file) to the storage area. */
900+
const char *put_filename = NULL;
901+
const char *put_basename = NULL;
902+
896903
/* Construct the new filename. */
897904
put_basename = file_basename(msr->msc_reqbody_mp, msr->msc_reqbody_filename);
898905
if (put_basename == NULL) {

apache2/re_operators.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,7 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
634634
free(msr->stream_input_data);
635635
msr->stream_input_data = NULL;
636636
msr->stream_input_length = 0;
637+
msr->stream_input_allocated_length = 0;
637638

638639
msr->stream_input_data = (char *)malloc(size+1);
639640

@@ -642,7 +643,8 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
642643
}
643644

644645
msr->stream_input_length = size;
645-
memset(msr->stream_input_data, 0x0, size+1);
646+
msr->stream_input_allocated_length = size + 1;
647+
memset(msr->stream_input_data, 0x0, size + 1);
646648

647649
msr->if_stream_changed = 1;
648650

iis/dependencies/build_yajl.bat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ copy /y "%WORK_DIR%\yajl\build\%YAJL_DIR%\lib\yajl_s.lib" "%OUTPUT_DIR%"
2828
@exit /B 0
2929

3030
:file_not_found_bin
31-
@echo File not found: "%SOURCE_DIR%\%PCRE%"
31+
@echo File not found: "%SOURCE_DIR%\%YAJL%"
3232
@goto failed
3333

3434
:build_failed

0 commit comments

Comments
 (0)