2 * ModSecurity for Apache 2.x, http://www.modsecurity.org/
3 * Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/)
5 * This product is released under the terms of the General Public Licence,
6 * version 2 (GPLv2). Please refer to the file LICENSE (included with this
7 * distribution) which contains the complete text of the licence.
9 * There are special exceptions to the terms and conditions of the GPL
10 * as it is applied to this software. View the full text of the exception in
11 * file MODSECURITY_LICENSING_EXCEPTION in the directory of this software
14 * If any of the files related to licensing are missing or if you have any
15 * other questions related to licensing please contact Breach Security, Inc.
16 * directly using the email address support@breach.com.
19 #include "modsecurity.h"
20 #include "msc_parsers.h"
22 #define CHUNK_CAPACITY 8192
25 * Prepare to accept the request body (part 2).
27 static apr_status_t modsecurity_request_body_start_init(modsec_rec *msr, char **error_msg) {
30 if(msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
31 /* Prepare to store request body in memory. */
33 msr->msc_reqbody_chunks = apr_array_make(msr->msc_reqbody_mp,
34 32, sizeof(msc_data_chunk *));
35 if (msr->msc_reqbody_chunks == NULL) {
36 *error_msg = apr_pstrdup(msr->mp, "Input filter: Failed to prepare in-memory storage.");
40 /* Prepare to store request body on disk. */
42 msr->msc_reqbody_filename = apr_psprintf(msr->mp, "%s/%s-%s-request_body-XXXXXX",
43 msr->txcfg->tmp_dir, current_filetime(msr->mp), msr->txid);
44 if (msr->msc_reqbody_filename == NULL) {
45 *error_msg = apr_pstrdup(msr->mp, "Input filter: Failed to generate an on-disk filename.");
49 msr->msc_reqbody_fd = msc_mkstemp((char *)msr->msc_reqbody_filename);
50 if (msr->msc_reqbody_fd < 0) {
51 *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to create temporary file: %s",
52 msr->msc_reqbody_filename);
56 msr_log(msr, 4, "Input filter: Created temporary file to store request body: %s",
57 msr->msc_reqbody_filename);
64 * Prepare to accept the request body (part 1).
66 apr_status_t modsecurity_request_body_start(modsec_rec *msr, char **error_msg) {
68 msr->msc_reqbody_length = 0;
70 /* Create a separate memory pool that will be used
71 * to allocate structures from (not data, which is allocated
74 apr_pool_create(&msr->msc_reqbody_mp, NULL);
76 /* Initialise request body processors, if any. */
78 if (msr->msc_reqbody_processor != NULL) {
79 char *my_error_msg = NULL;
81 if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
82 if (multipart_init(msr, &my_error_msg) < 0) {
83 *error_msg = apr_psprintf(msr->mp, "Multipart parsing error (init): %s", my_error_msg);
84 msr->msc_reqbody_error = 1;
85 msr->msc_reqbody_error_msg = my_error_msg;
86 msr_log(msr, 2, "%s", *error_msg);
90 if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
91 if (xml_init(msr, &my_error_msg) < 0) {
92 *error_msg = apr_psprintf(msr->mp, "XML parsing error (init): %s", my_error_msg);
93 msr->msc_reqbody_error = 1;
94 msr->msc_reqbody_error_msg = my_error_msg;
95 msr_log(msr, 2, "%s", *error_msg);
99 if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
100 /* Do nothing, URLENCODED processor does not support streaming yet. */
103 *error_msg = apr_psprintf(msr->mp, "Unknown request body processor: %s",
104 msr->msc_reqbody_processor);
109 return modsecurity_request_body_start_init(msr, error_msg);
113 * Stores a chunk of request body data to disk.
115 static apr_status_t modsecurity_request_body_store_disk(modsec_rec *msr,
116 const char *data, apr_size_t length, char **error_msg)
122 i = write(msr->msc_reqbody_fd, data, length);
124 *error_msg = apr_psprintf(msr->mp, "Input filter: Failed writing %" APR_SIZE_T_FMT
125 " bytes to temporary file (rc %" APR_SIZE_T_FMT ").", length, i);
133 * Stores one chunk of request body data in memory.
135 static apr_status_t modsecurity_request_body_store_memory(modsec_rec *msr,
136 const char *data, apr_size_t length, char **error_msg)
140 /* Would storing this chunk mean going over the limit? */
141 if ((msr->msc_reqbody_spilltodisk)
142 && (msr->msc_reqbody_length + length > (apr_size_t)msr->txcfg->reqbody_inmemory_limit))
144 msc_data_chunk **chunks;
145 unsigned int disklen = 0;
148 msr_log(msr, 4, "Input filter: Request too large to store in memory, switching to disk.");
150 /* NOTE Must use modsecurity_request_body_store_disk() here
151 * to prevent data to be sent to the streaming
155 /* Initialise disk storage */
156 msr->msc_reqbody_storage = MSC_REQBODY_DISK;
157 if (modsecurity_request_body_start_init(msr, error_msg) < 0) return -1;
159 /* Write the data we keep in memory */
160 chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
161 for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
162 disklen += chunks[i]->length;
164 if (modsecurity_request_body_store_disk(msr, chunks[i]->data, chunks[i]->length, error_msg) < 0) {
168 free(chunks[i]->data);
169 chunks[i]->data = NULL;
172 /* Clear the memory pool as we no longer need the bits. */
174 /* IMP1 But since we only used apr_pool_clear memory might
175 * not be released back to the OS straight away?
177 msr->msc_reqbody_chunks = NULL;
178 apr_pool_clear(msr->msc_reqbody_mp);
180 msr_log(msr, 4, "Input filter: Wrote %u bytes from memory to disk.", disklen);
182 /* Continue with disk storage from now on */
183 return modsecurity_request_body_store_disk(msr, data, length, error_msg);
186 /* If we're here that means we are not over the
187 * request body in-memory limit yet.
190 unsigned long int bucket_offset, bucket_left;
193 bucket_left = length;
195 /* Although we store the request body in chunks we don't
196 * want to use the same chunk sizes as the incoming memory
197 * buffers. They are often of very small sizes and that
198 * would make us waste a lot of memory. That's why we
199 * use our own chunks of CHUNK_CAPACITY sizes.
202 /* Loop until we empty this bucket into our chunks. */
203 while(bucket_left > 0) {
204 /* Allocate a new chunk if we have to. */
205 if (msr->msc_reqbody_chunk_current == NULL) {
206 msr->msc_reqbody_chunk_current = (msc_data_chunk *)
207 apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
208 if (msr->msc_reqbody_chunk_current == NULL) {
209 *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to allocate %lu bytes "
210 "for request body chunk.", (unsigned long)sizeof(msc_data_chunk));
214 msr->msc_reqbody_chunk_current->data = malloc(CHUNK_CAPACITY);
215 if (msr->msc_reqbody_chunk_current->data == NULL) {
216 *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to allocate %d bytes "
217 "for request body chunk data.", CHUNK_CAPACITY);
221 msr->msc_reqbody_chunk_current->length = 0;
222 msr->msc_reqbody_chunk_current->is_permanent = 1;
224 *(const msc_data_chunk **)apr_array_push(msr->msc_reqbody_chunks)
225 = msr->msc_reqbody_chunk_current;
228 if (bucket_left < (CHUNK_CAPACITY - msr->msc_reqbody_chunk_current->length)) {
229 /* There's enough space in the current chunk. */
230 memcpy(msr->msc_reqbody_chunk_current->data +
231 msr->msc_reqbody_chunk_current->length, data + bucket_offset, bucket_left);
232 msr->msc_reqbody_chunk_current->length += bucket_left;
235 /* Fill the existing chunk. */
236 unsigned long int copy_length = CHUNK_CAPACITY -
237 msr->msc_reqbody_chunk_current->length;
239 memcpy(msr->msc_reqbody_chunk_current->data +
240 msr->msc_reqbody_chunk_current->length, data + bucket_offset, copy_length);
241 bucket_offset += copy_length;
242 bucket_left -= copy_length;
243 msr->msc_reqbody_chunk_current->length += copy_length;
245 /* We're done with this chunk. Setting the pointer
246 * to NULL is going to force a new chunk to be allocated
249 msr->msc_reqbody_chunk_current = NULL;
253 msr->msc_reqbody_length += length;
260 * Stores one chunk of request body data. Returns -1 on error.
262 apr_status_t modsecurity_request_body_store(modsec_rec *msr,
263 const char *data, apr_size_t length, char **error_msg)
267 /* If we have a processor for this request body send
268 * data to it first (but only if it did not report an
269 * error on previous invocations).
271 if ((msr->msc_reqbody_processor != NULL)&&(msr->msc_reqbody_error == 0)) {
272 char *my_error_msg = NULL;
274 if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
275 /* The per-request data length counter will
276 * be updated by the multipart parser.
279 /* Process data as multipart/form-data. */
280 if (multipart_process_chunk(msr, data, length, &my_error_msg) < 0) {
281 *error_msg = apr_psprintf(msr->mp, "Multipart parsing error: %s", my_error_msg);
282 msr->msc_reqbody_error = 1;
283 msr->msc_reqbody_error_msg = *error_msg;
284 msr_log(msr, 2, "%s", *error_msg);
288 if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
289 /* Increase per-request data length counter. */
290 msr->msc_reqbody_no_files_length += length;
292 /* Process data as XML. */
293 if (xml_process_chunk(msr, data, length, &my_error_msg) < 0) {
294 *error_msg = apr_psprintf(msr->mp, "XML parsing error: %s", my_error_msg);
295 msr->msc_reqbody_error = 1;
296 msr->msc_reqbody_error_msg = *error_msg;
297 msr_log(msr, 2, "%s", *error_msg);
301 if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
302 /* Increase per-request data length counter. */
303 msr->msc_reqbody_no_files_length += length;
305 /* Do nothing else, URLENCODED processor does not support streaming. */
308 *error_msg = apr_psprintf(msr->mp, "Unknown request body processor: %s",
309 msr->msc_reqbody_processor);
312 } else if (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_OFF) {
313 /* Increase per-request data length counter if forcing buffering. */
314 msr->msc_reqbody_no_files_length += length;
317 /* Check that we are not over the request body no files limit. */
318 if (msr->msc_reqbody_no_files_length >= (unsigned long) msr->txcfg->reqbody_no_files_limit) {
323 if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
324 return modsecurity_request_body_store_memory(msr, data, length, error_msg);
327 if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
328 return modsecurity_request_body_store_disk(msr, data, length, error_msg);
331 /* Should never happen. */
332 *error_msg = apr_psprintf(msr->mp, "Internal error, unknown value for msc_reqbody_storage: %u",
333 msr->msc_reqbody_storage);
338 * Replace a bunch of chunks holding a request body with a single large chunk.
340 static apr_status_t modsecurity_request_body_end_raw(modsec_rec *msr, char **error_msg) {
341 msc_data_chunk **chunks, *one_chunk;
347 /* Allocate a buffer large enough to hold the request body. */
349 if (msr->msc_reqbody_length + 1 == 0) {
350 *error_msg = apr_psprintf(msr->mp, "Internal error, request body length will overflow: %u",
351 msr->msc_reqbody_length);
355 msr->msc_reqbody_buffer = malloc(msr->msc_reqbody_length + 1);
356 if (msr->msc_reqbody_buffer == NULL) {
357 *error_msg = apr_psprintf(msr->mp, "Unable to allocate memory to hold request body. Asked for %u bytes.",
358 msr->msc_reqbody_length + 1);
362 msr->msc_reqbody_buffer[msr->msc_reqbody_length] = '\0';
364 /* Copy the data we keep in chunks into the new buffer. */
367 d = msr->msc_reqbody_buffer;
368 chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
369 for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
370 if (sofar + chunks[i]->length <= msr->msc_reqbody_length) {
371 memcpy(d, chunks[i]->data, chunks[i]->length);
372 d += chunks[i]->length;
373 sofar += chunks[i]->length;
375 *error_msg = apr_psprintf(msr->mp, "Internal error, request body buffer overflow.");
380 /* Now free the memory used by the chunks. */
382 chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
383 for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
384 free(chunks[i]->data);
385 chunks[i]->data = NULL;
388 /* Create a new array with only one chunk in it. */
390 msr->msc_reqbody_chunks = apr_array_make(msr->msc_reqbody_mp, 2, sizeof(msc_data_chunk *));
391 if (msr->msc_reqbody_chunks == NULL) {
392 *error_msg = apr_pstrdup(msr->mp, "Failed to create structure to hold request body.");
396 one_chunk = (msc_data_chunk *)apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
397 one_chunk->data = msr->msc_reqbody_buffer;
398 one_chunk->length = msr->msc_reqbody_length;
399 one_chunk->is_permanent = 1;
400 *(const msc_data_chunk **)apr_array_push(msr->msc_reqbody_chunks) = one_chunk;
408 static apr_status_t modsecurity_request_body_end_urlencoded(modsec_rec *msr, char **error_msg) {
409 int invalid_count = 0;
413 /* Create the raw buffer */
414 if (modsecurity_request_body_end_raw(msr, error_msg) != 1) {
418 /* Parse URL-encoded arguments in the request body. */
420 if (parse_arguments(msr, msr->msc_reqbody_buffer, msr->msc_reqbody_length,
421 msr->txcfg->argument_separator, "BODY", msr->arguments, &invalid_count) < 0)
423 *error_msg = apr_pstrdup(msr->mp, "Initialisation: Error occurred while parsing BODY arguments.");
431 * Stops receiving the request body.
433 apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) {
436 /* Close open file descriptors, if any. */
437 if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
438 if (msr->msc_reqbody_fd > 0) {
439 close(msr->msc_reqbody_fd);
440 msr->msc_reqbody_fd = -1;
444 /* Note that we've read the body. */
445 msr->msc_reqbody_read = 1;
447 /* Finalise body processing. */
448 if ((msr->msc_reqbody_processor != NULL)&&(msr->msc_reqbody_error == 0)) {
449 char *my_error_msg = NULL;
451 if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
452 if (multipart_complete(msr, &my_error_msg) < 0) {
453 *error_msg = apr_psprintf(msr->mp, "Multipart parsing error: %s", my_error_msg);
454 msr->msc_reqbody_error = 1;
455 msr->msc_reqbody_error_msg = *error_msg;
456 msr_log(msr, 2, "%s", *error_msg);
460 if (multipart_get_arguments(msr, "BODY", msr->arguments) < 0) {
461 *error_msg = "Multipart parsing error: Failed to retrieve arguments.";
462 msr->msc_reqbody_error = 1;
463 msr->msc_reqbody_error_msg = *error_msg;
464 msr_log(msr, 2, "%s", *error_msg);
469 if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
470 return modsecurity_request_body_end_urlencoded(msr, error_msg);
473 if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
474 if (xml_complete(msr, &my_error_msg) < 0) {
475 *error_msg = apr_psprintf(msr->mp, "XML parser error: %s", my_error_msg);
476 msr->msc_reqbody_error = 1;
477 msr->msc_reqbody_error_msg = *error_msg;
478 msr_log(msr, 2, "%s", *error_msg);
482 } else if (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_OFF) {
483 /* Convert to a single continous buffer, but don't do anything else. */
484 return modsecurity_request_body_end_raw(msr, error_msg);
487 /* Note the request body no files length. */
488 msr_log(msr, 4, "Reqest body no files length: %" APR_SIZE_T_FMT, msr->msc_reqbody_no_files_length);
494 * Prepares to forward the request body.
496 apr_status_t modsecurity_request_body_retrieve_start(modsec_rec *msr, char **error_msg) {
499 if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
500 msr->msc_reqbody_chunk_position = 0;
501 msr->msc_reqbody_chunk_offset = 0;
503 msr->msc_reqbody_disk_chunk = apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
504 if (msr->msc_reqbody_disk_chunk == NULL) {
505 *error_msg = apr_psprintf(msr->mp, "Failed to allocate %lu bytes for request body disk chunk.",
506 (unsigned long)sizeof(msc_data_chunk));
509 msr->msc_reqbody_disk_chunk->is_permanent = 1;
512 if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
513 msr->msc_reqbody_disk_chunk = apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
514 if (msr->msc_reqbody_disk_chunk == NULL) {
515 *error_msg = apr_psprintf(msr->mp, "Failed to allocate %lu bytes for request body disk chunk.",
516 (unsigned long)sizeof(msc_data_chunk));
520 msr->msc_reqbody_disk_chunk->is_permanent = 0;
521 msr->msc_reqbody_disk_chunk->data = apr_palloc(msr->msc_reqbody_mp, CHUNK_CAPACITY);
522 if (msr->msc_reqbody_disk_chunk->data == NULL) {
523 *error_msg = apr_psprintf(msr->mp, "Failed to allocate %d bytes for request body disk chunk data.",
528 msr->msc_reqbody_fd = open(msr->msc_reqbody_filename, O_RDONLY | O_BINARY);
529 if (msr->msc_reqbody_fd < 0) {
530 *error_msg = apr_psprintf(msr->mp, "Failed to open temporary file for reading: %s",
531 msr->msc_reqbody_filename);
542 apr_status_t modsecurity_request_body_retrieve_end(modsec_rec *msr) {
543 if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
544 if (msr->msc_reqbody_fd > 0) {
545 close(msr->msc_reqbody_fd);
546 msr->msc_reqbody_fd = -1;
554 * Returns one chunk of request body data. It stores a NULL
555 * in the chunk pointer when there is no data to return. The
556 * return code is 1 if more calls can be made to retrieve more
557 * data, 0 if there is no more data to retrieve, or -1 on error.
559 * The caller can limit the amount of data returned by providing
560 * a non-negative value in nbytes.
562 apr_status_t modsecurity_request_body_retrieve(modsec_rec *msr,
563 msc_data_chunk **chunk, long int nbytes, char **error_msg)
565 msc_data_chunk **chunks;
570 *error_msg = apr_pstrdup(msr->mp, "Internal error, retrieving request body chunk.");
575 if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
576 /* Are there any chunks left? */
577 if (msr->msc_reqbody_chunk_position >= msr->msc_reqbody_chunks->nelts) {
578 /* No more chunks. */
582 /* We always respond with the same chunk, just different information in it. */
583 *chunk = msr->msc_reqbody_disk_chunk;
585 /* Advance to the current chunk and position on the
586 * next byte we need to send.
588 chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
589 msr->msc_reqbody_disk_chunk->data = chunks[msr->msc_reqbody_chunk_position]->data
590 + msr->msc_reqbody_chunk_offset;
593 /* Send what's left in this chunk as there is no limit on the size. */
594 msr->msc_reqbody_disk_chunk->length = chunks[msr->msc_reqbody_chunk_position]->length;
595 msr->msc_reqbody_chunk_position++;
596 msr->msc_reqbody_chunk_offset = 0;
598 /* We have a limit we must obey. */
600 if (chunks[msr->msc_reqbody_chunk_position]->length -
601 msr->msc_reqbody_chunk_offset <= (unsigned int)nbytes)
603 /* If what's left in our chunk is less than the limit
604 * then send it all back.
606 msr->msc_reqbody_disk_chunk->length =
607 chunks[msr->msc_reqbody_chunk_position]->length -
608 msr->msc_reqbody_chunk_offset;
609 msr->msc_reqbody_chunk_position++;
610 msr->msc_reqbody_chunk_offset = 0;
612 /* If we have more data in our chunk, send the
613 * maximum bytes we can (nbytes).
615 msr->msc_reqbody_disk_chunk->length = nbytes;
616 msr->msc_reqbody_chunk_offset += nbytes;
620 /* If we've advanced beyond our last chunk then
621 * we have no more data to send.
623 if (msr->msc_reqbody_chunk_position >= msr->msc_reqbody_chunks->nelts) {
624 return 0; /* No more chunks. */
627 /* More data available. */
631 if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
632 long int my_nbytes = CHUNK_CAPACITY;
635 /* Send CHUNK_CAPACITY bytes at a time unless a lower limit was requested. */
636 if ((nbytes != -1)&&(my_nbytes > nbytes)) {
640 i = read(msr->msc_reqbody_fd, msr->msc_reqbody_disk_chunk->data, my_nbytes);
642 *error_msg = apr_psprintf(msr->mp, "Input filter: Error reading from temporary file: %s",
647 *chunk = msr->msc_reqbody_disk_chunk;
648 msr->msc_reqbody_disk_chunk->length = i;
650 if (i == 0) return 0; /* No more data available. */
652 return 1; /* More data available. */
655 /* Should never happen. */
656 *error_msg = apr_psprintf(msr->mp, "Internal error, invalid msc_reqbody_storage value: %u",
657 msr->msc_reqbody_storage);
665 apr_status_t modsecurity_request_body_clear(modsec_rec *msr, char **error_msg) {
668 /* Release memory we used to store request body data. */
669 if (msr->msc_reqbody_chunks != NULL) {
670 msc_data_chunk **chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
673 for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
674 if (chunks[i]->data != NULL) {
675 free(chunks[i]->data);
676 chunks[i]->data = NULL;
681 if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
684 /* Should we keep the body? This normally
685 * happens when a PUT method was used, which
686 * means the body is actually a file.
688 if ((msr->upload_remove_files == 0)&&(strcasecmp(msr->request_method, "PUT") == 0)) {
689 if (msr->txcfg->upload_dir != NULL) {
692 *error_msg = apr_psprintf(msr->mp, "Input filter: SecUploadDir is undefined, "
693 "unable to store PUT file.");
697 /* Deal with a request body stored in a file. */
699 if (msr->msc_reqbody_filename != NULL) {
701 /* Move request body (which is a file) to the storage area. */
702 const char *put_filename = NULL;
703 const char *put_basename = NULL;
705 /* Construct the new filename. */
706 put_basename = file_basename(msr->msc_reqbody_mp, msr->msc_reqbody_filename);
707 if (put_basename == NULL) {
708 *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to generate basename to PUT file \"%s\"", log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename));
711 put_filename = apr_psprintf(msr->msc_reqbody_mp, "%s/%s",
712 msr->txcfg->upload_dir, put_basename);
713 if (put_filename == NULL) {
714 *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to generate filename to PUT file \"%s\"", log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename));
718 if (apr_file_rename(msr->msc_reqbody_filename, put_filename,
719 msr->msc_reqbody_mp) != APR_SUCCESS)
721 *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to rename file from \"%s\" to \"%s\".",
722 log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename),
723 log_escape(msr->msc_reqbody_mp, put_filename));
726 msr_log(msr, 4, "Input filter: Moved file from \"%s\" to \"%s\".",
727 log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename),
728 log_escape(msr->msc_reqbody_mp, put_filename));
731 /* make sure it is closed first */
732 if (msr->msc_reqbody_fd > 0) {
733 close(msr->msc_reqbody_fd);
734 msr->msc_reqbody_fd = -1;
737 /* We do not want to keep the request body. */
738 if (apr_file_remove(msr->msc_reqbody_filename,
739 msr->msc_reqbody_mp) != APR_SUCCESS)
741 *error_msg = apr_psprintf(msr->mp, "Input filter: Failed to delete temporary file: %s",
742 log_escape(msr->mp, msr->msc_reqbody_filename));
746 msr_log(msr, 4, "Input filter: Removed temporary file: %s",
747 msr->msc_reqbody_filename);
750 msr->msc_reqbody_filename = NULL;
754 if (msr->msc_reqbody_mp != NULL) {
755 apr_pool_destroy(msr->msc_reqbody_mp);
756 msr->msc_reqbody_mp = NULL;