diff options
author | Jeff Trawick <trawick@apache.org> | 2013-08-13 14:16:39 +0200 |
---|---|---|
committer | Jeff Trawick <trawick@apache.org> | 2013-08-13 14:16:39 +0200 |
commit | 8f3558bf2ddd8aa4d86051e6d9bdd718420d26bd (patch) | |
tree | 932bce3da8639574a5c2aff018262c010c49efef | |
parent | Add ap_log_data(), ap_log_rdata(), etc. for logging buffers. (diff) | |
download | apache2-8f3558bf2ddd8aa4d86051e6d9bdd718420d26bd.tar.xz apache2-8f3558bf2ddd8aa4d86051e6d9bdd718420d26bd.zip |
Add util_fcgi.h and associated definitions and support
routines for FastCGI, based largely on mod_proxy_fcgi.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1513454 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | CHANGES | 4 | ||||
-rw-r--r-- | NWGNUmakefile | 1 | ||||
-rw-r--r-- | build/nw_export.inc | 1 | ||||
-rw-r--r-- | include/ap_mmn.h | 3 | ||||
-rw-r--r-- | include/util_fcgi.h | 280 | ||||
-rw-r--r-- | libhttpd.dsp | 8 | ||||
-rw-r--r-- | server/Makefile.in | 2 | ||||
-rw-r--r-- | server/util_fcgi.c | 287 |
8 files changed, 584 insertions, 2 deletions
@@ -1,6 +1,10 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.0 + *) core: Add util_fcgi.h and associated definitions and support + routines for FastCGI, based largely on mod_proxy_fcgi. + [Jeff Trawick] + *) core: Add ap_log_data(), ap_log_rdata(), etc. for logging buffers. [Jeff Trawick] diff --git a/NWGNUmakefile b/NWGNUmakefile index 4678880056..1a5e91e72c 100644 --- a/NWGNUmakefile +++ b/NWGNUmakefile @@ -276,6 +276,7 @@ FILES_nlm_objs = \ $(OBJDIR)/util_expr_eval.o \ $(OBJDIR)/util_expr_parse.o \ $(OBJDIR)/util_expr_scan.o \ + $(OBJDIR)/util_fcgi.o \ $(OBJDIR)/util_filter.o \ $(OBJDIR)/util_md5.o \ $(OBJDIR)/util_mutex.o \ diff --git a/build/nw_export.inc b/build/nw_export.inc index 32c769b27f..0319465b4d 100644 --- a/build/nw_export.inc +++ b/build/nw_export.inc @@ -62,6 +62,7 @@ #include "util_charset.h" #include "util_cookies.h" #include "util_ebcdic.h" +#include "util_fcgi.h" #include "util_filter.h" /*#include "util_ldap.h"*/ #include "util_md5.h" diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 608da2caee..2a9cff0227 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -437,6 +437,7 @@ * 20130702.0 (2.5.0-dev) Remove pre_htaccess hook, add open_htaccess hook. * 20130702.1 (2.5.0-dev) Restore AUTH_HANDLED to mod_auth.h * 20130702.2 (2.5.0-dev) Add ap_log_data(), ap_log_rdata(), etc. + * 20130702.3 (2.5.0-dev) Add util_fcgi.h, FastCGI protocol support */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ @@ -444,7 +445,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20130702 #endif -#define MODULE_MAGIC_NUMBER_MINOR 2 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 3 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/util_fcgi.h b/include/util_fcgi.h new file mode 100644 index 0000000000..849fdee9c3 --- /dev/null +++ b/include/util_fcgi.h @@ -0,0 +1,280 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file util_fcgi.h + * @brief FastCGI protocol defitions and support routines + * + * @defgroup APACHE_CORE_FASTCGI FastCGI Tools + * @ingroup APACHE_CORE + * @{ + */ + +#ifndef APACHE_UTIL_FCGI_H +#define APACHE_UTIL_FCGI_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "httpd.h" + +/** + * @brief A structure that represents the fixed header fields + * at the beginning of a "FastCGI record" (i.e., the data prior + * to content data and padding). + */ +typedef struct { + /** See values for version, below */ + unsigned char version; + /** See values for type, below */ + unsigned char type; + /** request id, in two parts */ + unsigned char requestIdB1; + unsigned char requestIdB0; + /** content length, in two parts */ + unsigned char contentLengthB1; + unsigned char contentLengthB0; + /** padding length */ + unsigned char paddingLength; + /** 8-bit reserved field */ + unsigned char reserved; +} ap_fcgi_header; + +/* + * Number of bytes in the header portion of a FastCGI record + * (i.e., ap_fcgi_header structure). Future versions of the + * protocol may increase the size. + */ +#define AP_FCGI_HEADER_LEN 8 + +/* + * Maximum number of bytes in the content portion of a FastCGI record. + */ +#define AP_FCGI_MAX_CONTENT_LEN 65535 + +/** + * Possible values for the version field of ap_fcgi_header + */ +#define AP_FCGI_VERSION_1 1 + +/** + * Possible values for the type field of ap_fcgi_header + */ +#define AP_FCGI_BEGIN_REQUEST 1 +#define AP_FCGI_ABORT_REQUEST 2 +#define AP_FCGI_END_REQUEST 3 +#define AP_FCGI_PARAMS 4 +#define AP_FCGI_STDIN 5 +#define AP_FCGI_STDOUT 6 +#define AP_FCGI_STDERR 7 +#define AP_FCGI_DATA 8 +#define AP_FCGI_GET_VALUES 9 +#define AP_FCGI_GET_VALUES_RESULT 10 +#define AP_FCGI_UNKNOWN_TYPE 11 +#define AP_FCGI_MAXTYPE (AP_FCGI_UNKNOWN_TYPE) + +/** + * Offsets of the various fields of ap_fcgi_header + */ +#define AP_FCGI_HDR_VERSION_OFFSET 0 +#define AP_FCGI_HDR_TYPE_OFFSET 1 +#define AP_FCGI_HDR_REQUEST_ID_B1_OFFSET 2 +#define AP_FCGI_HDR_REQUEST_ID_B0_OFFSET 3 +#define AP_FCGI_HDR_CONTENT_LEN_B1_OFFSET 4 +#define AP_FCGI_HDR_CONTENT_LEN_B0_OFFSET 5 +#define AP_FCGI_HDR_PADDING_LEN_OFFSET 6 +#define AP_FCGI_HDR_RESERVED_OFFSET 7 + +/** + * @brief This represents the content data of the FastCGI record when + * the type is AP_FCGI_BEGIN_REQUEST. + */ +typedef struct { + /** + * role, in two parts + * See values for role, below + */ + unsigned char roleB1; + unsigned char roleB0; + /** + * flags + * See values for flags bits, below + */ + unsigned char flags; + /** reserved */ + unsigned char reserved[5]; +} ap_fcgi_begin_request_body; + +/* + * Values for role component of ap_fcgi_begin_request_body + */ +#define AP_FCGI_RESPONDER 1 +#define AP_FCGI_AUTHORIZER 2 +#define AP_FCGI_FILTER 3 + +/* + * Values for flags bits of ap_fcgi_begin_request_body + */ +#define AP_FCGI_KEEP_CONN 1 /* otherwise the application closes */ + +/** + * Offsets of the various fields of ap_fcgi_begin_request_body + */ +#define AP_FCGI_BRB_ROLEB1_OFFSET 0 +#define AP_FCGI_BRB_ROLEB0_OFFSET 1 +#define AP_FCGI_BRB_FLAGS_OFFSET 2 +#define AP_FCGI_BRB_RESERVED0_OFFSET 3 +#define AP_FCGI_BRB_RESERVED1_OFFSET 4 +#define AP_FCGI_BRB_RESERVED2_OFFSET 5 +#define AP_FCGI_BRB_RESERVED3_OFFSET 6 +#define AP_FCGI_BRB_RESERVED4_OFFSET 7 + +/** + * Pack ap_fcgi_header + * @param h The header to read from + * @param a The array to write to, of size AP_FCGI_HEADER_LEN + */ +AP_DECLARE(void) ap_fcgi_header_to_array(ap_fcgi_header *h, + unsigned char a[]); + +/** + * Unpack header of FastCGI record into ap_fcgi_header + * @param h The header to write to + * @param a The array to read from, of size AP_FCGI_HEADER_LEN + */ +AP_DECLARE(void) ap_fcgi_header_from_array(ap_fcgi_header *h, + unsigned char a[]); + +/** + * Unpack header of FastCGI record into individual fields + * @param version The version, on output + * @param type The type, on output + * @param request_id The request id, on output + * @param content_len The content length, on output + * @param padding_len The amount of padding following the content, on output + * @param a The array to read from, of size AP_FCGI_HEADER_LEN + */ +AP_DECLARE(void) ap_fcgi_header_fields_from_array(unsigned char *version, + unsigned char *type, + apr_uint16_t *request_id, + apr_uint16_t *content_len, + unsigned char *padding_len, + unsigned char a[]); + +/** + * Pack ap_fcgi_begin_request_body + * @param h The begin-request body to read from + * @param a The array to write to, of size AP_FCGI_HEADER_LEN + */ +AP_DECLARE(void) ap_fcgi_begin_request_body_to_array(ap_fcgi_begin_request_body *h, + unsigned char a[]); + +/** + * Fill in a FastCGI request header with the required field values. + * @param header The header to fill in + * @param type The type of record + * @param request_id The request id + * @param content_len The amount of content which follows the header + * @param padding_len The amount of padding which follows the content + * + * The header array must be at least AP_FCGI_HEADER_LEN bytes long. + */ +AP_DECLARE(void) ap_fcgi_fill_in_header(ap_fcgi_header *header, + unsigned char type, + apr_uint16_t request_id, + apr_uint16_t content_len, + unsigned char padding_len); + +/** + * Fill in a FastCGI begin request body with the required field values. + * @param brb The begin-request-body to fill in + * @param role AP_FCGI_RESPONDER or other roles + * @param flags 0 or a combination of flags like AP_FCGI_KEEP_CONN + */ +AP_DECLARE(void) ap_fcgi_fill_in_request_body(ap_fcgi_begin_request_body *brb, + int role, + unsigned char flags); + +/** + * Compute the buffer size needed to encode the next portion of + * the provided environment table. + * @param env The environment table + * @param maxlen The maximum buffer size allowable, capped at + * AP_FCGI_MAX_CONTENT_LEN. + * @param starting_elem On input, the next element of the table array + * to process in this FastCGI record. On output, the next element to + * process on the *next* FastCGI record. + * @return Size of buffer needed to encode the next part, or 0 + * if no more can be encoded. When 0 is returned: If starting_elem + * has reached the end of the table array, all has been encoded; + * otherwise, the next envvar can't be encoded within the specified + * limit. + * @note If an envvar can't be encoded within the specified limit, + * the caller can log a warning and increment starting_elem and try + * again or increase the limit or fail, as appropriate for the module. + */ +AP_DECLARE(apr_size_t) ap_fcgi_encoded_env_len(apr_table_t *env, + apr_size_t maxlen, + int *starting_elem); + +/** + * Encode the next portion of the provided environment table using + * a buffer previously allocated. + * @param r The request, for logging + * @param env The environment table + * @param buffer A buffer to contain the encoded environment table + * @param buflen The length of the buffer, previously computed by + * ap_fcgi_encoded_env_len(). + * @param starting_elem On input, the next element of the table array + * to process in this FastCGI record. On output, the next element to + * process on the *next* FastCGI record. + * @return APR_SUCCESS if a section could be encoded or APR_ENOSPC + * otherwise. + * @note The output starting_elem from ap_fcgi_encoded_env_len + * shouldn't be used as input to ap_fcgi_encode_env when building the + * same FastCGI record. + */ +AP_DECLARE(apr_status_t) ap_fcgi_encode_env(request_rec *r, + apr_table_t *env, + void *buffer, + apr_size_t buflen, + int *starting_elem); + +/** + * String forms for the value of the FCGI_ROLE envvar + */ +#define AP_FCGI_RESPONDER_STR "RESPONDER" +#define AP_FCGI_AUTHORIZER_STR "AUTHORIZER" +#define AP_FCGI_FILTER_STR "FILTER" + +/** + * FastCGI implementations that implement the AUTHORIZER role + * for Apache httpd and allow the application to participate in + * any of the Apache httpd AAA phases typically set the variable + * FCGI_APACHE_ROLE to one of these strings to indicate the + * specific AAA phase. + */ +#define AP_FCGI_APACHE_ROLE_AUTHENTICATOR_STR "AUTHENTICATOR" +#define AP_FCGI_APACHE_ROLE_AUTHORIZER_STR "AUTHORIZER" +#define AP_FCGI_APACHE_ROLE_ACCESS_CHECKER_STR "ACCESS_CHECKER" + +#ifdef __cplusplus +} +#endif + +#endif /* !APACHE_UTIL_FCGI_H */ +/** @} */ diff --git a/libhttpd.dsp b/libhttpd.dsp index 1f616be697..ae4b17bede 100644 --- a/libhttpd.dsp +++ b/libhttpd.dsp @@ -569,6 +569,14 @@ SOURCE=.\server\util_expr_parse.c # End Source File # Begin Source File +SOURCE=.\server\util_fcgi.c +# End Source File +# Begin Source File + +SOURCE=.\include\util_fcgi.h +# End Source File +# Begin Source File + SOURCE=.\server\util_filter.c # End Source File # Begin Source File diff --git a/server/Makefile.in b/server/Makefile.in index 9804379900..69e5fe09ed 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -7,7 +7,7 @@ SUBDIRS = mpm LTLIBRARY_NAME = libmain.la LTLIBRARY_SOURCES = \ - config.c log.c main.c vhost.c util.c \ + config.c log.c main.c vhost.c util.c util_fcgi.c \ util_script.c util_md5.c util_cfgtree.c util_ebcdic.c util_time.c \ connection.c listen.c util_mutex.c mpm_common.c mpm_unix.c \ util_charset.c util_cookies.c util_debug.c util_xml.c \ diff --git a/server/util_fcgi.c b/server/util_fcgi.c new file mode 100644 index 0000000000..8201f8cdf2 --- /dev/null +++ b/server/util_fcgi.c @@ -0,0 +1,287 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "httpd.h" +#include "http_core.h" +#include "http_log.h" +#include "util_fcgi.h" + +/* we know core's module_index is 0 */ +#undef APLOG_MODULE_INDEX +#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX + +AP_DECLARE(void) ap_fcgi_header_to_array(ap_fcgi_header *h, + unsigned char a[]) +{ + a[AP_FCGI_HDR_VERSION_OFFSET] = h->version; + a[AP_FCGI_HDR_TYPE_OFFSET] = h->type; + a[AP_FCGI_HDR_REQUEST_ID_B1_OFFSET] = h->requestIdB1; + a[AP_FCGI_HDR_REQUEST_ID_B0_OFFSET] = h->requestIdB0; + a[AP_FCGI_HDR_CONTENT_LEN_B1_OFFSET] = h->contentLengthB1; + a[AP_FCGI_HDR_CONTENT_LEN_B0_OFFSET] = h->contentLengthB0; + a[AP_FCGI_HDR_PADDING_LEN_OFFSET] = h->paddingLength; + a[AP_FCGI_HDR_RESERVED_OFFSET] = h->reserved; +} + +AP_DECLARE(void) ap_fcgi_header_from_array(ap_fcgi_header *h, + unsigned char a[]) +{ + h->version = a[AP_FCGI_HDR_VERSION_OFFSET]; + h->type = a[AP_FCGI_HDR_TYPE_OFFSET]; + h->requestIdB1 = a[AP_FCGI_HDR_REQUEST_ID_B1_OFFSET]; + h->requestIdB0 = a[AP_FCGI_HDR_REQUEST_ID_B0_OFFSET]; + h->contentLengthB1 = a[AP_FCGI_HDR_CONTENT_LEN_B1_OFFSET]; + h->contentLengthB0 = a[AP_FCGI_HDR_CONTENT_LEN_B0_OFFSET]; + h->paddingLength = a[AP_FCGI_HDR_PADDING_LEN_OFFSET]; + h->reserved = a[AP_FCGI_HDR_RESERVED_OFFSET]; +} + +AP_DECLARE(void) ap_fcgi_header_fields_from_array(unsigned char *version, + unsigned char *type, + apr_uint16_t *request_id, + apr_uint16_t *content_len, + unsigned char *padding_len, + unsigned char a[]) +{ + *version = a[AP_FCGI_HDR_VERSION_OFFSET]; + *type = a[AP_FCGI_HDR_TYPE_OFFSET]; + *request_id = (a[AP_FCGI_HDR_REQUEST_ID_B1_OFFSET] << 8) + + a[AP_FCGI_HDR_REQUEST_ID_B0_OFFSET]; + *content_len = (a[AP_FCGI_HDR_CONTENT_LEN_B1_OFFSET] << 8) + + a[AP_FCGI_HDR_CONTENT_LEN_B0_OFFSET]; + *padding_len = a[AP_FCGI_HDR_PADDING_LEN_OFFSET]; +} + +AP_DECLARE(void) ap_fcgi_begin_request_body_to_array(ap_fcgi_begin_request_body *h, + unsigned char a[]) +{ + a[AP_FCGI_BRB_ROLEB1_OFFSET] = h->roleB1; + a[AP_FCGI_BRB_ROLEB0_OFFSET] = h->roleB0; + a[AP_FCGI_BRB_FLAGS_OFFSET] = h->flags; + a[AP_FCGI_BRB_RESERVED0_OFFSET] = h->reserved[0]; + a[AP_FCGI_BRB_RESERVED1_OFFSET] = h->reserved[1]; + a[AP_FCGI_BRB_RESERVED2_OFFSET] = h->reserved[2]; + a[AP_FCGI_BRB_RESERVED3_OFFSET] = h->reserved[3]; + a[AP_FCGI_BRB_RESERVED4_OFFSET] = h->reserved[4]; +} + +AP_DECLARE(void) ap_fcgi_fill_in_header(ap_fcgi_header *header, + unsigned char type, + apr_uint16_t request_id, + apr_uint16_t content_len, + unsigned char padding_len) +{ + header->version = AP_FCGI_VERSION_1; + + header->type = type; + + header->requestIdB1 = ((request_id >> 8) & 0xff); + header->requestIdB0 = ((request_id) & 0xff); + + header->contentLengthB1 = ((content_len >> 8) & 0xff); + header->contentLengthB0 = ((content_len) & 0xff); + + header->paddingLength = padding_len; + + header->reserved = 0; +} + +AP_DECLARE(void) ap_fcgi_fill_in_request_body(ap_fcgi_begin_request_body *brb, + int role, + unsigned char flags) +{ + brb->roleB1 = ((role >> 8) & 0xff); + brb->roleB0 = (role & 0xff); + brb->flags = flags; + brb->reserved[0] = 0; + brb->reserved[1] = 0; + brb->reserved[2] = 0; + brb->reserved[3] = 0; + brb->reserved[4] = 0; +} + +AP_DECLARE(apr_size_t) ap_fcgi_encoded_env_len(apr_table_t *env, + apr_size_t maxlen, + int *starting_elem) +{ + const apr_array_header_t *envarr; + const apr_table_entry_t *elts; + apr_size_t envlen, actualenvlen; + int i; + + if (maxlen > AP_FCGI_MAX_CONTENT_LEN) { + maxlen = AP_FCGI_MAX_CONTENT_LEN; + } + + envarr = apr_table_elts(env); + elts = (const apr_table_entry_t *) envarr->elts; + + /* envlen - speculative, may overflow the limit + * actualenvlen - len required without overflowing + */ + envlen = actualenvlen = 0; + for (i = *starting_elem; i < envarr->nelts; ) { + apr_size_t keylen, vallen; + + if (!elts[i].key) { + (*starting_elem)++; + i++; + continue; + } + + keylen = strlen(elts[i].key); + + if (keylen >> 7 == 0) { + envlen += 1; + } + else { + envlen += 4; + } + + envlen += keylen; + + vallen = strlen(elts[i].val); + + if (vallen >> 7 == 0) { + envlen += 1; + } + else { + envlen += 4; + } + + envlen += vallen; + + if (envlen > maxlen) { + break; + } + + actualenvlen = envlen; + (*starting_elem)++; + i++; + } + + return actualenvlen; +} + +AP_DECLARE(apr_status_t) ap_fcgi_encode_env(request_rec *r, + apr_table_t *env, + void *buffer, + apr_size_t buflen, + int *starting_elem) +{ + apr_status_t rv = APR_SUCCESS; + const apr_array_header_t *envarr; + const apr_table_entry_t *elts; + char *itr; + int i; + + envarr = apr_table_elts(env); + elts = (const apr_table_entry_t *) envarr->elts; + + itr = buffer; + + for (i = *starting_elem; i < envarr->nelts; ) { + apr_size_t keylen, vallen; + + if (!elts[i].key) { + (*starting_elem)++; + i++; + continue; + } + + keylen = strlen(elts[i].key); + + if (keylen >> 7 == 0) { + if (buflen < 1) { + rv = APR_ENOSPC; /* overflow */ + break; + } + itr[0] = keylen & 0xff; + itr += 1; + buflen -= 1; + } + else { + if (buflen < 4) { + rv = APR_ENOSPC; /* overflow */ + break; + } + itr[0] = ((keylen >> 24) & 0xff) | 0x80; + itr[1] = ((keylen >> 16) & 0xff); + itr[2] = ((keylen >> 8) & 0xff); + itr[3] = ((keylen) & 0xff); + itr += 4; + buflen -= 4; + } + + vallen = strlen(elts[i].val); + + if (vallen >> 7 == 0) { + if (buflen < 1) { + rv = APR_ENOSPC; /* overflow */ + break; + } + itr[0] = vallen & 0xff; + itr += 1; + buflen -= 1; + } + else { + if (buflen < 4) { + rv = APR_ENOSPC; /* overflow */ + break; + } + itr[0] = ((vallen >> 24) & 0xff) | 0x80; + itr[1] = ((vallen >> 16) & 0xff); + itr[2] = ((vallen >> 8) & 0xff); + itr[3] = ((vallen) & 0xff); + itr += 4; + buflen -= 4; + } + + if (buflen < keylen) { + rv = APR_ENOSPC; /* overflow */ + break; + } + memcpy(itr, elts[i].key, keylen); + itr += keylen; + buflen -= keylen; + + if (buflen < vallen) { + rv = APR_ENOSPC; /* overflow */ + break; + } + memcpy(itr, elts[i].val, vallen); + itr += vallen; + + if (buflen == vallen) { + (*starting_elem)++; + i++; + break; /* filled up predicted space, as expected */ + } + + buflen -= vallen; + + (*starting_elem)++; + i++; + } + + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + APLOGNO() "ap_fcgi_encode_env: out of space " + "encoding environment"); + } + + return rv; +} |