/* 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;

}
示例#2
0
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;
}
示例#4
0
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;
}
示例#5
0
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 */
}
示例#6
0
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 */
}
示例#7
0
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;
}