diff options
Diffstat (limited to '')
-rw-r--r-- | server/util_fcgi.c | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/server/util_fcgi.c b/server/util_fcgi.c new file mode 100644 index 0000000..7fb2c8c --- /dev/null +++ b/server/util_fcgi.c @@ -0,0 +1,290 @@ +/* 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 = elts[i].val ? strlen(elts[i].val) : 0; + + 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 = elts[i].val ? strlen(elts[i].val) : 0; + + 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; + } + + if (elts[i].val) { + 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(02492) + "ap_fcgi_encode_env: out of space " + "encoding environment"); + } + + return rv; +} |