static ib_status_t ib_error_callback(ib_tx_t *tx, int status, void *cbdata) { #if 0 /* We're being called from a connection filter here. * So on input we have to anticipate the Request * while on output we're too late to do anything very interesting. */ ap_filter_t *f = vf; mod_ib_conn_ctx *ctx = ap_get_module_config(f->c->conn_config, &ironbee_module); if (ctx == NULL) { ctx = apr_pcalloc(f->c->pool, sizeof(mod_ib_conn_ctx)); ap_set_module_config(f->c->conn_config, &ironbee_module, ctx); } if (ap_is_HTTP_VALID_RESPONSE(status)) { /* Ironbee wants us to return an HTTP error */ ctx->status = status; } else if (status == DONE) { /* Ironbee wants us to return an HTTP error */ ctx->status = status; } else { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c, IB_PRODUCT_NAME ": requested unsupported action %d", status); return IB_ENOTIMPL; } #endif return IB_ENOTIMPL; }
AP_DECLARE(apr_bucket *) ap_bucket_error_create(int error, const char *buf, apr_pool_t *p, apr_bucket_alloc_t *list) { apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); APR_BUCKET_INIT(b); b->free = apr_bucket_free; b->list = list; if (!ap_is_HTTP_VALID_RESPONSE(error)) { error = HTTP_INTERNAL_SERVER_ERROR; } return ap_bucket_error_make(b, error, buf, p); }
AP_DECLARE(int) ap_scan_script_header_err_core_ex(request_rec *r, char *buffer, int (*getsfunc) (char *, int, void *), void *getsfunc_data, int module_index) { char x[MAX_STRING_LEN]; char *w, *l; int p; int cgi_status = HTTP_UNSET; apr_table_t *merge; apr_table_t *cookie_table; int trace_log = APLOG_R_MODULE_IS_LEVEL(r, module_index, APLOG_TRACE1); int first_header = 1; if (buffer) { *buffer = '\0'; } w = buffer ? buffer : x; /* temporary place to hold headers to merge in later */ merge = apr_table_make(r->pool, 10); /* The HTTP specification says that it is legal to merge duplicate * headers into one. Some browsers that support Cookies don't like * merged headers and prefer that each Set-Cookie header is sent * separately. Lets humour those browsers by not merging. * Oh what a pain it is. */ cookie_table = apr_table_make(r->pool, 2); apr_table_do(set_cookie_doo_doo, cookie_table, r->err_headers_out, "Set-Cookie", NULL); while (1) { int rv = (*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data); if (rv == 0) { const char *msg = "Premature end of script headers"; if (first_header) msg = "End of script output before headers"; ap_log_rerror(SCRIPT_LOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r, "%s: %s", msg, apr_filepath_name_get(r->filename)); return HTTP_INTERNAL_SERVER_ERROR; } else if (rv == -1) { ap_log_rerror(SCRIPT_LOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r, "Script timed out before returning headers: %s", apr_filepath_name_get(r->filename)); return HTTP_GATEWAY_TIME_OUT; } /* Delete terminal (CR?)LF */ p = strlen(w); /* Indeed, the host's '\n': '\012' for UNIX; '\015' for MacOS; '\025' for OS/390 -- whatever the script generates. */ if (p > 0 && w[p - 1] == '\n') { if (p > 1 && w[p - 2] == CR) { w[p - 2] = '\0'; } else { w[p - 1] = '\0'; } } /* * If we've finished reading the headers, check to make sure any * HTTP/1.1 conditions are met. If so, we're done; normal processing * will handle the script's output. If not, just return the error. * The appropriate thing to do would be to send the script process a * SIGPIPE to let it know we're ignoring it, close the channel to the * script process, and *then* return the failed-to-meet-condition * error. Otherwise we'd be waiting for the script to finish * blithering before telling the client the output was no good. * However, we don't have the information to do that, so we have to * leave it to an upper layer. */ if (w[0] == '\0') { int cond_status = OK; /* PR#38070: This fails because it gets confused when a * CGI Status header overrides ap_meets_conditions. * * We can fix that by dropping ap_meets_conditions when * Status has been set. Since this is the only place * cgi_status gets used, let's test it explicitly. * * The alternative would be to ignore CGI Status when * ap_meets_conditions returns anything interesting. * That would be safer wrt HTTP, but would break CGI. */ if ((cgi_status == HTTP_UNSET) && (r->method_number == M_GET)) { cond_status = ap_meets_conditions(r); } apr_table_overlap(r->err_headers_out, merge, APR_OVERLAP_TABLES_MERGE); if (!apr_is_empty_table(cookie_table)) { /* the cookies have already been copied to the cookie_table */ apr_table_unset(r->err_headers_out, "Set-Cookie"); r->err_headers_out = apr_table_overlay(r->pool, r->err_headers_out, cookie_table); } return cond_status; } if (trace_log) { if (first_header) ap_log_rerror(SCRIPT_LOG_MARK, APLOG_TRACE4, 0, r, "Headers from script '%s':", apr_filepath_name_get(r->filename)); ap_log_rerror(SCRIPT_LOG_MARK, APLOG_TRACE4, 0, r, " %s", w); } /* if we see a bogus header don't ignore it. Shout and scream */ #if APR_CHARSET_EBCDIC /* Chances are that we received an ASCII header text instead of * the expected EBCDIC header lines. Try to auto-detect: */ if (!(l = strchr(w, ':'))) { int maybeASCII = 0, maybeEBCDIC = 0; unsigned char *cp, native; apr_size_t inbytes_left, outbytes_left; for (cp = w; *cp != '\0'; ++cp) { native = apr_xlate_conv_byte(ap_hdrs_from_ascii, *cp); if (apr_isprint(*cp) && !apr_isprint(native)) ++maybeEBCDIC; if (!apr_isprint(*cp) && apr_isprint(native)) ++maybeASCII; } if (maybeASCII > maybeEBCDIC) { ap_log_error(SCRIPT_LOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02660) "CGI Interface Error: " "Script headers apparently ASCII: (CGI = %s)", r->filename); inbytes_left = outbytes_left = cp - w; apr_xlate_conv_buffer(ap_hdrs_from_ascii, w, &inbytes_left, w, &outbytes_left); } } #endif /*APR_CHARSET_EBCDIC*/ if (!(l = strchr(w, ':'))) { if (!buffer) { /* Soak up all the script output - may save an outright kill */ while ((*getsfunc)(w, MAX_STRING_LEN - 1, getsfunc_data) > 0) { continue; } } ap_log_rerror(SCRIPT_LOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r, "malformed header from script '%s': Bad header: %.30s", apr_filepath_name_get(r->filename), w); return HTTP_INTERNAL_SERVER_ERROR; } *l++ = '\0'; while (apr_isspace(*l)) { ++l; } if (!strcasecmp(w, "Content-type")) { char *tmp; /* Nuke trailing whitespace */ char *endp = l + strlen(l) - 1; while (endp > l && apr_isspace(*endp)) { *endp-- = '\0'; } tmp = apr_pstrdup(r->pool, l); ap_content_type_tolower(tmp); ap_set_content_type(r, tmp); } /* * If the script returned a specific status, that's what * we'll use - otherwise we assume 200 OK. */ else if (!strcasecmp(w, "Status")) { r->status = cgi_status = atoi(l); if (!ap_is_HTTP_VALID_RESPONSE(cgi_status)) ap_log_rerror(SCRIPT_LOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r, "Invalid status line from script '%s': %.30s", apr_filepath_name_get(r->filename), l); else if (APLOGrtrace1(r)) ap_log_rerror(SCRIPT_LOG_MARK, APLOG_TRACE1, 0, r, "Status line from script '%s': %.30s", apr_filepath_name_get(r->filename), l); r->status_line = apr_pstrdup(r->pool, l); } else if (!strcasecmp(w, "Location")) { apr_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Content-Length")) { apr_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Content-Range")) { apr_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Transfer-Encoding")) { apr_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "ETag")) { apr_table_set(r->headers_out, w, l); } /* * If the script gave us a Last-Modified header, we can't just * pass it on blindly because of restrictions on future values. */ else if (!strcasecmp(w, "Last-Modified")) { ap_update_mtime(r, apr_date_parse_http(l)); ap_set_last_modified(r); } else if (!strcasecmp(w, "Set-Cookie")) { apr_table_add(cookie_table, w, l); } else { apr_table_add(merge, w, l); } first_header = 0; } /* never reached - we leave this function within the while loop above */ return OK; }