static int resource_manager_atached(request_rec *r)
{
    mrm_config_t *conf = ap_get_module_config(r->server->module_config, &resource_manager_module);

    if (strcmp(apr_table_get(r->headers_in, "HOST"), conf->host) == 0) {
        manage_dir  = apr_psprintf(r->pool, "%s/%s", CGROUP_APACHE_ROOT, conf->host);
        manage_file = apr_psprintf(r->pool, "%s/tasks", manage_dir);
        manage_cpu  = apr_psprintf(r->pool, "%s/cpu.cfs_quota_us", manage_dir);
    
        apr_dir_make(manage_dir, APR_OS_DEFAULT, r->pool);
    
        if(apr_file_open(&manage_fp, manage_file, APR_WRITE, APR_OS_DEFAULT, r->pool) != APR_SUCCESS){
            return OK;
        }
        apr_file_printf(manage_fp, "%d\n", getpid());
        apr_file_flush(manage_fp);
        apr_file_close(manage_fp);
    
        if(apr_file_open(&manage_fp, manage_cpu, APR_WRITE, APR_OS_DEFAULT, r->pool) != APR_SUCCESS){
            return OK;
        }
        cpurate_from_mruby(r);
        apr_file_printf(manage_fp, "%ld\n", conf->cpurate);
        apr_file_flush(manage_fp);
        apr_file_close(manage_fp);
    }

    return DECLINED;
}
Beispiel #2
0
/*++

LogFormatV

    Adds an entry to the log file.

Arguments:
    level   - Log severity level.

    format  - Pointer to a buffer containing a printf-style format string.

    argList - Argument list to insert into 'format'.

Return Values:
    None.

Remarks:
    This function could be called before the logging subsystem is initialized.

--*/
void
LogFormatV(
    apr_uint32_t level,
    const char *format,
    va_list argList
    )
{
    apr_time_exp_t now;
    char *message;

    ASSERT(format != NULL);

    if (level <= maxLevel && handle != NULL) {
        // Write local time
        apr_time_exp_lt(&now, apr_time_now());
        apr_file_printf(handle, "%04d-%02d-%02d %02d:%02d:%02d - ",
            now.tm_year+1900, now.tm_mon, now.tm_mday,
            now.tm_hour, now.tm_min, now.tm_sec);

        // Format and write log message
        message = apr_pvsprintf(msgPool, format, argList);
        if (message == NULL) {
            message = "Unable to format message." APR_EOL_STR;
        }
        apr_file_puts(message, handle);
        apr_file_flush(handle);

        // Clear memory allocated when formatting the message
        apr_pool_clear(msgPool);
    }
}
Beispiel #3
0
AP_DECLARE(apr_status_t) ap_replace_stderr_log(apr_pool_t *p,
                                               const char *fname)
{
    apr_file_t *stderr_file;
    apr_status_t rc;
    char *filename = ap_server_root_relative(p, fname);
    if (!filename) {
        ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT,
                     APR_EBADPATH, NULL, "Invalid -E error log file %s",
                     fname);
        return APR_EBADPATH;
    }
    if ((rc = apr_file_open(&stderr_file, filename,
                            APR_APPEND | APR_WRITE | APR_CREATE | APR_LARGEFILE,
                            APR_OS_DEFAULT, p)) != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
                     "%s: could not open error log file %s.",
                     ap_server_argv0, fname);
        return rc;
    }
    if ((rc = apr_file_open_stderr(&stderr_log, p)) == APR_SUCCESS) {
        apr_file_flush(stderr_log);
        if ((rc = apr_file_dup2(stderr_log, stderr_file, p)) == APR_SUCCESS) {
            apr_file_close(stderr_file);
        }
    }
    if (rc != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_CRIT, rc, NULL,
                     "unable to replace stderr with error_log");
    }
    return rc;
}
Beispiel #4
0
/* ------------------------------------------- */
static int vlimit_logging(const char *msg, request_rec *r, vlimit_config *cfg, SHM_DATA *limit_stat)
{
    int len;
    time_t t;
    char *log_time;
    char *vlimit_log_buf;

    if (access(VLIMIT_LOG_FLAG_FILE, F_OK) == 0) {
        time(&t);
        log_time = (char *)ctime(&t);
        len = strlen(log_time);
        log_time[len - 1] = '\0';

        vlimit_log_buf = (char *)apr_psprintf(r->pool
            , "[%s] pid=[%d] name=[%s] client=[%s] %s ip_count: %d/%d file_count: %d/%d file=[%s] \n"
            , log_time
            , getpid()
            , apr_table_get(r->headers_in, "HOST")
            , r->connection->remote_ip
            , msg
            , get_ip_counter(limit_stat, r)
            , cfg->ip_limit
            , get_file_counter(limit_stat, r)
            , cfg->file_limit
            , r->filename
        );

        apr_file_puts(vlimit_log_buf, vlimit_log_fp);
        apr_file_flush(vlimit_log_fp);

        return 0;
    }
    
    return -1;
}
Beispiel #5
0
APR_DECLARE(apr_status_t) apr_file_buffer_set(apr_file_t *file, 
                                              char * buffer,
                                              apr_size_t bufsize)
{
    apr_status_t rv;

    apr_thread_mutex_lock(file->mutex);
 
    if(file->buffered) {
        /* Flush the existing buffer */
        rv = apr_file_flush(file);
        if (rv != APR_SUCCESS) {
            apr_thread_mutex_unlock(file->mutex);
            return rv;
        }
    }
        
    file->buffer = buffer;
    file->bufsize = bufsize;
    file->buffered = 1;
    file->bufpos = 0;
    file->direction = 0;
    file->dataRead = 0;
 
    if (file->bufsize == 0) {
            /* Setting the buffer size to zero is equivalent to turning 
             * buffering off. 
             */
            file->buffered = 0;
    }
    
    apr_thread_mutex_unlock(file->mutex);

    return APR_SUCCESS;
}
Beispiel #6
0
/////////////////////////////////////////////////////////////////////////////////
//
// Function:
//
// Purpose:
//
// Parameters:
//
// Return value:
//
// Author: Komatsu Yuji(Zheng Chuyu)
//
/////////////////////////////////////////////////////////////////////////////////
int jhklog_write(const char *message)
{
    int rc;
    char errmsg[100];
    apr_status_t rv;

    if (jx_log == NULL || message == NULL)
        return -1;

    if (jx_log->fp == NULL) {
        printf("%s", message);
        return 0;
    }

    rc = -1;
    jhklog_lock();

    if (jhklog_rotate() != 0)
        goto error;

    rv = apr_file_puts(message, jx_log->fp);
    if (rv != APR_SUCCESS) {
        apr_strerror(rv, errmsg, sizeof(errmsg));
        fprintf(stderr, "can not write to the file [%s]. %s\n",
                jx_log->logfile, errmsg);
        goto error;
    }
    apr_file_flush(jx_log->fp);

    rc = 0;
  error:
    jhklog_unlock();
    return rc;
}
// Called by child process.
static void write_pipe(apr_file_t* out, char const* message)
{
	apr_size_t const bytes_to_write = strlen(message) + 1;	// +1 for the length byte.
	assert(bytes_to_write < 256);
	char buf[256];
	strncpy(buf + 1, message, sizeof(buf) - 1);
	*reinterpret_cast<unsigned char*>(buf) = bytes_to_write - 1;

	apr_size_t bytes_written;
	apr_status_t status = apr_file_write_full(out, buf, bytes_to_write, &bytes_written);
	if (status != APR_SUCCESS)
	{
		std::cerr << "apr_file_write_full: " << apr_strerror(status, buf, sizeof(buf)) << std::endl;
	}
	else if (bytes_written != bytes_to_write)
	{
		std::cerr << "apr_file_write_full: bytes_written (" << bytes_written << ") != bytes_to_write (" << bytes_to_write << ")!" << std::endl;
	}
	status = apr_file_flush(out);
	if (status != APR_SUCCESS)
	{
		std::cerr << "apr_file_flush: " << apr_strerror(status, buf, sizeof(buf)) << std::endl;
	}

#ifdef _DEBUG
	std::cerr << "apr_file_write_full: Wrote " << bytes_written << " bytes to the pipe." << std::endl;
#endif
}
Beispiel #8
0
/* flushes a possibly-buffered filehandle (such as stdout) */
void MVM_file_flush(MVMThreadContext *tc, MVMObject *oshandle) {
    apr_status_t rv;
    MVMOSHandle *handle;

    verify_filehandle_type(tc, oshandle, &handle, "flush filehandle");

    if ((rv = apr_file_flush(handle->body.file_handle)) != APR_SUCCESS) {
        MVM_exception_throw_apr_error(tc, rv, "Failed to flush filehandle: ");
    }
}
static apr_status_t tmpfile_filter(ap_filter_t *f, apr_bucket_brigade *bbout,
	ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes) {

  apr_bucket_brigade* bbin = apr_brigade_create(f->r->pool,
	     f->r->connection->bucket_alloc);

  apr_file_t* tmpfile ;
  char* tmpname = apr_pstrdup(f->r->pool, "/tmp/mod-upload.XXXXXX") ;

  if ( f->ctx ) {
    APR_BRIGADE_INSERT_TAIL(bbout, apr_bucket_eos_create(bbout->bucket_alloc)) ;
    return APR_SUCCESS ;
  }
  if ( apr_file_mktemp(&tmpfile, tmpname, KEEPONCLOSE, f->r->pool) != APR_SUCCESS ) {
	            // error
    ap_remove_input_filter(f) ;
  }
  apr_pool_cleanup_register(f->r->pool, tmpfile,
		(void*)apr_file_close, apr_pool_cleanup_null) ;

  for ( ; ; ) {
    apr_bucket* b ;
    const char* ptr = 0 ;
    apr_size_t bytes ;
#ifdef DEBUG
    ap_log_rerror(APLOG_MARK,APLOG_DEBUG,0, f->r, "get_brigade") ;
#endif
    ap_get_brigade(f->next, bbin, AP_MODE_READBYTES, APR_BLOCK_READ, BUFLEN) ;
    for ( b = APR_BRIGADE_FIRST(bbin) ;
	b != APR_BRIGADE_SENTINEL(bbin) && ! f->ctx ;
	b = APR_BUCKET_NEXT(b) ) {
      if ( APR_BUCKET_IS_EOS(b) ) {
	f->ctx = f ;	// just using it as a flag; any nonzero will do
	apr_file_flush(tmpfile) ;
	apr_brigade_puts(bbout, ap_filter_flush, f, tmpname) ;
	APR_BRIGADE_INSERT_TAIL(bbout,
		apr_bucket_eos_create(bbout->bucket_alloc) ) ;
      } else if ( apr_bucket_read(b, &ptr, &bytes, APR_BLOCK_READ)
		== APR_SUCCESS ) {
#ifdef DEBUG
  ap_log_rerror(APLOG_MARK,APLOG_DEBUG,0, f->r, "	%d bytes in bucket", bytes) ;
#endif
	apr_file_write(tmpfile, ptr, &bytes) ;
      }
    }
    if ( f->ctx )
      break ;
    else
      apr_brigade_cleanup(bbin) ;
  }

  apr_brigade_destroy(bbin) ;

  return APR_SUCCESS ;
}
Beispiel #10
0
AP_DECLARE(apr_status_t) ap_replace_stderr_log(apr_pool_t *p,
                                               const char *fname)
{
    apr_file_t *stderr_file;
    apr_status_t rc;
    char *filename = ap_server_root_relative(p, fname);
    if (!filename) {
        ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT,
                     APR_EBADPATH, NULL, "Invalid -E error log file %s",
                     fname);
        return APR_EBADPATH;
    }
    if ((rc = apr_file_open(&stderr_file, filename,
                            APR_APPEND | APR_WRITE | APR_CREATE | APR_LARGEFILE,
                            APR_OS_DEFAULT, p)) != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
                     "%s: could not open error log file %s.",
                     ap_server_argv0, fname);
        return rc;
    }
    if (!stderr_pool) {
        /* This is safe provided we revert it when we are finished.
         * We don't manager the callers pool!
         */
        stderr_pool = p;
    }
    if ((rc = apr_file_open_stderr(&stderr_log, stderr_pool)) 
            == APR_SUCCESS) {
        apr_file_flush(stderr_log);
        if ((rc = apr_file_dup2(stderr_log, stderr_file, stderr_pool)) 
                == APR_SUCCESS) {
            apr_file_close(stderr_file);
            /*
             * You might ponder why stderr_pool should survive?
             * The trouble is, stderr_pool may have s_main->error_log,
             * so we aren't in a position to destory stderr_pool until
             * the next recycle.  There's also an apparent bug which 
             * is not; if some folk decided to call this function before 
             * the core open error logs hook, this pool won't survive.
             * Neither does the stderr logger, so this isn't a problem.
             */
        }
    }
    /* Revert, see above */
    if (stderr_pool == p)
        stderr_pool = NULL;

    if (rc != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_CRIT, rc, NULL,
                     "unable to replace stderr with error log file");
    }
    return rc;
}
Beispiel #11
0
static
apr_status_t
FileFlush(
    void *opaque
    )
{
    apr_file_t *file = opaque;

    ASSERT(opaque != NULL);

    return apr_file_flush(file);
}
Beispiel #12
0
apr_status_t apr_unix_file_cleanup(void *thefile)
{
    apr_file_t *file = thefile;
    apr_status_t flush_rv = APR_SUCCESS, rv = APR_SUCCESS;

    if (file->buffered) {
        flush_rv = apr_file_flush(file);
    }

    rv = file_cleanup(file, 0);

    return rv != APR_SUCCESS ? rv : flush_rv;
}
static int jk2_logger_file_close(jk_env_t *env,jk_logger_t *_this)
{
    apr_status_t rv;
    apr_file_t *f = _this->logger_private;
    
    if (!f)
        return JK_OK;
    
    apr_file_flush(f);
    rv = apr_file_close(f);
    _this->logger_private = NULL;

    /*     free(_this); */
    return JK_OK;
}
Beispiel #14
0
static apr_status_t setptr(apr_file_t *thefile, apr_off_t pos )
{
    apr_off_t newbufpos;
    apr_status_t rv;
    DWORD rc;

    if (thefile->direction == 1) {
        /* XXX: flush here is not mutex protected */
        rv = apr_file_flush(thefile);
        if (rv != APR_SUCCESS)
            return rv;
        thefile->bufpos = thefile->dataRead = 0;
        thefile->direction = 0;
    }

    /* We may be truncating to size here. 
     * XXX: testing an 'unsigned' as >= 0 below indicates a bug
     */
    newbufpos = pos - (thefile->filePtr - thefile->dataRead);

    if (newbufpos >= 0 && newbufpos <= (apr_off_t)thefile->dataRead) {
        thefile->bufpos = (apr_size_t)newbufpos;
        rv = APR_SUCCESS;
    } else {
        DWORD offlo = (DWORD)pos;
        LONG  offhi = (LONG)(pos >> 32);
        rc = SetFilePointer(thefile->filehand, offlo, &offhi, FILE_BEGIN);

        if (rc == (DWORD)-1)
            /* A legal value, perhaps?  MSDN implies prior SetLastError isn't
             * needed, googling for SetLastError SetFilePointer seems
             * to confirm this.  INVALID_SET_FILE_POINTER is too recently
             * added for us to rely on it as a constant.
             */
            rv = apr_get_os_error();
        else
            rv = APR_SUCCESS;

        if (rv == APR_SUCCESS) {
            rv = APR_SUCCESS;
            thefile->eof_hit = 0;
            thefile->bufpos = thefile->dataRead = 0;
            thefile->filePtr = pos;
        }
    }

    return rv;
}
Beispiel #15
0
static apr_status_t at_report_file_write(at_report_t *ctx, const char *msg)
{
    struct at_report_file *r = (struct at_report_file *)ctx;
    apr_file_t *f = r->file;
    apr_size_t len = strlen(msg);
    apr_status_t s;

    s = apr_file_write_full(f, msg, len, &len);
    if (s != APR_SUCCESS)
        return s;

    s = apr_file_putc('\n', f);
    if (s != APR_SUCCESS)
        return s;

    return apr_file_flush(f);
}
static int resource_manager_detached(request_rec *r)
{
    mrm_config_t *conf = ap_get_module_config(r->server->module_config, &resource_manager_module);

    if (strcmp(apr_table_get(r->headers_in, "HOST"), conf->host) == 0) {
        manage_dir  = apr_psprintf(r->pool, "%s/%s", CGROUP_APACHE_ROOT, conf->host);

        if(apr_file_open(&manage_fp, manage_cpu, APR_WRITE, APR_OS_DEFAULT, r->pool) != APR_SUCCESS){
            return OK;
        }
        apr_file_puts("100000\n", manage_fp);
        apr_file_flush(manage_fp);
        apr_file_close(manage_fp);
    }

    return OK;
}
Beispiel #17
0
static int make_file_slot_list(SHM_DATA *limit_stat, request_rec *r) {

    int i;
    int len;
    time_t t;
    char *log_time;
    char *vlimit_log_buf;

    if (access(VLIMIT_FILE_STAT_FLAG_FILE, F_OK) == 0 && access(VLIMIT_FILE_STAT_FILE, F_OK) != 0) {
        time(&t);
        log_time = (char *)ctime(&t);
        len = strlen(log_time);
        log_time[len - 1] = '\0';

        apr_file_t *vlimit_make_file_slot_fp = NULL;

        if(apr_file_open(&vlimit_make_file_slot_fp, VLIMIT_FILE_STAT_FILE, APR_WRITE|APR_APPEND|APR_CREATE,
            APR_OS_DEFAULT, r->pool) != APR_SUCCESS){
            return OK;
        }

    
        for (i = 0; i < MAX_CLIENTS; i++) { 
            if (limit_stat->file_stat_shm[i].counter > 0) {
                vlimit_log_buf = (char *)apr_psprintf(r->pool
                    , "[%s] slot=[%d] filename=[%s] counter=[%d]\n"
                    , log_time
                    , i
                    , limit_stat->file_stat_shm[i].filename
                    , limit_stat->file_stat_shm[i].counter
                );
                apr_file_puts(vlimit_log_buf, vlimit_make_file_slot_fp);
            }
        }

        apr_file_flush(vlimit_make_file_slot_fp);

        if(apr_file_close(vlimit_make_file_slot_fp) != APR_SUCCESS){
            return OK;
        }

        return 0;
    }
    
    return -1;
}
Beispiel #18
0
APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, const struct iovec *vec, apr_size_t nvec, apr_size_t *nbytes)
{
    int bytes;

    if (thefile->buffered) {
        apr_status_t rv = apr_file_flush(thefile);
        if (rv != APR_SUCCESS) {
            return rv;
        }
    }

    if ((bytes = writev(thefile->filedes, vec, nvec)) < 0) {
        *nbytes = 0;
        return errno;
    }
    else {
        *nbytes = bytes;
        return APR_SUCCESS;
    }
}
Beispiel #19
0
APR_DECLARE(apr_status_t) port_disasm_to_file(port_disassembler_t * disassembler,
                                              const char * code,
                                              unsigned int len,
                                              apr_file_t * thefile) {
#if defined(_IA32_)
    // check if nothing should be printed
    if (disassembler->line_size == 0) {
        return APR_SUCCESS;
    } 
    
    if (disassembler->num_bytes_total == 0) {
        // Calculate required number of bytes
        disassembler->num_bytes_total = disassembler->line_size * BYTES_TOTAL / BYTES_PER_LINE;
        // initialize stream
        disassembler->real_stream = apr_palloc(disassembler->user_pool,
            disassembler->num_bytes_total);
    }
    
    // initialize file
    disassembler->user_file = thefile;

    strcpy(disassembler->real_stream, "");

    disassembler->fprintf_func = disasm_fprint_default;

    disasm_print(disassembler, code, len);

    // flush
    apr_file_write(disassembler->user_file, disassembler->real_stream,
        &disassembler->num_bytes_used);
    apr_file_flush(disassembler->user_file);

    disassembler->user_file = NULL;
    disassembler->num_bytes_used = 0;

	return APR_SUCCESS;
#else
    return APR_ENOTIMPL;
#endif
}
Beispiel #20
0
APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, 
                                            apr_int32_t wanted,
                                            apr_file_t *thefile)
{
    struct_stat info;

    if (thefile->buffered) {
        apr_status_t rv = apr_file_flush(thefile);
        if (rv != APR_SUCCESS)
            return rv;
    }

    if (fstat(thefile->filedes, &info) == 0) {
        finfo->pool = thefile->pool;
        finfo->fname = thefile->fname;
        fill_out_finfo(finfo, &info, wanted);
        return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
    }
    else {
        return errno;
    }
}
void mod_stlog_logging(json_object *json_obj, const char *func, apr_pool_t *p)
{
    int len;
    time_t t;
    char *log_time, *val;
    char *mod_stlog_buf = NULL;
     
    time(&t);
    log_time = (char *)ctime(&t);
    len = strlen(log_time);
    log_time[len - 1] = '\0';

    json_object_object_add(json_obj, "time", json_object_new_string(ap_mrb_string_check(p, log_time)));
    json_object_object_add(json_obj, "pid", json_object_new_int(getpid()));
    json_object_object_add(json_obj, "hook", json_object_new_string(ap_mrb_string_check(p, func)));

    val = (char *)json_object_to_json_string(json_obj);

    mod_stlog_buf = (char *)apr_psprintf(p, "%s\n", val);
         
    apr_file_puts(mod_stlog_buf, mod_stlog_fp);
    apr_file_flush(mod_stlog_fp);
}
static int JK_METHOD jk2_logger_file_log(jk_env_t *env, jk_logger_t *l,                                 
                               int level,
                               const char *what)
{
    apr_status_t rv = APR_SUCCESS;
    apr_file_t *f = (apr_file_t *)l->logger_private;

    if (f == NULL) {
        /* This is usefull to debug what happens before logger is set.
           On apache you need -X option ( no detach, single process ) */
        if (what != NULL)
            fprintf(stderr, what);
        return JK_OK;
    }
    if(l && l->level <= level && l->logger_private && what) {       
        rv = apr_file_puts(what, f);
        /* flush the log for each entry only for debug level */
        if (rv == APR_SUCCESS && l->level == JK_LOG_DEBUG_LEVEL)
            rv = apr_file_flush(f);
        return JK_OK;
    }

    return JK_ERR;
}
Beispiel #23
0
static void Log_file(LogObject *self, const char *s, int l)
{
    /*
     * XXX This function is not currently being used.
     * The intention was that it be called instead of
     * Log_call() when 'target' is non zero. This would
     * be the case for 'stdout' and 'stderr'. Doing
     * this bypasses normally Apache logging mechanisms
     * though. May reawaken this code in mod_wsgi 4.0
     * by way of a mechanism to divert logging from a
     * daemon process to specfic log file or pipe using
     * an option to WSGIDaemonProcess.
     */

    char errstr[MAX_STRING_LEN];

    int plen = 0;
    int slen = 0;

    apr_file_t *logf = NULL;

    if (self->r)
        logf = self->r->server->error_log;
    else
        logf = wsgi_server->error_log;

    errstr[0] = '[';
    ap_recent_ctime(errstr + 1, apr_time_now());
    errstr[1 + APR_CTIME_LEN - 1] = ']';
    errstr[1 + APR_CTIME_LEN    ] = ' ';
    plen = 1 + APR_CTIME_LEN + 1;

    if (self->target) {
        int len;

        errstr[plen++] = '[';

        len = strlen(self->target);
        memcpy(errstr+plen, self->target, len);

        plen += len;

        errstr[plen++] = ']';
        errstr[plen++] = ' ';
    }

    slen = MAX_STRING_LEN - plen - 1;

    Py_BEGIN_ALLOW_THREADS

    /*
     * We actually break long lines up into segments
     * of around 8192 characters, with the date/time
     * and target information prefixing each line.
     * This is just to avoid having to allocate more
     * memory just to format the line with prefix.
     * We want to avoid writing the prefix separately
     * so at least try and write line in one atomic
     * operation.
     */

    while (1) {
        if (l > slen) {
            memcpy(errstr+plen, s, slen);
            errstr[plen+slen] = '\n';
            apr_file_write_full(logf, errstr, plen+slen+1, NULL);
            apr_file_flush(logf);
            s += slen;
            l -= slen;
        }
        else {
            memcpy(errstr+plen, s, l);
            errstr[plen+l] = '\n';
            apr_file_write_full(logf, errstr, plen+l+1, NULL);
            apr_file_flush(logf);
            break;
        }
    }

    Py_END_ALLOW_THREADS
}
Beispiel #24
0
static void log_error_core(const char *file, int line, int level,
                           apr_status_t status, const server_rec *s,
                           const conn_rec *c,
                           const request_rec *r, apr_pool_t *pool,
                           const char *fmt, va_list args)
{
    char errstr[MAX_STRING_LEN];
#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
    char scratch[MAX_STRING_LEN];
#endif
    apr_size_t len, errstrlen;
    apr_file_t *logf = NULL;
    const char *referer;
    int level_and_mask = level & APLOG_LEVELMASK;

    if (r && r->connection) {
        c = r->connection;
    }

    if (s == NULL) {
        /*
         * If we are doing stderr logging (startup), don't log messages that are
         * above the default server log level unless it is a startup/shutdown
         * notice
         */
        if ((level_and_mask != APLOG_NOTICE)
            && (level_and_mask > ap_default_loglevel)) {
            return;
        }

        logf = stderr_log;
    }
    else if (s->error_log) {
        /*
         * If we are doing normal logging, don't log messages that are
         * above the server log level unless it is a startup/shutdown notice
         */
        if ((level_and_mask != APLOG_NOTICE)
            && (level_and_mask > s->loglevel)) {
            return;
        }

        logf = s->error_log;
    }
#ifdef TPF
    else if (tpf_child) {
        /*
         * If we are doing normal logging, don't log messages that are
         * above the server log level unless it is a startup/shutdown notice
         */
        if ((level_and_mask != APLOG_NOTICE)
            && (level_and_mask > s->loglevel)) {
            return;
        }

        logf = stderr;
    }
#endif /* TPF */
    else {
        /*
         * If we are doing syslog logging, don't log messages that are
         * above the server log level (including a startup/shutdown notice)
         */
        if (level_and_mask > s->loglevel) {
            return;
        }
    }

    if (logf && ((level & APLOG_STARTUP) != APLOG_STARTUP)) {
        errstr[0] = '[';
        ap_recent_ctime(errstr + 1, apr_time_now());
        errstr[1 + APR_CTIME_LEN - 1] = ']';
        errstr[1 + APR_CTIME_LEN    ] = ' ';
        len = 1 + APR_CTIME_LEN + 1;
    } else {
        len = 0;
    }

    if ((level & APLOG_STARTUP) != APLOG_STARTUP) {
        len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                            "[%s] ", priorities[level_and_mask].t_name);
    }

#ifndef TPF
    if (file && level_and_mask == APLOG_DEBUG) {
#if defined(_OSD_POSIX) || defined(WIN32) || defined(__MVS__)
        char tmp[256];
        char *e = strrchr(file, '/');
#ifdef WIN32
        if (!e) {
            e = strrchr(file, '\\');
        }
#endif

        /* In OSD/POSIX, the compiler returns for __FILE__
         * a string like: __FILE__="*POSIX(/usr/include/stdio.h)"
         * (it even returns an absolute path for sources in
         * the current directory). Here we try to strip this
         * down to the basename.
         */
        if (e != NULL && e[1] != '\0') {
            apr_snprintf(tmp, sizeof(tmp), "%s", &e[1]);
            e = &tmp[strlen(tmp)-1];
            if (*e == ')') {
                *e = '\0';
            }
            file = tmp;
        }
#else /* _OSD_POSIX || WIN32 */
        const char *p;
        /* On Unix, __FILE__ may be an absolute path in a
         * VPATH build. */
        if (file[0] == '/' && (p = ap_strrchr_c(file, '/')) != NULL) {
            file = p + 1;
        }
#endif /*_OSD_POSIX || WIN32 */
        len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                            "%s(%d): ", file, line);
    }
#endif /* TPF */

    if (c) {
        /* XXX: TODO: add a method of selecting whether logged client
         * addresses are in dotted quad or resolved form... dotted
         * quad is the most secure, which is why I'm implementing it
         * first. -djg
         */
        len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                            "[client %s] ", c->remote_ip);
    }
    if (status != 0) {
        if (status < APR_OS_START_EAIERR) {
            len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                                "(%d)", status);
        }
        else if (status < APR_OS_START_SYSERR) {
            len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                                "(EAI %d)", status - APR_OS_START_EAIERR);
        }
        else if (status < 100000 + APR_OS_START_SYSERR) {
            len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                                "(OS %d)", status - APR_OS_START_SYSERR);
        }
        else {
            len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                                "(os 0x%08x)", status - APR_OS_START_SYSERR);
        }
        apr_strerror(status, errstr + len, MAX_STRING_LEN - len);
        len += strlen(errstr + len);
        if (MAX_STRING_LEN - len > 2) {
            errstr[len++] = ':';
            errstr[len++] = ' ';
            errstr[len] = '\0';
        }
    }

    errstrlen = len;
#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
    if (apr_vsnprintf(scratch, MAX_STRING_LEN - len, fmt, args)) {
        len += ap_escape_errorlog_item(errstr + len, scratch,
                                       MAX_STRING_LEN - len);
    }
#else
    len += apr_vsnprintf(errstr + len, MAX_STRING_LEN - len, fmt, args);
#endif

    if (   r && (referer = apr_table_get(r->headers_in, "Referer"))
#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
        && ap_escape_errorlog_item(scratch, referer, MAX_STRING_LEN - len)
#endif
        ) {
        len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                            ", referer: %s",
#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
                            scratch
#else
                            referer
#endif
                            );
    }

    /* NULL if we are logging to syslog */
    if (logf) {
        /* Truncate for the terminator (as apr_snprintf does) */
        if (len > MAX_STRING_LEN - sizeof(APR_EOL_STR)) {
            len = MAX_STRING_LEN - sizeof(APR_EOL_STR);
        }
        strcpy(errstr + len, APR_EOL_STR);
        apr_file_puts(errstr, logf);
        apr_file_flush(logf);
    }
#ifdef HAVE_SYSLOG
    else {
        syslog(level_and_mask, "%s", errstr);
    }
#endif

    ap_run_error_log(file, line, level, status, s, r, pool, errstr + errstrlen);
}
Beispiel #25
0
int ap_open_logs(apr_pool_t *pconf, apr_pool_t *p /* plog */,
                 apr_pool_t *ptemp, server_rec *s_main)
{
    apr_status_t rc = APR_SUCCESS;
    server_rec *virt, *q;
    int replace_stderr;
    apr_file_t *errfile = NULL;

    apr_pool_cleanup_register(p, NULL, clear_handle_list,
                              apr_pool_cleanup_null);
    if (open_error_log(s_main, 1, p) != OK) {
        return DONE;
    }

    replace_stderr = 1;
    if (s_main->error_log) {
        /* replace stderr with this new log */
        apr_file_flush(s_main->error_log);
        if ((rc = apr_file_open_stderr(&errfile, p)) == APR_SUCCESS) {
            rc = apr_file_dup2(errfile, s_main->error_log, p);
        }
        if (rc != APR_SUCCESS) {
            ap_log_error(APLOG_MARK, APLOG_CRIT, rc, s_main,
                         "unable to replace stderr with error_log");
        }
        else {
            replace_stderr = 0;
        }
    }
    /* note that stderr may still need to be replaced with something
     * because it points to the old error log, or back to the tty
     * of the submitter.
     * XXX: This is BS - /dev/null is non-portable
     */
    if (replace_stderr && freopen("/dev/null", "w", stderr) == NULL) {
        ap_log_error(APLOG_MARK, APLOG_CRIT, errno, s_main,
                     "unable to replace stderr with /dev/null");
    }

    for (virt = s_main->next; virt; virt = virt->next) {
        if (virt->error_fname) {
            for (q=s_main; q != virt; q = q->next) {
                if (q->error_fname != NULL
                    && strcmp(q->error_fname, virt->error_fname) == 0) {
                    break;
                }
            }

            if (q == virt) {
                if (open_error_log(virt, 0, p) != OK) {
                    return DONE;
                }
            }
            else {
                virt->error_log = q->error_log;
            }
        }
        else {
            virt->error_log = s_main->error_log;
        }
    }
    return OK;
}
Beispiel #26
0
static int aikido_handler(request_rec *r)
{
    apr_bucket_brigade *bb;
    apr_bucket *b;
    int seen_eos, child_stopped_reading;
    apr_pool_t *p;
    apr_status_t rv;
    conn_rec *c = r->connection;
    void *aikidoreq;
    int inpipes[2];
    int outpipes[2];
    apr_file_t *infile;
    apr_file_t *outfile;
    int e;
    pthread_t tid;
    pthread_attr_t attrs;
    ThreadData tdata;
    void *tresult;

    if (aikido == NULL) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                      "mod_aikido failed to initalize");
        return HTTP_INTERNAL_SERVER_ERROR;
    }
    p = r->main ? r->main->pool : r->pool;

    if (r->method_number == M_OPTIONS) {
        r->allowed |= (AP_METHOD_BIT << M_GET);
        r->allowed |= (AP_METHOD_BIT << M_POST);
        return DECLINED;
    }

    // create the request object
    aikidoreq = aikido_new_request (r);

    if (!aikido_check_uri(aikido, aikidoreq)) {
        aikido_delete_request (aikidoreq);
        return DECLINED;
    }

    e = socketpair (AF_UNIX, SOCK_STREAM, 0, inpipes);
    e |= socketpair (AF_UNIX, SOCK_STREAM, 0, outpipes);
    if (e != 0) {
        perror ("socketpair");
        aikido_delete_request (aikidoreq);
        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                      "Failed to create pipes");
        return HTTP_INTERNAL_SERVER_ERROR;
    }

    // redirect the output from the webapp to our outfile
    apr_os_file_put (&outfile, &outpipes[0], O_RDONLY, r->pool);   // open for reading from outpipes pipe

    // redirect the input to the webapp from out infile
    apr_os_file_put (&infile, &inpipes[1], O_CREAT | O_WRONLY, r->pool);        // open for writing to inpipes pipe

    ap_add_common_vars(r);
    ap_add_cgi_vars(r);


    bb = apr_brigade_create(r->pool, c->bucket_alloc);
    seen_eos = 0;
    child_stopped_reading = 0;
    do {
        apr_bucket *bucket;

        rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
                            APR_BLOCK_READ, HUGE_STRING_LEN);
       
        if (rv != APR_SUCCESS) {
            close (inpipes[0]);
            close (inpipes[1]);
            close (outpipes[0]);
            close (outpipes[1]);
            aikido_delete_request (aikidoreq);
            return rv;
        }

        bucket = APR_BRIGADE_FIRST(bb);
        while (bucket != APR_BRIGADE_SENTINEL(bb)) {
            const char *data;
            apr_size_t len;

            if (APR_BUCKET_IS_EOS(bucket)) {
                seen_eos = 1;
                break;
            }

            /* We can't do much with this. */
            if (APR_BUCKET_IS_FLUSH(bucket)) {
                continue;
            }

            /* If the child stopped, we still must read to EOS. */
            if (child_stopped_reading) {
                continue;
            } 

            /* read */
            apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
            
            /* Keep writing data to the child until done or too much time
             * elapses with no progress or an error occurs.
             */
            rv = apr_file_write_full(infile, data, len, NULL);

            if (rv != APR_SUCCESS) {
                /* silly script stopped reading, soak up remaining message */
                child_stopped_reading = 1;
            }
            bucket = APR_BUCKET_NEXT(bucket);
        }
        apr_brigade_cleanup(bb);
    }
    while (!seen_eos);

    /* Is this flush really needed? */
    apr_file_flush(infile);
    apr_file_close(infile);

    apr_brigade_cleanup(bb);

    /* start the reader thread */
    e = pthread_attr_init (&attrs);
    if (e != 0) {
        close (inpipes[0]);
        close (inpipes[1]);
        close (outpipes[0]);
        close (outpipes[1]);
        aikido_delete_request (aikidoreq);
        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                      "Failed to allocate script thread attributes");
        return HTTP_INTERNAL_SERVER_ERROR;
    }

    e = pthread_attr_setdetachstate (&attrs, PTHREAD_CREATE_JOINABLE) ;
    if (e != 0) {
        close (inpipes[0]);
        close (inpipes[1]);
        close (outpipes[0]);
        close (outpipes[1]);
        aikido_delete_request (aikidoreq);
        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                      "Failed to set script thread attributes");
        return HTTP_INTERNAL_SERVER_ERROR;
    }


    tdata.req = aikidoreq;
    tdata.in = inpipes[0];
    tdata.out = outpipes[1];

    e = pthread_create (&tid, NULL, script_thread, &tdata) ;
    if (e != 0) {
        close (inpipes[0]);
        close (inpipes[1]);
        close (outpipes[0]);
        close (outpipes[1]);
        aikido_delete_request (aikidoreq);
        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                      "Failed to run script thread");
        return HTTP_INTERNAL_SERVER_ERROR;
    }

    /* script thread is now executing script with i/o redirected to the pipes */


    /* read the script output from the pipe*/
    apr_file_pipe_timeout_set(outfile, 0);

    b = aikido_bucket_create(r, outfile, c->bucket_alloc);
    if (b == NULL) {
        pthread_join (tid, &tresult);       /* wait for script to complete */
        close (inpipes[0]);
        close (inpipes[1]);
        close (outpipes[0]);
        close (outpipes[1]);
        aikido_delete_request (aikidoreq);
        return HTTP_INTERNAL_SERVER_ERROR;
    }

    APR_BRIGADE_INSERT_TAIL(bb, b);
    b = apr_bucket_eos_create(c->bucket_alloc);
    APR_BRIGADE_INSERT_TAIL(bb, b);

    ap_pass_brigade(r->output_filters, bb);

    /* wait for the script thread to complete */
    pthread_join (tid, &tresult);
    
    /* terminate script output */
    close (inpipes[0]);
    close (inpipes[1]);
    close (outpipes[0]);
    close (outpipes[1]);

    /* delete the aikido request objects */
    aikido_delete_request (aikidoreq);

    return OK;
}
Beispiel #27
0
APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, apr_file_t *thefile)
{
    apr_status_t rv = APR_SUCCESS; /* get rid of gcc warning */
    apr_size_t nbytes;
    const char *str_start = str;
    char *final = str + len - 1;

    if (len <= 1) {  
        /* sort of like fgets(), which returns NULL and stores no bytes 
         */
        return APR_SUCCESS;
    }

    /* If we have an underlying buffer, we can be *much* more efficient
     * and skip over the apr_file_read calls.
     */
    if (thefile->buffered) {

#if APR_HAS_THREADS
        if (thefile->thlock) {
            apr_thread_mutex_lock(thefile->thlock);
        }
#endif

        if (thefile->direction == 1) {
            rv = apr_file_flush(thefile);
            if (rv) {
#if APR_HAS_THREADS
                if (thefile->thlock) {
                    apr_thread_mutex_unlock(thefile->thlock);
                }
#endif
                return rv;
            }

            thefile->direction = 0;
            thefile->bufpos = 0;
            thefile->dataRead = 0;
        }

        while (str < final) { /* leave room for trailing '\0' */
            /* Force ungetc leftover to call apr_file_read. */
            if (thefile->bufpos < thefile->dataRead &&
                thefile->ungetchar == -1) {
                *str = thefile->buffer[thefile->bufpos++];
            }
            else {
                nbytes = 1;
                rv = apr_file_read(thefile, str, &nbytes);
                if (rv != APR_SUCCESS) {
                    break;
                }
            }
            if (*str == '\n') {
                ++str;
                break;
            }
            ++str;
        }

#if APR_HAS_THREADS
        if (thefile->thlock) {
            apr_thread_mutex_unlock(thefile->thlock);
        }
#endif
    }
    else {
        while (str < final) { /* leave room for trailing '\0' */
Beispiel #28
0
APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *nbytes)
{
    apr_ssize_t rv;
    apr_size_t bytes_read;

    if (*nbytes <= 0) {
        *nbytes = 0;
        return APR_SUCCESS;
    }

    if (thefile->buffered) {
        char *pos = (char *)buf;
        apr_uint64_t blocksize;
        apr_uint64_t size = *nbytes;

#if APR_HAS_THREADS
        if (thefile->thlock) {
            apr_thread_mutex_lock(thefile->thlock);
        }
#endif

        if (thefile->direction == 1) {
            rv = apr_file_flush(thefile);
            if (rv) {
#if APR_HAS_THREADS
                if (thefile->thlock) {
                    apr_thread_mutex_unlock(thefile->thlock);
                }
#endif
                return rv;
            }
            thefile->bufpos = 0;
            thefile->direction = 0;
            thefile->dataRead = 0;
        }

        rv = 0;
        if (thefile->ungetchar != -1) {
            *pos = (char)thefile->ungetchar;
            ++pos;
            --size;
            thefile->ungetchar = -1;
        }
        while (rv == 0 && size > 0) {
            if (thefile->bufpos >= thefile->dataRead) {
                int bytesread = read(thefile->filedes, thefile->buffer, APR_FILE_BUFSIZE);
                if (bytesread == 0) {
                    thefile->eof_hit = TRUE;
                    rv = APR_EOF;
                    break;
                }
                else if (bytesread == -1) {
                    rv = errno;
                    break;
                }
                thefile->dataRead = bytesread;
                thefile->filePtr += thefile->dataRead;
                thefile->bufpos = 0;
            }

            blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size;
            memcpy(pos, thefile->buffer + thefile->bufpos, blocksize);
            thefile->bufpos += blocksize;
            pos += blocksize;
            size -= blocksize;
        }

        *nbytes = pos - (char *)buf;
        if (*nbytes) {
            rv = 0;
        }
#if APR_HAS_THREADS
        if (thefile->thlock) {
            apr_thread_mutex_unlock(thefile->thlock);
        }
#endif
        return rv;
    }
    else {
        bytes_read = 0;
        if (thefile->ungetchar != -1) {
            bytes_read = 1;
            *(char *)buf = (char)thefile->ungetchar;
            buf = (char *)buf + 1;
            (*nbytes)--;
            thefile->ungetchar = -1;
            if (*nbytes == 0) {
                *nbytes = bytes_read;
                return APR_SUCCESS;
            }
        }

        do {
            rv = read(thefile->filedes, buf, *nbytes);
        } while (rv == -1 && errno == EINTR);
#ifdef USE_WAIT_FOR_IO
        if (rv == -1 && 
            (errno == EAGAIN || errno == EWOULDBLOCK) && 
            thefile->timeout != 0) {
            apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 1);
            if (arv != APR_SUCCESS) {
                *nbytes = bytes_read;
                return arv;
            }
            else {
                do {
                    rv = read(thefile->filedes, buf, *nbytes);
                } while (rv == -1 && errno == EINTR);
            }
        }  
#endif
        *nbytes = bytes_read;
        if (rv == 0) {
            thefile->eof_hit = TRUE;
            return APR_EOF;
        }
        if (rv > 0) {
            *nbytes += rv;
            return APR_SUCCESS;
        }
        return errno;
    }
}
Beispiel #29
0
APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes)
{
    apr_size_t rv;

    if (thefile->buffered) {
        char *pos = (char *)buf;
        int blocksize;
        int size = *nbytes;

#if APR_HAS_THREADS
        if (thefile->thlock) {
            apr_thread_mutex_lock(thefile->thlock);
        }
#endif

        if ( thefile->direction == 0 ) {
            /* Position file pointer for writing at the offset we are 
             * logically reading from
             */
            apr_int64_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
            if (offset != thefile->filePtr)
                lseek(thefile->filedes, offset, SEEK_SET);
            thefile->bufpos = thefile->dataRead = 0;
            thefile->direction = 1;
        }

        rv = 0;
        while (rv == 0 && size > 0) {
            if (thefile->bufpos == APR_FILE_BUFSIZE)   /* write buffer is full*/
                rv = apr_file_flush(thefile);

            blocksize = size > APR_FILE_BUFSIZE - thefile->bufpos ? 
                        APR_FILE_BUFSIZE - thefile->bufpos : size;
            memcpy(thefile->buffer + thefile->bufpos, pos, blocksize);                      
            thefile->bufpos += blocksize;
            pos += blocksize;
            size -= blocksize;
        }

#if APR_HAS_THREADS
        if (thefile->thlock) {
            apr_thread_mutex_unlock(thefile->thlock);
        }
#endif
        return rv;
    }
    else {
        do {
            rv = write(thefile->filedes, buf, *nbytes);
        } while (rv == (apr_size_t)-1 && errno == EINTR);
#ifdef USE_WAIT_FOR_IO
        if (rv == (apr_size_t)-1 &&
            (errno == EAGAIN || errno == EWOULDBLOCK) && 
            thefile->timeout != 0) {
            apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 0);
            if (arv != APR_SUCCESS) {
                *nbytes = 0;
                return arv;
            }
            else {
                do {
                    do {
                        rv = write(thefile->filedes, buf, *nbytes);
                    } while (rv == (apr_size_t)-1 && errno == EINTR);
                    if (rv == (apr_size_t)-1 &&
                        (errno == EAGAIN || errno == EWOULDBLOCK)) {
                        *nbytes /= 2; /* yes, we'll loop if kernel lied
                                       * and we can't even write 1 byte
                                       */
                    }
                    else {
                        break;
                    }
                } while (1);
            }
        }  
#endif
        if (rv == (apr_size_t)-1) {
            (*nbytes) = 0;
            return errno;
        }
        *nbytes = rv;
        return APR_SUCCESS;
    }
}
static int cgi_handler(request_rec *r)
{
    int nph;
    apr_size_t dbpos = 0;
    const char *argv0;
    const char *command;
    const char **argv;
    char *dbuf = NULL;
    apr_file_t *script_out = NULL, *script_in = NULL, *script_err = NULL;
    apr_bucket_brigade *bb;
    apr_bucket *b;
    int is_included;
    int seen_eos, child_stopped_reading;
    apr_pool_t *p;
    cgi_server_conf *conf;
    apr_status_t rv;
    cgi_exec_info_t e_info;
    conn_rec *c = r->connection;

    if(strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script"))
        return DECLINED;

    is_included = !strcmp(r->protocol, "INCLUDED");

    p = r->main ? r->main->pool : r->pool;

    argv0 = apr_filepath_name_get(r->filename);
    nph = !(strncmp(argv0, "nph-", 4));
    conf = ap_get_module_config(r->server->module_config, &cgi_module);

    if (!(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r))
        return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,
                               "Options ExecCGI is off in this directory");
    if (nph && is_included)
        return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,
                               "attempt to include NPH CGI script");

    if (r->finfo.filetype == 0)
        return log_scripterror(r, conf, HTTP_NOT_FOUND, 0,
                               "script not found or unable to stat");
    if (r->finfo.filetype == APR_DIR)
        return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,
                               "attempt to invoke directory as script");

    if ((r->used_path_info == AP_REQ_REJECT_PATH_INFO) &&
        r->path_info && *r->path_info)
    {
        /* default to accept */
        return log_scripterror(r, conf, HTTP_NOT_FOUND, 0,
                               "AcceptPathInfo off disallows user's path");
    }
/*
    if (!ap_suexec_enabled) {
        if (!ap_can_exec(&r->finfo))
            return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,
                                   "file permissions deny server execution");
    }

*/
    ap_add_common_vars(r);
    ap_add_cgi_vars(r);

    e_info.process_cgi = 1;
    e_info.cmd_type    = APR_PROGRAM;
    e_info.detached    = 0;
    e_info.in_pipe     = APR_CHILD_BLOCK;
    e_info.out_pipe    = APR_CHILD_BLOCK;
    e_info.err_pipe    = APR_CHILD_BLOCK;
    e_info.prog_type   = RUN_AS_CGI;
    e_info.bb          = NULL;
    e_info.ctx         = NULL;
    e_info.next        = NULL;
    e_info.addrspace   = 0;

    /* build the command line */
    if ((rv = cgi_build_command(&command, &argv, r, p, &e_info)) != APR_SUCCESS) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                      "don't know how to spawn child process: %s",
                      r->filename);
        return HTTP_INTERNAL_SERVER_ERROR;
    }

    /* run the script in its own process */
    if ((rv = run_cgi_child(&script_out, &script_in, &script_err,
                            command, argv, r, p, &e_info)) != APR_SUCCESS) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                      "couldn't spawn child process: %s", r->filename);
        return HTTP_INTERNAL_SERVER_ERROR;
    }

    /* Transfer any put/post args, CERN style...
     * Note that we already ignore SIGPIPE in the core server.
     */
    bb = apr_brigade_create(r->pool, c->bucket_alloc);
    seen_eos = 0;
    child_stopped_reading = 0;
    if (conf->logname) {
        dbuf = apr_palloc(r->pool, conf->bufbytes + 1);
        dbpos = 0;
    }
    do {
        apr_bucket *bucket;

        rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
                            APR_BLOCK_READ, HUGE_STRING_LEN);

        if (rv != APR_SUCCESS) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                          "Error reading request entity data");
            return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
        }

        for (bucket = APR_BRIGADE_FIRST(bb);
             bucket != APR_BRIGADE_SENTINEL(bb);
             bucket = APR_BUCKET_NEXT(bucket))
        {
            const char *data;
            apr_size_t len;

            if (APR_BUCKET_IS_EOS(bucket)) {
                seen_eos = 1;
                break;
            }

            /* We can't do much with this. */
            if (APR_BUCKET_IS_FLUSH(bucket)) {
                continue;
            }

            /* If the child stopped, we still must read to EOS. */
            if (child_stopped_reading) {
                continue;
            }

            /* read */
            apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);

            if (conf->logname && dbpos < conf->bufbytes) {
                int cursize;

                if ((dbpos + len) > conf->bufbytes) {
                    cursize = conf->bufbytes - dbpos;
                }
                else {
                    cursize = len;
                }
                memcpy(dbuf + dbpos, data, cursize);
                dbpos += cursize;
            }

            /* Keep writing data to the child until done or too much time
             * elapses with no progress or an error occurs.
             */
            rv = apr_file_write_full(script_out, data, len, NULL);

            if (rv != APR_SUCCESS) {
                /* silly script stopped reading, soak up remaining message */
                child_stopped_reading = 1;
            }
        }
        apr_brigade_cleanup(bb);
    }
    while (!seen_eos);

    if (conf->logname) {
        dbuf[dbpos] = '\0';
    }
    /* Is this flush really needed? */
    apr_file_flush(script_out);
    apr_file_close(script_out);

    AP_DEBUG_ASSERT(script_in != NULL);

    apr_brigade_cleanup(bb);

#if APR_FILES_AS_SOCKETS
    apr_file_pipe_timeout_set(script_in, 0);
    apr_file_pipe_timeout_set(script_err, 0);

    b = cgi_bucket_create(r, script_in, script_err, c->bucket_alloc);
#else
    b = apr_bucket_pipe_create(script_in, c->bucket_alloc);
#endif
    APR_BRIGADE_INSERT_TAIL(bb, b);
    b = apr_bucket_eos_create(c->bucket_alloc);
    APR_BRIGADE_INSERT_TAIL(bb, b);

    /* Handle script return... */
    if (!nph) {
        const char *location;
        char sbuf[MAX_STRING_LEN];
        int ret;

        if ((ret = ap_scan_script_header_err_brigade(r, bb, sbuf))) {
            ret = log_script(r, conf, ret, dbuf, sbuf, bb, script_err);

            /*
             * ret could be HTTP_NOT_MODIFIED in the case that the CGI script
             * does not set an explicit status and ap_meets_conditions, which
             * is called by ap_scan_script_header_err_brigade, detects that
             * the conditions of the requests are met and the response is
             * not modified.
             * In this case set r->status and return OK in order to prevent
             * running through the error processing stack as this would
             * break with mod_cache, if the conditions had been set by
             * mod_cache itself to validate a stale entity.
             * BTW: We circumvent the error processing stack anyway if the
             * CGI script set an explicit status code (whatever it is) and
             * the only possible values for ret here are:
             *
             * HTTP_NOT_MODIFIED          (set by ap_meets_conditions)
             * HTTP_PRECONDITION_FAILED   (set by ap_meets_conditions)
             * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the
             * processing of the response of the CGI script, e.g broken headers
             * or a crashed CGI process).
             */
            if (ret == HTTP_NOT_MODIFIED) {
                r->status = ret;
                return OK;
            }

            return ret;
        }

        location = apr_table_get(r->headers_out, "Location");

        if (location && r->status == 200) {
            /* For a redirect whether internal or not, discard any
             * remaining stdout from the script, and log any remaining
             * stderr output, as normal. */
            discard_script_output(bb);
            apr_brigade_destroy(bb);
            apr_file_pipe_timeout_set(script_err, r->server->timeout);
            log_script_err(r, script_err);
        }

        if (location && location[0] == '/' && r->status == 200) {
            /* This redirect needs to be a GET no matter what the original
             * method was.
             */
            r->method = apr_pstrdup(r->pool, "GET");
            r->method_number = M_GET;

            /* We already read the message body (if any), so don't allow
             * the redirected request to think it has one.  We can ignore
             * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR.
             */
            apr_table_unset(r->headers_in, "Content-Length");

            ap_internal_redirect_handler(location, r);
            return OK;
        }
        else if (location && r->status == 200) {
            /* XX Note that if a script wants to produce its own Redirect
             * body, it now has to explicitly *say* "Status: 302"
             */
            return HTTP_MOVED_TEMPORARILY;
        }

        rv = ap_pass_brigade(r->output_filters, bb);
    }
    else /* nph */ {
        struct ap_filter_t *cur;

        /* get rid of all filters up through protocol...  since we
         * haven't parsed off the headers, there is no way they can
         * work
         */

        cur = r->proto_output_filters;
        while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) {
            cur = cur->next;
        }
        r->output_filters = r->proto_output_filters = cur;

        rv = ap_pass_brigade(r->output_filters, bb);
    }

    /* don't soak up script output if errors occurred writing it
     * out...  otherwise, we prolong the life of the script when the
     * connection drops or we stopped sending output for some other
     * reason */
    if (rv == APR_SUCCESS && !r->connection->aborted) {
        apr_file_pipe_timeout_set(script_err, r->server->timeout);
        log_script_err(r, script_err);
    }

    apr_file_close(script_err);

    return OK;                      /* NOT r->status, even if it has changed. */
}