API_EXPORT(void) ap_send_error_response(request_rec *r, int recursive_error)
API_EXPORT(long) ap_send_fd(FILE *f, request_rec *r)
API_EXPORT(void) ap_send_error_response(request_rec *r, int recursive_error){    int status = r->status;    int idx = ap_index_of_response(status);    char *custom_response;    const char *location = ap_table_get(r->headers_out, "Location");#ifdef CHARSET_EBCDIC    /* Error Responses (builtin / string literal / redirection) are TEXT! */    ap_bsetflag(r->connection->client, B_EBCDIC2ASCII, r->ebcdic.conv_out = 1);#endif    /*     * It's possible that the Location field might be in r->err_headers_out     * instead of r->headers_out; use the latter if possible, else the     * former.     */    if (location == NULL) {	location = ap_table_get(r->err_headers_out, "Location");    }    /* We need to special-case the handling of 204 and 304 responses,     * since they have specific HTTP requirements and do not include a     * message body.  Note that being assbackwards here is not an option.     */    if (status == HTTP_NOT_MODIFIED) {        if (!ap_is_empty_table(r->err_headers_out))            r->headers_out = ap_overlay_tables(r->pool, r->err_headers_out,                                               r->headers_out);        ap_hard_timeout("send 304", r);        ap_basic_http_header(r);        ap_set_keepalive(r);        ap_table_do((int (*)(void *, const char *, const char *)) ap_send_header_field,                    (void *) r, r->headers_out,                    "Connection",                    "Keep-Alive",                    "ETag",                    "Content-Location",                    "Expires",                    "Cache-Control",                    "Vary",                    "Warning",                    "WWW-Authenticate",                    "Proxy-Authenticate",                    NULL);        terminate_header(r->connection->client);        ap_kill_timeout(r);        return;    }    if (status == HTTP_NO_CONTENT) {        ap_send_http_header(r);        ap_finalize_request_protocol(r);        return;    }    if (!r->assbackwards) {        table *tmp = r->headers_out;        /* For all HTTP/1.x responses for which we generate the message,         * we need to avoid inheriting the "normal status" header fields         * that may have been set by the request handler before the         * error or redirect, except for Location on external redirects.         */        r->headers_out = r->err_headers_out;        r->err_headers_out = tmp;        ap_clear_table(r->err_headers_out);        if (ap_is_HTTP_REDIRECT(status) || (status == HTTP_CREATED)) {            if ((location != NULL) && *location) {	        ap_table_setn(r->headers_out, "Location", location);            }            else {                location = "";   /* avoids coredump when printing, below */            }        }        r->content_language = NULL;        r->content_languages = NULL;        r->content_encoding = NULL;        r->clength = 0;        if (ap_table_get(r->subprocess_env,                         "suppress-error-charset") != NULL) {            r->content_type = "text/html";        }        else {            r->content_type = "text/html; charset=iso-8859-1";        }        if ((status == METHOD_NOT_ALLOWED) || (status == NOT_IMPLEMENTED))            ap_table_setn(r->headers_out, "Allow", make_allow(r));        ap_send_http_header(r);        if (r->header_only) {            ap_finalize_request_protocol(r);            ap_rflush(r);            return;        }    }#ifdef CHARSET_EBCDIC    /* Server-generated response, converted */    ap_bsetflag(r->connection->client, B_EBCDIC2ASCII, r->ebcdic.conv_out = 1);#endif    ap_hard_timeout("send error body", r);    if ((custom_response = ap_response_code_string(r, idx))) {        /*         * We have a custom response output. This should only be         * a text-string to write back. But if the ErrorDocument         * was a local redirect and the requested resource failed         * for any reason, the custom_response will still hold the         * redirect URL. We don't really want to output this URL         * as a text message, so first check the custom response         * string to ensure that it is a text-string (using the         * same test used in ap_die(), i.e. does it start with a ").         * If it doesn't, we've got a recursive error, so find         * the original error and output that as well.         */        if (custom_response[0] == '\"') {            ap_rputs(custom_response + 1, r);            ap_kill_timeout(r);            ap_finalize_request_protocol(r);            ap_rflush(r);            return;        }        /*         * Redirect failed, so get back the original error         */        while (r->prev && (r->prev->status != HTTP_OK))            r = r->prev;    }    {        const char *title = status_lines[idx];        const char *h1;        const char *error_notes;        /* Accept a status_line set by a module, but only if it begins         * with the 3 digit status code         */        if (r->status_line != NULL            && strlen(r->status_line) > 4       /* long enough */            && ap_isdigit(r->status_line[0])            && ap_isdigit(r->status_line[1])            && ap_isdigit(r->status_line[2])            && ap_isspace(r->status_line[3])            && ap_isalnum(r->status_line[4])) {            title = r->status_line;        }        /* folks decided they didn't want the error code in the H1 text */        h1 = &title[4];        ap_rvputs(r,                  DOCTYPE_HTML_2_0                  "<HTML><HEAD>\n<TITLE>", title,                  "</TITLE>\n</HEAD><BODY>\n<H1>", h1, "</H1>\n",                  NULL);	switch (status) {	case HTTP_MOVED_PERMANENTLY:	case HTTP_MOVED_TEMPORARILY:	case HTTP_TEMPORARY_REDIRECT:	    ap_rvputs(r, "The document has moved <A HREF=\"",		      ap_escape_html(r->pool, location), "\">here</A>.<P>\n",		      NULL);	    break;	case HTTP_SEE_OTHER:	    ap_rvputs(r, "The answer to your request is located <A HREF=\"",		      ap_escape_html(r->pool, location), "\">here</A>.<P>\n",		      NULL);	    break;	case HTTP_USE_PROXY:	    ap_rvputs(r, "This resource is only accessible "		      "through the proxy\n",		      ap_escape_html(r->pool, location),		      "<BR>\nYou will need to ",		      "configure your client to use that proxy.<P>\n", NULL);	    break;	case HTTP_PROXY_AUTHENTICATION_REQUIRED:	case AUTH_REQUIRED:	    ap_rputs("This server could not verify that you\n"	             "are authorized to access the document\n"	             "requested.  Either you supplied the wrong\n"	             "credentials (e.g., bad password), or your\n"	             "browser doesn't understand how to supply\n"	             "the credentials required.<P>\n", r);	    break;	case BAD_REQUEST:	    ap_rputs("Your browser sent a request that "	             "this server could not understand.<P>\n", r);	    if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {		ap_rvputs(r, error_notes, "<P>\n", NULL);	    }	    break;	case HTTP_FORBIDDEN:	    ap_rvputs(r, "You don't have permission to access ",		      ap_escape_html(r->pool, r->uri),		      "\non this server.<P>\n", NULL);	    break;	case NOT_FOUND:	    ap_rvputs(r, "The requested URL ",		      ap_escape_html(r->pool, r->uri),		      " was not found on this server.<P>\n", NULL);	    break;	case METHOD_NOT_ALLOWED:	    ap_rvputs(r, "The requested method ", r->method,		      " is not allowed "		      "for the URL ", ap_escape_html(r->pool, r->uri),		      ".<P>\n", NULL);	    break;	case NOT_ACCEPTABLE:	    ap_rvputs(r,		      "An appropriate representation of the "		      "requested resource ",		      ap_escape_html(r->pool, r->uri),		      " could not be found on this server.<P>\n", NULL);	    /* fall through */	case MULTIPLE_CHOICES:	    {		const char *list;		if ((list = ap_table_get(r->notes, "variant-list")))		    ap_rputs(list, r);	    }	    break;	case LENGTH_REQUIRED:	    ap_rvputs(r, "A request of the requested method ", r->method,		      " requires a valid Content-length.<P>\n", NULL);	    if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {		ap_rvputs(r, error_notes, "<P>\n", NULL);	    }	    break;	case PRECONDITION_FAILED:	    ap_rvputs(r, "The precondition on the request for the URL ",		      ap_escape_html(r->pool, r->uri),		      " evaluated to false.<P>\n", NULL);	    break;	case HTTP_NOT_IMPLEMENTED:	    ap_rvputs(r, ap_escape_html(r->pool, r->method), " to ",		      ap_escape_html(r->pool, r->uri),		      " not supported.<P>\n", NULL);	    if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {		ap_rvputs(r, error_notes, "<P>\n", NULL);	    }	    break;	case BAD_GATEWAY:	    ap_rputs("The proxy server received an invalid" CRLF	             "response from an upstream server.<P>" CRLF, r);	    if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {		ap_rvputs(r, error_notes, "<P>\n", NULL);	    }	    break;	case VARIANT_ALSO_VARIES:	    ap_rvputs(r, "A variant for the requested resource\n<PRE>\n",		      ap_escape_html(r->pool, r->uri),		      "\n</PRE>\nis itself a negotiable resource. "		      "This indicates a configuration error.<P>\n", NULL);	    break;	case HTTP_REQUEST_TIME_OUT:	    ap_rputs("Server timeout waiting for the HTTP request from the client.\n", r);	    break;	case HTTP_GONE:	    ap_rvputs(r, "The requested resource<BR>",		      ap_escape_html(r->pool, r->uri),		      "<BR>\nis no longer available on this server ",		      "and there is no forwarding address.\n",		      "Please remove all references to this resource.\n",		      NULL);	    break;	case HTTP_REQUEST_ENTITY_TOO_LARGE:	    ap_rvputs(r, "The requested resource<BR>",		      ap_escape_html(r->pool, r->uri), "<BR>\n",		      "does not allow request data with ", r->method,		      " requests, or the amount of data provided in\n",		      "the request exceeds the capacity limit.\n", NULL);	    break;	case HTTP_REQUEST_URI_TOO_LARGE:	    ap_rputs("The requested URL's length exceeds the capacity\n"	             "limit for this server.<P>\n", r);	    if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {		ap_rvputs(r, error_notes, "<P>\n", NULL);	    }	    break;	case HTTP_UNSUPPORTED_MEDIA_TYPE:	    ap_rputs("The supplied request data is not in a format\n"	             "acceptable for processing by this resource.\n", r);	    break;	case HTTP_RANGE_NOT_SATISFIABLE:	    ap_rputs("None of the range-specifier values in the Range\n"	             "request-header field overlap the current extent\n"	             "of the selected resource.\n", r);	    break;	case HTTP_EXPECTATION_FAILED:	    ap_rvputs(r, "The expectation given in the Expect request-header"	              "\nfield could not be met by this server.<P>\n"	              "The client sent<PRE>\n    Expect: ",	              ap_table_get(r->headers_in, "Expect"), "\n</PRE>\n"	              "but we only allow the 100-continue expectation.\n",	              NULL);	    break;	case HTTP_UNPROCESSABLE_ENTITY:	    ap_rputs("The server understands the media type of the\n"	             "request entity, but was unable to process the\n"	             "contained instructions.\n", r);	    break;	case HTTP_LOCKED:	    ap_rputs("The requested resource is currently locked.\n"	             "The lock must be released or proper identification\n"	             "given before the method can be applied.\n", r);	    break;	case HTTP_FAILED_DEPENDENCY:	    ap_rputs("The method could not be performed on the resource\n"	             "because the requested action depended on another\n"	             "action and that other action failed.\n", r);	    break;	case HTTP_INSUFFICIENT_STORAGE:	    ap_rputs("The method could not be performed on the resource\n"	             "because the server is unable to store the\n"	             "representation needed to successfully complete the\n"	             "request.  There is insufficient free space left in\n"	             "your storage allocation.\n", r);	    break;	case HTTP_SERVICE_UNAVAILABLE:	    ap_rputs("The server is temporarily unable to service your\n"	             "request due to maintenance downtime or capacity\n"	             "problems. Please try again later.\n", r);	    break;	case HTTP_GATEWAY_TIME_OUT:	    ap_rputs("The proxy server did not receive a timely response\n"	             "from the upstream server.\n", r);	    break;	case HTTP_NOT_EXTENDED:	    ap_rputs("A mandatory extension policy in the request is not\n"	             "accepted by the server for this resource.\n", r);	    break;	default:            /* HTTP_INTERNAL_SERVER_ERROR */	    /*	     * This comparison to expose error-notes could be modified to	     * use a configuration directive and export based on that 	     * directive.  For now "*" is used to designate an error-notes	     * that is totally safe for any user to see (ie lacks paths,	     * database passwords, etc.)	     */	    if (((error_notes = ap_table_get(r->notes, "error-notes")) != NULL)		&& (h1 = ap_table_get(r->notes, "verbose-error-to")) != NULL		&& (strcmp(h1, "*") == 0)) {	        ap_rvputs(r, error_notes, "<P>\n", NULL);	    }	    else {	        ap_rvputs(r, "The server encountered an internal error or\n"	             "misconfiguration and was unable to complete\n"	             "your request.<P>\n"	             "Please contact the server administrator,\n ",	             ap_escape_html(r->pool, r->server->server_admin),	             " and inform them of the time the error occurred,\n"	             "and anything you might have done that may have\n"	             "caused the error.<P>\n"		     "More information about this error may be available\n"		     "in the server error log.<P>\n", NULL);	    }	 /*	  * It would be nice to give the user the information they need to	  * fix the problem directly since many users don't have access to	  * the error_log (think University sites) even though they can easily	  * get this error by misconfiguring an htaccess file.  However, the	  * error notes tend to include the real file pathname in this case,	  * which some people consider to be a breach of privacy.  Until we	  * can figure out a way to remove the pathname, leave this commented.	  *	  * if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {	  *     ap_rvputs(r, error_notes, "<P>\n", NULL);	  * }	  */	    break;	}        if (recursive_error) {            ap_rvputs(r, "<P>Additionally, a ",                      status_lines[ap_index_of_response(recursive_error)],                      "\nerror was encountered while trying to use an "                      "ErrorDocument to handle the request.\n", NULL);        }        ap_rputs(ap_psignature("<HR>\n", r), r);        ap_rputs("</BODY></HTML>\n", r);    }    ap_kill_timeout(r);    ap_finalize_request_protocol(r);    ap_rflush(r);}