From 67b1aa4bd8c7739ee1a3d78b79fc90700d663359 Mon Sep 17 00:00:00 2001 From: Jeff Trawick Date: Sat, 14 Sep 2013 18:14:49 +0000 Subject: [PATCH] Switch from private FastCGI protocol handling to util_fcgi API. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1523281 13f79535-47bb-0310-9956-ffa450edef68 --- modules/proxy/fcgi_protocol.h | 108 ------------ modules/proxy/mod_proxy_fcgi.c | 290 ++++++++------------------------- 2 files changed, 71 insertions(+), 327 deletions(-) delete mode 100644 modules/proxy/fcgi_protocol.h diff --git a/modules/proxy/fcgi_protocol.h b/modules/proxy/fcgi_protocol.h deleted file mode 100644 index a3cbcfca02..0000000000 --- a/modules/proxy/fcgi_protocol.h +++ /dev/null @@ -1,108 +0,0 @@ -/* 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 fcgi_protocol.h - * @brief FastCGI protocol defines - * - * @defgroup FCGI_defines FastCGI protocol definition - * @ingroup APACHE_INTERNAL - * @{ - */ - -#ifndef FCGI_PROTOCOL_H -#define FCGI_PROTOCOL_H - - -#define FCGI_VERSION 1 - -#define FCGI_BEGIN_REQUEST 1 -#define FCGI_ABORT_REQUEST 2 -#define FCGI_END_REQUEST 3 -#define FCGI_PARAMS 4 -#define FCGI_STDIN 5 -#define FCGI_STDOUT 6 -#define FCGI_STDERR 7 -#define FCGI_DATA 8 -#define FCGI_GET_VALUES 9 -#define FCGI_GET_VALUES_RESULT 10 -#define FCGI_UNKNOWN_TYPE 11 -#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE) - -typedef struct { - unsigned char version; - unsigned char type; - unsigned char requestIdB1; - unsigned char requestIdB0; - unsigned char contentLengthB1; - unsigned char contentLengthB0; - unsigned char paddingLength; - unsigned char reserved; -} fcgi_header; - -#define FCGI_HDR_VERSION_OFFSET 0 -#define FCGI_HDR_TYPE_OFFSET 1 -#define FCGI_HDR_REQUEST_ID_B1_OFFSET 2 -#define FCGI_HDR_REQUEST_ID_B0_OFFSET 3 -#define FCGI_HDR_CONTENT_LEN_B1_OFFSET 4 -#define FCGI_HDR_CONTENT_LEN_B0_OFFSET 5 -#define FCGI_HDR_PADDING_LEN_OFFSET 6 -#define FCGI_HDR_RESERVED_OFFSET 7 - -#define FCGI_BRB_ROLEB1_OFFSET 0 -#define FCGI_BRB_ROLEB0_OFFSET 1 -#define FCGI_BRB_FLAGS_OFFSET 2 -#define FCGI_BRB_RESERVED0_OFFSET 3 -#define FCGI_BRB_RESERVED1_OFFSET 4 -#define FCGI_BRB_RESERVED2_OFFSET 5 -#define FCGI_BRB_RESERVED3_OFFSET 6 -#define FCGI_BRB_RESERVED4_OFFSET 7 - -/* - * Number of bytes in a fcgi_header. Future versions of the protocol - * will not reduce this number. - */ -#define FCGI_HEADER_LEN 8 - -/* - * Mask for flags component of FCGI_BeginRequestBody - */ -#define FCGI_KEEP_CONN 1 - -/* - * Values for role component of FCGI_BeginRequestBody - */ -#define FCGI_RESPONDER 1 -#define FCGI_AUTHORIZER 2 -#define FCGI_FILTER 3 - -typedef struct { - unsigned char roleB1; - unsigned char roleB0; - unsigned char flags; - unsigned char reserved[5]; -} fcgi_begin_request_body; - -/* - * Maximum size of the allowed environment. - */ -#define FCGI_MAX_ENV_SIZE 65535 - -/* #define FCGI_DUMP_ENV_VARS */ - - -#endif /* FCGI_PROTOCOL_H */ -/** @} */ diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c index 875153fe35..b27d78c638 100644 --- a/modules/proxy/mod_proxy_fcgi.c +++ b/modules/proxy/mod_proxy_fcgi.c @@ -15,58 +15,11 @@ */ #include "mod_proxy.h" -#include "fcgi_protocol.h" +#include "util_fcgi.h" #include "util_script.h" module AP_MODULE_DECLARE_DATA proxy_fcgi_module; -/* - * The below 3 functions serve to map the FCGI structs - * back and forth between an 8 byte array. We do this to avoid - * any potential padding issues when we send or read these - * structures. - * - * NOTE: These have specific internal knowledge of the - * layout of the fcgi_header and fcgi_begin_request_body - * structs! - */ -static void fcgi_header_to_array(fcgi_header *h, unsigned char a[]) -{ - a[FCGI_HDR_VERSION_OFFSET] = h->version; - a[FCGI_HDR_TYPE_OFFSET] = h->type; - a[FCGI_HDR_REQUEST_ID_B1_OFFSET] = h->requestIdB1; - a[FCGI_HDR_REQUEST_ID_B0_OFFSET] = h->requestIdB0; - a[FCGI_HDR_CONTENT_LEN_B1_OFFSET] = h->contentLengthB1; - a[FCGI_HDR_CONTENT_LEN_B0_OFFSET] = h->contentLengthB0; - a[FCGI_HDR_PADDING_LEN_OFFSET] = h->paddingLength; - a[FCGI_HDR_RESERVED_OFFSET] = h->reserved; -} - -static void fcgi_header_from_array(fcgi_header *h, unsigned char a[]) -{ - h->version = a[FCGI_HDR_VERSION_OFFSET]; - h->type = a[FCGI_HDR_TYPE_OFFSET]; - h->requestIdB1 = a[FCGI_HDR_REQUEST_ID_B1_OFFSET]; - h->requestIdB0 = a[FCGI_HDR_REQUEST_ID_B0_OFFSET]; - h->contentLengthB1 = a[FCGI_HDR_CONTENT_LEN_B1_OFFSET]; - h->contentLengthB0 = a[FCGI_HDR_CONTENT_LEN_B0_OFFSET]; - h->paddingLength = a[FCGI_HDR_PADDING_LEN_OFFSET]; - h->reserved = a[FCGI_HDR_RESERVED_OFFSET]; -} - -static void fcgi_begin_request_body_to_array(fcgi_begin_request_body *h, - unsigned char a[]) -{ - a[FCGI_BRB_ROLEB1_OFFSET] = h->roleB1; - a[FCGI_BRB_ROLEB0_OFFSET] = h->roleB0; - a[FCGI_BRB_FLAGS_OFFSET] = h->flags; - a[FCGI_BRB_RESERVED0_OFFSET] = h->reserved[0]; - a[FCGI_BRB_RESERVED1_OFFSET] = h->reserved[1]; - a[FCGI_BRB_RESERVED2_OFFSET] = h->reserved[2]; - a[FCGI_BRB_RESERVED3_OFFSET] = h->reserved[3]; - a[FCGI_BRB_RESERVED4_OFFSET] = h->reserved[4]; -} - /* * Canonicalise http-like URLs. * scheme is the scheme for the URL @@ -129,33 +82,6 @@ static int proxy_fcgi_canon(request_rec *r, char *url) return OK; } -/* - * Fill in a fastcgi request header with the following type, request id, - * content length, and padding length. - * - * The header array must be at least FCGI_HEADER_LEN bytes long. - */ -static void fill_in_header(fcgi_header *header, - unsigned char type, - apr_uint16_t request_id, - apr_uint16_t content_len, - unsigned char padding_len) -{ - header->version = FCGI_VERSION; - - 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; -} - /* Wrapper for apr_socket_sendv that handles updating the worker stats. */ static apr_status_t send_data(proxy_conn_rec *conn, struct iovec *vec, @@ -238,25 +164,19 @@ static apr_status_t send_begin_request(proxy_conn_rec *conn, apr_uint16_t request_id) { struct iovec vec[2]; - fcgi_header header; - unsigned char farray[FCGI_HEADER_LEN]; - fcgi_begin_request_body brb; - unsigned char abrb[FCGI_HEADER_LEN]; + ap_fcgi_header header; + unsigned char farray[AP_FCGI_HEADER_LEN]; + ap_fcgi_begin_request_body brb; + unsigned char abrb[AP_FCGI_HEADER_LEN]; apr_size_t len; - fill_in_header(&header, FCGI_BEGIN_REQUEST, request_id, sizeof(abrb), 0); + ap_fcgi_fill_in_header(&header, AP_FCGI_BEGIN_REQUEST, request_id, + sizeof(abrb), 0); - brb.roleB1 = ((FCGI_RESPONDER >> 8) & 0xff); - brb.roleB0 = ((FCGI_RESPONDER) & 0xff); - brb.flags = FCGI_KEEP_CONN; - brb.reserved[0] = 0; - brb.reserved[1] = 0; - brb.reserved[2] = 0; - brb.reserved[3] = 0; - brb.reserved[4] = 0; + ap_fcgi_fill_in_request_body(&brb, AP_FCGI_RESPONDER, AP_FCGI_KEEP_CONN); - fcgi_header_to_array(&header, farray); - fcgi_begin_request_body_to_array(&brb, abrb); + ap_fcgi_header_to_array(&header, farray); + ap_fcgi_begin_request_body_to_array(&brb, abrb); vec[0].iov_base = (void *)farray; vec[0].iov_len = sizeof(farray); @@ -270,15 +190,14 @@ static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r, apr_uint16_t request_id) { const apr_array_header_t *envarr; - const apr_table_entry_t *elts; struct iovec vec[2]; - fcgi_header header; - unsigned char farray[FCGI_HEADER_LEN]; + ap_fcgi_header header; + unsigned char farray[AP_FCGI_HEADER_LEN]; apr_size_t bodylen, envlen; - char *body, *itr; + char *body; apr_status_t rv; - apr_size_t len; - int i, numenv; + apr_size_t avail_len, len; + int next_elem, starting_elem; ap_add_common_vars(r); ap_add_cgi_vars(r); @@ -295,104 +214,45 @@ static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r, envarr = apr_table_elts(r->subprocess_env); - elts = (const apr_table_entry_t *) envarr->elts; - - for (i = 0; i < envarr->nelts; ++i) { - apr_size_t keylen, vallen; - - if (! elts[i].key) { - continue; - } - - keylen = strlen(elts[i].key); - - if (keylen >> 7 == 0) { - envlen += 1; - } - else { - envlen += 4; - } - - envlen += keylen; - - vallen = strlen(elts[i].val); - #ifdef FCGI_DUMP_ENV_VARS - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01062) - "sending env var '%s' value '%s'", - elts[i].key, elts[i].val); -#endif - - if (vallen >> 7 == 0) { - envlen += 1; - } - else { - envlen += 4; - } - - envlen += vallen; - - /* The cast of bodylen is safe since FCGI_MAX_ENV_SIZE is for sure an int */ - if (envlen > FCGI_MAX_ENV_SIZE) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01063) - "truncating environment to %d bytes and %d elements", - (int)bodylen, i); - break; + { + const apr_table_entry_t *elts; + int i; + + elts = (const apr_table_entry_t *) envarr->elts; + for (i = 0; i < envarr->nelts; ++i) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01062) + "sending env var '%s' value '%s'", + elts[i].key, elts[i].val); } - - bodylen = envlen; } +#endif - numenv = i; + next_elem = 0; /* start encoding with first element */ + starting_elem = next_elem; + avail_len = AP_FCGI_MAX_CONTENT_LEN; + bodylen = ap_fcgi_encoded_env_len(r->subprocess_env, + avail_len, + &next_elem); + + if (next_elem < envarr->nelts) { + /* not everything encodable within limit specified in avail_len */ + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01063) + "truncating environment to %d bytes and %d elements", + (int)bodylen, next_elem); + } body = apr_pcalloc(r->pool, bodylen); + rv = ap_fcgi_encode_env(r, r->subprocess_env, body, bodylen, + &starting_elem); + /* we pre-compute, so we can't run out of space */ + ap_assert(rv == APR_SUCCESS); + /* compute and encode must be in sync */ + ap_assert(starting_elem == next_elem); - itr = body; - - for (i = 0; i < numenv; ++i) { - apr_size_t keylen, vallen; - - if (! elts[i].key) { - continue; - } - - keylen = strlen(elts[i].key); - - if (keylen >> 7 == 0) { - itr[0] = keylen & 0xff; - itr += 1; - } - else { - itr[0] = ((keylen >> 24) & 0xff) | 0x80; - itr[1] = ((keylen >> 16) & 0xff); - itr[2] = ((keylen >> 8) & 0xff); - itr[3] = ((keylen) & 0xff); - itr += 4; - } - - vallen = strlen(elts[i].val); - - if (vallen >> 7 == 0) { - itr[0] = vallen & 0xff; - itr += 1; - } - else { - itr[0] = ((vallen >> 24) & 0xff) | 0x80; - itr[1] = ((vallen >> 16) & 0xff); - itr[2] = ((vallen >> 8) & 0xff); - itr[3] = ((vallen) & 0xff); - itr += 4; - } - - memcpy(itr, elts[i].key, keylen); - itr += keylen; - - memcpy(itr, elts[i].val, vallen); - itr += vallen; - } - - fill_in_header(&header, FCGI_PARAMS, request_id, (apr_uint16_t)bodylen, 0); - fcgi_header_to_array(&header, farray); + ap_fcgi_fill_in_header(&header, AP_FCGI_PARAMS, request_id, + (apr_uint16_t)bodylen, 0); + ap_fcgi_header_to_array(&header, farray); vec[0].iov_base = (void *)farray; vec[0].iov_len = sizeof(farray); @@ -404,8 +264,8 @@ static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r, return rv; } - fill_in_header(&header, FCGI_PARAMS, request_id, 0, 0); - fcgi_header_to_array(&header, farray); + ap_fcgi_fill_in_header(&header, AP_FCGI_PARAMS, request_id, 0, 0); + ap_fcgi_header_to_array(&header, farray); vec[0].iov_base = (void *)farray; vec[0].iov_len = sizeof(farray); @@ -552,8 +412,8 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, int script_error_status = HTTP_OK; conn_rec *c = r->connection; struct iovec vec[2]; - fcgi_header header; - unsigned char farray[FCGI_HEADER_LEN]; + ap_fcgi_header header; + unsigned char farray[AP_FCGI_HEADER_LEN]; apr_pollfd_t pfd; int header_state = HDR_STATE_READING_HEADERS; apr_pool_t *setaside_pool; @@ -614,9 +474,9 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, break; } - fill_in_header(&header, FCGI_STDIN, request_id, - (apr_uint16_t) writebuflen, 0); - fcgi_header_to_array(&header, farray); + ap_fcgi_fill_in_header(&header, AP_FCGI_STDIN, request_id, + (apr_uint16_t) writebuflen, 0); + ap_fcgi_header_to_array(&header, farray); vec[nvec].iov_base = (void *)farray; vec[nvec].iov_len = sizeof(farray); @@ -635,9 +495,10 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, if (last_stdin) { pfd.reqevents = APR_POLLIN; /* Done with input data */ - if (writebuflen) { /* empty FCGI_STDIN not already sent? */ - fill_in_header(&header, FCGI_STDIN, request_id, 0, 0); - fcgi_header_to_array(&header, farray); + if (writebuflen) { /* empty AP_FCGI_STDIN not already sent? */ + ap_fcgi_fill_in_header(&header, AP_FCGI_STDIN, request_id, + 0, 0); + ap_fcgi_header_to_array(&header, farray); vec[0].iov_base = (void *)farray; vec[0].iov_len = sizeof(farray); @@ -653,16 +514,16 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, * the headers, even if we fill the entire length in the recv. */ char readbuf[AP_IOBUFSIZE + 1]; apr_size_t readbuflen; - apr_size_t clen; - int rid, type; + apr_uint16_t clen, rid; apr_bucket *b; - char plen; + unsigned char plen; + unsigned char type, version; memset(readbuf, 0, sizeof(readbuf)); memset(farray, 0, sizeof(farray)); /* First, we grab the header... */ - readbuflen = FCGI_HEADER_LEN; + readbuflen = AP_FCGI_HEADER_LEN; rv = get_data(conn, (char *) farray, &readbuflen); if (rv != APR_SUCCESS) { @@ -671,29 +532,25 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, dump_header_to_log(r, farray, readbuflen); - if (readbuflen != FCGI_HEADER_LEN) { + if (readbuflen != AP_FCGI_HEADER_LEN) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01067) "Failed to read entire header " "got %" APR_SIZE_T_FMT " wanted %d", - readbuflen, FCGI_HEADER_LEN); + readbuflen, AP_FCGI_HEADER_LEN); rv = APR_EINVAL; break; } - fcgi_header_from_array(&header, farray); + ap_fcgi_header_fields_from_array(&version, &type, &rid, + &clen, &plen, farray); - if (header.version != FCGI_VERSION) { + if (version != AP_FCGI_VERSION_1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01068) "Got bogus version %d", (int) header.version); rv = APR_EINVAL; break; } - type = header.type; - - rid = header.requestIdB1 << 8; - rid |= header.requestIdB0; - if (rid != request_id) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01069) "Got bogus rid %d, expected %d", @@ -702,11 +559,6 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, break; } - clen = header.contentLengthB1 << 8; - clen |= header.contentLengthB0; - - plen = header.paddingLength; - recv_again: if (clen > sizeof(readbuf) - 1) { readbuflen = sizeof(readbuf) - 1; @@ -726,7 +578,7 @@ recv_again: } switch (type) { - case FCGI_STDOUT: + case AP_FCGI_STDOUT: if (clen != 0) { b = apr_bucket_transient_create(readbuf, readbuflen, @@ -826,7 +678,7 @@ recv_again: } break; - case FCGI_STDERR: + case AP_FCGI_STDERR: /* TODO: Should probably clean up this logging a bit... */ if (clen) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01071) @@ -839,7 +691,7 @@ recv_again: } break; - case FCGI_END_REQUEST: + case AP_FCGI_END_REQUEST: done = 1; break; @@ -888,7 +740,7 @@ static int fcgi_do_request(apr_pool_t *p, request_rec *r, apr_uint16_t request_id = 1; apr_status_t rv; - /* Step 1: Send FCGI_BEGIN_REQUEST */ + /* Step 1: Send AP_FCGI_BEGIN_REQUEST */ rv = send_begin_request(conn, request_id); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01073) -- 2.40.0