static dav_error * dav_rawx_set_headers(request_rec *r, const dav_resource *resource) { if (!resource->exists) return NULL; DAV_DEBUG_REQ(r, 0, "%s(%s)", __FUNCTION__, resource_get_pathname(resource)); /* make sure the proper mtime is in the request record */ ap_update_mtime(r, resource->info->finfo.mtime); ap_set_last_modified(r); ap_set_etag(r); /* we accept byte-ranges */ apr_table_setn(r->headers_out, apr_pstrdup(r->pool, "Accept-Ranges"), apr_pstrdup(r->pool, "bytes")); /* set up the Content-Length header */ ap_set_content_length(r, resource->info->finfo.size); request_fill_headers(r, &(resource->info->chunk)); /* compute metadata_compress if compressed content */ if (resource->info->compression) { char *buf = apr_pstrcat(r->pool, "compression=on;compression_algorithm=", resource->info->compress_algo, ";compression_blocksize=", apr_psprintf(r->pool, "%d", resource->info->cp_chunk.block_size), ";", NULL); apr_table_setn(r->headers_out, apr_pstrdup(r->pool, "metadatacompress"), buf); } return NULL; }
static int write_http_response(mapcache_context_apache_request *ctx, mapcache_http_response *response) { request_rec *r = ctx->request; int rc; if(response->mtime) { ap_update_mtime(r, response->mtime); if((rc = ap_meets_conditions(r)) != OK) { return rc; } char *timestr = apr_palloc(r->pool, APR_RFC822_DATE_LEN); apr_rfc822_date(timestr, response->mtime); apr_table_setn(r->headers_out, "Last-Modified", timestr); } if(response->headers && !apr_is_empty_table(response->headers)) { const apr_array_header_t *elts = apr_table_elts(response->headers); int i; for(i=0;i<elts->nelts;i++) { apr_table_entry_t entry = APR_ARRAY_IDX(elts,i,apr_table_entry_t); if(!strcasecmp(entry.key,"Content-Type")) { ap_set_content_type(r,entry.val); } else { apr_table_set(r->headers_out, entry.key, entry.val); } } } if(response->data) { ap_set_content_length(r,response->data->size); ap_rwrite((void*)response->data->buf, response->data->size, r); } r->status = response->code; return OK; }
static int req_update_mtime(lua_State* L) { request_rec *r = CHECK_REQUEST_OBJECT(1); int mtime = luaL_checkint(L, 2); ap_update_mtime(r, apr_time_from_sec(mtime)); return 0; }
static int req_set_last_modified(lua_State* L) { request_rec *r = CHECK_REQUEST_OBJECT(1); lua_Integer mtime = luaL_optinteger(L, 2, 0); if (mtime) { ap_update_mtime(r, apr_time_from_sec(mtime)); } ap_set_last_modified(r); return 0; }
static void accept_headers(cache_handle_t *h, request_rec *r) { apr_table_t *cookie_table; const char *v; v = apr_table_get(h->resp_hdrs, "Content-Type"); if (v) { ap_set_content_type(r, v); apr_table_unset(h->resp_hdrs, "Content-Type"); } /* If the cache gave us a Last-Modified header, we can't just * pass it on blindly because of restrictions on future values. */ v = apr_table_get(h->resp_hdrs, "Last-Modified"); if (v) { ap_update_mtime(r, apr_date_parse_http(v)); ap_set_last_modified(r); apr_table_unset(h->resp_hdrs, "Last-Modified"); } /* 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); apr_table_do(set_cookie_doo_doo, cookie_table, h->resp_hdrs, "Set-Cookie", NULL); apr_table_unset(r->err_headers_out, "Set-Cookie"); apr_table_unset(h->resp_hdrs, "Set-Cookie"); apr_table_overlap(r->headers_out, h->resp_hdrs, APR_OVERLAP_TABLES_SET); apr_table_overlap(r->err_headers_out, h->resp_err_hdrs, APR_OVERLAP_TABLES_SET); if (!apr_is_empty_table(cookie_table)) { r->err_headers_out = apr_table_overlay(r->pool, r->err_headers_out, cookie_table); } }
/** * Take two sets of headers, sandwich them together, and apply the result to * r->headers_out. * * To complicate this, a header may be duplicated in either table. Should a * header exist in the top table, all matching headers will be removed from * the bottom table before the headers are combined. The Warning headers are * handled specially. Warnings are added rather than being replaced, while * in the case of revalidation 1xx Warnings are stripped. * * The Content-Type and Last-Modified headers are then re-parsed and inserted * into the request. */ void cache_accept_headers(cache_handle_t *h, request_rec *r, apr_table_t *top, apr_table_t *bottom, int revalidation) { const char *v; if (revalidation) { r->headers_out = apr_table_make(r->pool, 10); apr_table_do(filter_header_do, r->headers_out, bottom, NULL); } else if (r->headers_out != bottom) { r->headers_out = apr_table_copy(r->pool, bottom); } apr_table_do(remove_header_do, r->headers_out, top, NULL); apr_table_do(add_header_do, r->headers_out, top, NULL); v = apr_table_get(r->headers_out, "Content-Type"); if (v) { ap_set_content_type(r, v); /* * Also unset possible Content-Type headers in r->headers_out and * r->err_headers_out as they may be different to what we have received * from the cache. * Actually they are not needed as r->content_type set by * ap_set_content_type above will be used in the store_headers functions * of the storage providers as a fallback and the HTTP_HEADER filter * does overwrite the Content-Type header with r->content_type anyway. */ apr_table_unset(r->headers_out, "Content-Type"); apr_table_unset(r->err_headers_out, "Content-Type"); } /* If the cache gave us a Last-Modified header, we can't just * pass it on blindly because of restrictions on future values. */ v = apr_table_get(r->headers_out, "Last-Modified"); if (v) { ap_update_mtime(r, apr_date_parse_http(v)); ap_set_last_modified(r); } }
/* Apache Handle Process and Output */ static int req_meets(lua_State*L ) { request_rec *r = CHECK_REQUEST_OBJECT(1); apr_time_t mtime = luaL_checkint(L, 2); int len = luaL_checkint(L, 3); int status; if (mtime) ap_update_mtime(r, mtime * APR_USEC_PER_SEC); ap_set_last_modified(r); ap_set_etag(r); ap_set_accept_ranges(r); apr_table_setn(r->headers_out, "Content-Length", apr_itoa(r->pool, len)); status = ap_meets_conditions(r); if (status == 0) { lua_pushnil(L); } else lua_pushinteger(L, status); return 1; }
static int aclr_handler(request_rec *r) { int rc; const char *idhead; char *real_uri; const char *docroot; size_t docroot_len; ap_filter_t *f, *nextf; char iredirect[MAX_STRING_LEN]; aclr_dir_config *cfg = (aclr_dir_config *)ap_get_module_config (r->per_dir_config, &aclr_module); if (cfg->state != ACLR_ENABLED) { return DECLINED; } if (!ap_is_initial_req(r)) { return DECLINED; } idhead = apr_table_get(r->headers_in, xa_int_name); if (idhead == NULL) { return DECLINED; } #ifdef DEBUG const char *server_name = ap_get_server_name(r); #endif docroot = ap_document_root(r); docroot_len = strlen(docroot); /* obtain real URI from filename - for rewrited URIs */ if (strncmp(r->filename, docroot, docroot_len) != 0) { if (cfg->redirect_outside_of_docroot != ACLR_ENABLED) { aclr_debug(2, r->server, "file \"%s\" is outside of " "DocumentRoot \"%s\": %s%s", r->filename, docroot, server_name, r->uri); return DECLINED; } real_uri = r->uri; } else { real_uri = r->filename; real_uri += docroot_len; } snprintf(iredirect, sizeof(iredirect), "%s%s", idhead, real_uri); aclr_debug(3, r->server, "trying to process request: %s%s -> %s", server_name, r->uri, iredirect); aclr_debug(3, r->server, "r->filename: %s", r->filename); aclr_debug(3, r->server, "r->uri: %s", r->uri); aclr_debug(3, r->server, "docroot: %s", docroot); aclr_debug(3, r->server, "real_uri: %s", real_uri); if ((rc = ap_discard_request_body(r)) != OK) { return rc; } apr_table_set(r->headers_out, xa_ver_name, ACLR_VERSION); if ((r->method_number != M_GET) || (r->header_only)) { aclr_debug(2, r->server, "request method is not GET: %s%s", server_name, r->uri); return DECLINED; } if (r->finfo.filetype != APR_REG) { aclr_debug(2, r->server, "request file not found " "or is not regular file: %s%s", server_name, r->uri); return DECLINED; } if (cfg->fsize != UNSET && r->finfo.size < cfg->fsize) { aclr_debug(2, r->server, "file size %lu < minsize %lu: %s%s", r->finfo.size, cfg->fsize, server_name, r->uri); return DECLINED; } f = r->output_filters; do { nextf = f->next; aclr_debug(3, r->server, "output filter: %s", f->frec->name); if (strcmp(f->frec->name, "includes") == 0) { aclr_debug(2, r->server, "request uses INCLUDES filter: %s%s", server_name, r->uri); return DECLINED; } f = nextf; } while (f && f != r->proto_output_filters); apr_table_set(r->headers_out, xa_redir_name, iredirect); r->header_only = 0; ap_update_mtime(r, r->finfo.mtime); aclr_debug(1, r->server, "request %s%s redirected to %s", server_name, r->uri, iredirect); return OK; }
/** * Sets the HTTP headers, like the size of the content, the modification date... * @param r The request * @param resource The resource generated previously * @return NULL on success */ static dav_error *dav_ns_set_headers(request_rec *r, const dav_resource *resource) { dav_resource_private *info; dav_error *err; const char *etag; char buffer[1024]; /* Null resource */ if(!resource->exists) return NULL; info = resource->info; /* NS never serve files! Only metadata. */ if (!resource->collection && !resource->info->metalink) { if ((err = dav_ns_get_location(info, r->pool))) return err; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Resource %s located at %s", info->sfn, info->redirect); apr_table_setn(r->headers_out, "Location", info->redirect); #ifdef WITH_METALINK snprintf(buffer, sizeof(buffer), "<%s://%s%s?metalink>; rel=describedby; type=\"application/metalink+xml\"", info->d_conf->redir_scheme, info->request->hostname, info->request->uri); apr_table_set(r->err_headers_out, "Link", buffer); #endif return dav_new_error(r->pool, HTTP_MOVED_TEMPORARILY, 0, info->redirect); } /* Need to redirect? (Missing trailing /) */ if (info->redirect) { apr_table_setn(r->headers_out, "Location", info->redirect); return dav_new_error(r->pool, HTTP_MOVED_PERMANENTLY, 0, info->redirect); } /* Content-type */ if (resource->info->metalink) { ap_set_content_type(r, "application/metalink+xml"); snprintf(buffer, sizeof(buffer), "attachment; filename=\"%s.metalink\"", info->stat.name); apr_table_set(r->headers_out, "Content-Disposition", buffer); } else if (resource->collection) { ap_set_content_type(r, "text/html"); } /* Nice thing is, Apache takes care of implementing this */ apr_table_setn(r->headers_out, "Accept-Ranges", "bytes"); /* ETag */ etag = resource->hooks->getetag(resource); apr_table_setn(r->headers_out, "ETag", etag); /* NS saves the time in seconds since epoch, while Apache expects microseconds */ ap_update_mtime(r, info->stat.stat.st_mtime * 1000000); ap_set_last_modified(r); return NULL; }
AP_DECLARE(int) ap_scan_script_header_err_core(request_rec *r, char *buffer, int (*getsfunc) (char *, int, void *), void *getsfunc_data) { char x[MAX_STRING_LEN]; char *w, *l; int p; int cgi_status = HTTP_UNSET; apr_table_t *merge; apr_table_t *cookie_table; 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) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r, "Premature end of script headers: %s", apr_filepath_name_get(r->filename)); return HTTP_INTERNAL_SERVER_ERROR; } else if (rv == -1) { ap_log_rerror(APLOG_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 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(APLOG_MARK, APLOG_ERR, 0, r->server, "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, ':'))) { char malformed[(sizeof MALFORMED_MESSAGE) + 1 + MALFORMED_HEADER_LENGTH_TO_SHOW]; strcpy(malformed, MALFORMED_MESSAGE); strncat(malformed, w, MALFORMED_HEADER_LENGTH_TO_SHOW); if (!buffer) { /* Soak up all the script output - may save an outright kill */ while ((*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data)) { continue; } } ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r, "%s: %s", malformed, apr_filepath_name_get(r->filename)); return HTTP_INTERNAL_SERVER_ERROR; } *l++ = '\0'; while (*l && 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); 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); } /* * 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); } } return OK; }
static apr_status_t ap_xsendfile_output_filter(ap_filter_t *f, apr_bucket_brigade *in) { request_rec *r = f->r, *sr = NULL; xsendfile_conf_t *dconf = (xsendfile_conf_t *)ap_get_module_config(r->per_dir_config, &xsendfile_module), *sconf = (xsendfile_conf_t *)ap_get_module_config(r->server->module_config, &xsendfile_module), *conf = xsendfile_config_merge(r->pool, sconf, dconf); core_dir_config *coreconf = (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module); apr_status_t rv; apr_bucket *e; apr_file_t *fd = NULL; apr_finfo_t finfo; const char *file = NULL; char *translated = NULL; int errcode; #ifdef _DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: output_filter for %s", r->the_request); #endif /* should we proceed with this request? * sub-requests suck * furthermore default-handled requests suck, as they actually shouldn't be able to set headers */ if ( r->status != HTTP_OK || r->main || (r->handler && strcmp(r->handler, "default-handler") == 0) /* those table-keys are lower-case, right? */ ) { #ifdef _DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: not met [%d]", r->status); #endif ap_remove_output_filter(f); return ap_pass_brigade(f->next, in); } /* alright, look for x-sendfile */ file = apr_table_get(r->headers_out, AP_XSENDFILE_HEADER); apr_table_unset(r->headers_out, AP_XSENDFILE_HEADER); /* cgi/fastcgi will put the stuff into err_headers_out */ if (!file || !*file) { file = apr_table_get(r->err_headers_out, AP_XSENDFILE_HEADER); apr_table_unset(r->err_headers_out, AP_XSENDFILE_HEADER); } /* nothing there :p */ if (!file || !*file) { #ifdef _DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: nothing found"); #endif ap_remove_output_filter(f); return ap_pass_brigade(f->next, in); } /* drop *everything* might be pretty expensive to generate content first that goes straight to the bitbucket, but actually the scripts that might set this flag won't output too much anyway */ while (!APR_BRIGADE_EMPTY(in)) { e = APR_BRIGADE_FIRST(in); apr_bucket_delete(e); } r->eos_sent = 0; rv = ap_xsendfile_get_filepath(r, conf, file, &translated); if (rv != OK) { ap_log_rerror( APLOG_MARK, APLOG_ERR, rv, r, "xsendfile: unable to find file: %s", file ); ap_remove_output_filter(f); ap_die(HTTP_NOT_FOUND, r); return HTTP_NOT_FOUND; } #ifdef _DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: found %s", translated); #endif /* ry open the file */ if ((rv = apr_file_open( &fd, translated, APR_READ | APR_BINARY #if APR_HAS_SENDFILE | (coreconf->enable_sendfile == ENABLE_SENDFILE_ON ? APR_SENDFILE_ENABLED : 0) #endif , 0, r->pool )) != APR_SUCCESS) { ap_log_rerror( APLOG_MARK, APLOG_ERR, rv, r, "xsendfile: cannot open file: %s", translated ); ap_remove_output_filter(f); ap_die(HTTP_NOT_FOUND, r); return HTTP_NOT_FOUND; } #if APR_HAS_SENDFILE && defined(_DEBUG) if (coreconf->enable_sendfile != ENABLE_SENDFILE_ON) { ap_log_error( APLOG_MARK, APLOG_WARNING, 0, r->server, "xsendfile: sendfile configured, but not active %d", coreconf->enable_sendfile ); } #endif /* stat (for etag/cache/content-length stuff) */ if ((rv = apr_file_info_get(&finfo, APR_FINFO_NORM, fd)) != APR_SUCCESS) { ap_log_rerror( APLOG_MARK, APLOG_ERR, rv, r, "xsendfile: unable to stat file: %s", translated ); apr_file_close(fd); ap_remove_output_filter(f); ap_die(HTTP_FORBIDDEN, r); return HTTP_FORBIDDEN; } /* no inclusion of directories! we're serving files! */ if (finfo.filetype != APR_REG) { ap_log_rerror( APLOG_MARK, APLOG_ERR, APR_EBADPATH, r, "xsendfile: not a file %s", translated ); apr_file_close(fd); ap_remove_output_filter(f); ap_die(HTTP_NOT_FOUND, r); return HTTP_NOT_FOUND; } /* need to cheat here a bit as etag generator will use those ;) and we want local_copy and cache */ r->finfo.inode = finfo.inode; r->finfo.size = finfo.size; /* caching? why not :p */ r->no_cache = r->no_local_copy = 0; /* some script (f?cgi) place stuff in err_headers_out */ if ( conf->ignoreLM == XSENDFILE_ENABLED || ( !apr_table_get(r->headers_out, "last-modified") && !apr_table_get(r->headers_out, "last-modified") ) ) { apr_table_unset(r->err_headers_out, "last-modified"); ap_update_mtime(r, finfo.mtime); ap_set_last_modified(r); } if ( conf->ignoreETag == XSENDFILE_ENABLED || ( !apr_table_get(r->headers_out, "etag") && !apr_table_get(r->err_headers_out, "etag") ) ) { apr_table_unset(r->err_headers_out, "etag"); ap_set_etag(r); } apr_table_unset(r->err_headers_out, "content-length"); ap_set_content_length(r, finfo.size); /* as we dropped all the content this field is not valid anymore! */ apr_table_unset(r->headers_out, "Content-Encoding"); apr_table_unset(r->err_headers_out, "Content-Encoding"); /* cache or something? */ if ((errcode = ap_meets_conditions(r)) != OK) { #ifdef _DEBUG ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: met condition %d for %s", errcode, file ); #endif apr_file_close(fd); r->status = errcode; } else { /* For platforms where the size of the file may be larger than * that which can be stored in a single bucket (where the * length field is an apr_size_t), split it into several * buckets: */ if (sizeof(apr_off_t) > sizeof(apr_size_t) && finfo.size > AP_MAX_SENDFILE) { apr_off_t fsize = finfo.size; e = apr_bucket_file_create(fd, 0, AP_MAX_SENDFILE, r->pool, in->bucket_alloc); while (fsize > AP_MAX_SENDFILE) { apr_bucket *ce; apr_bucket_copy(e, &ce); APR_BRIGADE_INSERT_TAIL(in, ce); e->start += AP_MAX_SENDFILE; fsize -= AP_MAX_SENDFILE; } e->length = (apr_size_t)fsize; /* Resize just the last bucket */ } else { e = apr_bucket_file_create(fd, 0, (apr_size_t)finfo.size, r->pool, in->bucket_alloc); } #if APR_HAS_MMAP if (coreconf->enable_mmap == ENABLE_MMAP_ON) { apr_bucket_file_enable_mmap(e, 0); } #if defined(_DEBUG) else { ap_log_error( APLOG_MARK, APLOG_WARNING, 0, r->server, "xsendfile: mmap configured, but not active %d", coreconf->enable_mmap ); } #endif /* _DEBUG */ #endif /* APR_HAS_MMAP */ APR_BRIGADE_INSERT_TAIL(in, e); } e = apr_bucket_eos_create(in->bucket_alloc); APR_BRIGADE_INSERT_TAIL(in, e); /* remove ourselves from the filter chain */ ap_remove_output_filter(f); #ifdef _DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: sending %d bytes", (int)finfo.size); #endif /* send the data up the stack */ return ap_pass_brigade(f->next, in); }
apr_status_t jxr_process_response_headers(request_rec *r, char *buf) { apr_status_t rv = APR_SUCCESS; apr_size_t pos; apr_size_t len; char type; int nHeaders; int i; char name[MAX_STRING_LEN]; char value[MAX_STRING_LEN]; apr_size_t nlen, vlen; table *merge; table *cookie_table; char *w, *l; type = jxr_msg_get_type(buf); len = jxr_msg_get_length(buf, &pos); if (type != BLOCKTYPE_HTTP_HEADER) { // Invalid data compat_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, "mod_jaxer: invalid data type (%c) received, while expecting a header (%d)", type, BLOCKTYPE_HTTP_HEADER); return HTTP_INTERNAL_SERVER_ERROR; } /* temporary place to hold headers to merge in later */ merge = ap_make_table(r->pool, 10); cookie_table = ap_make_table(r->pool, 2); ap_table_do(set_cookie_doo_doo, cookie_table, r->err_headers_out, "Set-Cookie", NULL); nHeaders = jxr_msg_get_int16(buf, &pos); for (i=0; i<nHeaders; i++) { // Process one header -- name -- val nlen = jxr_msg_get_string(buf, &pos, name); vlen = jxr_msg_get_string(buf, &pos, value); w = name; l = value; 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 = ap_pstrdup(r->pool, l); ap_content_type_tolower(tmp); ap_set_content_type(r, tmp); } else if (!strcasecmp(w, "Status")) { /* * If the server returned a specific status, that's what * we'll use - otherwise we assume 200 OK. */ r->status = atoi(l); r->status_line = ap_pstrdup(r->pool, l); } else if (!strcasecmp(w, "Location")) { ap_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Content-Length")) { ap_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Content-Range")) { ap_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Transfer-Encoding")) { ap_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Last-Modified")) { /* * If the script gave us a Last-Modified header, we can't just * pass it on blindly because of restrictions on future values. */ ap_update_mtime(r, apr_date_parse_http(l)); ap_set_last_modified(r); } else if (!strcasecmp(w, "Set-Cookie")) { ap_table_add(cookie_table, w, l); } else { ap_table_add(merge, w, l); } } // now merge stuff ap_overlap_tables(r->err_headers_out, merge, AP_OVERLAP_TABLES_MERGE); if (!ap_is_empty_table(cookie_table)) { /* the cookies have already been copied to the cookie_table */ ap_table_unset(r->err_headers_out, "Set-Cookie"); r->err_headers_out = ap_overlay_tables(r->pool, r->err_headers_out, cookie_table); } return rv; }
static int file_cache_handler(request_rec *r) { a_file *match; int errstatus; int rc = OK; /* Bail out if r->handler isn't the default value, and doesn't look like a Content-Type * XXX: Even though we made the user explicitly list each path to cache? */ if (ap_strcmp_match(r->handler, "*/*") && !AP_IS_DEFAULT_HANDLER_NAME(r->handler)) { return DECLINED; } /* we don't handle anything but GET */ if (r->method_number != M_GET) return DECLINED; /* did xlat phase find the file? */ match = ap_get_module_config(r->request_config, &file_cache_module); if (match == NULL) { return DECLINED; } /* note that we would handle GET on this resource */ r->allowed |= (AP_METHOD_BIT << M_GET); /* This handler has no use for a request body (yet), but we still * need to read and discard it if the client sent one. */ if ((errstatus = ap_discard_request_body(r)) != OK) return errstatus; ap_update_mtime(r, match->finfo.mtime); /* ap_set_last_modified() always converts the file mtime to a string * which is slow. Accelerate the common case. * ap_set_last_modified(r); */ { apr_time_t mod_time; char *datestr; mod_time = ap_rationalize_mtime(r, r->mtime); if (mod_time == match->finfo.mtime) datestr = match->mtimestr; else { datestr = apr_palloc(r->pool, APR_RFC822_DATE_LEN); apr_rfc822_date(datestr, mod_time); } apr_table_setn(r->headers_out, "Last-Modified", datestr); } /* ap_set_content_length() always converts the same number and never * returns an error. Accelerate it. */ r->clength = match->finfo.size; apr_table_setn(r->headers_out, "Content-Length", match->sizestr); ap_set_etag(r); if ((errstatus = ap_meets_conditions(r)) != OK) { return errstatus; } /* Call appropriate handler */ if (!r->header_only) { if (match->is_mmapped == TRUE) rc = mmap_handler(r, match); else rc = sendfile_handler(r, match); } return rc; }
/* The content handler */ static int rcache_handler(request_rec *r) { rcache_info *info; info = ap_get_module_config(r->server->module_config, &rcache_module); info->data = ""; info->r = r; info->length = 0; info->type = ""; apr_status_t rv; const char *retrieve_url; if (strcmp(r->handler, "rcache")) { rv = DECLINED; goto finish; } // redis context and connection #ifdef CONN_PERSISTENT redisContext *c = info->c; redisReply *reply = info->reply; if (!c) { struct timeval timeout = { 1, 500000 }; // 1.5 seconds c = redisConnectWithTimeout(info->hostname, info->port, timeout); info->c = c; // ping pong test if ( !(c == NULL || c->err) ) { reply = redisCommand(c,"PING"); #ifdef DEBUG ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "PING: %s", reply->str); #endif } } #else redisContext *c; redisReply *reply; struct timeval timeout = { 1, 500000 }; // 1.5 seconds c = redisConnectWithTimeout(info->hostname, info->port, timeout); #endif // when redis connection error if (c == NULL || c->err) { if (c) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "Connection error: %s", c->errstr); } else { ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "Connection error: can't allocate redis context" ); } rv = HTTP_INTERNAL_SERVER_ERROR; goto finish; } #ifdef FLAG_WAIT int wait = 0; #endif if ( (retrieve_url = apr_table_get(r->subprocess_env, info->env_retrieve_url)) ) { #ifdef DEBUG ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "%s", r->path_info); ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "%s", retrieve_url); #endif #ifdef FLAG_WAIT // WAIT flag check. reply = redisCommand(c, "GET %s%s", info->prefix_wait, r->path_info); if( reply->type != REDIS_REPLY_NIL ) { // cache hot-replace check. if ( reply->type == REDIS_REPLY_STRING && 0 == strcmp(reply->str,"HOT") ){ redisCommand(c, "DEL %s%s", info->prefix_wait, r->path_info); #ifdef DEBUG ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "hot cache replace: %s", r->path_info ); #endif goto gencache; } // wait cache create. wait = 1; int loop = 10; while(loop){ reply = redisCommand(c, "GET %s%s", info->prefix_wait, r->path_info); #ifdef DEBUG ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "wait loop: remain %d sec", loop); #endif if( reply->type == REDIS_REPLY_NIL ) { goto read; } sleep(1); loop--; } // when timeup. delete flag. redisCommand(c, "DEL %s%s", info->prefix_wait, r->path_info); goto gencache; } #endif read: // read from redis. reply = redisCommand(c, "HMGET %s%s CONTENT TYPE LENGTH MTIME", info->prefix, r->path_info); if( reply->type == REDIS_REPLY_ARRAY ) { if ( reply->element[0]->len == 0 ) goto gencache; const char* tmp = apr_pstrdup(r->pool, reply->element[1]->str); ap_set_content_type(r, tmp); ap_set_content_length(r, atoi(reply->element[2]->str) ); apr_time_t time = atol(reply->element[3]->str); ap_update_mtime(r, time); ap_set_last_modified(r); ap_set_etag(r); apr_status_t rc = ap_meets_conditions(r); if (rc != OK) { rv = rc; goto finish; } if (!r->header_only) ap_rputs(reply->element[0]->str, r); rv = OK; goto finish; } }else{ rv = DECLINED; goto finish; } gencache: #ifdef FLAG_WAIT if (wait == 0) redisCommand(c, "SET %s%s 1", info->prefix_wait, r->path_info); #endif rv = rcache_curl(retrieve_url, info); // set content to redis if (rv == HTTP_OK) { if (strcmp(info->type,"")) info->type = "text/html"; if (info->length == 0) info->length = strlen(info->data); redisCommand(c,"HMSET %s%s CONTENT %s TYPE %s LENGTH %d MTIME %ld", info->prefix, r->path_info, info->data, info->type, info->length, info->mtime); ap_set_content_type(r, info->type); ap_set_content_length(r, info->length); ap_update_mtime(r, info->mtime); ap_set_last_modified(r); ap_set_etag(r); if (!r->header_only) ap_rputs(info->data, r); } #ifdef FLAG_WAIT redisCommand(c, "DEL %s%s", info->prefix_wait, r->path_info); #endif finish: #ifndef CONN_PERSISTENT freeReplyObject(reply); redisFree(c); #endif return rv; }
static int drive_flvx(request_rec *r) { apr_finfo_t fi; apr_bucket_brigade *bb; apr_off_t offset = 0; apr_off_t length = 0; apr_file_t *fp = NULL; apr_status_t rv = APR_SUCCESS; rv = apr_stat(&fi, r->filename, APR_FINFO_SIZE, r->pool); if (rv) { /* Let the core handle it. */ return DECLINED; } /* Open the file */ rv = apr_file_open(&fp, r->filename, APR_READ, APR_OS_DEFAULT, r->pool); if (rv) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "file permissions deny server access: %s", r->filename); return HTTP_FORBIDDEN; } offset = get_start(r); if (offset != 0 && offset < fi.size) { length = fi.size - offset; } else { length = fi.size; /* Offset should be reset if invalid mod by Artur Bodera */ offset = 0; } bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); if (offset != 0) { length += FLVX_HEADER_LEN; rv = apr_brigade_write(bb, NULL, NULL, FLVX_HEADER, FLVX_HEADER_LEN); if (rv) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "unable to write flv header in brigade"); return HTTP_INTERNAL_SERVER_ERROR; } } apr_brigade_insert_file(bb, fp, offset, length, r->pool); ap_set_content_type(r, "video/x-flv"); ap_set_content_length(r, length); /* Add last-modified headers mod by Artur Bodera */ ap_update_mtime(r, r->finfo.mtime); ap_set_last_modified(r); return ap_pass_brigade(r->output_filters, bb); }
/** * SOAP content handler. * * @return the value that instructs the caller concerning what happened and what to do next. * OK ("we did our thing") * DECLINED ("this isn't something with which we want to get involved") * HTTP_mumble ("an error status should be reported") */ static int gsoap_handler(request_rec * r) { static const int nResponseBufferLen = IOBUF_CHUNK_SIZE; const char *pszError = NULL; struct soap *psoap = NULL; struct apache_soap_interface *pIntf = NULL; int nRet = 0; char *pszResponse = NULL; gsoapConfiguration *pConfig = getConfiguration(r); gsoapRequestConfiguration *pRqConf = NULL; /* * only handle soap requests */ if (!strstr(r->handler, "soap")) return DECLINED; /* * only handle POST requests */ if (r->method_number != M_POST && r->method_number != M_GET) return DECLINED; pszResponse = apr_pcalloc(r->pool, nResponseBufferLen); assert(NULL != pConfig); psoap = (struct soap *)apr_pcalloc(r->pool, sizeof(struct soap)); pRqConf = apr_pcalloc(r->pool, sizeof(gsoapRequestConfiguration)); pszError = SoapSharedLibraries_loadAllLibraries(pConfig->m_pLibraries, r->pool, r); pIntf = pConfig->m_pLibraries->m_pIntf; ap_update_mtime(r, r->request_time); ap_set_last_modified(r); if (NULL != pszError) { static Bool bFirstTime = TRUE; if (bFirstTime) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "mod_gsoap: %s", pszError); bFirstTime = FALSE; } } /* * as a next step, we prepare a buffer that sends the request as first line to gsoap. * Then the remaining data. * We start returning bytes on frecv from this buffer, until it is empty. * then it is not necessary to fiddle around with gsoap's request line parsing. */ if (NULL == pszError) { pRqConf->r = r; pRqConf->headers_sent = FALSE; pRqConf->headers_received = FALSE; pRqConf->m_pszAllHeaders = NULL; pRqConf->m_nHeaderLength = strlen(r->the_request) + 2; pRqConf->m_pszCurrentHeaderReadingPosition = NULL; pRqConf->m_nOutBufCount = 0; pRqConf->m_nOutBufLength = nResponseBufferLen; pRqConf->m_pOutBuf = apr_pcalloc(r->pool, nResponseBufferLen); pRqConf->http_parse = NULL; pRqConf->m_pszAllHeaders = apr_pcalloc(r->pool, pRqConf->m_nHeaderLength + 1); pRqConf->m_pszCurrentHeaderReadingPosition = pRqConf->m_pszAllHeaders; strcpy(pRqConf->m_pszAllHeaders, r->the_request); strcat(pRqConf->m_pszAllHeaders, "\r\n"); pRqConf->pIntf = pIntf; } /* * We're about to start sending content, so we need to force the HTTP * headers to be sent at this point. Otherwise, no headers will be sent * at all. We can set any we like first, of course. **NOTE** Here's * where you set the "Content-type" header, and you do so by putting it in * r->content_type, *not* r->headers_out("Content-type"). If you don't * set it, it will be filled in with the server's default type (typically * "text/plain"). You *must* also ensure that r->content_type is lower * case. * */ /* * If we're only supposed to send header information (HEAD request), we're * already there. */ if (r->header_only) { return OK; } if (NULL != pszError) { SendErrorMessage(r, pszError); return OK; } nRet = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK); if (OK != nRet) { SendErrorMessage(r, "Failed to start receiving POST buffer"); return OK; } nRet = ap_should_client_block(r); /* we check whether this request is HTTP GET or not and handle the GET request */ if (r->method_number == M_GET) { HTTPGet_SendWSDL(r, pConfig->m_pLibraries->m_pSOAPLibrary->m_pszPath); return OK; } if (0 == nRet) { SendErrorMessage(r, "No body received"); return OK; } if (NULL != pszError) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "mod_gsoap: %s", pszError); SendErrorMessage(r, pszError); return OK; } if (NULL != pIntf->fsoap_init) { (*pIntf->fsoap_init) (psoap, r); psoap->namespaces = pIntf->namespaces; set_callbacks(r, pRqConf, psoap); if (NULL != pIntf->fsoap_serve) { nRet = (*pIntf->fsoap_serve) (psoap, r); } else { SendErrorMessage(r, "no soap_serve entry point"); return OK; } if (NULL != pIntf->fsoap_destroy) { pIntf->fsoap_destroy(psoap, r); /* not an error in 2.1.10 anymore */ } if (NULL != pIntf->fsoap_end) { pIntf->fsoap_end(psoap, r); } else { SendErrorMessage(r, "no soap_end entry point"); } if (NULL != pIntf->fsoap_done) { pIntf->fsoap_done(psoap, r); } else { SendErrorMessage(r, "no soap_done entry point"); } } else { SendErrorMessage(r, "no soap_init entry point"); return OK; } /* * We did what we wanted to do, so tell the rest of the server we * succeeded. We need not delete pszResponse, because it was allocated from the request pool. */ return OK; }
static int reflector_handler(request_rec * r) { apr_bucket_brigade *bbin, *bbout; reflector_cfg *conf; apr_status_t status; if (strcmp(r->handler, "reflector")) { return DECLINED; } conf = (reflector_cfg *) ap_get_module_config(r->per_dir_config, &reflector_module); ap_allow_methods(r, 1, "POST", "OPTIONS", NULL); if (r->method_number == M_OPTIONS) { return ap_send_http_options(r); } else if (r->method_number == M_POST) { const char *content_length, *content_type; int seen_eos; /* * Sometimes we'll get in a state where the input handling has * detected an error where we want to drop the connection, so if * that's the case, don't read the data as that is what we're trying * to avoid. * * This function is also a no-op on a subrequest. */ if (r->main || r->connection->keepalive == AP_CONN_CLOSE || ap_status_drops_connection(r->status)) { return OK; } /* copy headers from in to out if configured */ apr_table_do(header_do, r, conf->headers, NULL); /* last modified defaults to now, unless otherwise set on the way in */ if (!apr_table_get(r->headers_out, "Last-Modified")) { ap_update_mtime(r, apr_time_now()); ap_set_last_modified(r); } ap_set_accept_ranges(r); /* reflect the content length, if present */ if ((content_length = apr_table_get(r->headers_in, "Content-Length"))) { apr_off_t offset; apr_strtoff(&offset, content_length, NULL, 10); ap_set_content_length(r, offset); } /* reflect the content type, if present */ if ((content_type = apr_table_get(r->headers_in, "Content-Type"))) { ap_set_content_type(r, content_type); } bbin = apr_brigade_create(r->pool, r->connection->bucket_alloc); bbout = apr_brigade_create(r->pool, r->connection->bucket_alloc); seen_eos = 0; do { apr_bucket *bucket; status = ap_get_brigade(r->input_filters, bbin, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN); if (status != APR_SUCCESS) { if (status == AP_FILTER_ERROR) { apr_brigade_destroy(bbin); return status; } else { apr_brigade_destroy(bbin); return HTTP_BAD_REQUEST; } } for (bucket = APR_BRIGADE_FIRST(bbin); bucket != APR_BRIGADE_SENTINEL(bbin); bucket = APR_BUCKET_NEXT(bucket)) { const char *data; apr_size_t len; if (APR_BUCKET_IS_EOS(bucket)) { seen_eos = 1; break; } /* These are metadata buckets. */ if (bucket->length == 0) { continue; } /* * We MUST read because in case we have an unknown-length * bucket or one that morphs, we want to exhaust it. */ status = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ); if (status != APR_SUCCESS) { apr_brigade_destroy(bbin); return HTTP_BAD_REQUEST; } apr_brigade_write(bbout, NULL, NULL, data, len); status = ap_pass_brigade(r->output_filters, bbout); if (status != APR_SUCCESS) { /* no way to know what type of error occurred */ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(01410) "reflector_handler: ap_pass_brigade returned %i", status); return HTTP_INTERNAL_SERVER_ERROR; } } apr_brigade_cleanup(bbin); } while (!seen_eos); return OK; } else { return HTTP_METHOD_NOT_ALLOWED; } }
API_EXPORT(int) ap_scan_script_header_err_core(request_rec *r, char *buffer, int (*getsfunc) (char *, int, void *), void *getsfunc_data) { char x[MAX_STRING_LEN]; char *w, *l; int p; int cgi_status = HTTP_OK; table *merge; table *cookie_table; if (buffer) { *buffer = '\0'; } w = buffer ? buffer : x; ap_hard_timeout("read script header", r); /* temporary place to hold headers to merge in later */ merge = ap_make_table(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 = ap_make_table(r->pool, 2); ap_table_do(set_cookie_doo_doo, cookie_table, r->err_headers_out, "Set-Cookie", NULL); while (1) { if ((*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data) == 0) { ap_kill_timeout(r); ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "Premature end of script headers: %s", r->filename); return HTTP_INTERNAL_SERVER_ERROR; } /* 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; ap_kill_timeout(r); if ((cgi_status == HTTP_OK) && (r->method_number == M_GET)) { cond_status = ap_meets_conditions(r); } ap_overlap_tables(r->err_headers_out, merge, AP_OVERLAP_TABLES_MERGE); if (!ap_is_empty_table(cookie_table)) { /* the cookies have already been copied to the cookie_table */ ap_table_unset(r->err_headers_out, "Set-Cookie"); r->err_headers_out = ap_overlay_tables(r->pool, r->err_headers_out, cookie_table); } return cond_status; } /* if we see a bogus header don't ignore it. Shout and scream */ #ifdef 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; char *cp; for (cp = w; *cp != '\0'; ++cp) { if (isprint(*cp) && !isprint(os_toebcdic[*cp])) ++maybeEBCDIC; if (!isprint(*cp) && isprint(os_toebcdic[*cp])) ++maybeASCII; } if (maybeASCII > maybeEBCDIC) { ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "CGI Interface Error: Script headers apparently ASCII: (CGI = %s)", r->filename); ascii2ebcdic(w, w, cp - w); } } #endif if (!(l = strchr(w, ':'))) { char malformed[(sizeof MALFORMED_MESSAGE) + 1 + MALFORMED_HEADER_LENGTH_TO_SHOW]; strcpy(malformed, MALFORMED_MESSAGE); strncat(malformed, w, MALFORMED_HEADER_LENGTH_TO_SHOW); if (!buffer) { /* Soak up all the script output - may save an outright kill */ while ((*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data)) { continue; } } ap_kill_timeout(r); ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "%s: %s", malformed, r->filename); return HTTP_INTERNAL_SERVER_ERROR; } *l++ = '\0'; while (*l && ap_isspace(*l)) { ++l; } if (!strcasecmp(w, "Content-type")) { char *tmp; /* Nuke trailing whitespace */ char *endp = l + strlen(l) - 1; while (endp > l && ap_isspace(*endp)) { *endp-- = '\0'; } tmp = ap_pstrdup(r->pool, l); ap_content_type_tolower(tmp); r->content_type = 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); r->status_line = ap_pstrdup(r->pool, l); } else if (!strcasecmp(w, "Location")) { ap_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Content-Length")) { ap_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Transfer-Encoding")) { ap_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")) { time_t mtime = ap_parseHTTPdate(l); ap_update_mtime(r, mtime); ap_set_last_modified(r); } else if (!strcasecmp(w, "Set-Cookie")) { ap_table_add(cookie_table, w, l); } else { ap_table_add(merge, w, l); } } }