in modules/fcgid/fcgid_bridge.c [528:736]
static int add_request_body(request_rec *r, apr_pool_t *request_pool,
apr_bucket_brigade *output_brigade,
apr_off_t *body_length)
{
apr_bucket *bucket_input, *bucket_header;
apr_file_t *fd = NULL;
apr_off_t cur_pos = 0, request_size = 0;
apr_status_t rv;
FCGI_Header *stdin_request_header;
fcgid_server_conf *sconf = ap_get_module_config(r->server->module_config,
&fcgid_module);
int seen_eos = 0;
/* Stdin header and body */
/* I have to read all the request into memory before sending it
to fastcgi application server, this prevents slow clients from
keeping the server in processing too long.
But sometimes it's not acceptable (think about uploading a large attachment)
Request will be stored in tmp file if the size larger than max_mem_request_len
*/
apr_bucket_brigade *input_brigade = apr_brigade_create(request_pool,
r->connection->
bucket_alloc);
apr_bucket_brigade *tmp_brigade = apr_brigade_create(request_pool,
r->connection->
bucket_alloc);
do {
int loop_counter = 0;
if ((rv = ap_get_brigade(r->input_filters, input_brigade,
AP_MODE_READBYTES,
APR_BLOCK_READ,
HUGE_STRING_LEN)) != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r,
"mod_fcgid: can't get data from http client");
apr_brigade_destroy(output_brigade);
apr_brigade_destroy(tmp_brigade);
apr_brigade_destroy(input_brigade);
return HTTP_INTERNAL_SERVER_ERROR;
}
while ((bucket_input = APR_BRIGADE_FIRST(input_brigade)) != APR_BRIGADE_SENTINEL(input_brigade)) {
const char *data;
apr_size_t len;
apr_bucket *bucket_stdin;
++loop_counter;
if ((loop_counter % FCGID_BRIGADE_CLEAN_STEP) == 0) {
apr_brigade_cleanup(tmp_brigade);
}
APR_BUCKET_REMOVE(bucket_input);
APR_BRIGADE_INSERT_TAIL(tmp_brigade, bucket_input);
if (APR_BUCKET_IS_EOS(bucket_input)) {
seen_eos = 1;
break;
}
if (APR_BUCKET_IS_METADATA(bucket_input))
continue;
if ((rv = apr_bucket_read(bucket_input, &data, &len,
APR_BLOCK_READ)) != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r,
"mod_fcgid: can't read request from HTTP client");
apr_brigade_destroy(input_brigade);
apr_brigade_destroy(tmp_brigade);
apr_brigade_destroy(output_brigade);
return HTTP_INTERNAL_SERVER_ERROR;
}
/* Append a header, and the the bucket */
stdin_request_header = apr_bucket_alloc(sizeof(FCGI_Header),
r->connection->
bucket_alloc);
bucket_header =
apr_bucket_heap_create((const char *) stdin_request_header,
sizeof(*stdin_request_header),
apr_bucket_free,
r->connection->bucket_alloc);
request_size += len;
if (request_size > sconf->max_request_len) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
"mod_fcgid: HTTP request length %" APR_OFF_T_FMT
" (so far) exceeds MaxRequestLen (%"
APR_OFF_T_FMT ")", request_size,
sconf->max_request_len);
return HTTP_INTERNAL_SERVER_ERROR;
}
if (request_size > sconf->max_mem_request_len) {
apr_size_t wrote_len;
static const char *fd_key = "fcgid_fd";
if (fd == NULL) {
void *tmp;
apr_pool_userdata_get(&tmp, fd_key, r->connection->pool);
fd = tmp;
if (fd != NULL) {
if ((rv = apr_file_trunc(fd, 0)) != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r,
"mod_fcgid: can't truncate existing "
"temporary file");
return HTTP_INTERNAL_SERVER_ERROR;
}
}
}
if (fd == NULL) {
const char *tempdir = NULL;
char *template;
rv = apr_temp_dir_get(&tempdir, r->pool);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r,
"mod_fcgid: can't get tmp dir");
return HTTP_INTERNAL_SERVER_ERROR;
}
apr_filepath_merge(&template, tempdir,
"fcgid.tmp.XXXXXX",
APR_FILEPATH_NATIVE, r->pool);
rv = apr_file_mktemp(&fd, template, 0,
r->connection->pool);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r,
"mod_fcgid: can't open tmp file fot stdin request");
return HTTP_INTERNAL_SERVER_ERROR;
}
apr_pool_userdata_set((const void *) fd, fd_key,
apr_pool_cleanup_null,
r->connection->pool);
}
/* Write request to tmp file */
if ((rv =
apr_file_write_full(fd, (const void *) data, len,
&wrote_len)) != APR_SUCCESS
|| len != wrote_len) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING,
rv, r,
"mod_fcgid: can't write tmp file for stdin request");
return HTTP_INTERNAL_SERVER_ERROR;
}
/* Create file bucket */
bucket_stdin =
apr_bucket_file_create(fd, cur_pos, len, r->pool,
r->connection->bucket_alloc);
cur_pos += len;
}
else {
if (APR_BUCKET_IS_HEAP(bucket_input))
apr_bucket_copy(bucket_input, &bucket_stdin);
else {
/* mod_ssl have a bug? */
char *pcopydata =
apr_bucket_alloc(len, r->connection->bucket_alloc);
memcpy(pcopydata, data, len);
bucket_stdin =
apr_bucket_heap_create(pcopydata, len,
apr_bucket_free,
r->connection->bucket_alloc);
}
}
if (!init_header(FCGI_STDIN, 1, len, 0, stdin_request_header)) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
"mod_fcgid: header overflow");
apr_brigade_destroy(input_brigade);
apr_brigade_destroy(tmp_brigade);
apr_brigade_destroy(output_brigade);
return HTTP_INTERNAL_SERVER_ERROR;
}
APR_BRIGADE_INSERT_TAIL(output_brigade, bucket_header);
APR_BRIGADE_INSERT_TAIL(output_brigade, bucket_stdin);
}
apr_brigade_cleanup(input_brigade);
apr_brigade_cleanup(tmp_brigade);
}
while (!seen_eos);
apr_brigade_destroy(input_brigade);
apr_brigade_destroy(tmp_brigade);
/* Append an empty body stdin header */
stdin_request_header = apr_bucket_alloc(sizeof(FCGI_Header),
r->connection->bucket_alloc);
bucket_header =
apr_bucket_heap_create((const char *) stdin_request_header,
sizeof(*stdin_request_header),
apr_bucket_free, r->connection->bucket_alloc);
if (!init_header(FCGI_STDIN, 1, 0, 0, stdin_request_header)) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
"mod_fcgid: header overflow");
return HTTP_INTERNAL_SERVER_ERROR;
}
APR_BRIGADE_INSERT_TAIL(output_brigade, bucket_header);
*body_length = request_size;
return 0;
}