mod_cache.c

来自「apache服务器源代码(版本号:2.2.2)」· C语言 代码 · 共 1,250 行 · 第 1/3 页

C
1,250
字号
        /* RFC2616 13.4 we are allowed to cache 200, 203, 206, 300, 301 or 410         * We don't cache 206, because we don't (yet) cache partial responses.         * We include 304 Not Modified here too as this is the origin server         * telling us to serve the cached copy.         */        reason = apr_psprintf(p, "Response status %d", r->status);    }    else if (exps != NULL && exp == APR_DATE_BAD) {        /* if a broken Expires header is present, don't cache it */        reason = apr_pstrcat(p, "Broken expires header: ", exps, NULL);    }    else if (r->args && exps == NULL) {        /* if query string present but no expiration time, don't cache it         * (RFC 2616/13.9)         */        reason = "Query string present but no expires header";    }    else if (r->status == HTTP_NOT_MODIFIED &&             !cache->handle && !cache->stale_handle) {        /* if the server said 304 Not Modified but we have no cache         * file - pass this untouched to the user agent, it's not for us.         */        reason = "HTTP Status 304 Not Modified";    }    else if (r->status == HTTP_OK && lastmods == NULL && etag == NULL             && (exps == NULL) && (conf->no_last_mod_ignore ==0)) {        /* 200 OK response from HTTP/1.0 and up without Last-Modified,         * Etag, or Expires headers.         */        /* Note: mod-include clears last_modified/expires/etags - this         * is why we have an optional function for a key-gen ;-)         */        reason = "No Last-Modified, Etag, or Expires headers";    }    else if (r->header_only) {        /* HEAD requests */        reason = "HTTP HEAD request";    }    else if (!conf->store_nostore &&             ap_cache_liststr(NULL, cc_out, "no-store", NULL)) {        /* RFC2616 14.9.2 Cache-Control: no-store response         * indicating do not cache, or stop now if you are         * trying to cache it.         */        /* FIXME: The Cache-Control: no-store could have come in on a 304,         * FIXME: while the original request wasn't conditional.  IOW, we         * FIXME:  made the the request conditional earlier to revalidate         * FIXME: our cached response.         */        reason = "Cache-Control: no-store present";    }    else if (!conf->store_private &&             ap_cache_liststr(NULL, cc_out, "private", NULL)) {        /* RFC2616 14.9.1 Cache-Control: private response         * this object is marked for this user's eyes only. Behave         * as a tunnel.         */        /* FIXME: See above (no-store) */        reason = "Cache-Control: private present";    }    else if (apr_table_get(r->headers_in, "Authorization") != NULL             && !(ap_cache_liststr(NULL, cc_out, "s-maxage", NULL)                  || ap_cache_liststr(NULL, cc_out, "must-revalidate", NULL)                  || ap_cache_liststr(NULL, cc_out, "public", NULL))) {        /* RFC2616 14.8 Authorisation:         * if authorisation is included in the request, we don't cache,         * but we can cache if the following exceptions are true:         * 1) If Cache-Control: s-maxage is included         * 2) If Cache-Control: must-revalidate is included         * 3) If Cache-Control: public is included         */        reason = "Authorization required";    }    else if (ap_cache_liststr(NULL,                              apr_table_get(r->headers_out, "Vary"),                              "*", NULL)) {        reason = "Vary header contains '*'";    }    else if (r->no_cache) {        /* or we've been asked not to cache it above */        reason = "r->no_cache present";    }    if (reason) {        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                     "cache: %s not cached. Reason: %s", r->unparsed_uri,                     reason);        /* remove this filter from the chain */        ap_remove_output_filter(f);        /* ship the data up the stack */        return ap_pass_brigade(f->next, in);    }    /* Make it so that we don't execute this path again. */    cache->in_checked = 1;    /* Set the content length if known.     */    cl = apr_table_get(r->err_headers_out, "Content-Length");    if (cl == NULL) {        cl = apr_table_get(r->headers_out, "Content-Length");    }    if (cl) {        char *errp;        if (apr_strtoff(&size, cl, &errp, 10) || *errp || size < 0) {            cl = NULL; /* parse error, see next 'if' block */        }    }    if (!cl) {        /* if we don't get the content-length, see if we have all the         * buckets and use their length to calculate the size         */        apr_bucket *e;        int all_buckets_here=0;        int unresolved_length = 0;        size=0;        for (e = APR_BRIGADE_FIRST(in);             e != APR_BRIGADE_SENTINEL(in);             e = APR_BUCKET_NEXT(e))        {            if (APR_BUCKET_IS_EOS(e)) {                all_buckets_here=1;                break;            }            if (APR_BUCKET_IS_FLUSH(e)) {                unresolved_length = 1;                continue;            }            if (e->length == (apr_size_t)-1) {                break;            }            size += e->length;        }        if (!all_buckets_here) {            size = -1;        }    }    /* It's safe to cache the response.     *     * There are two possiblities at this point:     * - cache->handle == NULL. In this case there is no previously     * cached entity anywhere on the system. We must create a brand     * new entity and store the response in it.     * - cache->stale_handle != NULL. In this case there is a stale     * entity in the system which needs to be replaced by new     * content (unless the result was 304 Not Modified, which means     * the cached entity is actually fresh, and we should update     * the headers).     */    /* Did we have a stale cache entry that really is stale? */    if (cache->stale_handle) {        if (r->status == HTTP_NOT_MODIFIED) {            /* Oh, hey.  It isn't that stale!  Yay! */            cache->handle = cache->stale_handle;            info = &cache->handle->cache_obj->info;            rv = OK;        }        else {            /* Oh, well.  Toss it. */            cache->provider->remove_entity(cache->stale_handle);            /* Treat the request as if it wasn't conditional. */            cache->stale_handle = NULL;        }    }    /* no cache handle, create a new entity */    if (!cache->handle) {        rv = cache_create_entity(r, size);        info = apr_pcalloc(r->pool, sizeof(cache_info));        /* We only set info->status upon the initial creation. */        info->status = r->status;    }    if (rv != OK) {        /* Caching layer declined the opportunity to cache the response */        ap_remove_output_filter(f);        return ap_pass_brigade(f->next, in);    }    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                 "cache: Caching url: %s", r->unparsed_uri);    /* We are actually caching this response. So it does not     * make sense to remove this entity any more.     */    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                 "cache: Removing CACHE_REMOVE_URL filter.");    ap_remove_output_filter(cache->remove_url_filter);    /*     * We now want to update the cache file header information with     * the new date, last modified, expire and content length and write     * it away to our cache file. First, we determine these values from     * the response, using heuristics if appropriate.     *     * In addition, we make HTTP/1.1 age calculations and write them away     * too.     */    /* Read the date. Generate one if one is not supplied */    dates = apr_table_get(r->err_headers_out, "Date");    if (dates != NULL) {        date_in_errhdr = 1;    }    else {        dates = apr_table_get(r->headers_out, "Date");    }    if (dates != NULL) {        info->date = apr_date_parse_http(dates);    }    else {        info->date = APR_DATE_BAD;    }    now = apr_time_now();    if (info->date == APR_DATE_BAD) {  /* No, or bad date */        char *dates;        /* no date header (or bad header)! */        /* add one; N.B. use the time _now_ rather than when we were checking         * the cache         */        if (date_in_errhdr == 1) {            apr_table_unset(r->err_headers_out, "Date");        }        date = now;        dates = apr_pcalloc(r->pool, MAX_STRING_LEN);        apr_rfc822_date(dates, now);        apr_table_set(r->headers_out, "Date", dates);        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                     "cache: Added date header");        info->date = date;    }    else {        date = info->date;    }    /* set response_time for HTTP/1.1 age calculations */    info->response_time = now;    /* get the request time */    info->request_time = r->request_time;    /* check last-modified date */    if (lastmod != APR_DATE_BAD && lastmod > date) {        /* if it's in the future, then replace by date */        lastmod = date;        lastmods = dates;        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,                     r->server,                     "cache: Last modified is in the future, "                     "replacing with now");    }    /* if no expiry date then     *   if lastmod     *      expiry date = date + min((date - lastmod) * factor, maxexpire)     *   else     *      expire date = date + defaultexpire     */    if (exp == APR_DATE_BAD) {        char expire_hdr[APR_RFC822_DATE_LEN];        /* if lastmod == date then you get 0*conf->factor which results in         *   an expiration time of now. This causes some problems with         *   freshness calculations, so we choose the else path...         */        if ((lastmod != APR_DATE_BAD) && (lastmod < date)) {            apr_time_t x = (apr_time_t) ((date - lastmod) * conf->factor);            if (x > conf->maxex) {                x = conf->maxex;            }            exp = date + x;            apr_rfc822_date(expire_hdr, exp);            apr_table_set(r->headers_out, "Expires", expire_hdr);        }        else {            exp = date + conf->defex;            apr_rfc822_date(expire_hdr, exp);            apr_table_set(r->headers_out, "Expires", expire_hdr);        }    }    info->expire = exp;    /* We found a stale entry which wasn't really stale. */    if (cache->stale_handle) {        /* Load in the saved status and clear the status line. */        r->status = info->status;        r->status_line = NULL;        /* RFC 2616 10.3.5 states that entity headers are not supposed         * to be in the 304 response.  Therefore, we need to combine the         * response headers with the cached headers *before* we update         * the cached headers.         *         * However, before doing that, we need to first merge in         * err_headers_out and we also need to strip any hop-by-hop         * headers that might have snuck in.         */        r->headers_out = apr_table_overlay(r->pool, r->headers_out,                                           r->err_headers_out);        r->headers_out = ap_cache_cacheable_hdrs_out(r->pool, r->headers_out,                                                     r->server);        apr_table_clear(r->err_headers_out);        /* Merge in our cached headers.  However, keep any updated values. */        ap_cache_accept_headers(cache->handle, r, 1);    }    /* Write away header information to cache. It is possible that we are     * trying to update headers for an entity which has already been cached.     *     * This may fail, due to an unwritable cache area. E.g. filesystem full,     * permissions problems or a read-only (re)mount. This must be handled     * later.     */    rv = cache->provider->store_headers(cache->handle, r, info);    /* Did we just update the cached headers on a revalidated response?     *     * If so, we can now decide what to serve to the client.  This is done in     * the same way as with a regular response, but conditions are now checked     * against the cached or merged response headers.     */    if (cache->stale_handle) {        apr_bucket_brigade *bb;        apr_bucket *bkt;        int status;        bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);        /* Restore the original request headers and see if we need to         * return anything else than the cached response (ie. the original         * request was conditional).         */        r->headers_in = cache->stale_headers;        status = ap_meets_conditions(r);        if (status != OK) {            r->status = status;            bkt = apr_bucket_flush_create(bb->bucket_alloc);            APR_BRIGADE_INSERT_TAIL(bb, bkt);        }        else {            cache->provider->recall_body(cache->handle, r->pool, bb);        }        cache->block_response = 1;        /* Before returning we need to handle the possible case of an         * unwritable cache. Rather than leaving the entity in the cache         * and having it constantly re-validated, now that we have recalled         * the body it is safe to try and remove the url from the cache.         */        if (rv != APR_SUCCESS) {            ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,                         "cache: updating headers with store_headers failed. "                         "Removing cached url.");            rv = cache->provider->remove_url(cache->stale_handle, r->pool);            if (rv != OK) {                /* Probably a mod_disk_cache cache area has been (re)mounted                 * read-only, or that there is a permissions problem.                 */                ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,                     "cache: attempt to remove url from cache unsuccessful.");            }        }        return ap_pass_brigade(f->next, bb);    }    if(rv != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,                     "cache: store_headers failed");        ap_remove_output_filter(f);        return ap_pass_brigade(f->next, in);    }    rv = cache->provider->store_body(cache->handle, r, in);    if (rv != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,                     "cache: store_body failed");        ap_remove_output_filter(f);    }    return ap_pass_brigade(f->next, in);}/* * CACHE_REMOVE_URL filter * --------------- * * This filter gets added in the quick handler every time the CACHE_SAVE filter * gets inserted. Its purpose is to remove a confirmed stale cache entry from * the cache. * * CACHE_REMOVE_URL has to be a protocol filter to ensure that is run even if * the response is a canned error message, which removes the content filters * and thus the CACHE_SAVE filter from the chain. * * CACHE_REMOVE_URL expects cache request rec within its context because the * request this filter runs on can be different from the one whose cache entry * should be removed, due to internal redirects. * * Note that CACHE_SAVE_URL (as a content-set filter, hence run before the * protocol filters) will remove this filter if it decides to cache the file. * Therefore, if this filter is left in, it must mean we need to toss any * existing files. */static int cache_remove_url_filter(ap_filter_t *f, apr_bucket_brigade *in)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?