/* Parse x-www-url-formencoded args */ apr_table_t *parse_args(request_rec *r, char *args) { char* pair; char* last = NULL; char* eq; char *delim = "&"; apr_table_t *vars = apr_table_make(r->pool, 10); for (pair = apr_strtok(r->args, delim, &last); pair; pair = apr_strtok(NULL, delim, &last)) { for (eq = pair; *eq; ++eq) if (*eq == '+') *eq = ' '; ap_unescape_url(pair); eq = strchr(pair, '='); if (eq) { *eq++ = 0; apr_table_merge(vars, pair, eq); } else { apr_table_merge(vars, pair, ""); } } return vars; }
static apr_table_t *parse_headers(apr_array_header_t *hlines, apr_pool_t *pool) { if (hlines) { apr_table_t *headers = apr_table_make(pool, hlines->nelts); int i; for (i = 0; i < hlines->nelts; ++i) { char *hline = ((char **)hlines->elts)[i]; char *sep = ap_strchr(hline, ':'); if (!sep) { ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, pool, APLOGNO(02955) "h2_response: invalid header[%d] '%s'", i, (char*)hline); /* not valid format, abort */ return NULL; } (*sep++) = '\0'; while (*sep == ' ' || *sep == '\t') { ++sep; } if (!h2_util_ignore_header(hline)) { apr_table_merge(headers, hline, sep); } } return headers; } else { return apr_table_make(pool, 0); } }
h2_response *h2_response_create(int stream_id, const char *http_status, apr_array_header_t *hlines, apr_pool_t *pool) { apr_table_t *header; h2_response *response = apr_pcalloc(pool, sizeof(h2_response)); int i; if (response == NULL) { return NULL; } response->stream_id = stream_id; response->status = http_status; response->content_length = -1; if (hlines) { header = apr_table_make(pool, hlines->nelts); for (i = 0; i < hlines->nelts; ++i) { char *hline = ((char **)hlines->elts)[i]; char *sep = ap_strchr(hline, ':'); if (!sep) { ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, pool, APLOGNO(02955) "h2_response(%d): invalid header[%d] '%s'", response->stream_id, i, (char*)hline); /* not valid format, abort */ return NULL; } (*sep++) = '\0'; while (*sep == ' ' || *sep == '\t') { ++sep; } if (ignore_header(hline)) { /* never forward, ch. 8.1.2.2 */ } else { apr_table_merge(header, hline, sep); if (*sep && H2_HD_MATCH_LIT_CS("content-length", hline)) { char *end; response->content_length = apr_strtoi64(sep, &end, 10); if (sep == end) { ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, pool, APLOGNO(02956) "h2_response(%d): content-length" " value not parsed: %s", response->stream_id, sep); response->content_length = -1; } } } } } else { header = apr_table_make(pool, 0); } response->rheader = header; return response; }
static int twms_handler(request_rec *r) { twms_dir_conf *dcfg; const char *data; const char *val; apr_table_t *tab; apr_file_t *fh; apr_size_t nsend; apr_finfo_t info; if ((r->method_number != M_GET )||(r->args==0)) return DECLINED; data=r->args; // scfg=ap_get_module_config(r->server->module_config,&twms_module); dcfg=ap_get_module_config(r->per_dir_config,&twms_module); if (!dcfg) return DECLINED; // Does this ever happen? if (!ap_strstr(data,"GetTileService")) return DECLINED; // Do we have a config for this directory // ap_log_error(APLOG_MARK,APLOG_ERR,0,r->server,"TWMS_handler: args %s, path %s scfg %x dcfg %x dir %s conf %s", // data,r->parsed_uri.path,scfg,dcfg,dcfg->path,dcfg->Config); if (!dcfg->Config) return DECLINED; // This is overkill here, but it works tab=apr_table_make(r->pool,0); while (*data && (val=ap_getword(r->pool, &data, '&'))) { char *key=apr_pstrdup(r->pool,ap_getword(r->pool, &val, '=')); char *ival=apr_pstrdup(r->pool,val); ap_unescape_url(key);ap_unescape_url(ival); apr_table_merge(tab,key,ival); } if (!(val=apr_table_get(tab,"request"))) return DECLINED; if (apr_strnatcmp(val,"GetTileService")) return DECLINED; if (APR_SUCCESS!=apr_file_open(&fh,apr_pstrcat(r->pool,dcfg->path,dcfg->Config,0), APR_READ,APR_OS_DEFAULT,r->pool)) { ap_log_error(APLOG_MARK,APLOG_ERR,0,r->server,"TWMS file can't be read"); return HTTP_CONFLICT; } ap_log_error(APLOG_MARK,APLOG_ERR,0,r->server,"TWMS Sending GTS file"); apr_file_info_get(&info,APR_FINFO_SIZE,fh); ap_set_content_type(r,"text/xml"); ap_send_fd(fh,r,0,info.size,&nsend); apr_file_close(fh); return OK; }
CACHE_DECLARE(int) ap_cache_check_freshness(cache_handle_t *h, request_rec *r) { apr_int64_t age, maxage_req, maxage_cresp, maxage, smaxage, maxstale; apr_int64_t minfresh; const char *cc_cresp, *cc_req; const char *pragma; const char *agestr = NULL; const char *expstr = NULL; char *val; apr_time_t age_c = 0; cache_info *info = &(h->cache_obj->info); cache_server_conf *conf = (cache_server_conf *)ap_get_module_config(r->server->module_config, &cache_module); /* * We now want to check if our cached data is still fresh. This depends * on a few things, in this order: * * - RFC2616 14.9.4 End to end reload, Cache-Control: no-cache. no-cache in * either the request or the cached response means that we must * revalidate the request unconditionally, overriding any expiration * mechanism. It's equivalent to max-age=0,must-revalidate. * * - RFC2616 14.32 Pragma: no-cache This is treated the same as * Cache-Control: no-cache. * * - RFC2616 14.9.3 Cache-Control: max-stale, must-revalidate, * proxy-revalidate if the max-stale request header exists, modify the * stale calculations below so that an object can be at most <max-stale> * seconds stale before we request a revalidation, _UNLESS_ a * must-revalidate or proxy-revalidate cached response header exists to * stop us doing this. * * - RFC2616 14.9.3 Cache-Control: s-maxage the origin server specifies the * maximum age an object can be before it is considered stale. This * directive has the effect of proxy|must revalidate, which in turn means * simple ignore any max-stale setting. * * - RFC2616 14.9.4 Cache-Control: max-age this header can appear in both * requests and responses. If both are specified, the smaller of the two * takes priority. * * - RFC2616 14.21 Expires: if this request header exists in the cached * entity, and it's value is in the past, it has expired. * */ /* This value comes from the client's initial request. */ cc_req = apr_table_get(r->headers_in, "Cache-Control"); pragma = apr_table_get(r->headers_in, "Pragma"); if (ap_cache_liststr(NULL, pragma, "no-cache", NULL) || ap_cache_liststr(NULL, cc_req, "no-cache", NULL)) { if (!conf->ignorecachecontrol) { /* Treat as stale, causing revalidation */ return 0; } ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "Incoming request is asking for a uncached version of " "%s, but we know better and are ignoring it", r->unparsed_uri); } /* These come from the cached entity. */ cc_cresp = apr_table_get(h->resp_hdrs, "Cache-Control"); expstr = apr_table_get(h->resp_hdrs, "Expires"); if (ap_cache_liststr(NULL, cc_cresp, "no-cache", NULL)) { /* * The cached entity contained Cache-Control: no-cache, so treat as * stale causing revalidation */ return 0; } if ((agestr = apr_table_get(h->resp_hdrs, "Age"))) { age_c = apr_atoi64(agestr); } /* calculate age of object */ age = ap_cache_current_age(info, age_c, r->request_time); /* extract s-maxage */ if (cc_cresp && ap_cache_liststr(r->pool, cc_cresp, "s-maxage", &val) && val != NULL) { smaxage = apr_atoi64(val); } else { smaxage = -1; } /* extract max-age from request */ if (!conf->ignorecachecontrol && cc_req && ap_cache_liststr(r->pool, cc_req, "max-age", &val) && val != NULL) { maxage_req = apr_atoi64(val); } else { maxage_req = -1; } /* extract max-age from response */ if (cc_cresp && ap_cache_liststr(r->pool, cc_cresp, "max-age", &val) && val != NULL) { maxage_cresp = apr_atoi64(val); } else { maxage_cresp = -1; } /* * if both maxage request and response, the smaller one takes priority */ if (maxage_req == -1) { maxage = maxage_cresp; } else if (maxage_cresp == -1) { maxage = maxage_req; } else { maxage = MIN(maxage_req, maxage_cresp); } /* extract max-stale */ if (cc_req && ap_cache_liststr(r->pool, cc_req, "max-stale", &val)) { if(val != NULL) { maxstale = apr_atoi64(val); } else { /* * If no value is assigned to max-stale, then the client is willing * to accept a stale response of any age (RFC2616 14.9.3). We will * set it to one year in this case as this situation is somewhat * similar to a "never expires" Expires header (RFC2616 14.21) * which is set to a date one year from the time the response is * sent in this case. */ maxstale = APR_INT64_C(86400*365); } } else { maxstale = 0; } /* extract min-fresh */ if (!conf->ignorecachecontrol && cc_req && ap_cache_liststr(r->pool, cc_req, "min-fresh", &val) && val != NULL) { minfresh = apr_atoi64(val); } else { minfresh = 0; } /* override maxstale if must-revalidate or proxy-revalidate */ if (maxstale && ((cc_cresp && ap_cache_liststr(NULL, cc_cresp, "must-revalidate", NULL)) || (cc_cresp && ap_cache_liststr(NULL, cc_cresp, "proxy-revalidate", NULL)))) { maxstale = 0; } /* handle expiration */ if (((smaxage != -1) && (age < (smaxage - minfresh))) || ((maxage != -1) && (age < (maxage + maxstale - minfresh))) || ((smaxage == -1) && (maxage == -1) && (info->expire != APR_DATE_BAD) && (age < (apr_time_sec(info->expire - info->date) + maxstale - minfresh)))) { const char *warn_head; warn_head = apr_table_get(h->resp_hdrs, "Warning"); /* it's fresh darlings... */ /* set age header on response */ apr_table_set(h->resp_hdrs, "Age", apr_psprintf(r->pool, "%lu", (unsigned long)age)); /* add warning if maxstale overrode freshness calculation */ if (!(((smaxage != -1) && age < smaxage) || ((maxage != -1) && age < maxage) || (info->expire != APR_DATE_BAD && (apr_time_sec(info->expire - info->date)) > age))) { /* make sure we don't stomp on a previous warning */ if ((warn_head == NULL) || ((warn_head != NULL) && (ap_strstr_c(warn_head, "110") == NULL))) { apr_table_merge(h->resp_hdrs, "Warning", "110 Response is stale"); } } /* * If none of Expires, Cache-Control: max-age, or Cache-Control: * s-maxage appears in the response, and the respose header age * calculated is more than 24 hours add the warning 113 */ if ((maxage_cresp == -1) && (smaxage == -1) && (expstr == NULL) && (age > 86400)) { /* Make sure we don't stomp on a previous warning, and don't dup * a 113 marning that is already present. Also, make sure to add * the new warning to the correct *headers_out location. */ if ((warn_head == NULL) || ((warn_head != NULL) && (ap_strstr_c(warn_head, "113") == NULL))) { apr_table_merge(h->resp_hdrs, "Warning", "113 Heuristic expiration"); } } return 1; /* Cache object is fresh (enough) */ } return 0; /* Cache object is stale */ }
CACHE_DECLARE(int) ap_cache_check_freshness(cache_handle_t *h, request_rec *r) { apr_int64_t age, maxage_req, maxage_cresp, maxage, smaxage, maxstale; apr_int64_t minfresh; int age_in_errhdr = 0; const char *cc_cresp, *cc_ceresp, *cc_req; const char *agestr = NULL; const char *expstr = NULL; char *val; apr_time_t age_c = 0; cache_info *info = &(h->cache_obj->info); /* * We now want to check if our cached data is still fresh. This depends * on a few things, in this order: * * - RFC2616 14.9.4 End to end reload, Cache-Control: no-cache. no-cache in * either the request or the cached response means that we must * revalidate the request unconditionally, overriding any expiration * mechanism. It's equivalent to max-age=0,must-revalidate. * * - RFC2616 14.32 Pragma: no-cache This is treated the same as * Cache-Control: no-cache. * * - RFC2616 14.9.3 Cache-Control: max-stale, must-revalidate, * proxy-revalidate if the max-stale request header exists, modify the * stale calculations below so that an object can be at most <max-stale> * seconds stale before we request a revalidation, _UNLESS_ a * must-revalidate or proxy-revalidate cached response header exists to * stop us doing this. * * - RFC2616 14.9.3 Cache-Control: s-maxage the origin server specifies the * maximum age an object can be before it is considered stale. This * directive has the effect of proxy|must revalidate, which in turn means * simple ignore any max-stale setting. * * - RFC2616 14.9.4 Cache-Control: max-age this header can appear in both * requests and responses. If both are specified, the smaller of the two * takes priority. * * - RFC2616 14.21 Expires: if this request header exists in the cached * entity, and it's value is in the past, it has expired. * */ cc_cresp = apr_table_get(h->resp_hdrs, "Cache-Control"); cc_ceresp = apr_table_get(h->resp_err_hdrs, "Cache-Control"); cc_req = apr_table_get(h->req_hdrs, "Cache-Control"); if ((agestr = apr_table_get(h->resp_hdrs, "Age"))) { age_c = apr_atoi64(agestr); } else if ((agestr = apr_table_get(h->resp_err_hdrs, "Age"))) { age_c = apr_atoi64(agestr); age_in_errhdr = 1; } if (!(expstr = apr_table_get(h->resp_err_hdrs, "Expires"))) { expstr = apr_table_get(h->resp_hdrs, "Expires"); } /* calculate age of object */ age = ap_cache_current_age(info, age_c, r->request_time); /* extract s-maxage */ if (cc_cresp && ap_cache_liststr(r->pool, cc_cresp, "s-maxage", &val)) { smaxage = apr_atoi64(val); } else if (cc_ceresp && ap_cache_liststr(r->pool, cc_ceresp, "s-maxage", &val)) { smaxage = apr_atoi64(val); } else { smaxage = -1; } /* extract max-age from request */ if (cc_req && ap_cache_liststr(r->pool, cc_req, "max-age", &val)) { maxage_req = apr_atoi64(val); } else { maxage_req = -1; } /* extract max-age from response */ if (cc_cresp && ap_cache_liststr(r->pool, cc_cresp, "max-age", &val)) { maxage_cresp = apr_atoi64(val); } else if (cc_ceresp && ap_cache_liststr(r->pool, cc_ceresp, "max-age", &val)) { maxage_cresp = apr_atoi64(val); } else { maxage_cresp = -1; } /* * if both maxage request and response, the smaller one takes priority */ if (-1 == maxage_req) { maxage = maxage_cresp; } else if (-1 == maxage_cresp) { maxage = maxage_req; } else { maxage = MIN(maxage_req, maxage_cresp); } /* extract max-stale */ if (cc_req && ap_cache_liststr(r->pool, cc_req, "max-stale", &val)) { maxstale = apr_atoi64(val); } else { maxstale = 0; } /* extract min-fresh */ if (cc_req && ap_cache_liststr(r->pool, cc_req, "min-fresh", &val)) { minfresh = apr_atoi64(val); } else { minfresh = 0; } /* override maxstale if must-revalidate or proxy-revalidate */ if (maxstale && ((cc_cresp && ap_cache_liststr(NULL, cc_cresp, "must-revalidate", NULL)) || (cc_cresp && ap_cache_liststr(NULL, cc_cresp, "proxy-revalidate", NULL)) || (cc_ceresp && ap_cache_liststr(NULL, cc_ceresp, "must-revalidate", NULL)) || (cc_ceresp && ap_cache_liststr(NULL, cc_ceresp, "proxy-revalidate", NULL)))) { maxstale = 0; } /* handle expiration */ if (((smaxage != -1) && (age < (smaxage - minfresh))) || ((maxage != -1) && (age < (maxage + maxstale - minfresh))) || ((smaxage == -1) && (maxage == -1) && (info->expire != APR_DATE_BAD) && (age < (apr_time_sec(info->expire - info->date) + maxstale - minfresh)))) { const char *warn_head; apr_table_t *head_ptr; warn_head = apr_table_get(h->resp_hdrs, "Warning"); if (warn_head != NULL) { head_ptr = h->resp_hdrs; } else { warn_head = apr_table_get(h->resp_err_hdrs, "Warning"); head_ptr = h->resp_err_hdrs; } /* it's fresh darlings... */ /* set age header on response */ if (age_in_errhdr) { apr_table_set(h->resp_err_hdrs, "Age", apr_psprintf(r->pool, "%lu", (unsigned long)age)); } else { apr_table_set(h->resp_hdrs, "Age", apr_psprintf(r->pool, "%lu", (unsigned long)age)); } /* add warning if maxstale overrode freshness calculation */ if (!(((smaxage != -1) && age < smaxage) || ((maxage != -1) && age < maxage) || (info->expire != APR_DATE_BAD && (info->expire - info->date) > age))) { /* make sure we don't stomp on a previous warning */ if ((warn_head == NULL) || ((warn_head != NULL) && (ap_strstr_c(warn_head, "110") == NULL))) { apr_table_merge(head_ptr, "Warning", "110 Response is stale"); } } /* * If none of Expires, Cache-Control: max-age, or Cache-Control: * s-maxage appears in the response, and the respose header age * calculated is more than 24 hours add the warning 113 */ if ((maxage_cresp == -1) && (smaxage == -1) && (expstr == NULL) && (age > 86400)) { /* Make sure we don't stomp on a previous warning, and don't dup * a 113 marning that is already present. Also, make sure to add * the new warning to the correct *headers_out location. */ if ((warn_head == NULL) || ((warn_head != NULL) && (ap_strstr_c(warn_head, "113") == NULL))) { apr_table_merge(head_ptr, "Warning", "113 Heuristic expiration"); } } return 1; /* Cache object is fresh (enough) */ } return 0; /* Cache object is stale */ }
int modperl_callback(pTHX_ modperl_handler_t *handler, apr_pool_t *p, request_rec *r, server_rec *s, AV *args) { CV *cv = (CV *)NULL; I32 flags = G_EVAL|G_SCALAR; dSP; int count, status = OK; /* handler callbacks shouldn't affect each other's taintedness * state, so start every callback with a clear tainted status * before and after the callback one of the main problems we are * trying to solve is that when modperl_croak called (which calls * perl's croak((char *)NULL) to throw an error object) it leaves * the interpreter in the tainted state which later affects other * callbacks that call eval, etc., which triggers perl crash with: * Insecure dependency in eval while running setgid. Callback * called exit. */ TAINT_NOT; if ((status = modperl_handler_resolve(aTHX_ &handler, p, s)) != OK) { TAINT_NOT; return status; } ENTER;SAVETMPS; PUSHMARK(SP); if (MpHandlerMETHOD(handler)) { GV *gv; if (!handler->mgv_obj) { Perl_croak(aTHX_ "panic: %s method handler object is NULL!", modperl_handler_name(handler)); } gv = modperl_mgv_lookup(aTHX_ handler->mgv_obj); XPUSHs(modperl_mgv_sv(gv)); } if (args) { I32 items = AvFILLp(args) + 1; EXTEND(SP, items); Copy(AvARRAY(args), SP + 1, items, SV*); SP += items; } PUTBACK; if (MpHandlerANON(handler)) { #ifdef USE_ITHREADS cv = modperl_handler_anon_get(aTHX_ handler->mgv_obj); #else cv = handler->cv; #endif } else { GV *gv = modperl_mgv_lookup_autoload(aTHX_ handler->mgv_cv, s, p); if (gv) { cv = modperl_mgv_cv(gv); } else { const char *name; modperl_mgv_t *symbol = handler->mgv_cv; /* XXX: need to validate *symbol */ if (symbol && symbol->name) { name = modperl_mgv_as_string(aTHX_ symbol, p, 0); } else { name = handler->name; } MP_TRACE_h(MP_FUNC, "[%s %s] lookup of %s failed", modperl_pid_tid(p), modperl_server_desc(s, p), name); ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "lookup of '%s' failed", name); status = HTTP_INTERNAL_SERVER_ERROR; } } if (status == OK) { count = call_sv((SV*)cv, flags); SPAGAIN; if (count != 1) { /* XXX can this really happen with G_EVAL|G_SCALAR? */ status = OK; } else { SV *status_sv = POPs; if (status_sv == &PL_sv_undef) { /* ModPerl::Util::exit() and Perl_croak internally * arrange to return PL_sv_undef with G_EVAL|G_SCALAR */ status = OK; } else { status = SvIVx(status_sv); } } PUTBACK; } FREETMPS;LEAVE; if (SvTRUE(ERRSV)) { MP_TRACE_h(MP_FUNC, "$@ = %s", SvPV_nolen(ERRSV)); status = HTTP_INTERNAL_SERVER_ERROR; } if (status == HTTP_INTERNAL_SERVER_ERROR) { if (r && r->notes) { apr_table_merge(r->notes, "error-notes", SvPV_nolen(ERRSV)); } } TAINT_NOT; return status; }