Beispiel #1
0
static int req_internal_redirect(lua_State* L)
{
  request_rec *r = CHECK_REQUEST_OBJECT(1);
  const char *new_uri = luaL_optstring(L, 2, r->uri);

  ap_internal_redirect(new_uri, r);
  return 0;
}
Beispiel #2
0
CAMLprim value
netcgi2_apache_request_internal_redirect (value new_uri, value rv)
{
    CAMLparam2 (new_uri, rv);
    request_rec *r = Request_rec_val (rv);
    ap_internal_redirect (String_val (new_uri), r);
    CAMLreturn (Val_unit);
}
static int apreq_redirect_test_handler(request_rec *r)
{
    apreq_handle_t *req;
    const apreq_param_t *loc;

    if (strcmp(r->handler, "apreq_redirect_test") != 0)
        return DECLINED;

    req = apreq_handle_apache2(r);

    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
                  r, "looking for new location");
    loc = apreq_param(req, "location");
    if (!loc)
        return DECLINED;
    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
                  r, "redirecting to %s", loc->v.data);
    ap_internal_redirect(loc->v.data, r);
    return OK;
}
Beispiel #4
0
static am_status_t set_custom_response(am_request_t *rq, const char *text, const char *cont_type) {
    request_rec *r = (request_rec *) (rq != NULL ? rq->ctx : NULL);
    if (r == NULL || !ISVALID(text)) return AM_EINVAL;
    if (rq->status == AM_INTERNAL_REDIRECT) {
        ap_internal_redirect(text, r);
        rq->status = AM_DONE;
    } else if (rq->status == AM_REDIRECT) {
        apr_table_add(r->headers_out, "Location", text);
        ap_custom_response(r, HTTP_MOVED_TEMPORARILY, text);
    } else {
        if (rq->status == AM_PDP_DONE) {
            request_rec *sr = ap_sub_req_method_uri(am_method_num_to_str(rq->method),
                    rq->post_data_url, r, NULL);

            sr->headers_in = r->headers_in;
            sr->notes = r->notes;

            am_log_debug(rq->instance_id, "set_custom_response(): issuing sub-request %s to %s",
                    sr->method, rq->post_data_url);

            ap_run_sub_req(sr);
            ap_destroy_sub_req(sr);
            rq->status = AM_DONE;

        } else {
            size_t tl = strlen(text);
            if (ISVALID(cont_type)) {
                ap_set_content_type(r, cont_type);
            }
            ap_set_content_length(r, tl);
            ap_rwrite(text, (int) tl, r);
            ap_custom_response(r,
                    am_status_value(rq->status == AM_SUCCESS ||
                    rq->status == AM_DONE ? AM_SUCCESS : rq->status), text);
            ap_rflush(r);
        }
    }
    am_log_info(rq->instance_id, "set_custom_response(): status: %s", am_strerror(rq->status));
    return AM_SUCCESS;
}
Beispiel #5
0
/* XXX: Is there is still an O(n^2) attack possible here?  Please detail. */
BOOL WINAPI ServerSupportFunction (HCONN hConn, DWORD dwHSERequest,
                                   LPVOID lpvBuffer, LPDWORD lpdwSize,
                                   LPDWORD lpdwDataType) {
    isapi_cid *cid = (isapi_cid *)hConn;
    request_rec *r = cid->r;
    request_rec *subreq;

    switch (dwHSERequest) {
    case 1: /* HSE_REQ_SEND_URL_REDIRECT_RESP */
        /* Set the status to be returned when the HttpExtensionProc()
         * is done.
         * WARNING: Microsoft now advertises HSE_REQ_SEND_URL_REDIRECT_RESP
         *          and HSE_REQ_SEND_URL as equivalant per the Jan 2000 SDK.
         *          They most definately are not, even in their own samples.
         */
        ap_table_set(r->headers_out, "Location", lpvBuffer);
        cid->status = cid->r->status
                    = cid->ecb->dwHttpStatusCode = HTTP_MOVED_TEMPORARILY;
        return TRUE;

    case 2: /* HSE_REQ_SEND_URL */
        /* Soak up remaining input (there should be none) */
        if (r->remaining > 0) {
            char argsbuffer[HUGE_STRING_LEN];
            while (ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0);
        }

        /* Reset the method to GET */
        r->method = ap_pstrdup(r->pool, "GET");
        r->method_number = M_GET;

        /* Don't let anyone think there's still data */
        ap_table_unset(r->headers_in, "Content-Length");

        /* AV fault per PR3598 - redirected path is lost! */
        (char*)lpvBuffer = ap_pstrdup(r->pool, (char*)lpvBuffer);
        ap_internal_redirect((char*)lpvBuffer, r);
        return TRUE;

    case 3: /* HSE_REQ_SEND_RESPONSE_HEADER */
    {
        /* Parse them out, or die trying */
        DWORD statlen = 0, headlen = 0;
	if (lpvBuffer)
	    statlen = strlen((char*) lpvBuffer);
	if (lpdwDataType)
	    headlen = strlen((char*) lpdwDataType);
        return SendResponseHeaderEx(cid, (char*) lpvBuffer, (char*) lpdwDataType, 
                                    statlen, headlen);
    }

    case 4: /* HSE_REQ_DONE_WITH_SESSION */
        /* Do nothing... since we don't support async I/O, they'll
         * return from HttpExtensionProc soon
         */
        return TRUE;

    case 1001: /* HSE_REQ_MAP_URL_TO_PATH */
    {
        /* Map a URL to a filename */
        char *file = (char *)lpvBuffer;
	DWORD len;
        subreq = ap_sub_req_lookup_uri(ap_pstrndup(r->pool, file, *lpdwSize), r);

        len = ap_cpystrn(file, subreq->filename, *lpdwSize) - file;
	
        /* IIS puts a trailing slash on directories, Apache doesn't */
        if (S_ISDIR (subreq->finfo.st_mode)) {
            if (len < *lpdwSize - 1) {
                file[len++] = '\\';
                file[len] = '\0';
            }
        }
        *lpdwSize = len;
        return TRUE;
    }

    case 1002: /* HSE_REQ_GET_SSPI_INFO */
        if (LogNotSupported)
            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
                          "ISAPI ServerSupportFunction HSE_REQ_GET_SSPI_INFO "
                          "is not supported: %s", r->filename);
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;

    case 1003: /* HSE_APPEND_LOG_PARAMETER */
        /* Log lpvBuffer, of lpdwSize bytes, in the URI Query (cs-uri-query) field
         * This code will do for now...
         */
        ap_table_set(r->notes, "isapi-parameter", (char*) lpvBuffer);
        if (AppendLogToQuery) {
            if (r->args)
                r->args = ap_pstrcat(r->pool, r->args, (char*) lpvBuffer, NULL);
            else
                r->args = ap_pstrdup(r->pool, (char*) lpvBuffer);
        }
        if (AppendLogToErrors)
            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, r,
                          "ISAPI %s: %s", cid->r->filename,
                          (char*) lpvBuffer);
        return TRUE;

    /* We don't support all this async I/O, Microsoft-specific stuff */
    case 1005: /* HSE_REQ_IO_COMPLETION */
    case 1006: /* HSE_REQ_TRANSMIT_FILE */
        if (LogNotSupported)
            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
                          "ISAPI asynchronous I/O not supported: %s", 
                          r->filename);
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;

    case 1007: /* HSE_REQ_REFRESH_ISAPI_ACL */
        /* Since we don't override the user ID and access, we can't reset.
         */
        if (LogNotSupported)
            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
                          "ISAPI ServerSupportFunction "
                          "HSE_REQ_REFRESH_ISAPI_ACL "
                          "is not supported: %s", r->filename);
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;

    case 1008: /* HSE_REQ_IS_KEEP_CONN */
        *((LPBOOL) lpvBuffer) = (r->connection->keepalive == 1);
        return TRUE;

    case 1010: /* HSE_REQ_ASYNC_READ_CLIENT */
        if (LogNotSupported)
            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
                          "ISAPI asynchronous I/O not supported: %s", 
                          r->filename);
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;

    case 1011: /* HSE_REQ_GET_IMPERSONATION_TOKEN  Added in ISAPI 4.0 */
        if (LogNotSupported)
            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
                          "ISAPI ServerSupportFunction "
                          "HSE_REQ_GET_IMPERSONATION_TOKEN "
                          "is not supported: %s", r->filename);
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;

#ifdef HSE_REQ_MAP_URL_TO_PATH_EX
    case 1012: /* HSE_REQ_MAP_URL_TO_PATH_EX */
    {
        /* Map a URL to a filename */
        LPHSE_URL_MAPEX_INFO info = (LPHSE_URL_MAPEX_INFO) lpdwDataType;
        char* test_uri = ap_pstrndup(r->pool, (char *)lpvBuffer, *lpdwSize);

        subreq = ap_sub_req_lookup_uri(test_uri, r);
        info->cchMatchingURL = strlen(test_uri);        
        info->cchMatchingPath = ap_cpystrn(info->lpszPath, subreq->filename, 
                                           MAX_PATH) - info->lpszPath;
        
        /* Mapping started with assuming both strings matched.
         * Now roll on the path_info as a mismatch and handle
         * terminating slashes for directory matches.
         */
        if (subreq->path_info && *subreq->path_info) {
            ap_cpystrn(info->lpszPath + info->cchMatchingPath, 
                       subreq->path_info, MAX_PATH - info->cchMatchingPath);
            info->cchMatchingURL -= strlen(subreq->path_info);
            if (S_ISDIR(subreq->finfo.st_mode)
                 && info->cchMatchingPath < MAX_PATH - 1) {
                /* roll forward over path_info's first slash */
                ++info->cchMatchingPath;
                ++info->cchMatchingURL;
            }
        }
        else if (S_ISDIR(subreq->finfo.st_mode)
                 && info->cchMatchingPath < MAX_PATH - 1) {
            /* Add a trailing slash for directory */
            info->lpszPath[info->cchMatchingPath++] = '/';
            info->lpszPath[info->cchMatchingPath] = '\0';
        }

        /* If the matched isn't a file, roll match back to the prior slash */
        if (!subreq->finfo.st_mode) {
            while (info->cchMatchingPath && info->cchMatchingURL) {
                if (info->lpszPath[info->cchMatchingPath - 1] == '/') 
                    break;
                --info->cchMatchingPath;
                --info->cchMatchingURL;
            }
        }
        
        /* Paths returned with back slashes */
        for (test_uri = info->lpszPath; *test_uri; ++test_uri)
            if (*test_uri == '/')
                *test_uri = '\\';
        
        /* is a combination of:
         * HSE_URL_FLAGS_READ         0x001 Allow read
         * HSE_URL_FLAGS_WRITE        0x002 Allow write
         * HSE_URL_FLAGS_EXECUTE      0x004 Allow execute
         * HSE_URL_FLAGS_SSL          0x008 Require SSL
         * HSE_URL_FLAGS_DONT_CACHE   0x010 Don't cache (VRoot only)
         * HSE_URL_FLAGS_NEGO_CERT    0x020 Allow client SSL cert
         * HSE_URL_FLAGS_REQUIRE_CERT 0x040 Require client SSL cert
         * HSE_URL_FLAGS_MAP_CERT     0x080 Map client SSL cert to account
         * HSE_URL_FLAGS_SSL128       0x100 Require 128-bit SSL cert
         * HSE_URL_FLAGS_SCRIPT       0x200 Allow script execution
         *
         * XxX: As everywhere, EXEC flags could use some work...
         *      and this could go further with more flags, as desired.
         */ 
        info->dwFlags = (subreq->finfo.st_mode & _S_IREAD  ? 0x001 : 0)
                      | (subreq->finfo.st_mode & _S_IWRITE ? 0x002 : 0)
                      | (subreq->finfo.st_mode & _S_IEXEC  ? 0x204 : 0);
        return TRUE;
    }
#endif

    case 1014: /* HSE_REQ_ABORTIVE_CLOSE */
        if (LogNotSupported)
            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
                          "ISAPI ServerSupportFunction HSE_REQ_ABORTIVE_CLOSE"
                          " is not supported: %s", r->filename);
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;

    case 1015: /* HSE_REQ_GET_CERT_INFO_EX  Added in ISAPI 4.0 */
        if (LogNotSupported)
            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
                          "ISAPI ServerSupportFunction "
                          "HSE_REQ_GET_CERT_INFO_EX "
                          "is not supported: %s", r->filename);
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;

#ifdef HSE_REQ_SEND_RESPONSE_HEADER_EX
    case 1016: /* HSE_REQ_SEND_RESPONSE_HEADER_EX  Added in ISAPI 4.0 */
    {
        LPHSE_SEND_HEADER_EX_INFO shi
                                  = (LPHSE_SEND_HEADER_EX_INFO) lpvBuffer;
        /* XXX: ignore shi->fKeepConn?  We shouldn't need the advise */
        /* r->connection->keepalive = shi->fKeepConn; */
        return SendResponseHeaderEx(cid, shi->pszStatus, shi->pszHeader,
                                         shi->cchStatus, shi->cchHeader);
    }
#endif

    case 1017: /* HSE_REQ_CLOSE_CONNECTION  Added after ISAPI 4.0 */
        if (LogNotSupported)
            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
                          "ISAPI ServerSupportFunction "
                          "HSE_REQ_CLOSE_CONNECTION "
                          "is not supported: %s", r->filename);
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;

    case 1018: /* HSE_REQ_IS_CONNECTED  Added after ISAPI 4.0 */
        /* Returns True if client is connected c.f. MSKB Q188346
         * XXX: That statement is very ambigious... assuming the 
         * identical return mechanism as HSE_REQ_IS_KEEP_CONN.
         */
        *((LPBOOL) lpvBuffer) = (r->connection->aborted == 0);
        return TRUE;

    case 1020: /* HSE_REQ_EXTENSION_TRIGGER  Added after ISAPI 4.0 */
        /*  Undocumented - defined by the Microsoft Jan '00 Platform SDK
         */
        if (LogNotSupported)
            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
                          "ISAPI ServerSupportFunction "
                          "HSE_REQ_EXTENSION_TRIGGER "
                          "is not supported: %s", r->filename);
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;


    default:
        if (LogNotSupported)
            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
                          "ISAPI ServerSupportFunction (%d) not supported: "
                          "%s", dwHSERequest, r->filename);
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }
}
Beispiel #6
0
/**
 *	Performs the make, if necessary
 */
static int make_fixup(request_rec *r) {
	if (!r)
		return HTTP_INTERNAL_SERVER_ERROR;
	if (r->prev)
		return DECLINED; // We're running in a sub-request, ignore.
		
	dir_cfg* cfg=ap_get_module_config(r->per_dir_config,&make_module);
	if (!cfg->onoff) // Is module turned on?
		return DECLINED;
		
	const char* docroot=ap_document_root(r);

	if (cfg->debug) {
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: cfg:onoff:%d",cfg->onoff);
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: cfg:sourceRoot:%s",cfg->sourceRoot);
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: cfg:makefileName:%s",cfg->makefileName);
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: cfg:makeProgram:%s",cfg->makeProgram);
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: cfg:makeOptions:%s",cfg->makeOptions);
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: cfg:includeFileTypes:%s",cfg->includeFileTypes);
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: cfg:excludeFileTypes:%s",cfg->excludeFileTypes);
		// ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: cfg:excludeRegex:%s",cfg->excludeRegex);
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: cfg:errorURI:%s",cfg->errorURI);
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: cfg:errorCSS:%s",cfg->errorCSS);
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: DocumentRoot:%s",docroot);
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: URI:%s",r->uri);
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: Canonical Filename:%s",r->canonical_filename);
	}
	
	// Determine if this is a request I care about, i.e., the following is true:
	// The file type is in MakeIncludeFileTypes (if specified) and is not in MakeExcludeFileTypes (if specified)
	if (cfg->includeFileTypes || cfg->excludeFileTypes) {
		// Get file extension
		char* fname=basename(r->canonical_filename);
		char* ext=strchr(fname,'.');
		if (ext) {
			if (cfg->includeFileTypes && !strcasestr(cfg->includeFileTypes,ext)) {
				return DECLINED;
			}
			if (cfg->excludeFileTypes && strcasestr(cfg->excludeFileTypes,ext)) {
				return DECLINED;
			}
		}
	}
		
	// Locate Makefile: The Makefile should be in SourceRoot/REL_PATH/Makefile
	char relpath[256];
	char makefile[256];
	char make_target[256];

	// Determine the relative path part of r->canonical_filename, i.e., the part with the DocumentRoot removed
	strncpy(relpath,r->canonical_filename+strlen(docroot),sizeof(relpath)-1);
	// Truncate it before the basename
	char* p=strrchr(relpath,'/');
	if (p)
		*++p='\0';
	else {
		relpath[0]='/';
		relpath[1]='\0';
	}

	if (cfg->debug) {
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: relpath:%s",relpath);
	}
	
	int bFoundMakefile=FALSE;
	int bGiveUp=FALSE;
	
	do
	{
		// Determine the make target, i.e., the basename of r->canonical_filename
		strncpy(make_target,r->canonical_filename+strlen(docroot)+strlen(relpath),sizeof(make_target)-1);
		make_target[sizeof(make_target)-1]='\0';

		if (strlen(cfg->sourceRoot))
			strncpy(makefile,cfg->sourceRoot,sizeof(makefile)-1);
		else
			strncpy(makefile,docroot,sizeof(makefile)-1);
		strncat(makefile,relpath,sizeof(makefile)-strlen(makefile)-1);
		strncat(makefile,cfg->makefileName,sizeof(makefile)-strlen(makefile)-1);
		makefile[sizeof(makefile)-1]='\0';
	
		// If Makefile not found, ignore it (we only care if there •is* a Makefile)
		struct stat ss;
		if (!stat(makefile,&ss))
			bFoundMakefile=TRUE;
		else
		{
			if (cfg->debug)
				ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: Makefile not found:%s. Trying parent directory...",makefile);
			
			// Go up one dir until we find a Makefile (but don't go past cfg->sourceRoot)
			// Take a directory off relpath, move it to the start of make_target and retry looking for the Makefile
			// Find 2nd-to-last / in relpath, that's the start of the last directory name
			char* p=strrchr(relpath,'/');
			if (p)
			{
				do
					--p;
				while (p>=relpath && *p!='/');
				
				if (p>=relpath)
					*(p+1)='\0';
				else
					bGiveUp=TRUE;
			}
			else
				bGiveUp=TRUE;
		}
	}
	while (bFoundMakefile==FALSE && bGiveUp==FALSE);
	
	if (bFoundMakefile==FALSE) // Never found a Makefile
	{
		if (cfg->debug)
			ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: Unable to find a Makefile named:%s",cfg->makefileName);
		return DECLINED;
	}

	if (cfg->debug) {
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: relpath:%s",relpath);
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: makefile:%s",makefile);
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: make_target:%s",make_target);
	}

	// Build make command
	char* cmd=apr_psprintf(r->pool,"WWWDOCROOT=%s WWWRELPATH=%s %s -f %s -C %s %s %s 2>&1",
		docroot,
		relpath,
		cfg->makeProgram,
		cfg->makefileName,
		(const char*)dirname(makefile),
		cfg->makeOptions,
		make_target);

	if (cfg->debug)
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: cmd:%s",cmd);
	
	// Run Makefile to make target
	FILE* makep=popen(cmd,"r");
	if (!makep) { // If launching make fails, output errors from make and return HTTP error
		if (cfg->debug)
			ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: failed to popen:%s",cmd);
		return HTTP_INTERNAL_SERVER_ERROR;
	}

	// Compile regex
	regex_t regex;
	char* regexstr=apr_psprintf(r->pool,
		"^make:[[:space:]]+\\*\\*\\*[[:space:]]+No[[:space:]]+rule[[:space:]]+to[[:space:]]+make[[:space:]]+target[[:space:]]+`%s'\\.[[:space:]]+Stop\\.",
		make_target
		);
	if (regcomp(&regex,regexstr,REG_EXTENDED)) {
		if (cfg->debug)
			ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: regcomp failed");
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	
	int bSilentFail=FALSE;

	// Read output of make
	size_t make_output_size=10240; // TODO: allow the buffer to grow beyond 10K
	char* make_output=apr_palloc(r->pool,make_output_size);
	make_output[0]='\0';
	make_output_size--;
	p=make_output; // reuse p
	do {
		const char* newp=fgets(p,make_output_size,makep);
		if (newp) {
			if (cfg->debug)
				ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: make output:%s",newp);
			make_output_size-=strlen(newp);
			p+=strlen(newp);
			
			if (regexec(&regex,newp,0,0,0)==0) {
				if (cfg->debug)
					ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: regex match:%s",newp);
				bSilentFail=TRUE;
			}

		}
	}
	while (!feof(makep) && make_output_size>1);
	
	if (!make_output_size) {
		if (cfg->debug)
			ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: make output exceeded max length");
		// TODO: add appropriate message to make_output
	}

	int ret=pclose(makep);
	
	if (cfg->debug)
		ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: make exit code:%d",WEXITSTATUS(ret));
	
	if (WEXITSTATUS(ret)) {// make did not complete successfully, output make's output and tell Apache to stop.
		if (bSilentFail) {
			if (cfg->debug)
				ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,"mod_make: silently failing.");
			return DECLINED;
		}
		
		// Store make_output in request_rec so that the handler can display it 
		apr_table_set(r->notes,"make_output",make_output);
		// Redirect to our own content handler
		ap_internal_redirect(cfg->errorURI,r);
		return OK;
	}
	
    return DECLINED;
}
/*
 *	ic_transfer_response()
 *	----------------------
 *	Read the response from the Interchange server
 *	and relay it to the client
 */
static int ic_transfer_response(request_rec *r,BUFF *ic_buff)
{
	const char *location;
	int rc,ic_sock;
	char sbuf[MAX_STRING_LEN],argsbuffer[MAX_STRING_LEN];

	/*
	 *	get the socket we are using to talk to the
	 *	Interchange server, and wait for Interchange to
	 *	send us some data
	 */
	ic_sock = ap_bfileno(ic_buff,B_RD);
	rc = ic_select(ic_sock,0,IC_DEFAULT_TIMEOUT,0);
	if (rc < 0){
		ap_log_reason("Failed to select the response header",r->uri,r);
		return HTTP_INTERNAL_SERVER_ERROR;
	}

	/*
	 *	check the HTTP header to make sure that it looks valid
	 */
	if ((rc = ap_scan_script_header_err_buff(r,ic_buff,sbuf)) != OK) {
		if (rc == HTTP_INTERNAL_SERVER_ERROR) {
			ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"Malformed header return by Interchange: %s",sbuf);
		}
		return rc;
	}

	/*
	 *	check the header for an HTTP redirect request
	 */
	location = ap_table_get(r->headers_out,"Location");
	if (r->status == 200 && location){
		fd_set sock_set;

		/*
		 *	check if we need to do an external redirect
		 */
		if (*location != '/')
			return REDIRECT;

		/*
		 *	we are here because we need to do an internal redirect
		 *
		 *	soak up any data from the Interchange socket
		 */
		rc = ic_select(ic_sock,0,IC_DEFAULT_TIMEOUT,0);
		if (rc < 0){
			ap_log_reason("Failed to select the response text",r->uri,r);
			return HTTP_INTERNAL_SERVER_ERROR;
		}

		/*
		 *	soak up any body-text sent by the Interchange server
		 */
		ap_soft_timeout("mod_interchange: Interchange read",r);
		while (ap_bgets(argsbuffer,MAX_STRING_LEN,ic_buff) > 0)
			;
		ap_kill_timeout(r);

		/*
		 *	always use the GET method for internal redirects
		 *	also, unset the Content-Length so that nothing
		 *	else tries to re-read the text we just soaked up
		 */
		r->method = ap_pstrdup(r->pool,"GET");
		r->method_number = M_GET;
		ap_table_unset(r->headers_in,"Content-Length");
		ap_internal_redirect(location,r);
		return OK;
	}

	/*
	 *	we were not redirected, so send the HTTP headers
	 *	to the client
	 */
	ap_hard_timeout("mod_interchange: Client write",r);
	ap_send_http_header(r);
	if (ap_rflush(r) < 0){
		ap_log_reason("error sending headers to client",r->uri,r);
		return HTTP_INTERNAL_SERVER_ERROR;
	}

	/*
	 *	if Interchange is sending body text (HTML), then
	 *	relay this to the client
	 */
	if (!r->header_only){
		ap_reset_timeout(r);
		if ((rc = ap_bnonblock(ic_buff,B_RD)) != 0){
			ap_log_reason("error turning non blocking I/O on Interchange socket",r->uri,r);
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		ap_bsetflag(ic_buff,B_SAFEREAD,1);
		if (ap_send_fb(ic_buff,r) <= 0){
			ap_log_reason("error sending response body to client",r->uri,r);
			return HTTP_INTERNAL_SERVER_ERROR;
		}
	}
	ap_kill_timeout(r);
	return OK;
}