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; }
/* 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; }
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); }
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; }
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); } } }
static int req_meets_conditions(lua_State*L ) { request_rec *r = CHECK_REQUEST_OBJECT(1); lua_pushnumber(L, ap_meets_conditions(r)); return 1; }