1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "httpd.h"
18#include "http_core.h"
19#include "http_log.h"
20#include "util_fcgi.h"
21
22/* we know core's module_index is 0 */
23#undef APLOG_MODULE_INDEX
24#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
25
26AP_DECLARE(void) ap_fcgi_header_to_array(ap_fcgi_header *h,
27                                         unsigned char a[])
28{
29    a[AP_FCGI_HDR_VERSION_OFFSET]        = h->version;
30    a[AP_FCGI_HDR_TYPE_OFFSET]           = h->type;
31    a[AP_FCGI_HDR_REQUEST_ID_B1_OFFSET]  = h->requestIdB1;
32    a[AP_FCGI_HDR_REQUEST_ID_B0_OFFSET]  = h->requestIdB0;
33    a[AP_FCGI_HDR_CONTENT_LEN_B1_OFFSET] = h->contentLengthB1;
34    a[AP_FCGI_HDR_CONTENT_LEN_B0_OFFSET] = h->contentLengthB0;
35    a[AP_FCGI_HDR_PADDING_LEN_OFFSET]    = h->paddingLength;
36    a[AP_FCGI_HDR_RESERVED_OFFSET]       = h->reserved;
37}
38
39AP_DECLARE(void) ap_fcgi_header_from_array(ap_fcgi_header *h,
40                                           unsigned char a[])
41{
42    h->version         = a[AP_FCGI_HDR_VERSION_OFFSET];
43    h->type            = a[AP_FCGI_HDR_TYPE_OFFSET];
44    h->requestIdB1     = a[AP_FCGI_HDR_REQUEST_ID_B1_OFFSET];
45    h->requestIdB0     = a[AP_FCGI_HDR_REQUEST_ID_B0_OFFSET];
46    h->contentLengthB1 = a[AP_FCGI_HDR_CONTENT_LEN_B1_OFFSET];
47    h->contentLengthB0 = a[AP_FCGI_HDR_CONTENT_LEN_B0_OFFSET];
48    h->paddingLength   = a[AP_FCGI_HDR_PADDING_LEN_OFFSET];
49    h->reserved        = a[AP_FCGI_HDR_RESERVED_OFFSET];
50}
51
52AP_DECLARE(void) ap_fcgi_header_fields_from_array(unsigned char *version,
53                                                  unsigned char *type,
54                                                  apr_uint16_t *request_id,
55                                                  apr_uint16_t *content_len,
56                                                  unsigned char *padding_len,
57                                                  unsigned char a[])
58{
59    *version         = a[AP_FCGI_HDR_VERSION_OFFSET];
60    *type            = a[AP_FCGI_HDR_TYPE_OFFSET];
61    *request_id      = (a[AP_FCGI_HDR_REQUEST_ID_B1_OFFSET] << 8)
62                     +  a[AP_FCGI_HDR_REQUEST_ID_B0_OFFSET];
63    *content_len     = (a[AP_FCGI_HDR_CONTENT_LEN_B1_OFFSET] << 8)
64                     +  a[AP_FCGI_HDR_CONTENT_LEN_B0_OFFSET];
65    *padding_len     = a[AP_FCGI_HDR_PADDING_LEN_OFFSET];
66}
67
68AP_DECLARE(void) ap_fcgi_begin_request_body_to_array(ap_fcgi_begin_request_body *h,
69                                                     unsigned char a[])
70{
71    a[AP_FCGI_BRB_ROLEB1_OFFSET]    = h->roleB1;
72    a[AP_FCGI_BRB_ROLEB0_OFFSET]    = h->roleB0;
73    a[AP_FCGI_BRB_FLAGS_OFFSET]     = h->flags;
74    a[AP_FCGI_BRB_RESERVED0_OFFSET] = h->reserved[0];
75    a[AP_FCGI_BRB_RESERVED1_OFFSET] = h->reserved[1];
76    a[AP_FCGI_BRB_RESERVED2_OFFSET] = h->reserved[2];
77    a[AP_FCGI_BRB_RESERVED3_OFFSET] = h->reserved[3];
78    a[AP_FCGI_BRB_RESERVED4_OFFSET] = h->reserved[4];
79}
80
81AP_DECLARE(void) ap_fcgi_fill_in_header(ap_fcgi_header *header,
82                                        unsigned char type,
83                                        apr_uint16_t request_id,
84                                        apr_uint16_t content_len,
85                                        unsigned char padding_len)
86{
87    header->version = AP_FCGI_VERSION_1;
88
89    header->type = type;
90
91    header->requestIdB1 = ((request_id >> 8) & 0xff);
92    header->requestIdB0 = ((request_id) & 0xff);
93
94    header->contentLengthB1 = ((content_len >> 8) & 0xff);
95    header->contentLengthB0 = ((content_len) & 0xff);
96
97    header->paddingLength = padding_len;
98
99    header->reserved = 0;
100}
101
102AP_DECLARE(void) ap_fcgi_fill_in_request_body(ap_fcgi_begin_request_body *brb,
103                                              int role,
104                                              unsigned char flags)
105{
106    brb->roleB1 = ((role >> 8) & 0xff);
107    brb->roleB0 = (role & 0xff);
108    brb->flags = flags;
109    brb->reserved[0] = 0;
110    brb->reserved[1] = 0;
111    brb->reserved[2] = 0;
112    brb->reserved[3] = 0;
113    brb->reserved[4] = 0;
114}
115
116AP_DECLARE(apr_size_t) ap_fcgi_encoded_env_len(apr_table_t *env,
117                                               apr_size_t maxlen,
118                                               int *starting_elem)
119{
120    const apr_array_header_t *envarr;
121    const apr_table_entry_t *elts;
122    apr_size_t envlen, actualenvlen;
123    int i;
124
125    if (maxlen > AP_FCGI_MAX_CONTENT_LEN) {
126        maxlen = AP_FCGI_MAX_CONTENT_LEN;
127    }
128
129    envarr = apr_table_elts(env);
130    elts = (const apr_table_entry_t *) envarr->elts;
131
132    /* envlen - speculative, may overflow the limit
133     * actualenvlen - len required without overflowing
134     */
135    envlen = actualenvlen = 0;
136    for (i = *starting_elem; i < envarr->nelts; ) {
137        apr_size_t keylen, vallen;
138
139        if (!elts[i].key) {
140            (*starting_elem)++;
141            i++;
142            continue;
143        }
144
145        keylen = strlen(elts[i].key);
146
147        if (keylen >> 7 == 0) {
148            envlen += 1;
149        }
150        else {
151            envlen += 4;
152        }
153
154        envlen += keylen;
155
156        vallen = strlen(elts[i].val);
157
158        if (vallen >> 7 == 0) {
159            envlen += 1;
160        }
161        else {
162            envlen += 4;
163        }
164
165        envlen += vallen;
166
167        if (envlen > maxlen) {
168            break;
169        }
170
171        actualenvlen = envlen;
172        (*starting_elem)++;
173        i++;
174    }
175
176    return actualenvlen;
177}
178
179AP_DECLARE(apr_status_t) ap_fcgi_encode_env(request_rec *r,
180                                            apr_table_t *env,
181                                            void *buffer,
182                                            apr_size_t buflen,
183                                            int *starting_elem)
184{
185    apr_status_t rv = APR_SUCCESS;
186    const apr_array_header_t *envarr;
187    const apr_table_entry_t *elts;
188    char *itr;
189    int i;
190
191    envarr = apr_table_elts(env);
192    elts = (const apr_table_entry_t *) envarr->elts;
193
194    itr = buffer;
195
196    for (i = *starting_elem; i < envarr->nelts; ) {
197        apr_size_t keylen, vallen;
198
199        if (!elts[i].key) {
200            (*starting_elem)++;
201            i++;
202            continue;
203        }
204
205        keylen = strlen(elts[i].key);
206
207        if (keylen >> 7 == 0) {
208            if (buflen < 1) {
209                rv = APR_ENOSPC; /* overflow */
210                break;
211            }
212            itr[0] = keylen & 0xff;
213            itr += 1;
214            buflen -= 1;
215        }
216        else {
217            if (buflen < 4) {
218                rv = APR_ENOSPC; /* overflow */
219                break;
220            }
221            itr[0] = ((keylen >> 24) & 0xff) | 0x80;
222            itr[1] = ((keylen >> 16) & 0xff);
223            itr[2] = ((keylen >> 8) & 0xff);
224            itr[3] = ((keylen) & 0xff);
225            itr += 4;
226            buflen -= 4;
227        }
228
229        vallen = strlen(elts[i].val);
230
231        if (vallen >> 7 == 0) {
232            if (buflen < 1) {
233                rv = APR_ENOSPC; /* overflow */
234                break;
235            }
236            itr[0] = vallen & 0xff;
237            itr += 1;
238            buflen -= 1;
239        }
240        else {
241            if (buflen < 4) {
242                rv = APR_ENOSPC; /* overflow */
243                break;
244            }
245            itr[0] = ((vallen >> 24) & 0xff) | 0x80;
246            itr[1] = ((vallen >> 16) & 0xff);
247            itr[2] = ((vallen >> 8) & 0xff);
248            itr[3] = ((vallen) & 0xff);
249            itr += 4;
250            buflen -= 4;
251        }
252
253        if (buflen < keylen) {
254            rv = APR_ENOSPC; /* overflow */
255            break;
256        }
257        memcpy(itr, elts[i].key, keylen);
258        itr += keylen;
259        buflen -= keylen;
260
261        if (buflen < vallen) {
262            rv = APR_ENOSPC; /* overflow */
263            break;
264        }
265        memcpy(itr, elts[i].val, vallen);
266        itr += vallen;
267
268        if (buflen == vallen) {
269            (*starting_elem)++;
270            i++;
271            break; /* filled up predicted space, as expected */
272        }
273
274        buflen -= vallen;
275
276        (*starting_elem)++;
277        i++;
278    }
279
280    if (rv != APR_SUCCESS) {
281        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
282                      APLOGNO(02492) "ap_fcgi_encode_env: out of space "
283                      "encoding environment");
284    }
285
286    return rv;
287}
288