mod_proxy_fcgi.c revision 89c7a19f9c47b03f00f622a979490c9bccb2ff03
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny/* Licensed to the Apache Software Foundation (ASF) under one or more
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * contributor license agreements. See the NOTICE file distributed with
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * this work for additional information regarding copyright ownership.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * The ASF licenses this file to You under the Apache License, Version 2.0
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * (the "License"); you may not use this file except in compliance with
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * the License. You may obtain a copy of the License at
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny *
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * http://www.apache.org/licenses/LICENSE-2.0
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny *
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * Unless required by applicable law or agreed to in writing, software
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * distributed under the License is distributed on an "AS IS" BASIS,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * See the License for the specific language governing permissions and
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * limitations under the License.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "mod_proxy.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "fcgi_protocol.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "util_script.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenymodule AP_MODULE_DECLARE_DATA proxy_fcgi_module;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny/*
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * The below 3 functions serve to map the FCGI structs
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * back and forth between an 8 byte array. We do this to avoid
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce * any potential padding issues when we send or read these
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce * structures.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny *
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce * NOTE: These have specific internal knowledge of the
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * layout of the fcgi_header and fcgi_begin_request_body
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * structs!
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystatic void fcgi_header_to_array(fcgi_header *h, unsigned char a[])
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny{
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny a[FCGI_HDR_VERSION_OFFSET] = h->version;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce a[FCGI_HDR_TYPE_OFFSET] = h->type;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny a[FCGI_HDR_REQUEST_ID_B1_OFFSET] = h->requestIdB1;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny a[FCGI_HDR_REQUEST_ID_B0_OFFSET] = h->requestIdB0;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny a[FCGI_HDR_CONTENT_LEN_B1_OFFSET] = h->contentLengthB1;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce a[FCGI_HDR_CONTENT_LEN_B0_OFFSET] = h->contentLengthB0;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny a[FCGI_HDR_PADDING_LEN_OFFSET] = h->paddingLength;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny a[FCGI_HDR_RESERVED_OFFSET] = h->reserved;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny}
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystatic void fcgi_header_from_array(fcgi_header *h, unsigned char a[])
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny{
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny h->version = a[FCGI_HDR_VERSION_OFFSET];
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny h->type = a[FCGI_HDR_TYPE_OFFSET];
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce h->requestIdB1 = a[FCGI_HDR_REQUEST_ID_B1_OFFSET];
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny h->requestIdB0 = a[FCGI_HDR_REQUEST_ID_B0_OFFSET];
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny h->contentLengthB1 = a[FCGI_HDR_CONTENT_LEN_B1_OFFSET];
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny h->contentLengthB0 = a[FCGI_HDR_CONTENT_LEN_B0_OFFSET];
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny h->paddingLength = a[FCGI_HDR_PADDING_LEN_OFFSET];
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce h->reserved = a[FCGI_HDR_RESERVED_OFFSET];
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny}
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystatic void fcgi_begin_request_body_to_array(fcgi_begin_request_body *h,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny unsigned char a[])
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny{
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny a[FCGI_BRB_ROLEB1_OFFSET] = h->roleB1;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny a[FCGI_BRB_ROLEB0_OFFSET] = h->roleB0;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce a[FCGI_BRB_FLAGS_OFFSET] = h->flags;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce a[FCGI_BRB_RESERVED0_OFFSET] = h->reserved[0];
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny a[FCGI_BRB_RESERVED1_OFFSET] = h->reserved[1];
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny a[FCGI_BRB_RESERVED2_OFFSET] = h->reserved[2];
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny a[FCGI_BRB_RESERVED3_OFFSET] = h->reserved[3];
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny a[FCGI_BRB_RESERVED4_OFFSET] = h->reserved[4];
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny}
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce/*
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce * Canonicalise http-like URLs.
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce * scheme is the scheme for the URL
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce * url is the URL starting with the first '/'
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce * def_port is the default port for this scheme.
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce */
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorcestatic int proxy_fcgi_canon(request_rec *r, char *url)
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce{
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce char *host, sport[7];
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce const char *err, *path;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny apr_port_t port = 8000;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (strncasecmp(url, "fcgi:", 5) == 0) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny url += 5;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce }
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce else {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny return DECLINED;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce }
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, r->server,
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce "proxy: FCGI: canonicalising URL %s", url);
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce if (err) {
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce "error parsing URL %s: %s", url, err);
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce return HTTP_BAD_REQUEST;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny apr_snprintf(sport, sizeof(sport), ":%d", port);
6a8999bf933f72923a271831d85a01ef88a81f39Jakub Hrozek
6a8999bf933f72923a271831d85a01ef88a81f39Jakub Hrozek if (ap_strchr_c(host, ':')) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny /* if literal IPv6 address */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny host = apr_pstrcat(r->pool, "[", host, "]", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (apr_table_get(r->notes, "proxy-nocanon")) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny path = url; /* this is the raw path */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny else {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce r->proxyreq);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (path == NULL)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return HTTP_BAD_REQUEST;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny r->filename = apr_pstrcat(r->pool, "proxy:fcgi://", host, sport, "/",
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny path, NULL);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny "proxy: FCGI: set r->filename to %s", r->filename);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny r->path_info = apr_pstrcat(r->pool, "/", path, NULL);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny "proxy: FCGI: set r->path_info to %s", r->path_info);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return OK;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny}
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce/*
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * Fill in a fastcgi request header with the following type, request id,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * content length, and padding length.
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny *
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * The header array must be at least FCGI_HEADER_LEN bytes long.
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce */
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorcestatic void fill_in_header(fcgi_header *header,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny unsigned char type,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_uint16_t request_id,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_uint16_t content_len,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny unsigned char padding_len)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny{
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce header->version = FCGI_VERSION;
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce header->type = type;
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce header->requestIdB1 = ((request_id >> 8) & 0xff);
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce header->requestIdB0 = ((request_id) & 0xff);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce header->contentLengthB1 = ((content_len >> 8) & 0xff);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny header->contentLengthB0 = ((content_len) & 0xff);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny header->paddingLength = padding_len;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce header->reserved = 0;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce}
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce/* Wrapper for apr_socket_sendv that handles updating the worker stats. */
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorcestatic apr_status_t send_data(proxy_conn_rec *conn,
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce struct iovec *vec,
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce int nvec,
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce apr_size_t *len,
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce int blocking)
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce{
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce apr_status_t rv = APR_SUCCESS, arv;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce apr_size_t written = 0, to_write = 0;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny int i, offset;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_interval_time_t old_timeout;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce apr_socket_t *s = conn->sock;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce if (!blocking) {
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce arv = apr_socket_timeout_get(s, &old_timeout);
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce if (arv != APR_SUCCESS) {
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce return arv;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny arv = apr_socket_timeout_set(s, 0);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (arv != APR_SUCCESS) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return arv;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce for (i = 0; i < nvec; i++) {
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce to_write += vec[i].iov_len;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce }
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce offset = 0;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce while (to_write) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_size_t n = 0;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny rv = apr_socket_sendv(s, vec + offset, nvec - offset, &n);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (rv != APR_SUCCESS) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny break;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (n > 0) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny written += n;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (written >= to_write)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny break; /* short circuit out */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny for (i = offset; i < nvec; ) {
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce if (n >= vec[i].iov_len) {
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce offset++;
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce n -= vec[i++].iov_len;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny } else {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny vec[i].iov_len -= n;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny vec[i].iov_base = (char *) vec[i].iov_base + n;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny break;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny conn->worker->s->transferred += written;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny *len = written;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (!blocking) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny arv = apr_socket_timeout_set(s, old_timeout);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if ((arv != APR_SUCCESS) && (rv == APR_SUCCESS)) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return arv;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return rv;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny}
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny/* Wrapper for apr_socket_recv that handles updating the worker stats. */
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorcestatic apr_status_t get_data(proxy_conn_rec *conn,
0754ff886f909f0404038eb9c99dd61be1acf5b9Simo Sorce char *buffer,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_size_t *buflen)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny{
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_status_t rv = apr_socket_recv(conn->sock, buffer, buflen);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (rv == APR_SUCCESS) {
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce conn->worker->s->read += *buflen;
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce }
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce return rv;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce}
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorcestatic apr_status_t send_begin_request(proxy_conn_rec *conn, int request_id)
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce{
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce struct iovec vec[2];
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce fcgi_header header;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce unsigned char farray[FCGI_HEADER_LEN];
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce fcgi_begin_request_body brb;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce unsigned char abrb[FCGI_HEADER_LEN];
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce apr_size_t len;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce fill_in_header(&header, FCGI_BEGIN_REQUEST, request_id, sizeof(abrb), 0);
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce brb.roleB1 = ((FCGI_RESPONDER >> 8) & 0xff);
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce brb.roleB0 = ((FCGI_RESPONDER) & 0xff);
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce brb.flags = FCGI_KEEP_CONN;
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce brb.reserved[0] = 0;
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce brb.reserved[1] = 0;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny brb.reserved[2] = 0;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny brb.reserved[3] = 0;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny brb.reserved[4] = 0;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny fcgi_header_to_array(&header, farray);
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce fcgi_begin_request_body_to_array(&brb, abrb);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
c03b28a38b14fdb59f74864ae4dc56affe256508Simo Sorce vec[0].iov_base = farray;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny vec[0].iov_len = sizeof(farray);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny vec[1].iov_base = abrb;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny vec[1].iov_len = sizeof(abrb);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return send_data(conn, vec, 2, &len, 1);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny}
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorcestatic apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r,
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce int request_id)
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce{
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny const apr_array_header_t *envarr;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny const apr_table_entry_t *elts;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny struct iovec vec[2];
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny fcgi_header header;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny unsigned char farray[FCGI_HEADER_LEN];
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce apr_size_t bodylen, envlen;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny char *body, *itr;
c03b28a38b14fdb59f74864ae4dc56affe256508Simo Sorce apr_status_t rv;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_size_t len;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny int i, numenv;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny ap_add_common_vars(r);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny ap_add_cgi_vars(r);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* XXX are there any FastCGI specific env vars we need to send? */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny bodylen = envlen = 0;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* XXX mod_cgi/mod_cgid use ap_create_environment here, which fills in
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce * the TZ value specially. We could use that, but it would mean
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * parsing the key/value pairs back OUT of the allocated env array,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * not to mention allocating a totally useless array in the first
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce * place, which would suck. */
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny envarr = apr_table_elts(r->subprocess_env);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny elts = (const apr_table_entry_t *) envarr->elts;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny for (i = 0; i < envarr->nelts; ++i) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_size_t keylen, vallen;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (! elts[i].key) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny continue;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce keylen = strlen(elts[i].key);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
b58460076fe843c11d736ae244c1ac979a6473a4Simo Sorce if (keylen >> 7 == 0) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny envlen += 1;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny else {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny envlen += 4;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny envlen += keylen;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny vallen = strlen(elts[i].val);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#ifdef FCGI_DUMP_ENV_VARS
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "proxy: FCGI: sending env var '%s' value '%s'",
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny elts[i].key, elts[i].val);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#endif
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (vallen >> 7 == 0) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny envlen += 1;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny else {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny envlen += 4;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny envlen += vallen;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny /* The cast of bodylen is safe since FCGI_MAX_ENV_SIZE is for sure an int */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (envlen > FCGI_MAX_ENV_SIZE) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "proxy: FCGI: truncating environment to %d bytes and %d elements",
7616a65d63d3bd0f669a871fd0ed89185956e9ceSimo Sorce (int)bodylen, i);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny break;
c03b28a38b14fdb59f74864ae4dc56affe256508Simo Sorce }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny bodylen = envlen;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce numenv = i;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce body = apr_pcalloc(r->pool, bodylen);
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce itr = body;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce for (i = 0; i < numenv; ++i) {
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce apr_size_t keylen, vallen;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce if (! elts[i].key) {
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce continue;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce }
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce keylen = strlen(elts[i].key);
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (keylen >> 7 == 0) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny itr[0] = keylen & 0xff;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny itr += 1;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny else {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny itr[0] = ((keylen >> 24) & 0xff) | 0x80;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny itr[1] = ((keylen >> 16) & 0xff);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny itr[2] = ((keylen >> 8) & 0xff);
7616a65d63d3bd0f669a871fd0ed89185956e9ceSimo Sorce itr[3] = ((keylen) & 0xff);
7616a65d63d3bd0f669a871fd0ed89185956e9ceSimo Sorce itr += 4;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
c03b28a38b14fdb59f74864ae4dc56affe256508Simo Sorce
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny vallen = strlen(elts[i].val);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (vallen >> 7 == 0) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny itr[0] = vallen & 0xff;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny itr += 1;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny else {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny itr[0] = ((vallen >> 24) & 0xff) | 0x80;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny itr[1] = ((vallen >> 16) & 0xff);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny itr[2] = ((vallen >> 8) & 0xff);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny itr[3] = ((vallen) & 0xff);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny itr += 4;
7616a65d63d3bd0f669a871fd0ed89185956e9ceSimo Sorce }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
c03b28a38b14fdb59f74864ae4dc56affe256508Simo Sorce memcpy(itr, elts[i].key, keylen);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny itr += keylen;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny memcpy(itr, elts[i].val, vallen);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny itr += vallen;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny fill_in_header(&header, FCGI_PARAMS, request_id, bodylen, 0);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny fcgi_header_to_array(&header, farray);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny vec[0].iov_base = farray;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny vec[0].iov_len = sizeof(farray);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny vec[1].iov_base = body;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny vec[1].iov_len = bodylen;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny rv = send_data(conn, vec, 2, &len, 1);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (rv) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny return rv;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny fill_in_header(&header, FCGI_PARAMS, request_id, 0, 0);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny fcgi_header_to_array(&header, farray);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce vec[0].iov_base = farray;
efea50efda58be66638e5d38c8e57fdf9992f204Simo Sorce vec[0].iov_len = sizeof(farray);
efea50efda58be66638e5d38c8e57fdf9992f204Simo Sorce
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny return send_data(conn, vec, 1, &len, 1);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny}
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenyenum {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny HDR_STATE_READING_HEADERS,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny HDR_STATE_GOT_CR,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny HDR_STATE_GOT_CRLF,
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce HDR_STATE_GOT_CRLFCR,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny HDR_STATE_GOT_LF,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny HDR_STATE_DONE_WITH_HEADERS
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny};
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny/* Try to parse the script headers in the response from the back end fastcgi
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * server. Assumes that the contents of READBUF have already been added to
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * the end of OB. STATE holds the current header parsing state for this
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * request.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny *
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * Returns -1 on error, 0 if it can't find the end of the headers, and 1 if
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * it found the end of the headers and scans them successfully. */
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorcestatic int handle_headers(request_rec *r,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny int *state,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny char *readbuf,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny apr_bucket_brigade *ob)
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny{
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny conn_rec *c = r->connection;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny const char *itr = readbuf;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny while (*itr) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (*itr == '\r') {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny switch (*state) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny case HDR_STATE_GOT_CRLF:
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny *state = HDR_STATE_GOT_CRLFCR;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny break;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny default:
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny *state = HDR_STATE_GOT_CR;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny break;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny else if (*itr == '\n') {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny switch (*state) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny case HDR_STATE_GOT_LF:
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny *state = HDR_STATE_DONE_WITH_HEADERS;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny break;
efea50efda58be66638e5d38c8e57fdf9992f204Simo Sorce
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny case HDR_STATE_GOT_CR:
efea50efda58be66638e5d38c8e57fdf9992f204Simo Sorce *state = HDR_STATE_GOT_CRLF;
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce break;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny case HDR_STATE_GOT_CRLFCR:
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny *state = HDR_STATE_DONE_WITH_HEADERS;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny break;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny default:
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny *state = HDR_STATE_GOT_LF;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny break;
efea50efda58be66638e5d38c8e57fdf9992f204Simo Sorce }
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny else {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny *state = HDR_STATE_READING_HEADERS;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (*state == HDR_STATE_DONE_WITH_HEADERS)
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce break;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ++itr;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (*state == HDR_STATE_DONE_WITH_HEADERS) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny int status = ap_scan_script_header_err_brigade(r, ob, NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (status != OK) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny apr_bucket *b;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny r->status = status;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny apr_brigade_cleanup(ob);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny b = apr_bucket_eos_create(c->bucket_alloc);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny APR_BRIGADE_INSERT_TAIL(ob, b);
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_pass_brigade(r->output_filters, ob);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "proxy: FCGI: Error parsing script headers");
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny return -1;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny else {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny return 1;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny return 0;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny}
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidekstatic void dump_header_to_log(request_rec *r, unsigned char fheader[],
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny apr_size_t length)
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek{
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#ifdef FCGI_DUMP_HEADERS
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek apr_size_t posn = 0;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny char asc_line[20];
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny char hex_line[60];
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny int i = 0;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny memset(asc_line, 0, sizeof(asc_line));
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny memset(hex_line, 0, sizeof(hex_line));
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny while (posn < length) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny unsigned char c = fheader[posn];
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (i >= 20) {
i = 0;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"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_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "HEADER: %s %s",
asc_line, hex_line);
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "HEADER: -EOH-");
#endif
}
static apr_status_t dispatch(proxy_conn_rec *conn, request_rec *r,
int request_id)
{
apr_bucket_brigade *ib, *ob;
int seen_end_of_headers = 0, done = 0;
apr_status_t rv = APR_SUCCESS;
conn_rec *c = r->connection;
struct iovec vec[2];
fcgi_header header;
unsigned char farray[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;
pfd.reqevents = APR_POLLIN | APR_POLLOUT;
ib = apr_brigade_create(r->pool, c->bucket_alloc);
ob = apr_brigade_create(r->pool, c->bucket_alloc);
while (! done) {
apr_interval_time_t timeout = conn->worker->timeout;
apr_size_t len;
int n;
/* We need SOME kind of timeout here, or virtually anything will
* cause timeout errors. */
if (! conn->worker->timeout_set) {
timeout = apr_time_from_sec(30);
}
rv = apr_poll(&pfd, 1, &n, timeout);
if (rv != APR_SUCCESS) {
break;
}
if (pfd.rtnevents & APR_POLLOUT) {
char writebuf[AP_IOBUFSIZE];
apr_size_t writebuflen;
int last_stdin = 0;
rv = ap_get_brigade(r->input_filters, ib,
AP_MODE_READBYTES, APR_BLOCK_READ,
sizeof(writebuf));
if (rv != APR_SUCCESS) {
break;
}
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(ib))) {
last_stdin = 1;
}
writebuflen = sizeof(writebuf);
rv = apr_brigade_flatten(ib, writebuf, &writebuflen);
apr_brigade_cleanup(ib);
if (rv != APR_SUCCESS) {
break;
}
fill_in_header(&header, FCGI_STDIN, request_id,
(apr_uint16_t) writebuflen, 0);
fcgi_header_to_array(&header, farray);
vec[0].iov_base = farray;
vec[0].iov_len = sizeof(farray);
vec[1].iov_base = writebuf;
vec[1].iov_len = writebuflen;
rv = send_data(conn, vec, 2, &len, 0);
if (rv != APR_SUCCESS) {
break;
}
if (last_stdin) {
pfd.reqevents = APR_POLLIN; /* Done with input data */
fill_in_header(&header, FCGI_STDIN, request_id, 0, 0);
fcgi_header_to_array(&header, farray);
vec[0].iov_base = farray;
vec[0].iov_len = sizeof(farray);
rv = send_data(conn, vec, 1, &len, 1);
}
}
if (pfd.rtnevents & APR_POLLIN) {
/* readbuf has one byte on the end that is always 0, so it's
* able to work with a strstr when we search for the end of
* 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_bucket *b;
char plen;
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);
if (rv != APR_SUCCESS) {
break;
}
dump_header_to_log(r, farray, readbuflen);
if (readbuflen != FCGI_HEADER_LEN) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"proxy: FCGI: Failed to read entire header "
"got %" APR_SIZE_T_FMT " wanted %d",
readbuflen, FCGI_HEADER_LEN);
rv = APR_EINVAL;
break;
}
fcgi_header_from_array(&header, farray);
if (header.version != FCGI_VERSION) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"proxy: FCGI: 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_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"proxy: FCGI: Got bogus rid %d, expected %d",
rid, request_id);
rv = APR_EINVAL;
break;
}
clen = header.contentLengthB1 << 8;
clen |= header.contentLengthB0;
plen = header.paddingLength;
recv_again:
if (clen > sizeof(readbuf) - 1) {
readbuflen = sizeof(readbuf) - 1;
} else {
readbuflen = clen;
}
/* Now get the actual data. Yes it sucks to do this in a second
* recv call, this will eventually change when we move to real
* nonblocking recv calls. */
if (readbuflen != 0) {
rv = get_data(conn, readbuf, &readbuflen);
if (rv != APR_SUCCESS) {
break;
}
readbuf[readbuflen] = 0;
}
switch (type) {
case FCGI_STDOUT:
if (clen != 0) {
b = apr_bucket_transient_create(readbuf,
readbuflen,
c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(ob, b);
if (! seen_end_of_headers) {
int st = handle_headers(r, &header_state, readbuf, ob);
if (st == 1) {
seen_end_of_headers = 1;
rv = ap_pass_brigade(r->output_filters, ob);
if (rv != APR_SUCCESS) {
break;
}
apr_brigade_cleanup(ob);
apr_pool_clear(setaside_pool);
}
else if (st == -1) {
rv = APR_EINVAL;
break;
}
else {
/* We're still looking for the end of the
* headers, so this part of the data will need
* to persist. */
apr_bucket_setaside(b, setaside_pool);
}
} else {
/* we've already passed along the headers, so now pass
* through the content. we could simply continue to
* setaside the content and not pass until we see the
* 0 content-length (below, where we append the EOS),
* but that could be a huge amount of data; so we pass
* along smaller chunks
*/
rv = ap_pass_brigade(r->output_filters, ob);
if (rv != APR_SUCCESS) {
break;
}
apr_brigade_cleanup(ob);
}
/* If we didn't read all the data go back and get the
* rest of it. */
if (clen > readbuflen) {
clen -= readbuflen;
goto recv_again;
}
} else {
/* XXX what if we haven't seen end of the headers yet? */
b = apr_bucket_eos_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(ob, b);
rv = ap_pass_brigade(r->output_filters, ob);
if (rv != APR_SUCCESS) {
break;
}
/* XXX Why don't we cleanup here? (logic from AJP) */
}
break;
case FCGI_STDERR:
/* TODO: Should probably clean up this logging a bit... */
if (clen) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"proxy: FCGI: Got error '%s'", readbuf);
}
if (clen > readbuflen) {
clen -= readbuflen;
goto recv_again;
}
break;
case FCGI_END_REQUEST:
done = 1;
break;
default:
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"proxy: FCGI: Got bogus record %d", type);
break;
}
if (plen) {
readbuflen = plen;
rv = get_data(conn, readbuf, &readbuflen);
if (rv != APR_SUCCESS) {
break;
}
}
}
}
apr_brigade_destroy(ib);
apr_brigade_destroy(ob);
return rv;
}
/*
* process the request and write the response.
*/
static int fcgi_do_request(apr_pool_t *p, request_rec *r,
proxy_conn_rec *conn,
conn_rec *origin,
proxy_dir_conf *conf,
apr_uri_t *uri,
char *url, char *server_portstr)
{
/* Request IDs are arbitrary numbers that we assign to a
* single request. This would allow multiplex/pipelinig of
* multiple requests to the same FastCGI connection, but
* we don't support that, and always use a value of '1' to
* keep things simple. */
int request_id = 1;
apr_status_t rv;
/* Step 1: Send FCGI_BEGIN_REQUEST */
rv = send_begin_request(conn, request_id);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
"proxy: FCGI: Failed Writing Request to %s:",
server_portstr);
conn->close = 1;
return HTTP_SERVICE_UNAVAILABLE;
}
/* Step 2: Send Environment via FCGI_PARAMS */
rv = send_environment(conn, r, request_id);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
"proxy: FCGI: Failed writing Environment to %s:",
server_portstr);
conn->close = 1;
return HTTP_SERVICE_UNAVAILABLE;
}
/* Step 3: Read records from the back end server and handle them. */
rv = dispatch(conn, r, request_id);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
"proxy: FCGI: Error dispatching request to %s:",
server_portstr);
conn->close = 1;
return HTTP_SERVICE_UNAVAILABLE;
}
return OK;
}
#define FCGI_SCHEME "FCGI"
/*
* This handles fcgi:(dest) URLs
*/
static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker,
proxy_server_conf *conf,
char *url, const char *proxyname,
apr_port_t proxyport)
{
int status;
char server_portstr[32];
conn_rec *origin = NULL;
proxy_conn_rec *backend = NULL;
proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
&proxy_module);
apr_pool_t *p = r->pool;
apr_uri_t *uri = apr_palloc(r->pool, sizeof(*uri));
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: FCGI: url: %s proxyname: %s proxyport: %d",
url, proxyname, proxyport);
if (strncasecmp(url, "fcgi:", 5) == 0) {
url += 5;
}
else {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: FCGI: declining URL %s", url);
return DECLINED;
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: FCGI: serving URL %s", url);
/* Create space for state information */
if (! backend) {
status = ap_proxy_acquire_connection(FCGI_SCHEME, &backend, worker,
r->server);
if (status != OK) {
if (backend) {
backend->close = 1;
ap_proxy_release_connection(FCGI_SCHEME, backend, r->server);
}
return status;
}
}
backend->is_ssl = 0;
/* XXX Setting close to 0 is a great way to end up with
* timeouts at this point, since we lack good ways to manage the
* back end fastcgi processes. This should be revisited when we
* have a better story on that part of things. */
backend->close = 1;
/* Step One: Determine Who To Connect To */
status = ap_proxy_determine_connection(p, r, conf, worker, backend,
uri, &url, proxyname, proxyport,
server_portstr,
sizeof(server_portstr));
if (status != OK) {
goto cleanup;
}
/* Step Two: Make the Connection */
if (ap_proxy_connect_backend(FCGI_SCHEME, backend, worker, r->server)) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"proxy: FCGI: failed to make connection to backend: %s",
backend->hostname);
status = HTTP_SERVICE_UNAVAILABLE;
goto cleanup;
}
/* Step Three: Process the Request */
status = fcgi_do_request(p, r, backend, origin, dconf, uri, url,
server_portstr);
cleanup:
/* Do not close the socket */
ap_proxy_release_connection(FCGI_SCHEME, backend, r->server);
return status;
}
static void register_hooks(apr_pool_t *p)
{
proxy_hook_scheme_handler(proxy_fcgi_handler, NULL, NULL, APR_HOOK_FIRST);
proxy_hook_canon_handler(proxy_fcgi_canon, NULL, NULL, APR_HOOK_FIRST);
}
AP_DECLARE_MODULE(proxy_fcgi) = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-directory config structure */
NULL, /* merge per-directory config structures */
NULL, /* create per-server config structure */
NULL, /* merge per-server config structures */
NULL, /* command apr_table_t */
register_hooks /* register hooks */
};