]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Switch from private FastCGI protocol handling to util_fcgi API.
authorJeff Trawick <trawick@apache.org>
Sat, 14 Sep 2013 18:14:49 +0000 (18:14 +0000)
committerJeff Trawick <trawick@apache.org>
Sat, 14 Sep 2013 18:14:49 +0000 (18:14 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1523281 13f79535-47bb-0310-9956-ffa450edef68

modules/proxy/fcgi_protocol.h [deleted file]
modules/proxy/mod_proxy_fcgi.c

diff --git a/modules/proxy/fcgi_protocol.h b/modules/proxy/fcgi_protocol.h
deleted file mode 100644 (file)
index a3cbcfc..0000000
+++ /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 */
-/** @} */
index 875153fe357eef1fbd2199331a602382fcd52c8d..b27d78c638bb7807377d7db2daf9b5e6f424c3fd 100644 (file)
  */
 
 #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)