|
Packit Service |
f9aed3 |
/*
|
|
Packit Service |
f9aed3 |
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
Packit Service |
f9aed3 |
* contributor license agreements. See the NOTICE file distributed with
|
|
Packit Service |
f9aed3 |
* this work for additional information regarding copyright ownership.
|
|
Packit Service |
f9aed3 |
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
Packit Service |
f9aed3 |
* (the "License"); you may not use this file except in compliance with
|
|
Packit Service |
f9aed3 |
* the License. You may obtain a copy of the License at
|
|
Packit Service |
f9aed3 |
*
|
|
Packit Service |
f9aed3 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit Service |
f9aed3 |
*
|
|
Packit Service |
f9aed3 |
* Unless required by applicable law or agreed to in writing, software
|
|
Packit Service |
f9aed3 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit Service |
f9aed3 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit Service |
f9aed3 |
* See the License for the specific language governing permissions and
|
|
Packit Service |
f9aed3 |
* limitations under the License.
|
|
Packit Service |
f9aed3 |
*/
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
#include "httpd.h"
|
|
Packit Service |
f9aed3 |
#include "http_request.h"
|
|
Packit Service |
f9aed3 |
#include "apr_strings.h"
|
|
Packit Service |
f9aed3 |
#include "apr_portable.h"
|
|
Packit Service |
f9aed3 |
#include "apr_pools.h"
|
|
Packit Service |
f9aed3 |
#include "apr_file_io.h"
|
|
Packit Service |
f9aed3 |
#include "util_script.h"
|
|
Packit Service |
f9aed3 |
#include "fcgid_bridge.h"
|
|
Packit Service |
f9aed3 |
#include "fcgid_pm.h"
|
|
Packit Service |
f9aed3 |
#include "fcgid_proctbl.h"
|
|
Packit Service |
f9aed3 |
#include "fcgid_proc.h"
|
|
Packit Service |
f9aed3 |
#include "fcgid_conf.h"
|
|
Packit Service |
f9aed3 |
#include "fcgid_spawn_ctl.h"
|
|
Packit Service |
f9aed3 |
#include "fcgid_protocol.h"
|
|
Packit Service |
f9aed3 |
#include "fcgid_bucket.h"
|
|
Packit Service |
f9aed3 |
#define FCGID_APPLY_TRY_COUNT 2
|
|
Packit Service |
f9aed3 |
#define FCGID_REQUEST_COUNT 32
|
|
Packit Service |
f9aed3 |
#define FCGID_BRIGADE_CLEAN_STEP 32
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
static fcgid_procnode *apply_free_procnode(request_rec *r,
|
|
Packit Service |
f9aed3 |
fcgid_command * command)
|
|
Packit Service |
f9aed3 |
{
|
|
Packit Service |
f9aed3 |
/* Scan idle list, find a node match inode, deviceid and groupid
|
|
Packit Service |
f9aed3 |
If there is no one there, return NULL */
|
|
Packit Service |
f9aed3 |
fcgid_procnode *previous_node, *current_node, *next_node;
|
|
Packit Service |
f9aed3 |
fcgid_procnode *busy_list_header, *proc_table;
|
|
Packit Service |
f9aed3 |
apr_ino_t inode = command->inode;
|
|
Packit Service |
f9aed3 |
apr_dev_t deviceid = command->deviceid;
|
|
Packit Service |
f9aed3 |
uid_t uid = command->uid;
|
|
Packit Service |
f9aed3 |
gid_t gid = command->gid;
|
|
Packit Service |
f9aed3 |
const char *cmdline = command->cmdline;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
proc_table = proctable_get_table_array();
|
|
Packit Service |
f9aed3 |
previous_node = proctable_get_idle_list();
|
|
Packit Service |
f9aed3 |
busy_list_header = proctable_get_busy_list();
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
proctable_lock(r);
|
|
Packit Service |
f9aed3 |
current_node = &proc_table[previous_node->next_index];
|
|
Packit Service |
f9aed3 |
while (current_node != proc_table) {
|
|
Packit Service |
f9aed3 |
next_node = &proc_table[current_node->next_index];
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if (current_node->inode == inode
|
|
Packit Service |
f9aed3 |
&& current_node->deviceid == deviceid
|
|
Packit Service |
f9aed3 |
&& !strcmp(current_node->cmdline, cmdline)
|
|
Packit Service |
f9aed3 |
&& current_node->vhost_id == command->vhost_id
|
|
Packit Service |
f9aed3 |
&& current_node->uid == uid && current_node->gid == gid) {
|
|
Packit Service |
f9aed3 |
/* Unlink from idle list */
|
|
Packit Service |
f9aed3 |
previous_node->next_index = current_node->next_index;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Link to busy list */
|
|
Packit Service |
f9aed3 |
current_node->next_index = busy_list_header->next_index;
|
|
Packit Service |
f9aed3 |
busy_list_header->next_index = current_node - proc_table;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
proctable_unlock(r);
|
|
Packit Service |
f9aed3 |
return current_node;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
else
|
|
Packit Service |
f9aed3 |
previous_node = current_node;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
current_node = next_node;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
proctable_unlock(r);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Found nothing */
|
|
Packit Service |
f9aed3 |
return NULL;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
static void
|
|
Packit Service |
f9aed3 |
return_procnode(request_rec *r,
|
|
Packit Service |
f9aed3 |
fcgid_procnode *procnode, int communicate_error)
|
|
Packit Service |
f9aed3 |
{
|
|
Packit Service |
f9aed3 |
fcgid_procnode *previous_node, *current_node, *next_node;
|
|
Packit Service |
f9aed3 |
fcgid_procnode *proc_table = proctable_get_table_array();
|
|
Packit Service |
f9aed3 |
fcgid_procnode *error_list_header = proctable_get_error_list();
|
|
Packit Service |
f9aed3 |
fcgid_procnode *idle_list_header = proctable_get_idle_list();
|
|
Packit Service |
f9aed3 |
fcgid_procnode *busy_list_header = proctable_get_busy_list();
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
proctable_lock(r);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Unlink the node from busy list first */
|
|
Packit Service |
f9aed3 |
previous_node = busy_list_header;
|
|
Packit Service |
f9aed3 |
current_node = &proc_table[previous_node->next_index];
|
|
Packit Service |
f9aed3 |
while (current_node != proc_table) {
|
|
Packit Service |
f9aed3 |
next_node = &proc_table[current_node->next_index];
|
|
Packit Service |
f9aed3 |
if (current_node == procnode) {
|
|
Packit Service |
f9aed3 |
/* Unlink from busy list */
|
|
Packit Service |
f9aed3 |
previous_node->next_index = current_node->next_index;
|
|
Packit Service |
f9aed3 |
break;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
else
|
|
Packit Service |
f9aed3 |
previous_node = current_node;
|
|
Packit Service |
f9aed3 |
current_node = next_node;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Return to error list or idle list */
|
|
Packit Service |
f9aed3 |
if (communicate_error) {
|
|
Packit Service |
f9aed3 |
/* Link to error list */
|
|
Packit Service |
f9aed3 |
procnode->next_index = error_list_header->next_index;
|
|
Packit Service |
f9aed3 |
error_list_header->next_index = procnode - proc_table;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
else {
|
|
Packit Service |
f9aed3 |
/* Link to idle list */
|
|
Packit Service |
f9aed3 |
procnode->next_index = idle_list_header->next_index;
|
|
Packit Service |
f9aed3 |
idle_list_header->next_index = procnode - proc_table;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
proctable_unlock(r);
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
static int count_busy_processes(request_rec *r, fcgid_command *command)
|
|
Packit Service |
f9aed3 |
{
|
|
Packit Service |
f9aed3 |
int result = 0;
|
|
Packit Service |
f9aed3 |
fcgid_procnode *previous_node, *current_node, *next_node;
|
|
Packit Service |
f9aed3 |
fcgid_procnode *proc_table = proctable_get_table_array();
|
|
Packit Service |
f9aed3 |
fcgid_procnode *busy_list_header = proctable_get_busy_list();
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
proctable_lock(r);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
previous_node = busy_list_header;
|
|
Packit Service |
f9aed3 |
current_node = &proc_table[previous_node->next_index];
|
|
Packit Service |
f9aed3 |
while (current_node != proc_table) {
|
|
Packit Service |
f9aed3 |
if (current_node->inode == command->inode
|
|
Packit Service |
f9aed3 |
&& current_node->deviceid == command->deviceid
|
|
Packit Service |
f9aed3 |
&& !strcmp(current_node->cmdline, command->cmdline)
|
|
Packit Service |
f9aed3 |
&& current_node->vhost_id == command->vhost_id
|
|
Packit Service |
f9aed3 |
&& current_node->uid == command->uid
|
|
Packit Service |
f9aed3 |
&& current_node->gid == command->gid) {
|
|
Packit Service |
f9aed3 |
result++;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
next_node = &proc_table[current_node->next_index];
|
|
Packit Service |
f9aed3 |
current_node = next_node;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
proctable_unlock(r);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
return result;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
apr_status_t bucket_ctx_cleanup(void *thectx)
|
|
Packit Service |
f9aed3 |
{
|
|
Packit Service |
f9aed3 |
/* Cleanup jobs:
|
|
Packit Service |
f9aed3 |
1. Free bucket buffer
|
|
Packit Service |
f9aed3 |
2. Return procnode
|
|
Packit Service |
f9aed3 |
NOTE: ipc will be clean when request pool cleanup, so I don't need to close it here
|
|
Packit Service |
f9aed3 |
*/
|
|
Packit Service |
f9aed3 |
fcgid_bucket_ctx *ctx = (fcgid_bucket_ctx *) thectx;
|
|
Packit Service |
f9aed3 |
request_rec *r = ctx->ipc.request;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Free bucket buffer */
|
|
Packit Service |
f9aed3 |
if (ctx->buffer) {
|
|
Packit Service |
f9aed3 |
apr_bucket_destroy(ctx->buffer);
|
|
Packit Service |
f9aed3 |
ctx->buffer = NULL;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* proc_close_ipc() and ipc_handle_cleanup() do their own sanity
|
|
Packit Service |
f9aed3 |
* checks, but we'll do our own anyway
|
|
Packit Service |
f9aed3 |
*/
|
|
Packit Service |
f9aed3 |
if (ctx->ipc.ipc_handle_info) {
|
|
Packit Service |
f9aed3 |
proc_close_ipc(&ctx->ipc);
|
|
Packit Service |
f9aed3 |
ctx->ipc.ipc_handle_info = NULL;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if (ctx->procnode) {
|
|
Packit Service |
f9aed3 |
++ctx->procnode->requests_handled;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Return procnode
|
|
Packit Service |
f9aed3 |
I will return this slot to idle(or error) list
|
|
Packit Service |
f9aed3 |
*/
|
|
Packit Service |
f9aed3 |
if (ctx->procnode->diewhy == FCGID_DIE_BUSY_TIMEOUT) {
|
|
Packit Service |
f9aed3 |
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
|
|
Packit Service |
f9aed3 |
"mod_fcgid: %s took longer than busy timeout "
|
|
Packit Service |
f9aed3 |
"(%d secs)",
|
|
Packit Service |
f9aed3 |
r->uri,
|
|
Packit Service |
f9aed3 |
ctx->procnode->cmdopts.busy_timeout);
|
|
Packit Service |
f9aed3 |
return_procnode(r, ctx->procnode, 1 /* busy timeout */ );
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
else if (ctx->has_error) {
|
|
Packit Service |
f9aed3 |
ctx->procnode->diewhy = FCGID_DIE_COMM_ERROR;
|
|
Packit Service |
f9aed3 |
return_procnode(r, ctx->procnode, 1 /* communication error */ );
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
else if (ctx->procnode->cmdopts.max_requests_per_process
|
|
Packit Service |
f9aed3 |
&& ctx->procnode->requests_handled >=
|
|
Packit Service |
f9aed3 |
ctx->procnode->cmdopts.max_requests_per_process) {
|
|
Packit Service |
f9aed3 |
ctx->procnode->diewhy = FCGID_DIE_LIFETIME_EXPIRED;
|
|
Packit Service |
f9aed3 |
return_procnode(r, ctx->procnode, 1 /* handled all requests */ );
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
else
|
|
Packit Service |
f9aed3 |
return_procnode(r, ctx->procnode, 0 /* communication ok */ );
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
ctx->procnode = NULL;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
return APR_SUCCESS;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
static int getsfunc_fcgid_BRIGADE(char *buf, int len, void *arg)
|
|
Packit Service |
f9aed3 |
{
|
|
Packit Service |
f9aed3 |
apr_bucket_brigade *bb = (apr_bucket_brigade *) arg;
|
|
Packit Service |
f9aed3 |
const char *dst_end = buf + len - 1; /* leave room for terminating null */
|
|
Packit Service |
f9aed3 |
char *dst = buf;
|
|
Packit Service |
f9aed3 |
apr_bucket *e = APR_BRIGADE_FIRST(bb);
|
|
Packit Service |
f9aed3 |
apr_status_t rv;
|
|
Packit Service |
f9aed3 |
int done = 0;
|
|
Packit Service |
f9aed3 |
int getLF = 0;
|
|
Packit Service |
f9aed3 |
int getColon = 0;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
while ((dst < dst_end) && !done && e != APR_BRIGADE_SENTINEL(bb)) {
|
|
Packit Service |
f9aed3 |
const char *bucket_data;
|
|
Packit Service |
f9aed3 |
apr_size_t bucket_data_len;
|
|
Packit Service |
f9aed3 |
const char *src;
|
|
Packit Service |
f9aed3 |
const char *src_end;
|
|
Packit Service |
f9aed3 |
apr_bucket *next;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
rv = apr_bucket_read(e, &bucket_data, &bucket_data_len,
|
|
Packit Service |
f9aed3 |
APR_BLOCK_READ);
|
|
Packit Service |
f9aed3 |
if (rv != APR_SUCCESS) {
|
|
Packit Service |
f9aed3 |
return 0;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Move on to next bucket if it's fastcgi header bucket */
|
|
Packit Service |
f9aed3 |
if (e->type == &ap_bucket_type_fcgid_header
|
|
Packit Service |
f9aed3 |
|| e->type == &apr_bucket_type_immortal) {
|
|
Packit Service |
f9aed3 |
next = APR_BUCKET_NEXT(e);
|
|
Packit Service |
f9aed3 |
apr_bucket_delete(e);
|
|
Packit Service |
f9aed3 |
e = next;
|
|
Packit Service |
f9aed3 |
if (getLF) {
|
|
Packit Service |
f9aed3 |
done = 1;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
continue;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if (bucket_data_len == 0)
|
|
Packit Service |
f9aed3 |
return 0;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Base on RFC2616 section 4.2 */
|
|
Packit Service |
f9aed3 |
src = bucket_data;
|
|
Packit Service |
f9aed3 |
src_end = bucket_data + bucket_data_len;
|
|
Packit Service |
f9aed3 |
while ((src < src_end) && (dst < dst_end) && !done) {
|
|
Packit Service |
f9aed3 |
if (*src == ':')
|
|
Packit Service |
f9aed3 |
getColon = 1;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if (getLF && ((*src != ' ' && *src != '\t') || !getColon)) {
|
|
Packit Service |
f9aed3 |
done = 1;
|
|
Packit Service |
f9aed3 |
getColon = 0;
|
|
Packit Service |
f9aed3 |
break;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
else if (getLF && (*src == ' ' || *src == '\t')) {
|
|
Packit Service |
f9aed3 |
*dst++ = '\r';
|
|
Packit Service |
f9aed3 |
*dst++ = '\n';
|
|
Packit Service |
f9aed3 |
getLF = 0;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if (*src == '\n') {
|
|
Packit Service |
f9aed3 |
getLF = 1;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
else if (*src != '\r') {
|
|
Packit Service |
f9aed3 |
*dst++ = *src;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
src++;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if (src < src_end) {
|
|
Packit Service |
f9aed3 |
apr_bucket_split(e, src - bucket_data);
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
next = APR_BUCKET_NEXT(e);
|
|
Packit Service |
f9aed3 |
apr_bucket_delete(e);
|
|
Packit Service |
f9aed3 |
e = next;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
*dst = 0;
|
|
Packit Service |
f9aed3 |
return done;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
static int
|
|
Packit Service |
f9aed3 |
handle_request_ipc(request_rec *r, int role,
|
|
Packit Service |
f9aed3 |
apr_bucket_brigade *output_brigade,
|
|
Packit Service |
f9aed3 |
fcgid_bucket_ctx *bucket_ctx, const char **location_ptr)
|
|
Packit Service |
f9aed3 |
{
|
|
Packit Service |
f9aed3 |
int cond_status;
|
|
Packit Service |
f9aed3 |
apr_status_t rv;
|
|
Packit Service |
f9aed3 |
apr_bucket_brigade *brigade_stdout;
|
|
Packit Service |
f9aed3 |
char sbuf[MAX_STRING_LEN];
|
|
Packit Service |
f9aed3 |
const char *location;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Write output_brigade to fastcgi server */
|
|
Packit Service |
f9aed3 |
if ((rv = proc_write_ipc(&bucket_ctx->ipc,
|
|
Packit Service |
f9aed3 |
output_brigade)) != APR_SUCCESS) {
|
|
Packit Service |
f9aed3 |
bucket_ctx->has_error = 1;
|
|
Packit Service |
f9aed3 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Create brigade */
|
|
Packit Service |
f9aed3 |
brigade_stdout =
|
|
Packit Service |
f9aed3 |
apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
|
Packit Service |
f9aed3 |
APR_BRIGADE_INSERT_TAIL(brigade_stdout,
|
|
Packit Service |
f9aed3 |
ap_bucket_fcgid_header_create(r->connection->
|
|
Packit Service |
f9aed3 |
bucket_alloc,
|
|
Packit Service |
f9aed3 |
bucket_ctx));
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Check the script header first; return immediately on error. */
|
|
Packit Service |
f9aed3 |
if ((cond_status =
|
|
Packit Service |
f9aed3 |
ap_scan_script_header_err_core(r, sbuf, getsfunc_fcgid_BRIGADE,
|
|
Packit Service |
f9aed3 |
brigade_stdout))) {
|
|
Packit Service |
f9aed3 |
/*
|
|
Packit Service |
f9aed3 |
* cond_status could be HTTP_NOT_MODIFIED in the case that the FCGI
|
|
Packit Service |
f9aed3 |
* script does not set an explicit status and ap_meets_conditions,
|
|
Packit Service |
f9aed3 |
* which is called by ap_scan_script_header_err_brigade, detects that
|
|
Packit Service |
f9aed3 |
* the conditions of the requests are met and the response is
|
|
Packit Service |
f9aed3 |
* not modified.
|
|
Packit Service |
f9aed3 |
* In this case set r->status and return OK in order to prevent
|
|
Packit Service |
f9aed3 |
* running through the error processing stack as this would
|
|
Packit Service |
f9aed3 |
* break with mod_cache, if the conditions had been set by
|
|
Packit Service |
f9aed3 |
* mod_cache itself to validate a stale entity.
|
|
Packit Service |
f9aed3 |
* BTW: We circumvent the error processing stack anyway if the
|
|
Packit Service |
f9aed3 |
* FCGI script set an explicit status code (whatever it is) and
|
|
Packit Service |
f9aed3 |
* the only possible values for cond_status here are:
|
|
Packit Service |
f9aed3 |
*
|
|
Packit Service |
f9aed3 |
* HTTP_NOT_MODIFIED (set by ap_meets_conditions)
|
|
Packit Service |
f9aed3 |
* HTTP_PRECONDITION_FAILED (set by ap_meets_conditions)
|
|
Packit Service |
f9aed3 |
* HTTP_GATEWAY_TIME_OUT (script timed out, returned no headers)
|
|
Packit Service |
f9aed3 |
* HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the
|
|
Packit Service |
f9aed3 |
* processing of the response of the FCGI script, e.g broken headers
|
|
Packit Service |
f9aed3 |
* or a crashed FCGI process).
|
|
Packit Service |
f9aed3 |
*/
|
|
Packit Service |
f9aed3 |
if (cond_status == HTTP_NOT_MODIFIED) {
|
|
Packit Service |
f9aed3 |
/* We need to remove our fcgid_filter before returning this
|
|
Packit Service |
f9aed3 |
* status and code; otherwise, when ap_process_async_request()
|
|
Packit Service |
f9aed3 |
* invokes ap_finalize_request_protocol() and that calls
|
|
Packit Service |
f9aed3 |
* ap_pass_brigade(), fcgid_filter notices it has an empty
|
|
Packit Service |
f9aed3 |
* brigade and returns without calling ap_pass_brigade() itself,
|
|
Packit Service |
f9aed3 |
* which incorrectly circumvents the standard output filters.
|
|
Packit Service |
f9aed3 |
*/
|
|
Packit Service |
f9aed3 |
ap_remove_output_filter(r->output_filters);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
r->status = cond_status;
|
|
Packit Service |
f9aed3 |
return OK;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
return cond_status;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if (role == FCGI_AUTHORIZER) {
|
|
Packit Service |
f9aed3 |
return cond_status;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Check redirect */
|
|
Packit Service |
f9aed3 |
location = apr_table_get(r->headers_out, "Location");
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if (location && location[0] == '/' && r->status == 200) {
|
|
Packit Service |
f9aed3 |
/* This redirect needs to be a GET no matter what the original
|
|
Packit Service |
f9aed3 |
* method was.
|
|
Packit Service |
f9aed3 |
*/
|
|
Packit Service |
f9aed3 |
r->method = apr_pstrdup(r->pool, "GET");
|
|
Packit Service |
f9aed3 |
r->method_number = M_GET;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* We already read the message body (if any), so don't allow
|
|
Packit Service |
f9aed3 |
* the redirected request to think it has one. We can ignore
|
|
Packit Service |
f9aed3 |
* Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR.
|
|
Packit Service |
f9aed3 |
*/
|
|
Packit Service |
f9aed3 |
apr_table_unset(r->headers_in, "Content-Length");
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Setting this Location header value causes handle_request() to
|
|
Packit Service |
f9aed3 |
* invoke ap_internal_redirect_handler(); that calls
|
|
Packit Service |
f9aed3 |
* internal_internal_redirect() which sets the new sub-request's
|
|
Packit Service |
f9aed3 |
* r->output_filters back to r->proto_output_filters before
|
|
Packit Service |
f9aed3 |
* running the sub-request's handler. Because we return here
|
|
Packit Service |
f9aed3 |
* without invoking ap_pass_brigade(), our fcgid_filter is ignored.
|
|
Packit Service |
f9aed3 |
*/
|
|
Packit Service |
f9aed3 |
*location_ptr = location;
|
|
Packit Service |
f9aed3 |
return OK;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
else if (location && r->status == 200) {
|
|
Packit Service |
f9aed3 |
/* XX Note that if a script wants to produce its own Redirect
|
|
Packit Service |
f9aed3 |
* body, it now has to explicitly *say* "Status: 302"
|
|
Packit Service |
f9aed3 |
*/
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* This return code causes ap_process_async_request() to invoke
|
|
Packit Service |
f9aed3 |
* ap_die(); that calls ap_send_error_response(), which resets
|
|
Packit Service |
f9aed3 |
* r->output_filters back to r->proto_output_filters, thus removing
|
|
Packit Service |
f9aed3 |
* our fcgid_filter from the output chain before making a final call
|
|
Packit Service |
f9aed3 |
* to ap_finalize_request_protocol(), which passes the brigade to
|
|
Packit Service |
f9aed3 |
* the standard output filters.
|
|
Packit Service |
f9aed3 |
*/
|
|
Packit Service |
f9aed3 |
return HTTP_MOVED_TEMPORARILY;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Now pass any remaining response body data to output filters */
|
|
Packit Service |
f9aed3 |
if ((rv = ap_pass_brigade(r->output_filters,
|
|
Packit Service |
f9aed3 |
brigade_stdout)) != APR_SUCCESS) {
|
|
Packit Service |
f9aed3 |
if (!APR_STATUS_IS_ECONNABORTED(rv)) {
|
|
Packit Service |
f9aed3 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r,
|
|
Packit Service |
f9aed3 |
"mod_fcgid: ap_pass_brigade failed in "
|
|
Packit Service |
f9aed3 |
"handle_request_ipc function");
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
return cond_status;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
static int
|
|
Packit Service |
f9aed3 |
handle_request(request_rec * r, int role, fcgid_cmd_conf *cmd_conf,
|
|
Packit Service |
f9aed3 |
apr_bucket_brigade * output_brigade)
|
|
Packit Service |
f9aed3 |
{
|
|
Packit Service |
f9aed3 |
fcgid_command fcgi_request;
|
|
Packit Service |
f9aed3 |
fcgid_bucket_ctx *bucket_ctx;
|
|
Packit Service |
f9aed3 |
int i, j, cond_status;
|
|
Packit Service |
f9aed3 |
const char *location = NULL;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
bucket_ctx = apr_pcalloc(r->pool, sizeof(*bucket_ctx));
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
bucket_ctx->ipc.request = r;
|
|
Packit Service |
f9aed3 |
apr_pool_cleanup_register(r->pool, bucket_ctx,
|
|
Packit Service |
f9aed3 |
bucket_ctx_cleanup, apr_pool_cleanup_null);
|
|
Packit Service |
f9aed3 |
procmgr_init_spawn_cmd(&fcgi_request, r, cmd_conf);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Try to get a connected ipc handle */
|
|
Packit Service |
f9aed3 |
for (i = 0; i < FCGID_REQUEST_COUNT; i++) {
|
|
Packit Service |
f9aed3 |
/* Apply a free process slot, send a spawn request if I can't get one */
|
|
Packit Service |
f9aed3 |
for (j = 0; j < FCGID_APPLY_TRY_COUNT; j++) {
|
|
Packit Service |
f9aed3 |
bucket_ctx->ipc.connect_timeout =
|
|
Packit Service |
f9aed3 |
fcgi_request.cmdopts.ipc_connect_timeout;
|
|
Packit Service |
f9aed3 |
bucket_ctx->ipc.communation_timeout =
|
|
Packit Service |
f9aed3 |
fcgi_request.cmdopts.ipc_comm_timeout;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Apply a process slot */
|
|
Packit Service |
f9aed3 |
bucket_ctx->procnode = apply_free_procnode(r, &fcgi_request);
|
|
Packit Service |
f9aed3 |
if (bucket_ctx->procnode)
|
|
Packit Service |
f9aed3 |
break;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Avoid sleeping the very first time through if there are no
|
|
Packit Service |
f9aed3 |
busy processes; the problem is just that we haven't spawned
|
|
Packit Service |
f9aed3 |
anything yet, so waiting is pointless */
|
|
Packit Service |
f9aed3 |
if (i > 0 || j > 0 || count_busy_processes(r, &fcgi_request)) {
|
|
Packit Service |
f9aed3 |
apr_sleep(apr_time_from_sec(1));
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
bucket_ctx->procnode = apply_free_procnode(r, &fcgi_request);
|
|
Packit Service |
f9aed3 |
if (bucket_ctx->procnode)
|
|
Packit Service |
f9aed3 |
break;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Send a spawn request if I can't get a process slot */
|
|
Packit Service |
f9aed3 |
procmgr_send_spawn_cmd(&fcgi_request, r);
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Connect to the fastcgi server */
|
|
Packit Service |
f9aed3 |
if (bucket_ctx->procnode) {
|
|
Packit Service |
f9aed3 |
if (proc_connect_ipc(bucket_ctx->procnode,
|
|
Packit Service |
f9aed3 |
&bucket_ctx->ipc) != APR_SUCCESS) {
|
|
Packit Service |
f9aed3 |
proc_close_ipc(&bucket_ctx->ipc);
|
|
Packit Service |
f9aed3 |
bucket_ctx->procnode->diewhy = FCGID_DIE_CONNECT_ERROR;
|
|
Packit Service |
f9aed3 |
return_procnode(r, bucket_ctx->procnode, 1 /* has error */ );
|
|
Packit Service |
f9aed3 |
bucket_ctx->procnode = NULL;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
else
|
|
Packit Service |
f9aed3 |
break;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Now I get a connected ipc handle */
|
|
Packit Service |
f9aed3 |
if (!bucket_ctx->procnode) {
|
|
Packit Service |
f9aed3 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
|
|
Packit Service |
f9aed3 |
"mod_fcgid: can't apply process slot for %s",
|
|
Packit Service |
f9aed3 |
cmd_conf->cmdline);
|
|
Packit Service |
f9aed3 |
return HTTP_SERVICE_UNAVAILABLE;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
bucket_ctx->active_time = bucket_ctx->procnode->last_active_time =
|
|
Packit Service |
f9aed3 |
apr_time_now();
|
|
Packit Service |
f9aed3 |
bucket_ctx->procnode->diewhy = FCGID_DIE_KILLSELF;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
cond_status = handle_request_ipc(r, role, output_brigade,
|
|
Packit Service |
f9aed3 |
bucket_ctx, &location);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Release the process ASAP. This may already have been done in
|
|
Packit Service |
f9aed3 |
* ap_pass_brigade() by fcgid_header_bucket_read(), but not in the
|
|
Packit Service |
f9aed3 |
* case where handle_request_ipc() returned early without reading
|
|
Packit Service |
f9aed3 |
* the body of the HTTP response. This could be because of an error,
|
|
Packit Service |
f9aed3 |
* or because of a role or a status code which permits us to ignore
|
|
Packit Service |
f9aed3 |
* the message body.
|
|
Packit Service |
f9aed3 |
*
|
|
Packit Service |
f9aed3 |
* As an example, when handling a request in the FCGI_AUTHORIZER role,
|
|
Packit Service |
f9aed3 |
* we don't read through to the end of the response from the process,
|
|
Packit Service |
f9aed3 |
* we just read the HTTP headers. That means each phase of the
|
|
Packit Service |
f9aed3 |
* request handling sequence (e.g., authentication, authorization, etc.)
|
|
Packit Service |
f9aed3 |
* will require its own process unless we make sure to always release
|
|
Packit Service |
f9aed3 |
* any process we acquired regardless of whether we're reading the
|
|
Packit Service |
f9aed3 |
* response body.
|
|
Packit Service |
f9aed3 |
*
|
|
Packit Service |
f9aed3 |
* As another example, if we perform or cause an internal redirection
|
|
Packit Service |
f9aed3 |
* (for instance, by returning an error code that invokes a script
|
|
Packit Service |
f9aed3 |
* handler in ap_die() because of an ErrorDocument configuration), then
|
|
Packit Service |
f9aed3 |
* we must also release the process we acquired here so that it is
|
|
Packit Service |
f9aed3 |
* potentially available during the next handling phase.
|
|
Packit Service |
f9aed3 |
*/
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
apr_pool_cleanup_run(r->pool, bucket_ctx, bucket_ctx_cleanup);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Perform internal redirection if necessary */
|
|
Packit Service |
f9aed3 |
if (location) {
|
|
Packit Service |
f9aed3 |
ap_internal_redirect_handler(location, r);
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Return condition status */
|
|
Packit Service |
f9aed3 |
return cond_status;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
static int add_request_body(request_rec *r, apr_pool_t *request_pool,
|
|
Packit Service |
af40fa |
apr_bucket_brigade *output_brigade)
|
|
Packit Service |
f9aed3 |
{
|
|
Packit Service |
f9aed3 |
apr_bucket *bucket_input, *bucket_header;
|
|
Packit Service |
f9aed3 |
apr_file_t *fd = NULL;
|
|
Packit Service |
f9aed3 |
apr_off_t cur_pos = 0, request_size = 0;
|
|
Packit Service |
f9aed3 |
apr_status_t rv;
|
|
Packit Service |
f9aed3 |
FCGI_Header *stdin_request_header;
|
|
Packit Service |
f9aed3 |
fcgid_server_conf *sconf = ap_get_module_config(r->server->module_config,
|
|
Packit Service |
f9aed3 |
&fcgid_module);
|
|
Packit Service |
f9aed3 |
int seen_eos = 0;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Stdin header and body */
|
|
Packit Service |
f9aed3 |
/* I have to read all the request into memory before sending it
|
|
Packit Service |
f9aed3 |
to fastcgi application server, this prevents slow clients from
|
|
Packit Service |
f9aed3 |
keeping the server in processing too long.
|
|
Packit Service |
f9aed3 |
But sometimes it's not acceptable (think about uploading a large attachment)
|
|
Packit Service |
f9aed3 |
Request will be stored in tmp file if the size larger than max_mem_request_len
|
|
Packit Service |
f9aed3 |
*/
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
apr_bucket_brigade *input_brigade = apr_brigade_create(request_pool,
|
|
Packit Service |
f9aed3 |
r->connection->
|
|
Packit Service |
f9aed3 |
bucket_alloc);
|
|
Packit Service |
f9aed3 |
apr_bucket_brigade *tmp_brigade = apr_brigade_create(request_pool,
|
|
Packit Service |
f9aed3 |
r->connection->
|
|
Packit Service |
f9aed3 |
bucket_alloc);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
do {
|
|
Packit Service |
f9aed3 |
int loop_counter = 0;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if ((rv = ap_get_brigade(r->input_filters, input_brigade,
|
|
Packit Service |
f9aed3 |
AP_MODE_READBYTES,
|
|
Packit Service |
f9aed3 |
APR_BLOCK_READ,
|
|
Packit Service |
f9aed3 |
HUGE_STRING_LEN)) != APR_SUCCESS) {
|
|
Packit Service |
f9aed3 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r,
|
|
Packit Service |
f9aed3 |
"mod_fcgid: can't get data from http client");
|
|
Packit Service |
f9aed3 |
apr_brigade_destroy(output_brigade);
|
|
Packit Service |
f9aed3 |
apr_brigade_destroy(tmp_brigade);
|
|
Packit Service |
f9aed3 |
apr_brigade_destroy(input_brigade);
|
|
Packit Service |
f9aed3 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
while ((bucket_input = APR_BRIGADE_FIRST(input_brigade)) != APR_BRIGADE_SENTINEL(input_brigade)) {
|
|
Packit Service |
f9aed3 |
const char *data;
|
|
Packit Service |
f9aed3 |
apr_size_t len;
|
|
Packit Service |
f9aed3 |
apr_bucket *bucket_stdin;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
++loop_counter;
|
|
Packit Service |
f9aed3 |
if ((loop_counter % FCGID_BRIGADE_CLEAN_STEP) == 0) {
|
|
Packit Service |
f9aed3 |
apr_brigade_cleanup(tmp_brigade);
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
APR_BUCKET_REMOVE(bucket_input);
|
|
Packit Service |
f9aed3 |
APR_BRIGADE_INSERT_TAIL(tmp_brigade, bucket_input);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if (APR_BUCKET_IS_EOS(bucket_input)) {
|
|
Packit Service |
f9aed3 |
seen_eos = 1;
|
|
Packit Service |
f9aed3 |
break;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if (APR_BUCKET_IS_METADATA(bucket_input))
|
|
Packit Service |
f9aed3 |
continue;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if ((rv = apr_bucket_read(bucket_input, &data, &len,
|
|
Packit Service |
f9aed3 |
APR_BLOCK_READ)) != APR_SUCCESS) {
|
|
Packit Service |
f9aed3 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r,
|
|
Packit Service |
f9aed3 |
"mod_fcgid: can't read request from HTTP client");
|
|
Packit Service |
f9aed3 |
apr_brigade_destroy(input_brigade);
|
|
Packit Service |
f9aed3 |
apr_brigade_destroy(tmp_brigade);
|
|
Packit Service |
f9aed3 |
apr_brigade_destroy(output_brigade);
|
|
Packit Service |
f9aed3 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Append a header, and the the bucket */
|
|
Packit Service |
f9aed3 |
stdin_request_header = apr_bucket_alloc(sizeof(FCGI_Header),
|
|
Packit Service |
f9aed3 |
r->connection->
|
|
Packit Service |
f9aed3 |
bucket_alloc);
|
|
Packit Service |
f9aed3 |
bucket_header =
|
|
Packit Service |
f9aed3 |
apr_bucket_heap_create((const char *) stdin_request_header,
|
|
Packit Service |
f9aed3 |
sizeof(*stdin_request_header),
|
|
Packit Service |
f9aed3 |
apr_bucket_free,
|
|
Packit Service |
f9aed3 |
r->connection->bucket_alloc);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
request_size += len;
|
|
Packit Service |
f9aed3 |
if (request_size > sconf->max_request_len) {
|
|
Packit Service |
f9aed3 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
|
|
Packit Service |
f9aed3 |
"mod_fcgid: HTTP request length %" APR_OFF_T_FMT
|
|
Packit Service |
f9aed3 |
" (so far) exceeds MaxRequestLen (%"
|
|
Packit Service |
f9aed3 |
APR_OFF_T_FMT ")", request_size,
|
|
Packit Service |
f9aed3 |
sconf->max_request_len);
|
|
Packit Service |
f9aed3 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if (request_size > sconf->max_mem_request_len) {
|
|
Packit Service |
f9aed3 |
apr_size_t wrote_len;
|
|
Packit Service |
f9aed3 |
static const char *fd_key = "fcgid_fd";
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if (fd == NULL) {
|
|
Packit Service |
f9aed3 |
void *tmp;
|
|
Packit Service |
f9aed3 |
apr_pool_userdata_get(&tmp, fd_key, r->connection->pool);
|
|
Packit Service |
f9aed3 |
fd = tmp;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if (fd != NULL) {
|
|
Packit Service |
f9aed3 |
if ((rv = apr_file_trunc(fd, 0)) != APR_SUCCESS) {
|
|
Packit Service |
f9aed3 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r,
|
|
Packit Service |
f9aed3 |
"mod_fcgid: can't truncate existing "
|
|
Packit Service |
f9aed3 |
"temporary file");
|
|
Packit Service |
f9aed3 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if (fd == NULL) {
|
|
Packit Service |
f9aed3 |
const char *tempdir = NULL;
|
|
Packit Service |
f9aed3 |
char *template;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
rv = apr_temp_dir_get(&tempdir, r->pool);
|
|
Packit Service |
f9aed3 |
if (rv != APR_SUCCESS) {
|
|
Packit Service |
f9aed3 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r,
|
|
Packit Service |
f9aed3 |
"mod_fcgid: can't get tmp dir");
|
|
Packit Service |
f9aed3 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
apr_filepath_merge(&template, tempdir,
|
|
Packit Service |
f9aed3 |
"fcgid.tmp.XXXXXX",
|
|
Packit Service |
f9aed3 |
APR_FILEPATH_NATIVE, r->pool);
|
|
Packit Service |
f9aed3 |
rv = apr_file_mktemp(&fd, template, 0,
|
|
Packit Service |
f9aed3 |
r->connection->pool);
|
|
Packit Service |
f9aed3 |
if (rv != APR_SUCCESS) {
|
|
Packit Service |
f9aed3 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r,
|
|
Packit Service |
f9aed3 |
"mod_fcgid: can't open tmp file fot stdin request");
|
|
Packit Service |
f9aed3 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
apr_pool_userdata_set((const void *) fd, fd_key,
|
|
Packit Service |
f9aed3 |
apr_pool_cleanup_null,
|
|
Packit Service |
f9aed3 |
r->connection->pool);
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Write request to tmp file */
|
|
Packit Service |
f9aed3 |
if ((rv =
|
|
Packit Service |
f9aed3 |
apr_file_write_full(fd, (const void *) data, len,
|
|
Packit Service |
f9aed3 |
&wrote_len)) != APR_SUCCESS
|
|
Packit Service |
f9aed3 |
|| len != wrote_len) {
|
|
Packit Service |
f9aed3 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING,
|
|
Packit Service |
f9aed3 |
rv, r,
|
|
Packit Service |
f9aed3 |
"mod_fcgid: can't write tmp file for stdin request");
|
|
Packit Service |
f9aed3 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
/* Create file bucket */
|
|
Packit Service |
f9aed3 |
bucket_stdin =
|
|
Packit Service |
f9aed3 |
apr_bucket_file_create(fd, cur_pos, len, r->pool,
|
|
Packit Service |
f9aed3 |
r->connection->bucket_alloc);
|
|
Packit Service |
f9aed3 |
cur_pos += len;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
else {
|
|
Packit Service |
f9aed3 |
if (APR_BUCKET_IS_HEAP(bucket_input))
|
|
Packit Service |
f9aed3 |
apr_bucket_copy(bucket_input, &bucket_stdin);
|
|
Packit Service |
f9aed3 |
else {
|
|
Packit Service |
f9aed3 |
/* mod_ssl have a bug? */
|
|
Packit Service |
f9aed3 |
char *pcopydata =
|
|
Packit Service |
f9aed3 |
apr_bucket_alloc(len, r->connection->bucket_alloc);
|
|
Packit Service |
f9aed3 |
memcpy(pcopydata, data, len);
|
|
Packit Service |
f9aed3 |
bucket_stdin =
|
|
Packit Service |
f9aed3 |
apr_bucket_heap_create(pcopydata, len,
|
|
Packit Service |
f9aed3 |
apr_bucket_free,
|
|
Packit Service |
f9aed3 |
r->connection->bucket_alloc);
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
if (!init_header(FCGI_STDIN, 1, len, 0, stdin_request_header)) {
|
|
Packit Service |
f9aed3 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
|
|
Packit Service |
f9aed3 |
"mod_fcgid: header overflow");
|
|
Packit Service |
f9aed3 |
apr_brigade_destroy(input_brigade);
|
|
Packit Service |
f9aed3 |
apr_brigade_destroy(tmp_brigade);
|
|
Packit Service |
f9aed3 |
apr_brigade_destroy(output_brigade);
|
|
Packit Service |
f9aed3 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
APR_BRIGADE_INSERT_TAIL(output_brigade, bucket_header);
|
|
Packit Service |
f9aed3 |
APR_BRIGADE_INSERT_TAIL(output_brigade, bucket_stdin);
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
apr_brigade_cleanup(input_brigade);
|
|
Packit Service |
f9aed3 |
apr_brigade_cleanup(tmp_brigade);
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
while (!seen_eos);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
apr_brigade_destroy(input_brigade);
|
|
Packit Service |
f9aed3 |
apr_brigade_destroy(tmp_brigade);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Append an empty body stdin header */
|
|
Packit Service |
f9aed3 |
stdin_request_header = apr_bucket_alloc(sizeof(FCGI_Header),
|
|
Packit Service |
f9aed3 |
r->connection->bucket_alloc);
|
|
Packit Service |
f9aed3 |
bucket_header =
|
|
Packit Service |
f9aed3 |
apr_bucket_heap_create((const char *) stdin_request_header,
|
|
Packit Service |
f9aed3 |
sizeof(*stdin_request_header),
|
|
Packit Service |
f9aed3 |
apr_bucket_free, r->connection->bucket_alloc);
|
|
Packit Service |
f9aed3 |
if (!init_header(FCGI_STDIN, 1, 0, 0, stdin_request_header)) {
|
|
Packit Service |
f9aed3 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
|
|
Packit Service |
f9aed3 |
"mod_fcgid: header overflow");
|
|
Packit Service |
f9aed3 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
APR_BRIGADE_INSERT_TAIL(output_brigade, bucket_header);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
return 0;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
int bridge_request(request_rec * r, int role, fcgid_cmd_conf *cmd_conf)
|
|
Packit Service |
f9aed3 |
{
|
|
Packit Service |
af40fa |
apr_bucket_brigade *output_brigade;
|
|
Packit Service |
f9aed3 |
apr_bucket *bucket_eos;
|
|
Packit Service |
af40fa |
char **envp = ap_create_environment(r->pool,
|
|
Packit Service |
af40fa |
r->subprocess_env);
|
|
Packit Service |
f9aed3 |
int rc;
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Create brigade for the request to fastcgi server */
|
|
Packit Service |
f9aed3 |
output_brigade =
|
|
Packit Service |
f9aed3 |
apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
af40fa |
/* Build the begin request and environ request, append them to output_brigade */
|
|
Packit Service |
f9aed3 |
if (!build_begin_block
|
|
Packit Service |
f9aed3 |
(role, r, r->connection->bucket_alloc, output_brigade)
|
|
Packit Service |
f9aed3 |
|| !build_env_block(r, envp, r->connection->bucket_alloc,
|
|
Packit Service |
f9aed3 |
output_brigade)) {
|
|
Packit Service |
f9aed3 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
|
|
Packit Service |
f9aed3 |
"mod_fcgid: can't build begin or env request");
|
|
Packit Service |
f9aed3 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
f9aed3 |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
af40fa |
if (role == FCGI_RESPONDER) {
|
|
Packit Service |
af40fa |
rc = add_request_body(r, r->pool, output_brigade);
|
|
Packit Service |
af40fa |
if (rc) {
|
|
Packit Service |
af40fa |
return rc;
|
|
Packit Service |
af40fa |
}
|
|
Packit Service |
af40fa |
}
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* The eos bucket now */
|
|
Packit Service |
f9aed3 |
bucket_eos = apr_bucket_eos_create(r->connection->bucket_alloc);
|
|
Packit Service |
f9aed3 |
APR_BRIGADE_INSERT_TAIL(output_brigade, bucket_eos);
|
|
Packit Service |
f9aed3 |
|
|
Packit Service |
f9aed3 |
/* Bridge the request */
|
|
Packit Service |
f9aed3 |
return handle_request(r, role, cmd_conf, output_brigade);
|
|
Packit Service |
f9aed3 |
}
|