|
Packit |
90a5c9 |
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
Packit |
90a5c9 |
* contributor license agreements. See the NOTICE file distributed with
|
|
Packit |
90a5c9 |
* this work for additional information regarding copyright ownership.
|
|
Packit |
90a5c9 |
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
Packit |
90a5c9 |
* (the "License"); you may not use this file except in compliance with
|
|
Packit |
90a5c9 |
* the License. You may obtain a copy of the License at
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Unless required by applicable law or agreed to in writing, software
|
|
Packit |
90a5c9 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
90a5c9 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
90a5c9 |
* See the License for the specific language governing permissions and
|
|
Packit |
90a5c9 |
* limitations under the License.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "apr_lib.h"
|
|
Packit |
90a5c9 |
#include "apr_file_io.h"
|
|
Packit |
90a5c9 |
#include "apr_strings.h"
|
|
Packit |
90a5c9 |
#include "apr_buckets.h"
|
|
Packit |
90a5c9 |
#include "httpd.h"
|
|
Packit |
90a5c9 |
#include "http_config.h"
|
|
Packit |
90a5c9 |
#include "http_log.h"
|
|
Packit |
90a5c9 |
#include "http_core.h"
|
|
Packit |
90a5c9 |
#include "http_protocol.h"
|
|
Packit |
90a5c9 |
#include "ap_provider.h"
|
|
Packit |
90a5c9 |
#include "ap_socache.h"
|
|
Packit |
90a5c9 |
#include "util_filter.h"
|
|
Packit |
90a5c9 |
#include "util_script.h"
|
|
Packit |
90a5c9 |
#include "util_charset.h"
|
|
Packit |
90a5c9 |
#include "util_mutex.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "mod_cache.h"
|
|
Packit |
90a5c9 |
#include "mod_status.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "cache_socache_common.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*
|
|
Packit |
90a5c9 |
* mod_cache_socache: Shared Object Cache Based HTTP 1.1 Cache.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Flow to Find the entry:
|
|
Packit |
90a5c9 |
* Incoming client requests URI /foo/bar/baz
|
|
Packit |
90a5c9 |
* Fetch URI key (may contain Format #1 or Format #2)
|
|
Packit |
90a5c9 |
* If format #1 (Contains a list of Vary Headers):
|
|
Packit |
90a5c9 |
* Use each header name (from .header) with our request values (headers_in) to
|
|
Packit |
90a5c9 |
* regenerate key using HeaderName+HeaderValue+.../foo/bar/baz
|
|
Packit |
90a5c9 |
* re-read in key (must be format #2)
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Format #1:
|
|
Packit |
90a5c9 |
* apr_uint32_t format;
|
|
Packit |
90a5c9 |
* apr_time_t expire;
|
|
Packit |
90a5c9 |
* apr_array_t vary_headers (delimited by CRLF)
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Format #2:
|
|
Packit |
90a5c9 |
* cache_socache_info_t (first sizeof(apr_uint32_t) bytes is the format)
|
|
Packit |
90a5c9 |
* entity name (sobj->name) [length is in cache_socache_info_t->name_len]
|
|
Packit |
90a5c9 |
* r->headers_out (delimited by CRLF)
|
|
Packit |
90a5c9 |
* CRLF
|
|
Packit |
90a5c9 |
* r->headers_in (delimited by CRLF)
|
|
Packit |
90a5c9 |
* CRLF
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
module AP_MODULE_DECLARE_DATA cache_socache_module;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*
|
|
Packit |
90a5c9 |
* cache_socache_object_t
|
|
Packit |
90a5c9 |
* Pointed to by cache_object_t::vobj
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
typedef struct cache_socache_object_t
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_pool_t *pool; /* pool */
|
|
Packit |
90a5c9 |
unsigned char *buffer; /* the cache buffer */
|
|
Packit |
90a5c9 |
apr_size_t buffer_len; /* size of the buffer */
|
|
Packit |
90a5c9 |
apr_bucket_brigade *body; /* brigade containing the body, if any */
|
|
Packit |
90a5c9 |
apr_table_t *headers_in; /* Input headers to save */
|
|
Packit |
90a5c9 |
apr_table_t *headers_out; /* Output headers to save */
|
|
Packit |
90a5c9 |
cache_socache_info_t socache_info; /* Header information. */
|
|
Packit |
90a5c9 |
apr_size_t body_offset; /* offset to the start of the body */
|
|
Packit |
90a5c9 |
apr_off_t body_length; /* length of the cached entity body */
|
|
Packit |
90a5c9 |
apr_time_t expire; /* when to expire the entry */
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
const char *name; /* Requested URI without vary bits - suitable for mortals. */
|
|
Packit |
90a5c9 |
const char *key; /* On-disk prefix; URI with Vary bits (if present) */
|
|
Packit |
90a5c9 |
apr_off_t offset; /* Max size to set aside */
|
|
Packit |
90a5c9 |
apr_time_t timeout; /* Max time to set aside */
|
|
Packit |
90a5c9 |
unsigned int newbody :1; /* whether a new body is present */
|
|
Packit |
90a5c9 |
unsigned int done :1; /* Is the attempt to cache complete? */
|
|
Packit |
90a5c9 |
} cache_socache_object_t;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*
|
|
Packit |
90a5c9 |
* mod_cache_socache configuration
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
#define DEFAULT_MAX_FILE_SIZE 100*1024
|
|
Packit |
90a5c9 |
#define DEFAULT_MAXTIME 86400
|
|
Packit |
90a5c9 |
#define DEFAULT_MINTIME 600
|
|
Packit |
90a5c9 |
#define DEFAULT_READSIZE 0
|
|
Packit |
90a5c9 |
#define DEFAULT_READTIME 0
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct cache_socache_provider_conf
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const char *args;
|
|
Packit |
90a5c9 |
ap_socache_provider_t *socache_provider;
|
|
Packit |
90a5c9 |
ap_socache_instance_t *socache_instance;
|
|
Packit |
90a5c9 |
} cache_socache_provider_conf;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct cache_socache_conf
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_provider_conf *provider;
|
|
Packit |
90a5c9 |
} cache_socache_conf;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct cache_socache_dir_conf
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_off_t max; /* maximum file size for cached files */
|
|
Packit |
90a5c9 |
apr_time_t maxtime; /* maximum expiry time */
|
|
Packit |
90a5c9 |
apr_time_t mintime; /* minimum expiry time */
|
|
Packit |
90a5c9 |
apr_off_t readsize; /* maximum data to attempt to cache in one go */
|
|
Packit |
90a5c9 |
apr_time_t readtime; /* maximum time taken to cache in one go */
|
|
Packit |
90a5c9 |
unsigned int max_set :1;
|
|
Packit |
90a5c9 |
unsigned int maxtime_set :1;
|
|
Packit |
90a5c9 |
unsigned int mintime_set :1;
|
|
Packit |
90a5c9 |
unsigned int readsize_set :1;
|
|
Packit |
90a5c9 |
unsigned int readtime_set :1;
|
|
Packit |
90a5c9 |
} cache_socache_dir_conf;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Shared object cache and mutex */
|
|
Packit |
90a5c9 |
static const char * const cache_socache_id = "cache-socache";
|
|
Packit |
90a5c9 |
static apr_global_mutex_t *socache_mutex = NULL;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*
|
|
Packit |
90a5c9 |
* Local static functions
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t read_array(request_rec *r, apr_array_header_t *arr,
|
|
Packit |
90a5c9 |
unsigned char *buffer, apr_size_t buffer_len, apr_size_t *slider)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_size_t val = *slider;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while (*slider < buffer_len) {
|
|
Packit |
90a5c9 |
if (buffer[*slider] == '\r') {
|
|
Packit |
90a5c9 |
if (val == *slider) {
|
|
Packit |
90a5c9 |
(*slider)++;
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
*((const char **) apr_array_push(arr)) = apr_pstrndup(r->pool,
|
|
Packit |
90a5c9 |
(const char *) buffer + val, *slider - val);
|
|
Packit |
90a5c9 |
(*slider)++;
|
|
Packit |
90a5c9 |
if (buffer[*slider] == '\n') {
|
|
Packit |
90a5c9 |
(*slider)++;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
val = *slider;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (buffer[*slider] == '\0') {
|
|
Packit |
90a5c9 |
(*slider)++;
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
(*slider)++;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t store_array(apr_array_header_t *arr, unsigned char *buffer,
|
|
Packit |
90a5c9 |
apr_size_t buffer_len, apr_size_t *slider)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int i, len;
|
|
Packit |
90a5c9 |
const char **elts;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
elts = (const char **) arr->elts;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (i = 0; i < arr->nelts; i++) {
|
|
Packit |
90a5c9 |
apr_size_t e_len = strlen(elts[i]);
|
|
Packit |
90a5c9 |
if (e_len + 3 >= buffer_len - *slider) {
|
|
Packit |
90a5c9 |
return APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
len = apr_snprintf(buffer ? (char *) buffer + *slider : NULL,
|
|
Packit |
90a5c9 |
buffer ? buffer_len - *slider : 0, "%s" CRLF, elts[i]);
|
|
Packit |
90a5c9 |
*slider += len;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (buffer) {
|
|
Packit |
90a5c9 |
memcpy(buffer + *slider, CRLF, sizeof(CRLF) - 1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
*slider += sizeof(CRLF) - 1;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t read_table(cache_handle_t *handle, request_rec *r,
|
|
Packit |
90a5c9 |
apr_table_t *table, unsigned char *buffer, apr_size_t buffer_len,
|
|
Packit |
90a5c9 |
apr_size_t *slider)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_size_t key = *slider, colon = 0, len = 0;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while (*slider < buffer_len) {
|
|
Packit |
90a5c9 |
if (buffer[*slider] == ':') {
|
|
Packit |
90a5c9 |
if (!colon) {
|
|
Packit |
90a5c9 |
colon = *slider;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
(*slider)++;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (buffer[*slider] == '\r') {
|
|
Packit |
90a5c9 |
len = colon;
|
|
Packit |
90a5c9 |
if (key == *slider) {
|
|
Packit |
90a5c9 |
(*slider)++;
|
|
Packit |
90a5c9 |
if (buffer[*slider] == '\n') {
|
|
Packit |
90a5c9 |
(*slider)++;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (!colon || buffer[colon++] != ':') {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02344)
|
|
Packit |
90a5c9 |
"Premature end of cache headers.");
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
/* Do not go past the \r from above as apr_isspace('\r') is true */
|
|
Packit |
90a5c9 |
while (apr_isspace(buffer[colon]) && (colon < *slider)) {
|
|
Packit |
90a5c9 |
colon++;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
apr_table_addn(table, apr_pstrndup(r->pool, (const char *) buffer
|
|
Packit |
90a5c9 |
+ key, len - key), apr_pstrndup(r->pool,
|
|
Packit |
90a5c9 |
(const char *) buffer + colon, *slider - colon));
|
|
Packit |
90a5c9 |
(*slider)++;
|
|
Packit |
90a5c9 |
if (buffer[*slider] == '\n') {
|
|
Packit |
90a5c9 |
(*slider)++;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
key = *slider;
|
|
Packit |
90a5c9 |
colon = 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (buffer[*slider] == '\0') {
|
|
Packit |
90a5c9 |
(*slider)++;
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
(*slider)++;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t store_table(apr_table_t *table, unsigned char *buffer,
|
|
Packit |
90a5c9 |
apr_size_t buffer_len, apr_size_t *slider)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int i, len;
|
|
Packit |
90a5c9 |
apr_table_entry_t *elts;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
elts = (apr_table_entry_t *) apr_table_elts(table)->elts;
|
|
Packit |
90a5c9 |
for (i = 0; i < apr_table_elts(table)->nelts; ++i) {
|
|
Packit |
90a5c9 |
if (elts[i].key != NULL) {
|
|
Packit |
90a5c9 |
apr_size_t key_len = strlen(elts[i].key);
|
|
Packit |
90a5c9 |
apr_size_t val_len = strlen(elts[i].val);
|
|
Packit |
90a5c9 |
if (key_len + val_len + 5 >= buffer_len - *slider) {
|
|
Packit |
90a5c9 |
return APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
len = apr_snprintf(buffer ? (char *) buffer + *slider : NULL,
|
|
Packit |
90a5c9 |
buffer ? buffer_len - *slider : 0, "%s: %s" CRLF,
|
|
Packit |
90a5c9 |
elts[i].key, elts[i].val);
|
|
Packit |
90a5c9 |
*slider += len;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (3 >= buffer_len - *slider) {
|
|
Packit |
90a5c9 |
return APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (buffer) {
|
|
Packit |
90a5c9 |
memcpy(buffer + *slider, CRLF, sizeof(CRLF) - 1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
*slider += sizeof(CRLF) - 1;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char* regen_key(apr_pool_t *p, apr_table_t *headers,
|
|
Packit |
90a5c9 |
apr_array_header_t *varray, const char *oldkey,
|
|
Packit |
90a5c9 |
apr_size_t *newkeylen)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
struct iovec *iov;
|
|
Packit |
90a5c9 |
int i, k;
|
|
Packit |
90a5c9 |
int nvec;
|
|
Packit |
90a5c9 |
const char *header;
|
|
Packit |
90a5c9 |
const char **elts;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
nvec = (varray->nelts * 2) + 1;
|
|
Packit |
90a5c9 |
iov = apr_palloc(p, sizeof(struct iovec) * nvec);
|
|
Packit |
90a5c9 |
elts = (const char **) varray->elts;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* TODO:
|
|
Packit |
90a5c9 |
* - Handle multiple-value headers better. (sort them?)
|
|
Packit |
90a5c9 |
* - Handle Case in-sensitive Values better.
|
|
Packit |
90a5c9 |
* This isn't the end of the world, since it just lowers the cache
|
|
Packit |
90a5c9 |
* hit rate, but it would be nice to fix.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* The majority are case insenstive if they are values (encoding etc).
|
|
Packit |
90a5c9 |
* Most of rfc2616 is case insensitive on header contents.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* So the better solution may be to identify headers which should be
|
|
Packit |
90a5c9 |
* treated case-sensitive?
|
|
Packit |
90a5c9 |
* HTTP URI's (3.2.3) [host and scheme are insensitive]
|
|
Packit |
90a5c9 |
* HTTP method (5.1.1)
|
|
Packit |
90a5c9 |
* HTTP-date values (3.3.1)
|
|
Packit |
90a5c9 |
* 3.7 Media Types [exerpt]
|
|
Packit |
90a5c9 |
* The type, subtype, and parameter attribute names are case-
|
|
Packit |
90a5c9 |
* insensitive. Parameter values might or might not be case-sensitive,
|
|
Packit |
90a5c9 |
* depending on the semantics of the parameter name.
|
|
Packit |
90a5c9 |
* 4.20 Except [exerpt]
|
|
Packit |
90a5c9 |
* Comparison of expectation values is case-insensitive for unquoted
|
|
Packit |
90a5c9 |
* tokens (including the 100-continue token), and is case-sensitive for
|
|
Packit |
90a5c9 |
* quoted-string expectation-extensions.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (i = 0, k = 0; i < varray->nelts; i++) {
|
|
Packit |
90a5c9 |
header = apr_table_get(headers, elts[i]);
|
|
Packit |
90a5c9 |
if (!header) {
|
|
Packit |
90a5c9 |
header = "";
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
iov[k].iov_base = (char*) elts[i];
|
|
Packit |
90a5c9 |
iov[k].iov_len = strlen(elts[i]);
|
|
Packit |
90a5c9 |
k++;
|
|
Packit |
90a5c9 |
iov[k].iov_base = (char*) header;
|
|
Packit |
90a5c9 |
iov[k].iov_len = strlen(header);
|
|
Packit |
90a5c9 |
k++;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
iov[k].iov_base = (char*) oldkey;
|
|
Packit |
90a5c9 |
iov[k].iov_len = strlen(oldkey);
|
|
Packit |
90a5c9 |
k++;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return apr_pstrcatv(p, iov, k, newkeylen);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int array_alphasort(const void *fn1, const void *fn2)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return strcmp(*(char**) fn1, *(char**) fn2);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void tokens_to_array(apr_pool_t *p, const char *data,
|
|
Packit |
90a5c9 |
apr_array_header_t *arr)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
char *token;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while ((token = ap_get_list_item(p, &data)) != NULL) {
|
|
Packit |
90a5c9 |
*((const char **) apr_array_push(arr)) = token;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Sort it so that "Vary: A, B" and "Vary: B, A" are stored the same. */
|
|
Packit |
90a5c9 |
qsort((void *) arr->elts, arr->nelts, sizeof(char *), array_alphasort);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*
|
|
Packit |
90a5c9 |
* Hook and mod_cache callback functions
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static int create_entity(cache_handle_t *h, request_rec *r, const char *key,
|
|
Packit |
90a5c9 |
apr_off_t len, apr_bucket_brigade *bb)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_dir_conf *dconf =
|
|
Packit |
90a5c9 |
ap_get_module_config(r->per_dir_config, &cache_socache_module);
|
|
Packit |
90a5c9 |
cache_socache_conf *conf = ap_get_module_config(r->server->module_config,
|
|
Packit |
90a5c9 |
&cache_socache_module);
|
|
Packit |
90a5c9 |
cache_object_t *obj;
|
|
Packit |
90a5c9 |
cache_socache_object_t *sobj;
|
|
Packit |
90a5c9 |
apr_size_t total;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (conf->provider == NULL) {
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* we don't support caching of range requests (yet) */
|
|
Packit |
90a5c9 |
/* TODO: but we could */
|
|
Packit |
90a5c9 |
if (r->status == HTTP_PARTIAL_CONTENT) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02345)
|
|
Packit |
90a5c9 |
"URL %s partial content response not cached",
|
|
Packit |
90a5c9 |
key);
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*
|
|
Packit |
90a5c9 |
* We have a chicken and egg problem. We don't know until we
|
|
Packit |
90a5c9 |
* attempt to store_headers just how big the response will be
|
|
Packit |
90a5c9 |
* and whether it will fit in the cache limits set. But we
|
|
Packit |
90a5c9 |
* need to make a decision now as to whether we plan to try.
|
|
Packit |
90a5c9 |
* If we make the wrong decision, we could prevent another
|
|
Packit |
90a5c9 |
* cache implementation, such as cache_disk, from getting the
|
|
Packit |
90a5c9 |
* opportunity to cache, and that would be unfortunate.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* In a series of tests, from cheapest to most expensive,
|
|
Packit |
90a5c9 |
* decide whether or not to ignore this attempt to cache,
|
|
Packit |
90a5c9 |
* with a small margin just to be sure.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
if (len < 0) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02346)
|
|
Packit |
90a5c9 |
"URL '%s' had no explicit size, ignoring", key);
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (len > dconf->max) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02347)
|
|
Packit |
90a5c9 |
"URL '%s' body larger than limit, ignoring "
|
|
Packit |
90a5c9 |
"(%" APR_OFF_T_FMT " > %" APR_OFF_T_FMT ")",
|
|
Packit |
90a5c9 |
key, len, dconf->max);
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* estimate the total cached size, given current headers */
|
|
Packit |
90a5c9 |
total = len + sizeof(cache_socache_info_t) + strlen(key);
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != store_table(r->headers_out, NULL, dconf->max, &total)
|
|
Packit |
90a5c9 |
|| APR_SUCCESS != store_table(r->headers_in, NULL, dconf->max,
|
|
Packit |
90a5c9 |
&total)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02348)
|
|
Packit |
90a5c9 |
"URL '%s' estimated headers size larger than limit, ignoring "
|
|
Packit |
90a5c9 |
"(%" APR_SIZE_T_FMT " > %" APR_OFF_T_FMT ")",
|
|
Packit |
90a5c9 |
key, total, dconf->max);
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (total >= dconf->max) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02349)
|
|
Packit |
90a5c9 |
"URL '%s' body and headers larger than limit, ignoring "
|
|
Packit |
90a5c9 |
"(%" APR_OFF_T_FMT " > %" APR_OFF_T_FMT ")",
|
|
Packit |
90a5c9 |
key, len, dconf->max);
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Allocate and initialize cache_object_t and cache_socache_object_t */
|
|
Packit |
90a5c9 |
h->cache_obj = obj = apr_pcalloc(r->pool, sizeof(*obj));
|
|
Packit |
90a5c9 |
obj->vobj = sobj = apr_pcalloc(r->pool, sizeof(*sobj));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
obj->key = apr_pstrdup(r->pool, key);
|
|
Packit |
90a5c9 |
sobj->key = obj->key;
|
|
Packit |
90a5c9 |
sobj->name = obj->key;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int open_entity(cache_handle_t *h, request_rec *r, const char *key)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_dir_conf *dconf =
|
|
Packit |
90a5c9 |
ap_get_module_config(r->per_dir_config, &cache_socache_module);
|
|
Packit |
90a5c9 |
cache_socache_conf *conf = ap_get_module_config(r->server->module_config,
|
|
Packit |
90a5c9 |
&cache_socache_module);
|
|
Packit |
90a5c9 |
apr_uint32_t format;
|
|
Packit |
90a5c9 |
apr_size_t slider;
|
|
Packit |
90a5c9 |
unsigned int buffer_len;
|
|
Packit |
90a5c9 |
const char *nkey;
|
|
Packit |
90a5c9 |
apr_status_t rc;
|
|
Packit |
90a5c9 |
cache_object_t *obj;
|
|
Packit |
90a5c9 |
cache_info *info;
|
|
Packit |
90a5c9 |
cache_socache_object_t *sobj;
|
|
Packit |
90a5c9 |
apr_size_t len;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
nkey = NULL;
|
|
Packit |
90a5c9 |
h->cache_obj = NULL;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!conf->provider || !conf->provider->socache_instance) {
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Create and init the cache object */
|
|
Packit |
90a5c9 |
obj = apr_pcalloc(r->pool, sizeof(cache_object_t));
|
|
Packit |
90a5c9 |
sobj = apr_pcalloc(r->pool, sizeof(cache_socache_object_t));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
info = &(obj->info);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Create a temporary pool for the buffer, and destroy it if something
|
|
Packit |
90a5c9 |
* goes wrong so we don't have large buffers of unused memory hanging
|
|
Packit |
90a5c9 |
* about for the lifetime of the response.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
apr_pool_create(&sobj->pool, r->pool);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
sobj->buffer = apr_palloc(sobj->pool, dconf->max);
|
|
Packit |
90a5c9 |
sobj->buffer_len = dconf->max;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* attempt to retrieve the cached entry */
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
apr_status_t status = apr_global_mutex_lock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02350)
|
|
Packit |
90a5c9 |
"could not acquire lock, ignoring: %s", obj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
buffer_len = sobj->buffer_len;
|
|
Packit |
90a5c9 |
rc = conf->provider->socache_provider->retrieve(
|
|
Packit |
90a5c9 |
conf->provider->socache_instance, r->server, (unsigned char *) key,
|
|
Packit |
90a5c9 |
strlen(key), sobj->buffer, &buffer_len, r->pool);
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
apr_status_t status = apr_global_mutex_unlock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02351)
|
|
Packit |
90a5c9 |
"could not release lock, ignoring: %s", obj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (rc != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rc, r, APLOGNO(02352)
|
|
Packit |
90a5c9 |
"Key not found in cache: %s", key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (buffer_len >= sobj->buffer_len) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rc, r, APLOGNO(02353)
|
|
Packit |
90a5c9 |
"Key found in cache but too big, ignoring: %s", key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* read the format from the cache file */
|
|
Packit |
90a5c9 |
memcpy(&format, sobj->buffer, sizeof(format));
|
|
Packit |
90a5c9 |
slider = sizeof(format);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (format == CACHE_SOCACHE_VARY_FORMAT_VERSION) {
|
|
Packit |
90a5c9 |
apr_array_header_t* varray;
|
|
Packit |
90a5c9 |
apr_time_t expire;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
memcpy(&expire, sobj->buffer + slider, sizeof(expire));
|
|
Packit |
90a5c9 |
slider += sizeof(expire);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
varray = apr_array_make(r->pool, 5, sizeof(char*));
|
|
Packit |
90a5c9 |
rc = read_array(r, varray, sobj->buffer, buffer_len, &slider);
|
|
Packit |
90a5c9 |
if (rc != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, APLOGNO(02354)
|
|
Packit |
90a5c9 |
"Cannot parse vary entry for key: %s", key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
nkey = regen_key(r->pool, r->headers_in, varray, key, &len;;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* attempt to retrieve the cached entry */
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
apr_status_t status = apr_global_mutex_lock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02355)
|
|
Packit |
90a5c9 |
"could not acquire lock, ignoring: %s", obj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
buffer_len = sobj->buffer_len;
|
|
Packit |
90a5c9 |
rc = conf->provider->socache_provider->retrieve(
|
|
Packit |
90a5c9 |
conf->provider->socache_instance, r->server,
|
|
Packit |
90a5c9 |
(unsigned char *) nkey, len, sobj->buffer,
|
|
Packit |
90a5c9 |
&buffer_len, r->pool);
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
apr_status_t status = apr_global_mutex_unlock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02356)
|
|
Packit |
90a5c9 |
"could not release lock, ignoring: %s", obj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (rc != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rc, r, APLOGNO(02357)
|
|
Packit |
90a5c9 |
"Key not found in cache: %s", key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (buffer_len >= sobj->buffer_len) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rc, r, APLOGNO(02358)
|
|
Packit |
90a5c9 |
"Key found in cache but too big, ignoring: %s", key);
|
|
Packit |
90a5c9 |
goto fail;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (format != CACHE_SOCACHE_DISK_FORMAT_VERSION) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02359)
|
|
Packit |
90a5c9 |
"Key '%s' found in cache has version %d, expected %d, ignoring",
|
|
Packit |
90a5c9 |
key, format, CACHE_SOCACHE_DISK_FORMAT_VERSION);
|
|
Packit |
90a5c9 |
goto fail;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
nkey = key;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
obj->key = nkey;
|
|
Packit |
90a5c9 |
sobj->key = nkey;
|
|
Packit |
90a5c9 |
sobj->name = key;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (buffer_len >= sizeof(cache_socache_info_t)) {
|
|
Packit |
90a5c9 |
memcpy(&sobj->socache_info, sobj->buffer, sizeof(cache_socache_info_t));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, APLOGNO(02360)
|
|
Packit |
90a5c9 |
"Cache entry for key '%s' too short, removing", nkey);
|
|
Packit |
90a5c9 |
goto fail;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
slider = sizeof(cache_socache_info_t);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Store it away so we can get it later. */
|
|
Packit |
90a5c9 |
info->status = sobj->socache_info.status;
|
|
Packit |
90a5c9 |
info->date = sobj->socache_info.date;
|
|
Packit |
90a5c9 |
info->expire = sobj->socache_info.expire;
|
|
Packit |
90a5c9 |
info->request_time = sobj->socache_info.request_time;
|
|
Packit |
90a5c9 |
info->response_time = sobj->socache_info.response_time;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
memcpy(&info->control, &sobj->socache_info.control, sizeof(cache_control_t));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (sobj->socache_info.name_len <= buffer_len - slider) {
|
|
Packit |
90a5c9 |
if (strncmp((const char *) sobj->buffer + slider, sobj->name,
|
|
Packit |
90a5c9 |
sobj->socache_info.name_len)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, APLOGNO(02361)
|
|
Packit |
90a5c9 |
"Cache entry for key '%s' URL mismatch, ignoring", nkey);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
slider += sobj->socache_info.name_len;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, APLOGNO(02362)
|
|
Packit |
90a5c9 |
"Cache entry for key '%s' too short, removing", nkey);
|
|
Packit |
90a5c9 |
goto fail;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Is this a cached HEAD request? */
|
|
Packit |
90a5c9 |
if (sobj->socache_info.header_only && !r->header_only) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02363)
|
|
Packit |
90a5c9 |
"HEAD request cached, non-HEAD requested, ignoring: %s",
|
|
Packit |
90a5c9 |
sobj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
h->req_hdrs = apr_table_make(r->pool, 20);
|
|
Packit |
90a5c9 |
h->resp_hdrs = apr_table_make(r->pool, 20);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Call routine to read the header lines/status line */
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != read_table(h, r, h->resp_hdrs, sobj->buffer, buffer_len,
|
|
Packit |
90a5c9 |
&slider)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, APLOGNO(02364)
|
|
Packit |
90a5c9 |
"Cache entry for key '%s' response headers unreadable, removing", nkey);
|
|
Packit |
90a5c9 |
goto fail;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != read_table(h, r, h->req_hdrs, sobj->buffer, buffer_len,
|
|
Packit |
90a5c9 |
&slider)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, APLOGNO(02365)
|
|
Packit |
90a5c9 |
"Cache entry for key '%s' request headers unreadable, removing", nkey);
|
|
Packit |
90a5c9 |
goto fail;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Retrieve the body if we have one */
|
|
Packit |
90a5c9 |
sobj->body = apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
|
Packit |
90a5c9 |
len = buffer_len - slider;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*
|
|
Packit |
90a5c9 |
* Optimisation: if the body is small, we want to make a
|
|
Packit |
90a5c9 |
* copy of the body and free the temporary pool, as we
|
|
Packit |
90a5c9 |
* don't want large blocks of unused memory hanging around
|
|
Packit |
90a5c9 |
* to the end of the response. In contrast, if the body is
|
|
Packit |
90a5c9 |
* large, we would rather leave the body where it is in the
|
|
Packit |
90a5c9 |
* temporary pool, and save ourselves the copy.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
if (len * 2 > dconf->max) {
|
|
Packit |
90a5c9 |
apr_bucket *e;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* large - use the brigade as is, we're done */
|
|
Packit |
90a5c9 |
e = apr_bucket_immortal_create((const char *) sobj->buffer + slider,
|
|
Packit |
90a5c9 |
len, r->connection->bucket_alloc);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
APR_BRIGADE_INSERT_TAIL(sobj->body, e);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* small - make a copy of the data... */
|
|
Packit |
90a5c9 |
apr_brigade_write(sobj->body, NULL, NULL, (const char *) sobj->buffer
|
|
Packit |
90a5c9 |
+ slider, len);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* ...and get rid of the large memory buffer */
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* make the configuration stick */
|
|
Packit |
90a5c9 |
h->cache_obj = obj;
|
|
Packit |
90a5c9 |
obj->vobj = sobj;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
fail:
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
apr_status_t status = apr_global_mutex_lock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02366)
|
|
Packit |
90a5c9 |
"could not acquire lock, ignoring: %s", obj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
conf->provider->socache_provider->remove(
|
|
Packit |
90a5c9 |
conf->provider->socache_instance, r->server,
|
|
Packit |
90a5c9 |
(unsigned char *) nkey, strlen(nkey), r->pool);
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
apr_status_t status = apr_global_mutex_unlock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02367)
|
|
Packit |
90a5c9 |
"could not release lock, ignoring: %s", obj->key);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int remove_entity(cache_handle_t *h)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
/* Null out the cache object pointer so next time we start from scratch */
|
|
Packit |
90a5c9 |
h->cache_obj = NULL;
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int remove_url(cache_handle_t *h, request_rec *r)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_conf *conf = ap_get_module_config(r->server->module_config,
|
|
Packit |
90a5c9 |
&cache_socache_module);
|
|
Packit |
90a5c9 |
cache_socache_object_t *sobj;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
sobj = (cache_socache_object_t *) h->cache_obj->vobj;
|
|
Packit |
90a5c9 |
if (!sobj) {
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Remove the key from the cache */
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
apr_status_t status = apr_global_mutex_lock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02368)
|
|
Packit |
90a5c9 |
"could not acquire lock, ignoring: %s", sobj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
conf->provider->socache_provider->remove(conf->provider->socache_instance,
|
|
Packit |
90a5c9 |
r->server, (unsigned char *) sobj->key, strlen(sobj->key), r->pool);
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
apr_status_t status = apr_global_mutex_unlock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02369)
|
|
Packit |
90a5c9 |
"could not release lock, ignoring: %s", sobj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t recall_headers(cache_handle_t *h, request_rec *r)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
/* we recalled the headers during open_entity, so do nothing */
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t recall_body(cache_handle_t *h, apr_pool_t *p,
|
|
Packit |
90a5c9 |
apr_bucket_brigade *bb)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_object_t *sobj = (cache_socache_object_t*) h->cache_obj->vobj;
|
|
Packit |
90a5c9 |
apr_bucket *e;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
e = APR_BRIGADE_FIRST(sobj->body);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (e != APR_BRIGADE_SENTINEL(sobj->body)) {
|
|
Packit |
90a5c9 |
APR_BUCKET_REMOVE(e);
|
|
Packit |
90a5c9 |
APR_BRIGADE_INSERT_TAIL(bb, e);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t store_headers(cache_handle_t *h, request_rec *r,
|
|
Packit |
90a5c9 |
cache_info *info)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_dir_conf *dconf =
|
|
Packit |
90a5c9 |
ap_get_module_config(r->per_dir_config, &cache_socache_module);
|
|
Packit |
90a5c9 |
cache_socache_conf *conf = ap_get_module_config(r->server->module_config,
|
|
Packit |
90a5c9 |
&cache_socache_module);
|
|
Packit |
90a5c9 |
apr_size_t slider;
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
cache_object_t *obj = h->cache_obj;
|
|
Packit |
90a5c9 |
cache_socache_object_t *sobj = (cache_socache_object_t*) obj->vobj;
|
|
Packit |
90a5c9 |
cache_socache_info_t *socache_info;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
memcpy(&h->cache_obj->info, info, sizeof(cache_info));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (r->headers_out) {
|
|
Packit |
90a5c9 |
sobj->headers_out = ap_cache_cacheable_headers_out(r);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (r->headers_in) {
|
|
Packit |
90a5c9 |
sobj->headers_in = ap_cache_cacheable_headers_in(r);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
sobj->expire
|
|
Packit |
90a5c9 |
= obj->info.expire > r->request_time + dconf->maxtime ? r->request_time
|
|
Packit |
90a5c9 |
+ dconf->maxtime
|
|
Packit |
90a5c9 |
: obj->info.expire + dconf->mintime;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_pool_create(&sobj->pool, r->pool);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
sobj->buffer = apr_palloc(sobj->pool, dconf->max);
|
|
Packit |
90a5c9 |
sobj->buffer_len = dconf->max;
|
|
Packit |
90a5c9 |
socache_info = (cache_socache_info_t *) sobj->buffer;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (sobj->headers_out) {
|
|
Packit |
90a5c9 |
const char *vary;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
vary = apr_table_get(sobj->headers_out, "Vary");
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (vary) {
|
|
Packit |
90a5c9 |
apr_array_header_t* varray;
|
|
Packit |
90a5c9 |
apr_uint32_t format = CACHE_SOCACHE_VARY_FORMAT_VERSION;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
memcpy(sobj->buffer, &format, sizeof(format));
|
|
Packit |
90a5c9 |
slider = sizeof(format);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
memcpy(sobj->buffer + slider, &obj->info.expire,
|
|
Packit |
90a5c9 |
sizeof(obj->info.expire));
|
|
Packit |
90a5c9 |
slider += sizeof(obj->info.expire);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
varray = apr_array_make(r->pool, 6, sizeof(char*));
|
|
Packit |
90a5c9 |
tokens_to_array(r->pool, vary, varray);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != (rv = store_array(varray, sobj->buffer,
|
|
Packit |
90a5c9 |
sobj->buffer_len, &slider))) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02370)
|
|
Packit |
90a5c9 |
"buffer too small for Vary array, caching aborted: %s",
|
|
Packit |
90a5c9 |
obj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
apr_status_t status = apr_global_mutex_lock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02371)
|
|
Packit |
90a5c9 |
"could not acquire lock, ignoring: %s", obj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
rv = conf->provider->socache_provider->store(
|
|
Packit |
90a5c9 |
conf->provider->socache_instance, r->server,
|
|
Packit |
90a5c9 |
(unsigned char *) obj->key, strlen(obj->key), sobj->expire,
|
|
Packit |
90a5c9 |
(unsigned char *) sobj->buffer, (unsigned int) slider,
|
|
Packit |
90a5c9 |
sobj->pool);
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
apr_status_t status = apr_global_mutex_unlock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02372)
|
|
Packit |
90a5c9 |
"could not release lock, ignoring: %s", obj->key);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(02373)
|
|
Packit |
90a5c9 |
"Vary not written to cache, ignoring: %s", obj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
obj->key = sobj->key = regen_key(r->pool, sobj->headers_in, varray,
|
|
Packit |
90a5c9 |
sobj->name, NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
socache_info->format = CACHE_SOCACHE_DISK_FORMAT_VERSION;
|
|
Packit |
90a5c9 |
socache_info->date = obj->info.date;
|
|
Packit |
90a5c9 |
socache_info->expire = obj->info.expire;
|
|
Packit |
90a5c9 |
socache_info->entity_version = sobj->socache_info.entity_version++;
|
|
Packit |
90a5c9 |
socache_info->request_time = obj->info.request_time;
|
|
Packit |
90a5c9 |
socache_info->response_time = obj->info.response_time;
|
|
Packit |
90a5c9 |
socache_info->status = obj->info.status;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (r->header_only && r->status != HTTP_NOT_MODIFIED) {
|
|
Packit |
90a5c9 |
socache_info->header_only = 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
socache_info->header_only = sobj->socache_info.header_only;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
socache_info->name_len = strlen(sobj->name);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
memcpy(&socache_info->control, &obj->info.control, sizeof(cache_control_t));
|
|
Packit |
90a5c9 |
slider = sizeof(cache_socache_info_t);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (slider + socache_info->name_len >= sobj->buffer_len) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02374)
|
|
Packit |
90a5c9 |
"cache buffer too small for name: %s",
|
|
Packit |
90a5c9 |
sobj->name);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
memcpy(sobj->buffer + slider, sobj->name, socache_info->name_len);
|
|
Packit |
90a5c9 |
slider += socache_info->name_len;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (sobj->headers_out) {
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != store_table(sobj->headers_out, sobj->buffer,
|
|
Packit |
90a5c9 |
sobj->buffer_len, &slider)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02375)
|
|
Packit |
90a5c9 |
"out-headers didn't fit in buffer: %s", sobj->name);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Parse the vary header and dump those fields from the headers_in. */
|
|
Packit |
90a5c9 |
/* TODO: Make call to the same thing cache_select calls to crack Vary. */
|
|
Packit |
90a5c9 |
if (sobj->headers_in) {
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != store_table(sobj->headers_in, sobj->buffer,
|
|
Packit |
90a5c9 |
sobj->buffer_len, &slider)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02376)
|
|
Packit |
90a5c9 |
"in-headers didn't fit in buffer %s",
|
|
Packit |
90a5c9 |
sobj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
sobj->body_offset = slider;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t store_body(cache_handle_t *h, request_rec *r,
|
|
Packit |
90a5c9 |
apr_bucket_brigade *in, apr_bucket_brigade *out)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_bucket *e;
|
|
Packit |
90a5c9 |
apr_status_t rv = APR_SUCCESS;
|
|
Packit |
90a5c9 |
cache_socache_object_t *sobj =
|
|
Packit |
90a5c9 |
(cache_socache_object_t *) h->cache_obj->vobj;
|
|
Packit |
90a5c9 |
cache_socache_dir_conf *dconf =
|
|
Packit |
90a5c9 |
ap_get_module_config(r->per_dir_config, &cache_socache_module);
|
|
Packit |
90a5c9 |
int seen_eos = 0;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!sobj->offset) {
|
|
Packit |
90a5c9 |
sobj->offset = dconf->readsize;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (!sobj->timeout && dconf->readtime) {
|
|
Packit |
90a5c9 |
sobj->timeout = apr_time_now() + dconf->readtime;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!sobj->newbody) {
|
|
Packit |
90a5c9 |
sobj->body_length = 0;
|
|
Packit |
90a5c9 |
sobj->newbody = 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (sobj->offset) {
|
|
Packit |
90a5c9 |
apr_brigade_partition(in, sobj->offset, &e);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while (APR_SUCCESS == rv && !APR_BRIGADE_EMPTY(in)) {
|
|
Packit |
90a5c9 |
const char *str;
|
|
Packit |
90a5c9 |
apr_size_t length;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
e = APR_BRIGADE_FIRST(in);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* are we done completely? if so, pass any trailing buckets right through */
|
|
Packit |
90a5c9 |
if (sobj->done || !sobj->pool) {
|
|
Packit |
90a5c9 |
APR_BUCKET_REMOVE(e);
|
|
Packit |
90a5c9 |
APR_BRIGADE_INSERT_TAIL(out, e);
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* have we seen eos yet? */
|
|
Packit |
90a5c9 |
if (APR_BUCKET_IS_EOS(e)) {
|
|
Packit |
90a5c9 |
seen_eos = 1;
|
|
Packit |
90a5c9 |
sobj->done = 1;
|
|
Packit |
90a5c9 |
APR_BUCKET_REMOVE(e);
|
|
Packit |
90a5c9 |
APR_BRIGADE_INSERT_TAIL(out, e);
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* honour flush buckets, we'll get called again */
|
|
Packit |
90a5c9 |
if (APR_BUCKET_IS_FLUSH(e)) {
|
|
Packit |
90a5c9 |
APR_BUCKET_REMOVE(e);
|
|
Packit |
90a5c9 |
APR_BRIGADE_INSERT_TAIL(out, e);
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* metadata buckets are preserved as is */
|
|
Packit |
90a5c9 |
if (APR_BUCKET_IS_METADATA(e)) {
|
|
Packit |
90a5c9 |
APR_BUCKET_REMOVE(e);
|
|
Packit |
90a5c9 |
APR_BRIGADE_INSERT_TAIL(out, e);
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* read the bucket, write to the cache */
|
|
Packit |
90a5c9 |
rv = apr_bucket_read(e, &str, &length, APR_BLOCK_READ);
|
|
Packit |
90a5c9 |
APR_BUCKET_REMOVE(e);
|
|
Packit |
90a5c9 |
APR_BRIGADE_INSERT_TAIL(out, e);
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02377)
|
|
Packit |
90a5c9 |
"Error when reading bucket for URL %s",
|
|
Packit |
90a5c9 |
h->cache_obj->key);
|
|
Packit |
90a5c9 |
/* Remove the intermediate cache file and return non-APR_SUCCESS */
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* don't write empty buckets to the cache */
|
|
Packit |
90a5c9 |
if (!length) {
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
sobj->body_length += length;
|
|
Packit |
90a5c9 |
if (sobj->body_length >= sobj->buffer_len - sobj->body_offset) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02378)
|
|
Packit |
90a5c9 |
"URL %s failed the buffer size check "
|
|
Packit |
90a5c9 |
"(%" APR_OFF_T_FMT ">=%" APR_SIZE_T_FMT ")",
|
|
Packit |
90a5c9 |
h->cache_obj->key, sobj->body_length,
|
|
Packit |
90a5c9 |
sobj->buffer_len - sobj->body_offset);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
memcpy(sobj->buffer + sobj->body_offset + sobj->body_length - length,
|
|
Packit |
90a5c9 |
str, length);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* have we reached the limit of how much we're prepared to write in one
|
|
Packit |
90a5c9 |
* go? If so, leave, we'll get called again. This prevents us from trying
|
|
Packit |
90a5c9 |
* to swallow too much data at once, or taking so long to write the data
|
|
Packit |
90a5c9 |
* the client times out.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
sobj->offset -= length;
|
|
Packit |
90a5c9 |
if (sobj->offset <= 0) {
|
|
Packit |
90a5c9 |
sobj->offset = 0;
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if ((dconf->readtime && apr_time_now() > sobj->timeout)) {
|
|
Packit |
90a5c9 |
sobj->timeout = 0;
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Was this the final bucket? If yes, perform sanity checks.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
if (seen_eos) {
|
|
Packit |
90a5c9 |
const char *cl_header = apr_table_get(r->headers_out, "Content-Length");
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (r->connection->aborted || r->no_cache) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02380)
|
|
Packit |
90a5c9 |
"Discarding body for URL %s "
|
|
Packit |
90a5c9 |
"because connection has been aborted.",
|
|
Packit |
90a5c9 |
h->cache_obj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (cl_header) {
|
|
Packit |
90a5c9 |
apr_off_t cl;
|
|
Packit |
90a5c9 |
char *cl_endp;
|
|
Packit |
90a5c9 |
if (apr_strtoff(&cl, cl_header, &cl_endp, 10) != APR_SUCCESS
|
|
Packit |
90a5c9 |
|| *cl_endp != '\0' || cl != sobj->body_length) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02381)
|
|
Packit |
90a5c9 |
"URL %s didn't receive complete response, not caching",
|
|
Packit |
90a5c9 |
h->cache_obj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* All checks were fine, we're good to go when the commit comes */
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t commit_entity(cache_handle_t *h, request_rec *r)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_conf *conf = ap_get_module_config(r->server->module_config,
|
|
Packit |
90a5c9 |
&cache_socache_module);
|
|
Packit |
90a5c9 |
cache_object_t *obj = h->cache_obj;
|
|
Packit |
90a5c9 |
cache_socache_object_t *sobj = (cache_socache_object_t *) obj->vobj;
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
apr_status_t status = apr_global_mutex_lock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02384)
|
|
Packit |
90a5c9 |
"could not acquire lock, ignoring: %s", obj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
rv = conf->provider->socache_provider->store(
|
|
Packit |
90a5c9 |
conf->provider->socache_instance, r->server,
|
|
Packit |
90a5c9 |
(unsigned char *) sobj->key, strlen(sobj->key), sobj->expire,
|
|
Packit |
90a5c9 |
sobj->buffer, sobj->body_offset + sobj->body_length, sobj->pool);
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
apr_status_t status = apr_global_mutex_unlock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02385)
|
|
Packit |
90a5c9 |
"could not release lock, ignoring: %s", obj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, APLOGNO(02386)
|
|
Packit |
90a5c9 |
"could not write to cache, ignoring: %s", sobj->key);
|
|
Packit |
90a5c9 |
goto fail;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02387)
|
|
Packit |
90a5c9 |
"commit_entity: Headers and body for URL %s cached for maximum of %d seconds.",
|
|
Packit |
90a5c9 |
sobj->name, (apr_uint32_t)apr_time_sec(sobj->expire - r->request_time));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
fail:
|
|
Packit |
90a5c9 |
/* For safety, remove any existing entry on failure, just in case it could not
|
|
Packit |
90a5c9 |
* be revalidated successfully.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
apr_status_t status = apr_global_mutex_lock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02388)
|
|
Packit |
90a5c9 |
"could not acquire lock, ignoring: %s", obj->key);
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
conf->provider->socache_provider->remove(conf->provider->socache_instance,
|
|
Packit |
90a5c9 |
r->server, (unsigned char *) sobj->key, strlen(sobj->key), r->pool);
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
apr_status_t status = apr_global_mutex_unlock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02389)
|
|
Packit |
90a5c9 |
"could not release lock, ignoring: %s", obj->key);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_pool_destroy(sobj->pool);
|
|
Packit |
90a5c9 |
sobj->pool = NULL;
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t invalidate_entity(cache_handle_t *h, request_rec *r)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
/* mark the entity as invalidated */
|
|
Packit |
90a5c9 |
h->cache_obj->info.control.invalidated = 1;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return commit_entity(h, r);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *create_dir_config(apr_pool_t *p, char *dummy)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_dir_conf *dconf =
|
|
Packit |
90a5c9 |
apr_pcalloc(p, sizeof(cache_socache_dir_conf));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
dconf->max = DEFAULT_MAX_FILE_SIZE;
|
|
Packit |
90a5c9 |
dconf->maxtime = apr_time_from_sec(DEFAULT_MAXTIME);
|
|
Packit |
90a5c9 |
dconf->mintime = apr_time_from_sec(DEFAULT_MINTIME);
|
|
Packit |
90a5c9 |
dconf->readsize = DEFAULT_READSIZE;
|
|
Packit |
90a5c9 |
dconf->readtime = DEFAULT_READTIME;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return dconf;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *merge_dir_config(apr_pool_t *p, void *basev, void *addv)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_dir_conf
|
|
Packit |
90a5c9 |
*new =
|
|
Packit |
90a5c9 |
(cache_socache_dir_conf *) apr_pcalloc(p, sizeof(cache_socache_dir_conf));
|
|
Packit |
90a5c9 |
cache_socache_dir_conf *add = (cache_socache_dir_conf *) addv;
|
|
Packit |
90a5c9 |
cache_socache_dir_conf *base = (cache_socache_dir_conf *) basev;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
new->max = (add->max_set == 0) ? base->max : add->max;
|
|
Packit |
90a5c9 |
new->max_set = add->max_set || base->max_set;
|
|
Packit |
90a5c9 |
new->maxtime = (add->maxtime_set == 0) ? base->maxtime : add->maxtime;
|
|
Packit |
90a5c9 |
new->maxtime_set = add->maxtime_set || base->maxtime_set;
|
|
Packit |
90a5c9 |
new->mintime = (add->mintime_set == 0) ? base->mintime : add->mintime;
|
|
Packit |
90a5c9 |
new->mintime_set = add->mintime_set || base->mintime_set;
|
|
Packit |
90a5c9 |
new->readsize = (add->readsize_set == 0) ? base->readsize : add->readsize;
|
|
Packit |
90a5c9 |
new->readsize_set = add->readsize_set || base->readsize_set;
|
|
Packit |
90a5c9 |
new->readtime = (add->readtime_set == 0) ? base->readtime : add->readtime;
|
|
Packit |
90a5c9 |
new->readtime_set = add->readtime_set || base->readtime_set;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return new;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *create_config(apr_pool_t *p, server_rec *s)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_conf *conf = apr_pcalloc(p, sizeof(cache_socache_conf));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return conf;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *merge_config(apr_pool_t *p, void *basev, void *overridesv)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_conf *ps;
|
|
Packit |
90a5c9 |
cache_socache_conf *base = (cache_socache_conf *) basev;
|
|
Packit |
90a5c9 |
cache_socache_conf *overrides = (cache_socache_conf *) overridesv;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* socache server config only has one field */
|
|
Packit |
90a5c9 |
ps = overrides ? overrides : base;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return ps;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*
|
|
Packit |
90a5c9 |
* mod_cache_socache configuration directives handlers.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static const char *set_cache_socache(cmd_parms *cmd, void *in_struct_ptr,
|
|
Packit |
90a5c9 |
const char *arg)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_conf *conf = ap_get_module_config(cmd->server->module_config,
|
|
Packit |
90a5c9 |
&cache_socache_module);
|
|
Packit |
90a5c9 |
cache_socache_provider_conf *provider = conf->provider
|
|
Packit |
90a5c9 |
= apr_pcalloc(cmd->pool, sizeof(cache_socache_provider_conf));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
const char *err = NULL, *sep, *name;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Argument is of form 'name:args' or just 'name'. */
|
|
Packit |
90a5c9 |
sep = ap_strchr_c(arg, ':');
|
|
Packit |
90a5c9 |
if (sep) {
|
|
Packit |
90a5c9 |
name = apr_pstrmemdup(cmd->pool, arg, sep - arg);
|
|
Packit |
90a5c9 |
sep++;
|
|
Packit |
90a5c9 |
provider->args = sep;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
name = arg;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
provider->socache_provider = ap_lookup_provider(AP_SOCACHE_PROVIDER_GROUP,
|
|
Packit |
90a5c9 |
name, AP_SOCACHE_PROVIDER_VERSION);
|
|
Packit |
90a5c9 |
if (provider->socache_provider == NULL) {
|
|
Packit |
90a5c9 |
err = apr_psprintf(cmd->pool,
|
|
Packit |
90a5c9 |
"Unknown socache provider '%s'. Maybe you need "
|
|
Packit |
90a5c9 |
"to load the appropriate socache module "
|
|
Packit |
90a5c9 |
"(mod_socache_%s?)", name, name);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return err;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_cache_max(cmd_parms *parms, void *in_struct_ptr,
|
|
Packit |
90a5c9 |
const char *arg)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_dir_conf *dconf = (cache_socache_dir_conf *) in_struct_ptr;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (apr_strtoff(&dconf->max, arg, NULL, 10) != APR_SUCCESS
|
|
Packit |
90a5c9 |
|| dconf->max < 1024 || dconf->max > APR_UINT32_MAX) {
|
|
Packit |
90a5c9 |
return "CacheSocacheMaxSize argument must be a integer representing "
|
|
Packit |
90a5c9 |
"the max size of a cached entry (headers and body), at least 1024 "
|
|
Packit |
90a5c9 |
"and at most " APR_STRINGIFY(APR_UINT32_MAX);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
dconf->max_set = 1;
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_cache_maxtime(cmd_parms *parms, void *in_struct_ptr,
|
|
Packit |
90a5c9 |
const char *arg)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_dir_conf *dconf = (cache_socache_dir_conf *) in_struct_ptr;
|
|
Packit |
90a5c9 |
apr_off_t seconds;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (apr_strtoff(&seconds, arg, NULL, 10) != APR_SUCCESS || seconds < 0) {
|
|
Packit |
90a5c9 |
return "CacheSocacheMaxTime argument must be the maximum amount of time in seconds to cache an entry.";
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
dconf->maxtime = apr_time_from_sec(seconds);
|
|
Packit |
90a5c9 |
dconf->maxtime_set = 1;
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_cache_mintime(cmd_parms *parms, void *in_struct_ptr,
|
|
Packit |
90a5c9 |
const char *arg)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_dir_conf *dconf = (cache_socache_dir_conf *) in_struct_ptr;
|
|
Packit |
90a5c9 |
apr_off_t seconds;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (apr_strtoff(&seconds, arg, NULL, 10) != APR_SUCCESS || seconds < 0) {
|
|
Packit |
90a5c9 |
return "CacheSocacheMinTime argument must be the minimum amount of time in seconds to cache an entry.";
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
dconf->mintime = apr_time_from_sec(seconds);
|
|
Packit |
90a5c9 |
dconf->mintime_set = 1;
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_cache_readsize(cmd_parms *parms, void *in_struct_ptr,
|
|
Packit |
90a5c9 |
const char *arg)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_dir_conf *dconf = (cache_socache_dir_conf *) in_struct_ptr;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (apr_strtoff(&dconf->readsize, arg, NULL, 10) != APR_SUCCESS
|
|
Packit |
90a5c9 |
|| dconf->readsize < 0) {
|
|
Packit |
90a5c9 |
return "CacheSocacheReadSize argument must be a non-negative integer representing the max amount of data to cache in go.";
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
dconf->readsize_set = 1;
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_cache_readtime(cmd_parms *parms, void *in_struct_ptr,
|
|
Packit |
90a5c9 |
const char *arg)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
cache_socache_dir_conf *dconf = (cache_socache_dir_conf *) in_struct_ptr;
|
|
Packit |
90a5c9 |
apr_off_t milliseconds;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (apr_strtoff(&milliseconds, arg, NULL, 10) != APR_SUCCESS
|
|
Packit |
90a5c9 |
|| milliseconds < 0) {
|
|
Packit |
90a5c9 |
return "CacheSocacheReadTime argument must be a non-negative integer representing the max amount of time taken to cache in go.";
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
dconf->readtime = apr_time_from_msec(milliseconds);
|
|
Packit |
90a5c9 |
dconf->readtime_set = 1;
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t remove_lock(void *data)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
apr_global_mutex_destroy(socache_mutex);
|
|
Packit |
90a5c9 |
socache_mutex = NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t destroy_cache(void *data)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
server_rec *s = data;
|
|
Packit |
90a5c9 |
cache_socache_conf *conf =
|
|
Packit |
90a5c9 |
ap_get_module_config(s->module_config, &cache_socache_module);
|
|
Packit |
90a5c9 |
if (conf->provider && conf->provider->socache_instance) {
|
|
Packit |
90a5c9 |
conf->provider->socache_provider->destroy(
|
|
Packit |
90a5c9 |
conf->provider->socache_instance, s);
|
|
Packit |
90a5c9 |
conf->provider->socache_instance = NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int socache_status_hook(request_rec *r, int flags)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t status = APR_SUCCESS;
|
|
Packit |
90a5c9 |
cache_socache_conf *conf = ap_get_module_config(r->server->module_config,
|
|
Packit |
90a5c9 |
&cache_socache_module);
|
|
Packit |
90a5c9 |
if (!conf->provider || !conf->provider->socache_provider ||
|
|
Packit |
90a5c9 |
!conf->provider->socache_instance) {
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!(flags & AP_STATUS_SHORT)) {
|
|
Packit |
90a5c9 |
ap_rputs(" \n"
|
|
Packit |
90a5c9 |
"\n"
|
|
Packit |
90a5c9 |
"\n"
|
|
Packit |
90a5c9 |
"<font color=\"#ffffff\" face=\"Arial,Helvetica\">"
|
|
Packit |
90a5c9 |
"mod_cache_socache Status:</font>\n"
|
|
Packit |
90a5c9 |
"\n"
|
|
Packit |
90a5c9 |
"\n", r);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_rputs("ModCacheSocacheStatus\n", r);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (socache_mutex) {
|
|
Packit |
90a5c9 |
status = apr_global_mutex_lock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02816)
|
|
Packit |
90a5c9 |
"could not acquire lock for cache status");
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
if (!(flags & AP_STATUS_SHORT)) {
|
|
Packit |
90a5c9 |
ap_rputs("No cache status data available\n", r);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_rputs("NotAvailable\n", r);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
} else {
|
|
Packit |
90a5c9 |
conf->provider->socache_provider->status(conf->provider->socache_instance,
|
|
Packit |
90a5c9 |
r, flags);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (socache_mutex && status == APR_SUCCESS) {
|
|
Packit |
90a5c9 |
status = apr_global_mutex_unlock(socache_mutex);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02817)
|
|
Packit |
90a5c9 |
"could not release lock for cache status");
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!(flags & AP_STATUS_SHORT)) {
|
|
Packit |
90a5c9 |
ap_rputs("\n\n", r);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void socache_status_register(apr_pool_t *p)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
APR_OPTIONAL_HOOK(ap, status_hook, socache_status_hook, NULL, NULL, APR_HOOK_MIDDLE);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int socache_precfg(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptmp)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t rv = ap_mutex_register(pconf, cache_socache_id, NULL,
|
|
Packit |
90a5c9 |
APR_LOCK_DEFAULT, 0);
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, plog, APLOGNO(02390)
|
|
Packit |
90a5c9 |
"failed to register %s mutex", cache_socache_id);
|
|
Packit |
90a5c9 |
return 500; /* An HTTP status would be a misnomer! */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Register to handle mod_status status page generation */
|
|
Packit |
90a5c9 |
socache_status_register(pconf);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int socache_post_config(apr_pool_t *pconf, apr_pool_t *plog,
|
|
Packit |
90a5c9 |
apr_pool_t *ptmp, server_rec *base_server)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
server_rec *s;
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
const char *errmsg;
|
|
Packit |
90a5c9 |
static struct ap_socache_hints socache_hints =
|
|
Packit |
90a5c9 |
{ 64, 2048, 60000000 };
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (s = base_server; s; s = s->next) {
|
|
Packit |
90a5c9 |
cache_socache_conf *conf =
|
|
Packit |
90a5c9 |
ap_get_module_config(s->module_config, &cache_socache_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!conf->provider) {
|
|
Packit |
90a5c9 |
continue;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!socache_mutex && conf->provider->socache_provider->flags
|
|
Packit |
90a5c9 |
& AP_SOCACHE_FLAG_NOTMPSAFE) {
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = ap_global_mutex_create(&socache_mutex, NULL, cache_socache_id,
|
|
Packit |
90a5c9 |
NULL, s, pconf, 0);
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, plog, APLOGNO(02391)
|
|
Packit |
90a5c9 |
"failed to create %s mutex", cache_socache_id);
|
|
Packit |
90a5c9 |
return 500; /* An HTTP status would be a misnomer! */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
apr_pool_cleanup_register(pconf, NULL, remove_lock,
|
|
Packit |
90a5c9 |
apr_pool_cleanup_null);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
errmsg = conf->provider->socache_provider->create(
|
|
Packit |
90a5c9 |
&conf->provider->socache_instance, conf->provider->args, ptmp,
|
|
Packit |
90a5c9 |
pconf);
|
|
Packit |
90a5c9 |
if (errmsg) {
|
|
Packit |
90a5c9 |
ap_log_perror(APLOG_MARK, APLOG_CRIT, 0, plog,
|
|
Packit |
90a5c9 |
APLOGNO(02392) "%s", errmsg);
|
|
Packit |
90a5c9 |
return 500; /* An HTTP status would be a misnomer! */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = conf->provider->socache_provider->init(
|
|
Packit |
90a5c9 |
conf->provider->socache_instance, cache_socache_id,
|
|
Packit |
90a5c9 |
&socache_hints, s, pconf);
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, plog, APLOGNO(02393)
|
|
Packit |
90a5c9 |
"failed to initialise %s cache", cache_socache_id);
|
|
Packit |
90a5c9 |
return 500; /* An HTTP status would be a misnomer! */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
apr_pool_cleanup_register(pconf, (void *) s, destroy_cache,
|
|
Packit |
90a5c9 |
apr_pool_cleanup_null);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void socache_child_init(apr_pool_t *p, server_rec *s)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const char *lock;
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
if (!socache_mutex) {
|
|
Packit |
90a5c9 |
return; /* don't waste the overhead of creating mutex & cache */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
lock = apr_global_mutex_lockfile(socache_mutex);
|
|
Packit |
90a5c9 |
rv = apr_global_mutex_child_init(&socache_mutex, lock, p);
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(02394)
|
|
Packit |
90a5c9 |
"failed to initialise mutex in child_init");
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const command_rec cache_socache_cmds[] =
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("CacheSocache", set_cache_socache, NULL, RSRC_CONF,
|
|
Packit |
90a5c9 |
"The shared object cache to store cache files"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("CacheSocacheMaxTime", set_cache_maxtime, NULL, RSRC_CONF | ACCESS_CONF,
|
|
Packit |
90a5c9 |
"The maximum cache expiry age to cache a document in seconds"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("CacheSocacheMinTime", set_cache_mintime, NULL, RSRC_CONF | ACCESS_CONF,
|
|
Packit |
90a5c9 |
"The minimum cache expiry age to cache a document in seconds"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("CacheSocacheMaxSize", set_cache_max, NULL, RSRC_CONF | ACCESS_CONF,
|
|
Packit |
90a5c9 |
"The maximum cache entry size (headers and body) to cache a document"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("CacheSocacheReadSize", set_cache_readsize, NULL, RSRC_CONF | ACCESS_CONF,
|
|
Packit |
90a5c9 |
"The maximum quantity of data to attempt to read and cache in one go"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("CacheSocacheReadTime", set_cache_readtime, NULL, RSRC_CONF | ACCESS_CONF,
|
|
Packit |
90a5c9 |
"The maximum time taken to attempt to read and cache in go"),
|
|
Packit |
90a5c9 |
{ NULL }
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const cache_provider cache_socache_provider =
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
&remove_entity, &store_headers, &store_body, &recall_headers, &recall_body,
|
|
Packit |
90a5c9 |
&create_entity, &open_entity, &remove_url, &commit_entity,
|
|
Packit |
90a5c9 |
&invalidate_entity
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void cache_socache_register_hook(apr_pool_t *p)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
/* cache initializer */
|
|
Packit |
90a5c9 |
ap_register_provider(p, CACHE_PROVIDER_GROUP, "socache", "0",
|
|
Packit |
90a5c9 |
&cache_socache_provider);
|
|
Packit |
90a5c9 |
ap_hook_pre_config(socache_precfg, NULL, NULL, APR_HOOK_MIDDLE);
|
|
Packit |
90a5c9 |
ap_hook_post_config(socache_post_config, NULL, NULL, APR_HOOK_MIDDLE);
|
|
Packit |
90a5c9 |
ap_hook_child_init(socache_child_init, NULL, NULL, APR_HOOK_MIDDLE);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
AP_DECLARE_MODULE(cache_socache) = { STANDARD20_MODULE_STUFF,
|
|
Packit |
90a5c9 |
create_dir_config, /* create per-directory config structure */
|
|
Packit |
90a5c9 |
merge_dir_config, /* merge per-directory config structures */
|
|
Packit |
90a5c9 |
create_config, /* create per-server config structure */
|
|
Packit |
90a5c9 |
merge_config, /* merge per-server config structures */
|
|
Packit |
90a5c9 |
cache_socache_cmds, /* command apr_table_t */
|
|
Packit |
90a5c9 |
cache_socache_register_hook /* register hooks */
|
|
Packit |
90a5c9 |
};
|