You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ji...@apache.org on 2013/11/15 18:09:17 UTC
svn commit: r1542330 - in /httpd/httpd/branches/2.4.x: ./ CHANGES STATUS
docs/manual/ docs/manual/howto/ docs/manual/mod/
docs/manual/mod/mod_macro.xml docs/manual/rewrite/
modules/proxy/fcgi_protocol.h modules/proxy/mod_proxy_fcgi.c
Author: jim
Date: Fri Nov 15 17:09:16 2013
New Revision: 1542330
URL: http://svn.apache.org/r1542330
Log:
Merge r1523281, r1524368, r1525276, r1525280, r1525281 from trunk:
Switch from private FastCGI protocol handling to util_fcgi API.
Use apr_socket_timeout_get instead of hard-coded 30 seconds timeout.
Bring some envvar flexibility from mod_authnz_fcgi to mod_proxy_fcgi:
mod_proxy_fcgi: Remove 64K limit on encoded length of all envvars.
An individual envvar with an encoded length of more than 16K will be
omitted.
Borrow a fix from mod_authnz_fcgi:
mod_proxy_fcgi: Handle reading protocol data that is split between
packets.
Use ap_log_rdata() to dump the FastCGI header, axing a bunch
of custom data dumping code.
Submitted by: trawick, jkaluza, trawick, trawick, trawick
Reviewed/backported by: jim
Modified:
httpd/httpd/branches/2.4.x/ (props changed)
httpd/httpd/branches/2.4.x/CHANGES
httpd/httpd/branches/2.4.x/STATUS
httpd/httpd/branches/2.4.x/docs/manual/ (props changed)
httpd/httpd/branches/2.4.x/docs/manual/howto/ (props changed)
httpd/httpd/branches/2.4.x/docs/manual/mod/ (props changed)
httpd/httpd/branches/2.4.x/docs/manual/mod/mod_macro.xml (props changed)
httpd/httpd/branches/2.4.x/docs/manual/rewrite/ (props changed)
httpd/httpd/branches/2.4.x/modules/proxy/fcgi_protocol.h
httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_fcgi.c
Propchange: httpd/httpd/branches/2.4.x/
------------------------------------------------------------------------------
Merged /httpd/httpd/trunk:r1523281,1524368,1525276,1525280-1525281
Modified: httpd/httpd/branches/2.4.x/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/CHANGES?rev=1542330&r1=1542329&r2=1542330&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/CHANGES [utf-8] (original)
+++ httpd/httpd/branches/2.4.x/CHANGES [utf-8] Fri Nov 15 17:09:16 2013
@@ -2,6 +2,13 @@
Changes with Apache 2.4.7
+ *) mod_proxy_fcgi: Remove 64K limit on encoded length of all envvars.
+ An individual envvar with an encoded length of more than 16K will be
+ omitted. [Jeff Trawick]
+
+ *) mod_proxy_fcgi: Handle reading protocol data that is split between
+ packets. [Jeff Trawick]
+
*) mod_ssl: Improve handling of ephemeral DH and ECDH keys by
allowing custom parameters to be configured via SSLCertificateFile,
and by adding standardized DH parameters for 1024/2048/3072/4096 bits.
Modified: httpd/httpd/branches/2.4.x/STATUS
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/STATUS?rev=1542330&r1=1542329&r2=1542330&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/STATUS (original)
+++ httpd/httpd/branches/2.4.x/STATUS Fri Nov 15 17:09:16 2013
@@ -97,14 +97,6 @@ RELEASE SHOWSTOPPERS:
PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
[ start all new proposals below, under PATCHES PROPOSED. ]
- * mod_proxy_fcgi: Sync with trunk
- trunk patch: https://svn.apache.org/viewvc?view=revision&revision=1523281
- https://svn.apache.org/viewvc?view=revision&revision=1524368
- https://svn.apache.org/viewvc?view=revision&revision=1525276
- https://svn.apache.org/viewvc?view=revision&revision=1525280
- https://svn.apache.org/viewvc?view=revision&revision=1525281
- 2.4.x patch: http://people.apache.org/~jim/patches/proxy-fcgi.patch
- +1: trawick, jim, jorton
PATCHES PROPOSED TO BACKPORT FROM TRUNK:
[ New proposals should be added at the end of the list ]
Propchange: httpd/httpd/branches/2.4.x/docs/manual/
------------------------------------------------------------------------------
Merged /httpd/httpd/trunk/docs/manual:r1523281,1524368,1525276,1525280-1525281
Propchange: httpd/httpd/branches/2.4.x/docs/manual/howto/
------------------------------------------------------------------------------
Merged /httpd/httpd/trunk/docs/manual/howto:r1523281,1524368,1525276,1525280-1525281
Propchange: httpd/httpd/branches/2.4.x/docs/manual/mod/
------------------------------------------------------------------------------
Merged /httpd/httpd/trunk/docs/manual/mod:r1523281,1524368,1525276,1525280-1525281
Propchange: httpd/httpd/branches/2.4.x/docs/manual/mod/mod_macro.xml
------------------------------------------------------------------------------
Merged /httpd/httpd/trunk/docs/manual/mod/mod_macro.xml:r1523281,1524368,1525276,1525280-1525281
Propchange: httpd/httpd/branches/2.4.x/docs/manual/rewrite/
------------------------------------------------------------------------------
Merged /httpd/httpd/trunk/docs/manual/rewrite:r1523281,1524368,1525276,1525280-1525281
Modified: httpd/httpd/branches/2.4.x/modules/proxy/fcgi_protocol.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/fcgi_protocol.h?rev=1542330&r1=1542329&r2=1542330&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/proxy/fcgi_protocol.h (original)
+++ httpd/httpd/branches/2.4.x/modules/proxy/fcgi_protocol.h Fri Nov 15 17:09:16 2013
@@ -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 */
-/** @} */
Modified: httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_fcgi.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_fcgi.c?rev=1542330&r1=1542329&r2=1542330&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_fcgi.c (original)
+++ httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_fcgi.c Fri Nov 15 17:09:16 2013
@@ -15,59 +15,12 @@
*/
#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
* url is the URL starting with the first '/'
@@ -129,33 +82,6 @@ static int proxy_fcgi_canon(request_rec
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,
@@ -234,29 +160,43 @@ static apr_status_t get_data(proxy_conn_
return rv;
}
+static apr_status_t get_data_full(proxy_conn_rec *conn,
+ char *buffer,
+ apr_size_t buflen)
+{
+ apr_size_t readlen;
+ apr_size_t cumulative_len = 0;
+ apr_status_t rv;
+
+ do {
+ readlen = buflen - cumulative_len;
+ rv = get_data(conn, buffer + cumulative_len, &readlen);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+ cumulative_len += readlen;
+ } while (cumulative_len < buflen);
+
+ return APR_SUCCESS;
+}
+
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);
@@ -267,26 +207,24 @@ static apr_status_t send_begin_request(p
}
static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r,
+ apr_pool_t *temp_pool,
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];
- apr_size_t bodylen, envlen;
- char *body, *itr;
+ ap_fcgi_header header;
+ unsigned char farray[AP_FCGI_HEADER_LEN];
+ char *body;
apr_status_t rv;
- apr_size_t len;
- int i, numenv;
+ apr_size_t avail_len, len, required_len;
+ int next_elem, starting_elem;
ap_add_common_vars(r);
ap_add_cgi_vars(r);
/* XXX are there any FastCGI specific env vars we need to send? */
- bodylen = envlen = 0;
-
/* XXX mod_cgi/mod_cgid use ap_create_environment here, which fills in
* the TZ value specially. We could use that, but it would mean
* parsing the key/value pairs back OUT of the allocated env array,
@@ -294,118 +232,75 @@ static apr_status_t send_environment(pro
* place, which would suck. */
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;
+ {
+ int i;
+
+ 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);
}
-
- 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;
- }
-
- bodylen = envlen;
}
+#endif
- numenv = i;
-
- body = apr_pcalloc(r->pool, bodylen);
-
- itr = body;
-
- for (i = 0; i < numenv; ++i) {
- apr_size_t keylen, vallen;
-
- if (! elts[i].key) {
- continue;
- }
-
- keylen = strlen(elts[i].key);
+ /* Send envvars over in as many FastCGI records as it takes, */
+ next_elem = 0; /* starting with the first one */
- 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;
+ avail_len = 16 * 1024; /* our limit per record, which could have been up
+ * to AP_FCGI_MAX_CONTENT_LEN
+ */
+
+ while (next_elem < envarr->nelts) {
+ starting_elem = next_elem;
+ required_len = ap_fcgi_encoded_env_len(r->subprocess_env,
+ avail_len,
+ &next_elem);
+
+ if (!required_len) {
+ if (next_elem < envarr->nelts) {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+ APLOGNO(02536) "couldn't encode envvar '%s' in %"
+ APR_SIZE_T_FMT " bytes",
+ elts[next_elem].key, avail_len);
+ /* skip this envvar and continue */
+ ++next_elem;
+ continue;
+ }
+ /* only an unused element at the end of the array */
+ break;
}
- vallen = strlen(elts[i].val);
-
- if (vallen >> 7 == 0) {
- itr[0] = vallen & 0xff;
- itr += 1;
+ body = apr_palloc(temp_pool, required_len);
+ rv = ap_fcgi_encode_env(r, r->subprocess_env, body, required_len,
+ &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);
+
+ ap_fcgi_fill_in_header(&header, AP_FCGI_PARAMS, request_id,
+ (apr_uint16_t)required_len, 0);
+ ap_fcgi_header_to_array(&header, farray);
+
+ vec[0].iov_base = (void *)farray;
+ vec[0].iov_len = sizeof(farray);
+ vec[1].iov_base = body;
+ vec[1].iov_len = required_len;
+
+ rv = send_data(conn, vec, 2, &len, 1);
+ apr_pool_clear(temp_pool);
+
+ if (rv) {
+ return rv;
}
- 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);
-
- vec[0].iov_base = (void *)farray;
- vec[0].iov_len = sizeof(farray);
- vec[1].iov_base = body;
- vec[1].iov_len = bodylen;
-
- rv = send_data(conn, vec, 2, &len, 1);
- if (rv) {
- return rv;
- }
-
- fill_in_header(&header, FCGI_PARAMS, request_id, 0, 0);
- fcgi_header_to_array(&header, farray);
+ /* Envvars sent, so say we're done */
+ 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);
@@ -482,69 +377,9 @@ static int handle_headers(request_rec *r
return 0;
}
-static void dump_header_to_log(request_rec *r, unsigned char fheader[],
- apr_size_t length)
-{
-#ifdef FCGI_DUMP_HEADERS
- apr_size_t posn = 0;
- char asc_line[20];
- char hex_line[60];
- int i = 0;
-
- memset(asc_line, 0, sizeof(asc_line));
- memset(hex_line, 0, sizeof(hex_line));
-
- while (posn < length) {
- unsigned char c = fheader[posn];
-
- if (i >= 20) {
- i = 0;
-
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01064)
- "HEADER: %s %s", asc_line, hex_line);
-
- memset(asc_line, 0, sizeof(asc_line));
- memset(hex_line, 0, sizeof(hex_line));
- }
-
- if (isprint(c)) {
- asc_line[i] = c;
- }
- else {
- asc_line[i] = '.';
- }
-
- if ((c >> 4) >= 10) {
- hex_line[i * 3] = 'a' + ((c >> 4) - 10);
- }
- else {
- hex_line[i * 3] = '0' + (c >> 4);
- }
-
- if ((c & 0x0F) >= 10) {
- hex_line[i * 3 + 1] = 'a' + ((c & 0x0F) - 10);
- }
- else {
- hex_line[i * 3 + 1] = '0' + (c & 0xF);
- }
-
- hex_line[i * 3 + 2] = ' ';
-
- i++;
- posn++;
- }
-
- if (i != 1) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01065) "HEADER: %s %s",
- asc_line, hex_line);
- }
-
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01066) "HEADER: -EOH-");
-#endif
-}
-
static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf,
- request_rec *r, apr_uint16_t request_id)
+ request_rec *r, apr_pool_t *setaside_pool,
+ apr_uint16_t request_id)
{
apr_bucket_brigade *ib, *ob;
int seen_end_of_headers = 0, done = 0;
@@ -552,14 +387,11 @@ static apr_status_t dispatch(proxy_conn_
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;
-
- apr_pool_create(&setaside_pool, r->pool);
-
+
pfd.desc_type = APR_POLL_SOCKET;
pfd.desc.s = conn->sock;
pfd.p = r->pool;
@@ -569,15 +401,13 @@ static apr_status_t dispatch(proxy_conn_
ob = apr_brigade_create(r->pool, c->bucket_alloc);
while (! done) {
- apr_interval_time_t timeout = conn->worker->s->timeout;
+ apr_interval_time_t timeout;
apr_size_t len;
int n;
/* We need SOME kind of timeout here, or virtually anything will
* cause timeout errors. */
- if (! conn->worker->s->timeout_set) {
- timeout = apr_time_from_sec(30);
- }
+ apr_socket_timeout_get(conn->sock, &timeout);
rv = apr_poll(&pfd, 1, &n, timeout);
if (rv != APR_SUCCESS) {
@@ -614,9 +444,9 @@ static apr_status_t dispatch(proxy_conn_
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 +465,10 @@ static apr_status_t dispatch(proxy_conn_
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,47 +484,37 @@ static apr_status_t dispatch(proxy_conn_
* 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;
-
- rv = get_data(conn, (char *) farray, &readbuflen);
+ rv = get_data_full(conn, (char *) farray, AP_FCGI_HEADER_LEN);
if (rv != APR_SUCCESS) {
- break;
- }
-
- dump_header_to_log(r, farray, readbuflen);
-
- if (readbuflen != 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);
- rv = APR_EINVAL;
+ "Failed to read FastCGI header");
break;
}
- fcgi_header_from_array(&header, farray);
+#ifdef FCGI_DUMP_HEADERS
+ ap_log_rdata(APLOG_MARK, APLOG_DEBUG, r, "FastCGI header",
+ farray, AP_FCGI_HEADER_LEN, 0);
+#endif
+
+ 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 +523,6 @@ static apr_status_t dispatch(proxy_conn_
break;
}
- clen = header.contentLengthB1 << 8;
- clen |= header.contentLengthB0;
-
- plen = header.paddingLength;
-
recv_again:
if (clen > sizeof(readbuf) - 1) {
readbuflen = sizeof(readbuf) - 1;
@@ -726,7 +542,7 @@ recv_again:
}
switch (type) {
- case FCGI_STDOUT:
+ case AP_FCGI_STDOUT:
if (clen != 0) {
b = apr_bucket_transient_create(readbuf,
readbuflen,
@@ -826,7 +642,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 +655,7 @@ recv_again:
}
break;
- case FCGI_END_REQUEST:
+ case AP_FCGI_END_REQUEST:
done = 1;
break;
@@ -850,10 +666,10 @@ recv_again:
}
if (plen) {
- readbuflen = plen;
-
- rv = get_data(conn, readbuf, &readbuflen);
+ rv = get_data_full(conn, readbuf, plen);
if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ APLOGNO(02537) "Error occurred reading padding");
break;
}
}
@@ -887,8 +703,9 @@ static int fcgi_do_request(apr_pool_t *p
* keep things simple. */
apr_uint16_t request_id = 1;
apr_status_t rv;
+ apr_pool_t *temp_pool;
- /* 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)
@@ -897,8 +714,10 @@ static int fcgi_do_request(apr_pool_t *p
return HTTP_SERVICE_UNAVAILABLE;
}
+ apr_pool_create(&temp_pool, r->pool);
+
/* Step 2: Send Environment via FCGI_PARAMS */
- rv = send_environment(conn, r, request_id);
+ rv = send_environment(conn, r, temp_pool, request_id);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01074)
"Failed writing Environment to %s:", server_portstr);
@@ -907,7 +726,7 @@ static int fcgi_do_request(apr_pool_t *p
}
/* Step 3: Read records from the back end server and handle them. */
- rv = dispatch(conn, conf, r, request_id);
+ rv = dispatch(conn, conf, r, temp_pool, request_id);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01075)
"Error dispatching request to %s:", server_portstr);
Re: svn commit: r1542330 - in /httpd/httpd/branches/2.4.x: ./ CHANGES
STATUS docs/manual/ docs/manual/howto/ docs/manual/mod/ docs/manual/mod/mod_macro.xml
docs/manual/rewrite/ modules/proxy/fcgi_protocol.h modules/proxy/mod_proxy_fcgi.c
Posted by Jeff Trawick <tr...@gmail.com>.
On Fri, Nov 15, 2013 at 12:09 PM, <ji...@apache.org> wrote:
> Author: jim
> Date: Fri Nov 15 17:09:16 2013
> New Revision: 1542330
>
> URL: http://svn.apache.org/r1542330
> Log:
> Merge r1523281, r1524368, r1525276, r1525280, r1525281 from trunk:
>
> Switch from private FastCGI protocol handling to util_fcgi API.
>
>
> Use apr_socket_timeout_get instead of hard-coded 30 seconds timeout.
>
>
> Bring some envvar flexibility from mod_authnz_fcgi to mod_proxy_fcgi:
>
> mod_proxy_fcgi: Remove 64K limit on encoded length of all envvars.
> An individual envvar with an encoded length of more than 16K will be
> omitted.
>
>
> Borrow a fix from mod_authnz_fcgi:
>
> mod_proxy_fcgi: Handle reading protocol data that is split between
> packets.
>
>
> Use ap_log_rdata() to dump the FastCGI header, axing a bunch
> of custom data dumping code.
>
Ouch; I reviewed the backport but I guess my eyes were glazed over from
looking at those diffs so many times a while back.
ap_log_rdata() isn't in the 2.4.x branch. The call to this function is
ifdef-ed out so there's no build issue. I'd just let sleeping dogs lie
until somebody really wants to log the envvars. (And maybe somebody will
want ap_log_*data() in the 2.4.x branch by then.) But YMMV.
>
> Submitted by: trawick, jkaluza, trawick, trawick, trawick
> Reviewed/backported by: jim
>
> Modified:
> httpd/httpd/branches/2.4.x/ (props changed)
> httpd/httpd/branches/2.4.x/CHANGES
> httpd/httpd/branches/2.4.x/STATUS
> httpd/httpd/branches/2.4.x/docs/manual/ (props changed)
> httpd/httpd/branches/2.4.x/docs/manual/howto/ (props changed)
> httpd/httpd/branches/2.4.x/docs/manual/mod/ (props changed)
> httpd/httpd/branches/2.4.x/docs/manual/mod/mod_macro.xml (props
> changed)
> httpd/httpd/branches/2.4.x/docs/manual/rewrite/ (props changed)
> httpd/httpd/branches/2.4.x/modules/proxy/fcgi_protocol.h
> httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_fcgi.c
>
> Propchange: httpd/httpd/branches/2.4.x/
>
> ------------------------------------------------------------------------------
> Merged /httpd/httpd/trunk:r1523281,1524368,1525276,1525280-1525281
>
> Modified: httpd/httpd/branches/2.4.x/CHANGES
> URL:
> http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/CHANGES?rev=1542330&r1=1542329&r2=1542330&view=diff
>
> ==============================================================================
> --- httpd/httpd/branches/2.4.x/CHANGES [utf-8] (original)
> +++ httpd/httpd/branches/2.4.x/CHANGES [utf-8] Fri Nov 15 17:09:16 2013
> @@ -2,6 +2,13 @@
>
> Changes with Apache 2.4.7
>
> + *) mod_proxy_fcgi: Remove 64K limit on encoded length of all envvars.
> + An individual envvar with an encoded length of more than 16K will be
> + omitted. [Jeff Trawick]
> +
> + *) mod_proxy_fcgi: Handle reading protocol data that is split between
> + packets. [Jeff Trawick]
> +
> *) mod_ssl: Improve handling of ephemeral DH and ECDH keys by
> allowing custom parameters to be configured via SSLCertificateFile,
> and by adding standardized DH parameters for 1024/2048/3072/4096
> bits.
>
> Modified: httpd/httpd/branches/2.4.x/STATUS
> URL:
> http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/STATUS?rev=1542330&r1=1542329&r2=1542330&view=diff
>
> ==============================================================================
> --- httpd/httpd/branches/2.4.x/STATUS (original)
> +++ httpd/httpd/branches/2.4.x/STATUS Fri Nov 15 17:09:16 2013
> @@ -97,14 +97,6 @@ RELEASE SHOWSTOPPERS:
> PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
> [ start all new proposals below, under PATCHES PROPOSED. ]
>
> - * mod_proxy_fcgi: Sync with trunk
> - trunk patch:
> https://svn.apache.org/viewvc?view=revision&revision=1523281
> -
> https://svn.apache.org/viewvc?view=revision&revision=1524368
> -
> https://svn.apache.org/viewvc?view=revision&revision=1525276
> -
> https://svn.apache.org/viewvc?view=revision&revision=1525280
> -
> https://svn.apache.org/viewvc?view=revision&revision=1525281
> - 2.4.x patch: http://people.apache.org/~jim/patches/proxy-fcgi.patch
> - +1: trawick, jim, jorton
>
> PATCHES PROPOSED TO BACKPORT FROM TRUNK:
> [ New proposals should be added at the end of the list ]
>
> Propchange: httpd/httpd/branches/2.4.x/docs/manual/
>
> ------------------------------------------------------------------------------
> Merged
> /httpd/httpd/trunk/docs/manual:r1523281,1524368,1525276,1525280-1525281
>
> Propchange: httpd/httpd/branches/2.4.x/docs/manual/howto/
>
> ------------------------------------------------------------------------------
> Merged
> /httpd/httpd/trunk/docs/manual/howto:r1523281,1524368,1525276,1525280-1525281
>
> Propchange: httpd/httpd/branches/2.4.x/docs/manual/mod/
>
> ------------------------------------------------------------------------------
> Merged
> /httpd/httpd/trunk/docs/manual/mod:r1523281,1524368,1525276,1525280-1525281
>
> Propchange: httpd/httpd/branches/2.4.x/docs/manual/mod/mod_macro.xml
>
> ------------------------------------------------------------------------------
> Merged
> /httpd/httpd/trunk/docs/manual/mod/mod_macro.xml:r1523281,1524368,1525276,1525280-1525281
>
> Propchange: httpd/httpd/branches/2.4.x/docs/manual/rewrite/
>
> ------------------------------------------------------------------------------
> Merged
> /httpd/httpd/trunk/docs/manual/rewrite:r1523281,1524368,1525276,1525280-1525281
>
> Modified: httpd/httpd/branches/2.4.x/modules/proxy/fcgi_protocol.h
> URL:
> http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/fcgi_protocol.h?rev=1542330&r1=1542329&r2=1542330&view=diff
>
> ==============================================================================
> --- httpd/httpd/branches/2.4.x/modules/proxy/fcgi_protocol.h (original)
> +++ httpd/httpd/branches/2.4.x/modules/proxy/fcgi_protocol.h Fri Nov 15
> 17:09:16 2013
> @@ -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 */
> -/** @} */
>
> Modified: httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_fcgi.c
> URL:
> http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_fcgi.c?rev=1542330&r1=1542329&r2=1542330&view=diff
>
> ==============================================================================
> --- httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_fcgi.c (original)
> +++ httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_fcgi.c Fri Nov 15
> 17:09:16 2013
> @@ -15,59 +15,12 @@
> */
>
> #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
> * url is the URL starting with the first '/'
> @@ -129,33 +82,6 @@ static int proxy_fcgi_canon(request_rec
> 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,
> @@ -234,29 +160,43 @@ static apr_status_t get_data(proxy_conn_
> return rv;
> }
>
> +static apr_status_t get_data_full(proxy_conn_rec *conn,
> + char *buffer,
> + apr_size_t buflen)
> +{
> + apr_size_t readlen;
> + apr_size_t cumulative_len = 0;
> + apr_status_t rv;
> +
> + do {
> + readlen = buflen - cumulative_len;
> + rv = get_data(conn, buffer + cumulative_len, &readlen);
> + if (rv != APR_SUCCESS) {
> + return rv;
> + }
> + cumulative_len += readlen;
> + } while (cumulative_len < buflen);
> +
> + return APR_SUCCESS;
> +}
> +
> 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);
> @@ -267,26 +207,24 @@ static apr_status_t send_begin_request(p
> }
>
> static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r,
> + apr_pool_t *temp_pool,
> 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];
> - apr_size_t bodylen, envlen;
> - char *body, *itr;
> + ap_fcgi_header header;
> + unsigned char farray[AP_FCGI_HEADER_LEN];
> + char *body;
> apr_status_t rv;
> - apr_size_t len;
> - int i, numenv;
> + apr_size_t avail_len, len, required_len;
> + int next_elem, starting_elem;
>
> ap_add_common_vars(r);
> ap_add_cgi_vars(r);
>
> /* XXX are there any FastCGI specific env vars we need to send? */
>
> - bodylen = envlen = 0;
> -
> /* XXX mod_cgi/mod_cgid use ap_create_environment here, which fills in
> * the TZ value specially. We could use that, but it would mean
> * parsing the key/value pairs back OUT of the allocated env
> array,
> @@ -294,118 +232,75 @@ static apr_status_t send_environment(pro
> * place, which would suck. */
>
> 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;
> + {
> + int i;
> +
> + 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);
> }
> -
> - 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;
> - }
> -
> - bodylen = envlen;
> }
> +#endif
>
> - numenv = i;
> -
> - body = apr_pcalloc(r->pool, bodylen);
> -
> - itr = body;
> -
> - for (i = 0; i < numenv; ++i) {
> - apr_size_t keylen, vallen;
> -
> - if (! elts[i].key) {
> - continue;
> - }
> -
> - keylen = strlen(elts[i].key);
> + /* Send envvars over in as many FastCGI records as it takes, */
> + next_elem = 0; /* starting with the first one */
>
> - 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;
> + avail_len = 16 * 1024; /* our limit per record, which could have been
> up
> + * to AP_FCGI_MAX_CONTENT_LEN
> + */
> +
> + while (next_elem < envarr->nelts) {
> + starting_elem = next_elem;
> + required_len = ap_fcgi_encoded_env_len(r->subprocess_env,
> + avail_len,
> + &next_elem);
> +
> + if (!required_len) {
> + if (next_elem < envarr->nelts) {
> + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
> + APLOGNO(02536) "couldn't encode envvar '%s'
> in %"
> + APR_SIZE_T_FMT " bytes",
> + elts[next_elem].key, avail_len);
> + /* skip this envvar and continue */
> + ++next_elem;
> + continue;
> + }
> + /* only an unused element at the end of the array */
> + break;
> }
>
> - vallen = strlen(elts[i].val);
> -
> - if (vallen >> 7 == 0) {
> - itr[0] = vallen & 0xff;
> - itr += 1;
> + body = apr_palloc(temp_pool, required_len);
> + rv = ap_fcgi_encode_env(r, r->subprocess_env, body, required_len,
> + &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);
> +
> + ap_fcgi_fill_in_header(&header, AP_FCGI_PARAMS, request_id,
> + (apr_uint16_t)required_len, 0);
> + ap_fcgi_header_to_array(&header, farray);
> +
> + vec[0].iov_base = (void *)farray;
> + vec[0].iov_len = sizeof(farray);
> + vec[1].iov_base = body;
> + vec[1].iov_len = required_len;
> +
> + rv = send_data(conn, vec, 2, &len, 1);
> + apr_pool_clear(temp_pool);
> +
> + if (rv) {
> + return rv;
> }
> - 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);
> -
> - vec[0].iov_base = (void *)farray;
> - vec[0].iov_len = sizeof(farray);
> - vec[1].iov_base = body;
> - vec[1].iov_len = bodylen;
> -
> - rv = send_data(conn, vec, 2, &len, 1);
> - if (rv) {
> - return rv;
> - }
> -
> - fill_in_header(&header, FCGI_PARAMS, request_id, 0, 0);
> - fcgi_header_to_array(&header, farray);
> + /* Envvars sent, so say we're done */
> + 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);
> @@ -482,69 +377,9 @@ static int handle_headers(request_rec *r
> return 0;
> }
>
> -static void dump_header_to_log(request_rec *r, unsigned char fheader[],
> - apr_size_t length)
> -{
> -#ifdef FCGI_DUMP_HEADERS
> - apr_size_t posn = 0;
> - char asc_line[20];
> - char hex_line[60];
> - int i = 0;
> -
> - memset(asc_line, 0, sizeof(asc_line));
> - memset(hex_line, 0, sizeof(hex_line));
> -
> - while (posn < length) {
> - unsigned char c = fheader[posn];
> -
> - if (i >= 20) {
> - i = 0;
> -
> - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01064)
> - "HEADER: %s %s", asc_line, hex_line);
> -
> - memset(asc_line, 0, sizeof(asc_line));
> - memset(hex_line, 0, sizeof(hex_line));
> - }
> -
> - if (isprint(c)) {
> - asc_line[i] = c;
> - }
> - else {
> - asc_line[i] = '.';
> - }
> -
> - if ((c >> 4) >= 10) {
> - hex_line[i * 3] = 'a' + ((c >> 4) - 10);
> - }
> - else {
> - hex_line[i * 3] = '0' + (c >> 4);
> - }
> -
> - if ((c & 0x0F) >= 10) {
> - hex_line[i * 3 + 1] = 'a' + ((c & 0x0F) - 10);
> - }
> - else {
> - hex_line[i * 3 + 1] = '0' + (c & 0xF);
> - }
> -
> - hex_line[i * 3 + 2] = ' ';
> -
> - i++;
> - posn++;
> - }
> -
> - if (i != 1) {
> - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01065)
> "HEADER: %s %s",
> - asc_line, hex_line);
> - }
> -
> - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01066) "HEADER:
> -EOH-");
> -#endif
> -}
> -
> static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf,
> - request_rec *r, apr_uint16_t request_id)
> + request_rec *r, apr_pool_t *setaside_pool,
> + apr_uint16_t request_id)
> {
> apr_bucket_brigade *ib, *ob;
> int seen_end_of_headers = 0, done = 0;
> @@ -552,14 +387,11 @@ static apr_status_t dispatch(proxy_conn_
> 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;
> -
> - apr_pool_create(&setaside_pool, r->pool);
> -
> +
> pfd.desc_type = APR_POLL_SOCKET;
> pfd.desc.s = conn->sock;
> pfd.p = r->pool;
> @@ -569,15 +401,13 @@ static apr_status_t dispatch(proxy_conn_
> ob = apr_brigade_create(r->pool, c->bucket_alloc);
>
> while (! done) {
> - apr_interval_time_t timeout = conn->worker->s->timeout;
> + apr_interval_time_t timeout;
> apr_size_t len;
> int n;
>
> /* We need SOME kind of timeout here, or virtually anything will
> * cause timeout errors. */
> - if (! conn->worker->s->timeout_set) {
> - timeout = apr_time_from_sec(30);
> - }
> + apr_socket_timeout_get(conn->sock, &timeout);
>
> rv = apr_poll(&pfd, 1, &n, timeout);
> if (rv != APR_SUCCESS) {
> @@ -614,9 +444,9 @@ static apr_status_t dispatch(proxy_conn_
> 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 +465,10 @@ static apr_status_t dispatch(proxy_conn_
> 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,47 +484,37 @@ static apr_status_t dispatch(proxy_conn_
> * 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;
> -
> - rv = get_data(conn, (char *) farray, &readbuflen);
> + rv = get_data_full(conn, (char *) farray, AP_FCGI_HEADER_LEN);
> if (rv != APR_SUCCESS) {
> - break;
> - }
> -
> - dump_header_to_log(r, farray, readbuflen);
> -
> - if (readbuflen != 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);
> - rv = APR_EINVAL;
> + "Failed to read FastCGI header");
> break;
> }
>
> - fcgi_header_from_array(&header, farray);
> +#ifdef FCGI_DUMP_HEADERS
> + ap_log_rdata(APLOG_MARK, APLOG_DEBUG, r, "FastCGI header",
> + farray, AP_FCGI_HEADER_LEN, 0);
> +#endif
> +
> + 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 +523,6 @@ static apr_status_t dispatch(proxy_conn_
> break;
> }
>
> - clen = header.contentLengthB1 << 8;
> - clen |= header.contentLengthB0;
> -
> - plen = header.paddingLength;
> -
> recv_again:
> if (clen > sizeof(readbuf) - 1) {
> readbuflen = sizeof(readbuf) - 1;
> @@ -726,7 +542,7 @@ recv_again:
> }
>
> switch (type) {
> - case FCGI_STDOUT:
> + case AP_FCGI_STDOUT:
> if (clen != 0) {
> b = apr_bucket_transient_create(readbuf,
> readbuflen,
> @@ -826,7 +642,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 +655,7 @@ recv_again:
> }
> break;
>
> - case FCGI_END_REQUEST:
> + case AP_FCGI_END_REQUEST:
> done = 1;
> break;
>
> @@ -850,10 +666,10 @@ recv_again:
> }
>
> if (plen) {
> - readbuflen = plen;
> -
> - rv = get_data(conn, readbuf, &readbuflen);
> + rv = get_data_full(conn, readbuf, plen);
> if (rv != APR_SUCCESS) {
> + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
> + APLOGNO(02537) "Error occurred reading
> padding");
> break;
> }
> }
> @@ -887,8 +703,9 @@ static int fcgi_do_request(apr_pool_t *p
> * keep things simple. */
> apr_uint16_t request_id = 1;
> apr_status_t rv;
> + apr_pool_t *temp_pool;
>
> - /* 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)
> @@ -897,8 +714,10 @@ static int fcgi_do_request(apr_pool_t *p
> return HTTP_SERVICE_UNAVAILABLE;
> }
>
> + apr_pool_create(&temp_pool, r->pool);
> +
> /* Step 2: Send Environment via FCGI_PARAMS */
> - rv = send_environment(conn, r, request_id);
> + rv = send_environment(conn, r, temp_pool, request_id);
> if (rv != APR_SUCCESS) {
> ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01074)
> "Failed writing Environment to %s:",
> server_portstr);
> @@ -907,7 +726,7 @@ static int fcgi_do_request(apr_pool_t *p
> }
>
> /* Step 3: Read records from the back end server and handle them. */
> - rv = dispatch(conn, conf, r, request_id);
> + rv = dispatch(conn, conf, r, temp_pool, request_id);
> if (rv != APR_SUCCESS) {
> ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01075)
> "Error dispatching request to %s:", server_portstr);
>
>
>
--
Born in Roswell... married an alien...
http://emptyhammock.com/