| /* 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; | |
| } |