static int cgid_handler(request_rec *r)
{
    conn_rec *c = r->connection;
    int retval, nph, dbpos;
    char *argv0, *dbuf;
    apr_bucket_brigade *bb;
    apr_bucket *b;
    cgid_server_conf *conf;
    int is_included;
    int seen_eos, child_stopped_reading;
    int sd;
    char **env;
    apr_file_t *tempsock, *script_err, *errpipe_out;
    struct cleanup_script_info *info;
    apr_status_t rv;
    cgid_dirconf *dc;
    apr_interval_time_t timeout;

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

    conf = ap_get_module_config(r->server->module_config, &cgid_module);
    dc = ap_get_module_config(r->per_dir_config, &cgid_module);

    timeout = dc->timeout > 0 ? dc->timeout : r->server->timeout;
    is_included = !strcmp(r->protocol, "INCLUDED");

    if ((argv0 = strrchr(r->filename, '/')) != NULL) {
        argv0++;
    }
    else {
        argv0 = r->filename;
    }

    nph = !(strncmp(argv0, "nph-", 4));

    argv0 = r->filename;

    if (!(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r)) {
        return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01262)
                "Options ExecCGI is off in this directory");
    }

    if (nph && is_included) {
        return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01263)
                "attempt to include NPH CGI script");
    }

#if defined(OS2) || defined(WIN32)
#error mod_cgid does not work on this platform.  If you teach it to, look
#error at mod_cgi.c for required code in this path.
#else
    if (r->finfo.filetype == APR_NOFILE) {
        return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, APLOGNO(01264)
                "script not found or unable to stat");
    }
#endif
    if (r->finfo.filetype == APR_DIR) {
        return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01265)
                "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, APLOGNO(01266)
                               "AcceptPathInfo off disallows user's path");
    }
    /*
    if (!ap_suexec_enabled) {
        if (!ap_can_exec(&r->finfo))
            return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01267)
                                   "file permissions deny server execution");
    }
    */

#ifdef HAVE_CGID_FDPASSING
    rv = apr_file_pipe_create(&script_err, &errpipe_out, r->pool);
    if (rv) {
        return log_scripterror(r, conf, HTTP_SERVICE_UNAVAILABLE, rv, APLOGNO(10176)
                               "could not create pipe for stderr");
    }
#else
    script_err = NULL;
    errpipe_out = NULL;
#endif
    
    /*
     * httpd core function used to add common environment variables like
     * DOCUMENT_ROOT. 
     */
    ap_add_common_vars(r);
    ap_add_cgi_vars(r);
    env = ap_create_environment(r->pool, r->subprocess_env);

    if ((retval = connect_to_daemon(&sd, r, conf)) != OK) {
        return retval;
    }

    rv = send_req(sd, errpipe_out, r, argv0, env, CGI_REQ);
    if (rv != APR_SUCCESS) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01268)
                     "write to cgi daemon process");
    }

    /* The write-end of the pipe is only used by the server, so close
     * it here. */
    if (errpipe_out) apr_file_close(errpipe_out);
    
    info = apr_palloc(r->pool, sizeof(struct cleanup_script_info));
    info->conf = conf;
    info->r = r;
    rv = get_cgi_pid(r, conf, &(info->pid));

    if (APR_SUCCESS == rv){  
        apr_pool_cleanup_register(r->pool, info,
                              cleanup_script,
                              apr_pool_cleanup_null);
    }
    else { 
        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, "error determining cgi PID");
    }

    /* We are putting the socket discriptor into an apr_file_t so that we can
     * use a pipe bucket to send the data to the client.  APR will create
     * a cleanup for the apr_file_t which will close the socket, so we'll
     * get rid of the cleanup we registered when we created the socket.
     */

    apr_os_pipe_put_ex(&tempsock, &sd, 1, r->pool);
    apr_file_pipe_timeout_set(tempsock, timeout);
    apr_pool_cleanup_kill(r->pool, (void *)((long)sd), close_unix_socket);

    /* Transfer any put/post args, CERN style...
     * Note that we already ignore SIGPIPE in the core server.
     */
    bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
    seen_eos = 0;
    child_stopped_reading = 0;
    dbuf = NULL;
    dbpos = 0;
    if (conf->logname) {
        dbuf = apr_palloc(r->pool, conf->bufbytes + 1);
    }
    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, APLOGNO(01270)
                          "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(tempsock, data, len, NULL);

            if (rv != APR_SUCCESS) {
                /* silly script stopped reading, soak up remaining message */
                child_stopped_reading = 1;
                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,  APLOGNO(02651)
                              "Error writing request body to script %s", 
                              r->filename);

            }
        }
        apr_brigade_cleanup(bb);
    }
    while (!seen_eos);

    if (conf->logname) {
        dbuf[dbpos] = '\0';
    }

    /* we're done writing, or maybe we didn't write at all;
     * force EOF on child's stdin so that the cgi detects end (or
     * absence) of data
     */
    shutdown(sd, 1);

    bb = apr_brigade_create(r->pool, c->bucket_alloc);
#ifdef HAVE_CGID_FDPASSING
    b = cgi_bucket_create(r, dc->timeout, tempsock, script_err, c->bucket_alloc);
    if (b == NULL)
        return HTTP_INTERNAL_SERVER_ERROR; /* should call log_scripterror() w/ _UNAVAILABLE? */
#else
    b = apr_bucket_pipe_create(tempsock, c->bucket_alloc);
#endif
    APR_BRIGADE_INSERT_TAIL(bb, b);
    b = apr_bucket_eos_create(c->bucket_alloc);
    APR_BRIGADE_INSERT_TAIL(bb, b);

    return cgi_handle_response(r, nph, bb, timeout, conf, dbuf, script_err);
}