Apache HTTPD
mod_cache_socache.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "apr_lib.h"
18#include "apr_file_io.h"
19#include "apr_strings.h"
20#include "apr_buckets.h"
21
22#include "apr_version.h"
23#if !APR_VERSION_AT_LEAST(2,0,0)
24#include "apu_version.h"
25#endif
26
27#include "httpd.h"
28#include "http_config.h"
29#include "http_log.h"
30#include "http_core.h"
31#include "http_protocol.h"
32#include "ap_provider.h"
33#include "ap_socache.h"
34#include "util_filter.h"
35#include "util_script.h"
36#include "util_charset.h"
37#include "util_mutex.h"
38
39#include "mod_cache.h"
40#include "mod_status.h"
41
43
44/*
45 * mod_cache_socache: Shared Object Cache Based HTTP 1.1 Cache.
46 *
47 * Flow to Find the entry:
48 * Incoming client requests URI /foo/bar/baz
49 * Fetch URI key (may contain Format #1 or Format #2)
50 * If format #1 (Contains a list of Vary Headers):
51 * Use each header name (from .header) with our request values (headers_in) to
52 * regenerate key using HeaderName+HeaderValue+.../foo/bar/baz
53 * re-read in key (must be format #2)
54 *
55 * Format #1:
56 * apr_uint32_t format;
57 * apr_time_t expire;
58 * apr_array_t vary_headers (delimited by CRLF)
59 *
60 * Format #2:
61 * cache_socache_info_t (first sizeof(apr_uint32_t) bytes is the format)
62 * entity name (sobj->name) [length is in cache_socache_info_t->name_len]
63 * r->headers_out (delimited by CRLF)
64 * CRLF
65 * r->headers_in (delimited by CRLF)
66 * CRLF
67 */
68
69module AP_MODULE_DECLARE_DATA cache_socache_module;
70
71/*
72 * cache_socache_object_t
73 * Pointed to by cache_object_t::vobj
74 */
76{
77 apr_pool_t *pool; /* pool */
78 unsigned char *buffer; /* the cache buffer */
79 apr_size_t buffer_len; /* size of the buffer */
80 apr_bucket_brigade *body; /* brigade containing the body, if any */
81 apr_table_t *headers_in; /* Input headers to save */
82 apr_table_t *headers_out; /* Output headers to save */
83 cache_socache_info_t socache_info; /* Header information. */
84 apr_size_t body_offset; /* offset to the start of the body */
85 apr_off_t body_length; /* length of the cached entity body */
86 apr_time_t expire; /* when to expire the entry */
87
88 const char *name; /* Requested URI without vary bits - suitable for mortals. */
89 const char *key; /* On-disk prefix; URI with Vary bits (if present) */
90 apr_off_t offset; /* Max size to set aside */
91 apr_time_t timeout; /* Max time to set aside */
92 unsigned int newbody :1; /* whether a new body is present */
93 unsigned int done :1; /* Is the attempt to cache complete? */
95
96/*
97 * mod_cache_socache configuration
98 */
99#define DEFAULT_MAX_FILE_SIZE 100*1024
100#define DEFAULT_MAXTIME 86400
101#define DEFAULT_MINTIME 600
102#define DEFAULT_READSIZE 0
103#define DEFAULT_READTIME 0
104
111
116
118{
119 apr_off_t max; /* maximum file size for cached files */
120 apr_time_t maxtime; /* maximum expiry time */
121 apr_time_t mintime; /* minimum expiry time */
122 apr_off_t readsize; /* maximum data to attempt to cache in one go */
123 apr_time_t readtime; /* maximum time taken to cache in one go */
124 unsigned int max_set :1;
125 unsigned int maxtime_set :1;
126 unsigned int mintime_set :1;
127 unsigned int readsize_set :1;
128 unsigned int readtime_set :1;
130
131/* Shared object cache and mutex */
132static const char * const cache_socache_id = "cache-socache";
134
135/*
136 * Local static functions
137 */
138
140 unsigned char *buffer, apr_size_t buffer_len, apr_size_t *slider)
141{
143
144 while (*slider < buffer_len) {
145 if (buffer[*slider] == '\r') {
146 if (val == *slider) {
147 (*slider)++;
148 return APR_SUCCESS;
149 }
150 *((const char **) apr_array_push(arr)) = apr_pstrndup(r->pool,
151 (const char *) buffer + val, *slider - val);
152 (*slider)++;
153 if (buffer[*slider] == '\n') {
154 (*slider)++;
155 }
156 val = *slider;
157 }
158 else if (buffer[*slider] == '\0') {
159 (*slider)++;
160 return APR_SUCCESS;
161 }
162 else {
163 (*slider)++;
164 }
165 }
166
167 return APR_EOF;
168}
169
171 apr_size_t buffer_len, apr_size_t *slider)
172{
173 int i, len;
174 const char **elts;
175
176 elts = (const char **) arr->elts;
177
178 for (i = 0; i < arr->nelts; i++) {
179 apr_size_t e_len = strlen(elts[i]);
180 if (e_len + 3 >= buffer_len - *slider) {
181 return APR_EOF;
182 }
183 len = apr_snprintf(buffer ? (char *) buffer + *slider : NULL,
184 buffer ? buffer_len - *slider : 0, "%s" CRLF, elts[i]);
185 *slider += len;
186 }
187 if (buffer) {
188 memcpy(buffer + *slider, CRLF, sizeof(CRLF) - 1);
189 }
190 *slider += sizeof(CRLF) - 1;
191
192 return APR_SUCCESS;
193}
194
196 apr_table_t *table, unsigned char *buffer, apr_size_t buffer_len,
198{
199 apr_size_t key = *slider, colon = 0, len = 0;
200
201 while (*slider < buffer_len) {
202 if (buffer[*slider] == ':') {
203 if (!colon) {
204 colon = *slider;
205 }
206 (*slider)++;
207 }
208 else if (buffer[*slider] == '\r') {
209 len = colon;
210 if (key == *slider) {
211 (*slider)++;
212 if (buffer[*slider] == '\n') {
213 (*slider)++;
214 }
215 return APR_SUCCESS;
216 }
217 if (!colon || buffer[colon++] != ':') {
219 "Premature end of cache headers.");
220 return APR_EGENERAL;
221 }
222 /* Do not go past the \r from above as apr_isspace('\r') is true */
223 while (apr_isspace(buffer[colon]) && (colon < *slider)) {
224 colon++;
225 }
226 apr_table_addn(table, apr_pstrmemdup(r->pool, (const char *) buffer
227 + key, len - key), apr_pstrmemdup(r->pool,
228 (const char *) buffer + colon, *slider - colon));
229 (*slider)++;
230 if (buffer[*slider] == '\n') {
231 (*slider)++;
232 }
233 key = *slider;
234 colon = 0;
235 }
236 else if (buffer[*slider] == '\0') {
237 (*slider)++;
238 return APR_SUCCESS;
239 }
240 else {
241 (*slider)++;
242 }
243 }
244
245 return APR_EOF;
246}
247
248static apr_status_t store_table(apr_table_t *table, unsigned char *buffer,
249 apr_size_t buffer_len, apr_size_t *slider)
250{
251 int i, len;
252 apr_table_entry_t *elts;
253
254 elts = (apr_table_entry_t *) apr_table_elts(table)->elts;
255 for (i = 0; i < apr_table_elts(table)->nelts; ++i) {
256 if (elts[i].key != NULL) {
257 apr_size_t key_len = strlen(elts[i].key);
258 apr_size_t val_len = strlen(elts[i].val);
259 if (key_len + val_len + 5 >= buffer_len - *slider) {
260 return APR_EOF;
261 }
262 len = apr_snprintf(buffer ? (char *) buffer + *slider : NULL,
263 buffer ? buffer_len - *slider : 0, "%s: %s" CRLF,
264 elts[i].key, elts[i].val);
265 *slider += len;
266 }
267 }
268 if (3 >= buffer_len - *slider) {
269 return APR_EOF;
270 }
271 if (buffer) {
272 memcpy(buffer + *slider, CRLF, sizeof(CRLF) - 1);
273 }
274 *slider += sizeof(CRLF) - 1;
275
276 return APR_SUCCESS;
277}
278
279static const char* regen_key(apr_pool_t *p, apr_table_t *headers,
280 apr_array_header_t *varray, const char *oldkey,
282{
283 struct iovec *iov;
284 int i, k;
285 int nvec;
286 const char *header;
287 const char **elts;
288
289 nvec = (varray->nelts * 2) + 1;
290 iov = apr_palloc(p, sizeof(struct iovec) * nvec);
291 elts = (const char **) varray->elts;
292
293 /* TODO:
294 * - Handle multiple-value headers better. (sort them?)
295 * - Handle Case in-sensitive Values better.
296 * This isn't the end of the world, since it just lowers the cache
297 * hit rate, but it would be nice to fix.
298 *
299 * The majority are case insenstive if they are values (encoding etc).
300 * Most of rfc2616 is case insensitive on header contents.
301 *
302 * So the better solution may be to identify headers which should be
303 * treated case-sensitive?
304 * HTTP URI's (3.2.3) [host and scheme are insensitive]
305 * HTTP method (5.1.1)
306 * HTTP-date values (3.3.1)
307 * 3.7 Media Types [excerpt]
308 * The type, subtype, and parameter attribute names are case-
309 * insensitive. Parameter values might or might not be case-sensitive,
310 * depending on the semantics of the parameter name.
311 * 4.20 Except [excerpt]
312 * Comparison of expectation values is case-insensitive for unquoted
313 * tokens (including the 100-continue token), and is case-sensitive for
314 * quoted-string expectation-extensions.
315 */
316
317 for (i = 0, k = 0; i < varray->nelts; i++) {
318 header = apr_table_get(headers, elts[i]);
319 if (!header) {
320 header = "";
321 }
322 iov[k].iov_base = (char*) elts[i];
323 iov[k].iov_len = strlen(elts[i]);
324 k++;
325 iov[k].iov_base = (char*) header;
326 iov[k].iov_len = strlen(header);
327 k++;
328 }
329 iov[k].iov_base = (char*) oldkey;
330 iov[k].iov_len = strlen(oldkey);
331 k++;
332
333 return apr_pstrcatv(p, iov, k, newkeylen);
334}
335
336static int array_alphasort(const void *fn1, const void *fn2)
337{
338 return strcmp(*(char**) fn1, *(char**) fn2);
339}
340
341static void tokens_to_array(apr_pool_t *p, const char *data,
343{
344 char *token;
345
346 while ((token = ap_get_list_item(p, &data)) != NULL) {
347 *((const char **) apr_array_push(arr)) = token;
348 }
349
350 /* Sort it so that "Vary: A, B" and "Vary: B, A" are stored the same. */
351 qsort((void *) arr->elts, arr->nelts, sizeof(char *), array_alphasort);
352}
353
354/*
355 * Hook and mod_cache callback functions
356 */
357static int create_entity(cache_handle_t *h, request_rec *r, const char *key,
359{
361 ap_get_module_config(r->per_dir_config, &cache_socache_module);
363 &cache_socache_module);
366 apr_size_t total;
367
368 if (conf->provider == NULL) {
369 return DECLINED;
370 }
371
372 /* we don't support caching of range requests (yet) */
373 /* TODO: but we could */
374 if (r->status == HTTP_PARTIAL_CONTENT) {
376 "URL %s partial content response not cached",
377 key);
378 return DECLINED;
379 }
380
381 /*
382 * We have a chicken and egg problem. We don't know until we
383 * attempt to store_headers just how big the response will be
384 * and whether it will fit in the cache limits set. But we
385 * need to make a decision now as to whether we plan to try.
386 * If we make the wrong decision, we could prevent another
387 * cache implementation, such as cache_disk, from getting the
388 * opportunity to cache, and that would be unfortunate.
389 *
390 * In a series of tests, from cheapest to most expensive,
391 * decide whether or not to ignore this attempt to cache,
392 * with a small margin just to be sure.
393 */
394 if (len < 0) {
396 "URL '%s' had no explicit size, ignoring", key);
397 return DECLINED;
398 }
399 if (len > dconf->max) {
401 "URL '%s' body larger than limit, ignoring "
402 "(%" APR_OFF_T_FMT " > %" APR_OFF_T_FMT ")",
403 key, len, dconf->max);
404 return DECLINED;
405 }
406
407 /* estimate the total cached size, given current headers */
408 total = len + sizeof(cache_socache_info_t) + strlen(key);
409 if (APR_SUCCESS != store_table(r->headers_out, NULL, dconf->max, &total)
410 || APR_SUCCESS != store_table(r->headers_in, NULL, dconf->max,
411 &total)) {
413 "URL '%s' estimated headers size larger than limit, ignoring "
414 "(%" APR_SIZE_T_FMT " > %" APR_OFF_T_FMT ")",
415 key, total, dconf->max);
416 return DECLINED;
417 }
418
419 if (total >= dconf->max) {
421 "URL '%s' body and headers larger than limit, ignoring "
422 "(%" APR_OFF_T_FMT " > %" APR_OFF_T_FMT ")",
423 key, len, dconf->max);
424 return DECLINED;
425 }
426
427 /* Allocate and initialize cache_object_t and cache_socache_object_t */
428 h->cache_obj = obj = apr_pcalloc(r->pool, sizeof(*obj));
429 obj->vobj = sobj = apr_pcalloc(r->pool, sizeof(*sobj));
430
431 obj->key = apr_pstrdup(r->pool, key);
432 sobj->key = obj->key;
433 sobj->name = obj->key;
434
435 return OK;
436}
437
439{
442 sobj->body = NULL;
443 return APR_SUCCESS;
444}
445
446static int open_entity(cache_handle_t *h, request_rec *r, const char *key)
447{
449 ap_get_module_config(r->per_dir_config, &cache_socache_module);
451 &cache_socache_module);
454 unsigned int buffer_len;
455 const char *nkey;
461
462 nkey = NULL;
463 h->cache_obj = NULL;
464
465 if (!conf->provider || !conf->provider->socache_instance) {
466 return DECLINED;
467 }
468
469 /* Create and init the cache object */
470 obj = apr_pcalloc(r->pool, sizeof(cache_object_t));
472
473 info = &(obj->info);
474
475 /* Create a temporary pool for the buffer, and destroy it if something
476 * goes wrong so we don't have large buffers of unused memory hanging
477 * about for the lifetime of the response.
478 */
479 apr_pool_create(&sobj->pool, r->pool);
480 apr_pool_tag(sobj->pool, "mod_cache_socache (open_entity)");
481
482 sobj->buffer = apr_palloc(sobj->pool, dconf->max);
483 sobj->buffer_len = dconf->max;
484
485 /* attempt to retrieve the cached entry */
486 if (socache_mutex) {
488 if (status != APR_SUCCESS) {
490 "could not acquire lock, ignoring: %s", obj->key);
491 apr_pool_destroy(sobj->pool);
492 sobj->pool = NULL;
493 return DECLINED;
494 }
495 }
496 buffer_len = sobj->buffer_len;
498 conf->provider->socache_instance, r->server, (unsigned char *) key,
499 strlen(key), sobj->buffer, &buffer_len, r->pool);
500 if (socache_mutex) {
502 if (status != APR_SUCCESS) {
504 "could not release lock, ignoring: %s", obj->key);
505 apr_pool_destroy(sobj->pool);
506 sobj->pool = NULL;
507 return DECLINED;
508 }
509 }
510 if (rc != APR_SUCCESS) {
512 "Key not found in cache: %s", key);
513 apr_pool_destroy(sobj->pool);
514 sobj->pool = NULL;
515 return DECLINED;
516 }
517 if (buffer_len >= sobj->buffer_len) {
519 "Key found in cache but too big, ignoring: %s", key);
520 apr_pool_destroy(sobj->pool);
521 sobj->pool = NULL;
522 return DECLINED;
523 }
524
525 /* read the format from the cache file */
526 memcpy(&format, sobj->buffer, sizeof(format));
527 slider = sizeof(format);
528
531 apr_time_t expire;
532
533 memcpy(&expire, sobj->buffer + slider, sizeof(expire));
534 slider += sizeof(expire);
535
536 varray = apr_array_make(r->pool, 5, sizeof(char*));
537 rc = read_array(r, varray, sobj->buffer, buffer_len, &slider);
538 if (rc != APR_SUCCESS) {
540 "Cannot parse vary entry for key: %s", key);
541 apr_pool_destroy(sobj->pool);
542 sobj->pool = NULL;
543 return DECLINED;
544 }
545
547
548 /* attempt to retrieve the cached entry */
549 if (socache_mutex) {
551 if (status != APR_SUCCESS) {
553 "could not acquire lock, ignoring: %s", obj->key);
554 apr_pool_destroy(sobj->pool);
555 sobj->pool = NULL;
556 return DECLINED;
557 }
558 }
559 buffer_len = sobj->buffer_len;
562 (unsigned char *) nkey, len, sobj->buffer,
563 &buffer_len, r->pool);
564 if (socache_mutex) {
566 if (status != APR_SUCCESS) {
568 "could not release lock, ignoring: %s", obj->key);
569 apr_pool_destroy(sobj->pool);
570 sobj->pool = NULL;
571 return DECLINED;
572 }
573 }
574 if (rc != APR_SUCCESS) {
576 "Key not found in cache: %s", key);
577 apr_pool_destroy(sobj->pool);
578 sobj->pool = NULL;
579 return DECLINED;
580 }
581 if (buffer_len >= sobj->buffer_len) {
583 "Key found in cache but too big, ignoring: %s", key);
584 goto fail;
585 }
586
587 }
590 "Key '%s' found in cache has version %d, expected %d, ignoring",
592 goto fail;
593 }
594 else {
595 nkey = key;
596 }
597
598 obj->key = nkey;
599 sobj->key = nkey;
600 sobj->name = key;
601
602 if (buffer_len >= sizeof(cache_socache_info_t)) {
603 memcpy(&sobj->socache_info, sobj->buffer, sizeof(cache_socache_info_t));
604 }
605 else {
607 "Cache entry for key '%s' too short, removing", nkey);
608 goto fail;
609 }
611
612 /* Store it away so we can get it later. */
613 info->status = sobj->socache_info.status;
614 info->date = sobj->socache_info.date;
615 info->expire = sobj->socache_info.expire;
616 info->request_time = sobj->socache_info.request_time;
617 info->response_time = sobj->socache_info.response_time;
618
619 memcpy(&info->control, &sobj->socache_info.control, sizeof(cache_control_t));
620
621 if (sobj->socache_info.name_len <= buffer_len - slider) {
622 if (strncmp((const char *) sobj->buffer + slider, sobj->name,
623 sobj->socache_info.name_len)) {
625 "Cache entry for key '%s' URL mismatch, ignoring", nkey);
626 apr_pool_destroy(sobj->pool);
627 sobj->pool = NULL;
628 return DECLINED;
629 }
630 slider += sobj->socache_info.name_len;
631 }
632 else {
634 "Cache entry for key '%s' too short, removing", nkey);
635 goto fail;
636 }
637
638 /* Is this a cached HEAD request? */
639 if (sobj->socache_info.header_only && !r->header_only) {
641 "HEAD request cached, non-HEAD requested, ignoring: %s",
642 sobj->key);
643 apr_pool_destroy(sobj->pool);
644 sobj->pool = NULL;
645 return DECLINED;
646 }
647
648 h->req_hdrs = apr_table_make(r->pool, 20);
649 h->resp_hdrs = apr_table_make(r->pool, 20);
650
651 /* Call routine to read the header lines/status line */
652 if (APR_SUCCESS != read_table(h, r, h->resp_hdrs, sobj->buffer, buffer_len,
653 &slider)) {
655 "Cache entry for key '%s' response headers unreadable, removing", nkey);
656 goto fail;
657 }
658 if (APR_SUCCESS != read_table(h, r, h->req_hdrs, sobj->buffer, buffer_len,
659 &slider)) {
661 "Cache entry for key '%s' request headers unreadable, removing", nkey);
662 goto fail;
663 }
664
665 /* Retrieve the body if we have one */
666 len = buffer_len - slider;
667 if (len > 0) {
668 apr_bucket *e;
669 /* Create the body brigade later concatenated to the output filters'
670 * brigade by recall_body(). Since sobj->buffer (the data) point to
671 * sobj->pool (a subpool of r->pool), be safe by using a pool bucket
672 * which can morph to heap if sobj->pool is destroyed while the bucket
673 * is still alive. But if sobj->pool gets destroyed while the bucket is
674 * still in sobj->body (i.e. recall_body() was never called), we don't
675 * need to morph to something just about to be freed, so a pre_cleanup
676 * will take care of cleaning up sobj->body before this happens (and is
677 * a noop otherwise).
678 */
681 e = apr_bucket_pool_create((const char *) sobj->buffer + slider, len,
682 sobj->pool, r->connection->bucket_alloc);
684 }
685
686 /* make the configuration stick */
687 h->cache_obj = obj;
688 obj->vobj = sobj;
689
690 return OK;
691
692fail:
693 if (socache_mutex) {
695 if (status != APR_SUCCESS) {
697 "could not acquire lock, ignoring: %s", obj->key);
698 apr_pool_destroy(sobj->pool);
699 sobj->pool = NULL;
700 return DECLINED;
701 }
702 }
705 (unsigned char *) nkey, strlen(nkey), r->pool);
706 if (socache_mutex) {
708 if (status != APR_SUCCESS) {
710 "could not release lock, ignoring: %s", obj->key);
711 }
712 }
713 apr_pool_destroy(sobj->pool);
714 sobj->pool = NULL;
715 return DECLINED;
716}
717
719{
720 /* Null out the cache object pointer so next time we start from scratch */
721 h->cache_obj = NULL;
722 return OK;
723}
724
726{
728 &cache_socache_module);
730
731 sobj = (cache_socache_object_t *) h->cache_obj->vobj;
732 if (!sobj) {
733 return DECLINED;
734 }
735
736 /* Remove the key from the cache */
737 if (socache_mutex) {
739 if (status != APR_SUCCESS) {
741 "could not acquire lock, ignoring: %s", sobj->key);
742 apr_pool_destroy(sobj->pool);
743 sobj->pool = NULL;
744 return DECLINED;
745 }
746 }
748 r->server, (unsigned char *) sobj->key, strlen(sobj->key), r->pool);
749 if (socache_mutex) {
751 if (status != APR_SUCCESS) {
753 "could not release lock, ignoring: %s", sobj->key);
754 apr_pool_destroy(sobj->pool);
755 sobj->pool = NULL;
756 return DECLINED;
757 }
758 }
759
760 return OK;
761}
762
764{
765 /* we recalled the headers during open_entity, so do nothing */
766 return APR_SUCCESS;
767}
768
771{
773
774 if (sobj->body) {
775 APR_BRIGADE_CONCAT(bb, sobj->body);
776 }
777
778 return APR_SUCCESS;
779}
780
783{
785 ap_get_module_config(r->per_dir_config, &cache_socache_module);
787 &cache_socache_module);
789 apr_status_t rv;
790 cache_object_t *obj = h->cache_obj;
792 cache_socache_info_t *socache_info;
793
794 memcpy(&h->cache_obj->info, info, sizeof(cache_info));
795
796 if (r->headers_out) {
797 sobj->headers_out = ap_cache_cacheable_headers_out(r);
798 }
799
800 if (r->headers_in) {
801 sobj->headers_in = ap_cache_cacheable_headers_in(r);
802 }
803
804 sobj->expire
805 = obj->info.expire > r->request_time + dconf->maxtime ? r->request_time
806 + dconf->maxtime
807 : obj->info.expire + dconf->mintime;
808
809 apr_pool_create(&sobj->pool, r->pool);
810 apr_pool_tag(sobj->pool, "mod_cache_socache (store_headers)");
811
812 sobj->buffer = apr_palloc(sobj->pool, dconf->max);
813 sobj->buffer_len = dconf->max;
814 socache_info = (cache_socache_info_t *) sobj->buffer;
815
816 if (sobj->headers_out) {
817 const char *vary;
818
819 vary = apr_table_get(sobj->headers_out, "Vary");
820
821 if (vary) {
824
825 memcpy(sobj->buffer, &format, sizeof(format));
826 slider = sizeof(format);
827
828 memcpy(sobj->buffer + slider, &obj->info.expire,
829 sizeof(obj->info.expire));
830 slider += sizeof(obj->info.expire);
831
832 varray = apr_array_make(r->pool, 6, sizeof(char*));
833 tokens_to_array(r->pool, vary, varray);
834
835 if (APR_SUCCESS != (rv = store_array(varray, sobj->buffer,
836 sobj->buffer_len, &slider))) {
838 "buffer too small for Vary array, caching aborted: %s",
839 obj->key);
840 apr_pool_destroy(sobj->pool);
841 sobj->pool = NULL;
842 return rv;
843 }
844 if (socache_mutex) {
846 if (status != APR_SUCCESS) {
848 "could not acquire lock, ignoring: %s", obj->key);
849 apr_pool_destroy(sobj->pool);
850 sobj->pool = NULL;
851 return status;
852 }
853 }
854 rv = conf->provider->socache_provider->store(
856 (unsigned char *) obj->key, strlen(obj->key), sobj->expire,
857 (unsigned char *) sobj->buffer, (unsigned int) slider,
858 sobj->pool);
859 if (socache_mutex) {
861 if (status != APR_SUCCESS) {
863 "could not release lock, ignoring: %s", obj->key);
864 }
865 }
866 if (rv != APR_SUCCESS) {
868 "Vary not written to cache, ignoring: %s", obj->key);
869 apr_pool_destroy(sobj->pool);
870 sobj->pool = NULL;
871 return rv;
872 }
873
874 obj->key = sobj->key = regen_key(r->pool, sobj->headers_in, varray,
875 sobj->name, NULL);
876 }
877 }
878
880 socache_info->date = obj->info.date;
881 socache_info->expire = obj->info.expire;
882 socache_info->entity_version = sobj->socache_info.entity_version++;
883 socache_info->request_time = obj->info.request_time;
884 socache_info->response_time = obj->info.response_time;
885 socache_info->status = obj->info.status;
886
887 if (r->header_only && r->status != HTTP_NOT_MODIFIED) {
888 socache_info->header_only = 1;
889 }
890 else {
891 socache_info->header_only = sobj->socache_info.header_only;
892 }
893
894 socache_info->name_len = strlen(sobj->name);
895
896 memcpy(&socache_info->control, &obj->info.control, sizeof(cache_control_t));
898
899 if (slider + socache_info->name_len >= sobj->buffer_len) {
901 "cache buffer too small for name: %s",
902 sobj->name);
903 apr_pool_destroy(sobj->pool);
904 sobj->pool = NULL;
905 return APR_EGENERAL;
906 }
907 memcpy(sobj->buffer + slider, sobj->name, socache_info->name_len);
908 slider += socache_info->name_len;
909
910 if (sobj->headers_out) {
911 if (APR_SUCCESS != store_table(sobj->headers_out, sobj->buffer,
912 sobj->buffer_len, &slider)) {
914 "out-headers didn't fit in buffer: %s", sobj->name);
915 apr_pool_destroy(sobj->pool);
916 sobj->pool = NULL;
917 return APR_EGENERAL;
918 }
919 }
920
921 /* Parse the vary header and dump those fields from the headers_in. */
922 /* TODO: Make call to the same thing cache_select calls to crack Vary. */
923 if (sobj->headers_in) {
924 if (APR_SUCCESS != store_table(sobj->headers_in, sobj->buffer,
925 sobj->buffer_len, &slider)) {
927 "in-headers didn't fit in buffer %s",
928 sobj->key);
929 apr_pool_destroy(sobj->pool);
930 sobj->pool = NULL;
931 return APR_EGENERAL;
932 }
933 }
934
935 sobj->body_offset = slider;
936
937 return APR_SUCCESS;
938}
939
942{
943 apr_bucket *e;
946 (cache_socache_object_t *) h->cache_obj->vobj;
948 ap_get_module_config(r->per_dir_config, &cache_socache_module);
949 int seen_eos = 0;
950
951 if (!sobj->offset) {
952 sobj->offset = dconf->readsize;
953 }
954 if (!sobj->timeout && dconf->readtime) {
955 sobj->timeout = apr_time_now() + dconf->readtime;
956 }
957
958 if (!sobj->newbody) {
959 sobj->body_length = 0;
960 sobj->newbody = 1;
961 }
962 if (sobj->offset) {
963 apr_brigade_partition(in, sobj->offset, &e);
964 }
965
966 while (APR_SUCCESS == rv && !APR_BRIGADE_EMPTY(in)) {
967 const char *str;
969
971
972 /* are we done completely? if so, pass any trailing buckets right through */
973 if (sobj->done || !sobj->pool) {
976 continue;
977 }
978
979 /* have we seen eos yet? */
980 if (APR_BUCKET_IS_EOS(e)) {
981 seen_eos = 1;
982 sobj->done = 1;
985 break;
986 }
987
988 /* honour flush buckets, we'll get called again */
989 if (APR_BUCKET_IS_FLUSH(e)) {
992 break;
993 }
994
995 /* metadata buckets are preserved as is */
999 continue;
1000 }
1001
1002 /* read the bucket, write to the cache */
1006 if (rv != APR_SUCCESS) {
1008 "Error when reading bucket for URL %s",
1009 h->cache_obj->key);
1010 /* Remove the intermediate cache file and return non-APR_SUCCESS */
1011 apr_pool_destroy(sobj->pool);
1012 sobj->pool = NULL;
1013 return rv;
1014 }
1015
1016 /* don't write empty buckets to the cache */
1017 if (!length) {
1018 continue;
1019 }
1020
1021 sobj->body_length += length;
1022 if (sobj->body_length >= sobj->buffer_len - sobj->body_offset) {
1024 "URL %s failed the buffer size check "
1025 "(%" APR_OFF_T_FMT ">=%" APR_SIZE_T_FMT ")",
1026 h->cache_obj->key, sobj->body_length,
1027 sobj->buffer_len - sobj->body_offset);
1028 apr_pool_destroy(sobj->pool);
1029 sobj->pool = NULL;
1030 return APR_EGENERAL;
1031 }
1032 memcpy(sobj->buffer + sobj->body_offset + sobj->body_length - length,
1033 str, length);
1034
1035 /* have we reached the limit of how much we're prepared to write in one
1036 * go? If so, leave, we'll get called again. This prevents us from trying
1037 * to swallow too much data at once, or taking so long to write the data
1038 * the client times out.
1039 */
1040 sobj->offset -= length;
1041 if (sobj->offset <= 0) {
1042 sobj->offset = 0;
1043 break;
1044 }
1045 if ((dconf->readtime && apr_time_now() > sobj->timeout)) {
1046 sobj->timeout = 0;
1047 break;
1048 }
1049
1050 }
1051
1052 /* Was this the final bucket? If yes, perform sanity checks.
1053 */
1054 if (seen_eos) {
1055 const char *cl_header;
1056 apr_off_t cl;
1057
1058 if (r->connection->aborted || r->no_cache) {
1060 "Discarding body for URL %s "
1061 "because connection has been aborted.",
1062 h->cache_obj->key);
1063 apr_pool_destroy(sobj->pool);
1064 sobj->pool = NULL;
1065 return APR_EGENERAL;
1066 }
1067
1068 cl_header = apr_table_get(r->headers_out, "Content-Length");
1070 || cl != sobj->body_length)) {
1072 "URL %s didn't receive complete response, not caching",
1073 h->cache_obj->key);
1074 apr_pool_destroy(sobj->pool);
1075 sobj->pool = NULL;
1076 return APR_EGENERAL;
1077 }
1078
1079 /* All checks were fine, we're good to go when the commit comes */
1080
1081 }
1082
1083 return APR_SUCCESS;
1084}
1085
1087{
1089 &cache_socache_module);
1090 cache_object_t *obj = h->cache_obj;
1092 apr_status_t rv;
1093
1094 if (socache_mutex) {
1096 if (status != APR_SUCCESS) {
1098 "could not acquire lock, ignoring: %s", obj->key);
1099 apr_pool_destroy(sobj->pool);
1100 sobj->pool = NULL;
1101 return status;
1102 }
1103 }
1104 rv = conf->provider->socache_provider->store(
1106 (unsigned char *) sobj->key, strlen(sobj->key), sobj->expire,
1107 sobj->buffer, sobj->body_offset + sobj->body_length, sobj->pool);
1108 if (socache_mutex) {
1110 if (status != APR_SUCCESS) {
1112 "could not release lock, ignoring: %s", obj->key);
1113 apr_pool_destroy(sobj->pool);
1114 sobj->pool = NULL;
1115 return status;
1116 }
1117 }
1118 if (rv != APR_SUCCESS) {
1120 "could not write to cache, ignoring: %s", sobj->key);
1121 goto fail;
1122 }
1123
1125 "commit_entity: Headers and body for URL %s cached for maximum of %d seconds.",
1126 sobj->name, (apr_uint32_t)apr_time_sec(sobj->expire - r->request_time));
1127
1128 apr_pool_destroy(sobj->pool);
1129 sobj->pool = NULL;
1130
1131 return APR_SUCCESS;
1132
1133fail:
1134 /* For safety, remove any existing entry on failure, just in case it could not
1135 * be revalidated successfully.
1136 */
1137 if (socache_mutex) {
1139 if (status != APR_SUCCESS) {
1141 "could not acquire lock, ignoring: %s", obj->key);
1142 apr_pool_destroy(sobj->pool);
1143 sobj->pool = NULL;
1144 return rv;
1145 }
1146 }
1148 r->server, (unsigned char *) sobj->key, strlen(sobj->key), r->pool);
1149 if (socache_mutex) {
1151 if (status != APR_SUCCESS) {
1153 "could not release lock, ignoring: %s", obj->key);
1154 }
1155 }
1156
1157 apr_pool_destroy(sobj->pool);
1158 sobj->pool = NULL;
1159 return rv;
1160}
1161
1163{
1164 /* mark the entity as invalidated */
1165 h->cache_obj->info.control.invalidated = 1;
1166
1167 return commit_entity(h, r);
1168}
1169
1171{
1172 cache_socache_dir_conf *dconf =
1174
1175 dconf->max = DEFAULT_MAX_FILE_SIZE;
1178 dconf->readsize = DEFAULT_READSIZE;
1179 dconf->readtime = DEFAULT_READTIME;
1180
1181 return dconf;
1182}
1183
1184static void *merge_dir_config(apr_pool_t *p, void *basev, void *addv)
1185{
1187 *new =
1191
1192 new->max = (add->max_set == 0) ? base->max : add->max;
1193 new->max_set = add->max_set || base->max_set;
1194 new->maxtime = (add->maxtime_set == 0) ? base->maxtime : add->maxtime;
1195 new->maxtime_set = add->maxtime_set || base->maxtime_set;
1196 new->mintime = (add->mintime_set == 0) ? base->mintime : add->mintime;
1197 new->mintime_set = add->mintime_set || base->mintime_set;
1198 new->readsize = (add->readsize_set == 0) ? base->readsize : add->readsize;
1199 new->readsize_set = add->readsize_set || base->readsize_set;
1200 new->readtime = (add->readtime_set == 0) ? base->readtime : add->readtime;
1201 new->readtime_set = add->readtime_set || base->readtime_set;
1202
1203 return new;
1204}
1205
1207{
1209
1210 return conf;
1211}
1212
1213static void *merge_config(apr_pool_t *p, void *basev, void *overridesv)
1214{
1218
1219 /* socache server config only has one field */
1220 ps = overrides ? overrides : base;
1221
1222 return ps;
1223}
1224
1225/*
1226 * mod_cache_socache configuration directives handlers.
1227 */
1229 const char *arg)
1230{
1231 cache_socache_conf *conf = ap_get_module_config(cmd->server->module_config,
1232 &cache_socache_module);
1233 cache_socache_provider_conf *provider = conf->provider
1235
1236 const char *err = NULL, *sep, *name;
1237
1238 /* Argument is of form 'name:args' or just 'name'. */
1239 sep = ap_strchr_c(arg, ':');
1240 if (sep) {
1241 name = apr_pstrmemdup(cmd->pool, arg, sep - arg);
1242 sep++;
1243 provider->args = sep;
1244 }
1245 else {
1246 name = arg;
1247 }
1248
1251 if (provider->socache_provider == NULL) {
1252 err = apr_psprintf(cmd->pool,
1253 "Unknown socache provider '%s'. Maybe you need "
1254 "to load the appropriate socache module "
1255 "(mod_socache_%s?)", name, name);
1256 }
1257 return err;
1258}
1259
1260static const char *set_cache_max(cmd_parms *parms, void *in_struct_ptr,
1261 const char *arg)
1262{
1264
1265 if (apr_strtoff(&dconf->max, arg, NULL, 10) != APR_SUCCESS
1266 || dconf->max < 1024 || dconf->max > APR_UINT32_MAX) {
1267 return "CacheSocacheMaxSize argument must be a integer representing "
1268 "the max size of a cached entry (headers and body), at least 1024 "
1269 "and at most " APR_STRINGIFY(APR_UINT32_MAX);
1270 }
1271 dconf->max_set = 1;
1272 return NULL;
1273}
1274
1276 const char *arg)
1277{
1280
1281 if (apr_strtoff(&seconds, arg, NULL, 10) != APR_SUCCESS || seconds < 0) {
1282 return "CacheSocacheMaxTime argument must be the maximum amount of time in seconds to cache an entry.";
1283 }
1285 dconf->maxtime_set = 1;
1286 return NULL;
1287}
1288
1290 const char *arg)
1291{
1294
1295 if (apr_strtoff(&seconds, arg, NULL, 10) != APR_SUCCESS || seconds < 0) {
1296 return "CacheSocacheMinTime argument must be the minimum amount of time in seconds to cache an entry.";
1297 }
1299 dconf->mintime_set = 1;
1300 return NULL;
1301}
1302
1304 const char *arg)
1305{
1307
1308 if (apr_strtoff(&dconf->readsize, arg, NULL, 10) != APR_SUCCESS
1309 || dconf->readsize < 0) {
1310 return "CacheSocacheReadSize argument must be a non-negative integer representing the max amount of data to cache in go.";
1311 }
1312 dconf->readsize_set = 1;
1313 return NULL;
1314}
1315
1317 const char *arg)
1318{
1321
1323 || milliseconds < 0) {
1324 return "CacheSocacheReadTime argument must be a non-negative integer representing the max amount of time taken to cache in go.";
1325 }
1327 dconf->readtime_set = 1;
1328 return NULL;
1329}
1330
1332{
1333 if (socache_mutex) {
1336 }
1337 return APR_SUCCESS;
1338}
1339
1341{
1342 server_rec *s = data;
1343 cache_socache_conf *conf =
1344 ap_get_module_config(s->module_config, &cache_socache_module);
1345 if (conf->provider && conf->provider->socache_instance) {
1347 conf->provider->socache_instance, s);
1349 }
1350 return APR_SUCCESS;
1351}
1352
1354{
1357 &cache_socache_module);
1358 if (!conf->provider || !conf->provider->socache_provider ||
1359 !conf->provider->socache_instance) {
1360 return DECLINED;
1361 }
1362
1363 if (!(flags & AP_STATUS_SHORT)) {
1364 ap_rputs("<hr>\n"
1365 "<table cellspacing=0 cellpadding=0>\n"
1366 "<tr><td bgcolor=\"#000000\">\n"
1367 "<b><font color=\"#ffffff\" face=\"Arial,Helvetica\">"
1368 "mod_cache_socache Status:</font></b>\n"
1369 "</td></tr>\n"
1370 "<tr><td bgcolor=\"#ffffff\">\n", r);
1371 }
1372 else {
1373 ap_rputs("ModCacheSocacheStatus\n", r);
1374 }
1375
1376 if (socache_mutex) {
1378 if (status != APR_SUCCESS) {
1380 "could not acquire lock for cache status");
1381 }
1382 }
1383
1384 if (status != APR_SUCCESS) {
1385 if (!(flags & AP_STATUS_SHORT)) {
1386 ap_rputs("No cache status data available\n", r);
1387 }
1388 else {
1389 ap_rputs("NotAvailable\n", r);
1390 }
1391 } else {
1393 r, flags);
1394 }
1395
1396 if (socache_mutex && status == APR_SUCCESS) {
1398 if (status != APR_SUCCESS) {
1400 "could not release lock for cache status");
1401 }
1402 }
1403
1404 if (!(flags & AP_STATUS_SHORT)) {
1405 ap_rputs("</td></tr>\n</table>\n", r);
1406 }
1407 return OK;
1408}
1409
1414
1416{
1418 APR_LOCK_DEFAULT, 0);
1419 if (rv != APR_SUCCESS) {
1421 "failed to register %s mutex", cache_socache_id);
1422 return 500; /* An HTTP status would be a misnomer! */
1423 }
1424
1425 /* Register to handle mod_status status page generation */
1427
1428 return OK;
1429}
1430
1432 apr_pool_t *ptmp, server_rec *base_server)
1433{
1434 server_rec *s;
1435 apr_status_t rv;
1436 const char *errmsg;
1437 static struct ap_socache_hints socache_hints =
1438 { 64, 2048, 60000000 };
1439
1440 for (s = base_server; s; s = s->next) {
1441 cache_socache_conf *conf =
1442 ap_get_module_config(s->module_config, &cache_socache_module);
1443
1444 if (!conf->provider) {
1445 continue;
1446 }
1447
1450
1452 NULL, s, pconf, 0);
1453 if (rv != APR_SUCCESS) {
1455 "failed to create %s mutex", cache_socache_id);
1456 return 500; /* An HTTP status would be a misnomer! */
1457 }
1460 }
1461
1462 errmsg = conf->provider->socache_provider->create(
1463 &conf->provider->socache_instance, conf->provider->args, ptmp,
1464 pconf);
1465 if (errmsg) {
1467 APLOGNO(02392) "%s", errmsg);
1468 return 500; /* An HTTP status would be a misnomer! */
1469 }
1470
1471 rv = conf->provider->socache_provider->init(
1473 &socache_hints, s, pconf);
1474 if (rv != APR_SUCCESS) {
1476 "failed to initialise %s cache", cache_socache_id);
1477 return 500; /* An HTTP status would be a misnomer! */
1478 }
1481
1482 }
1483
1484 return OK;
1485}
1486
1488{
1489 const char *lock;
1490 apr_status_t rv;
1491 if (!socache_mutex) {
1492 return; /* don't waste the overhead of creating mutex & cache */
1493 }
1496 if (rv != APR_SUCCESS) {
1498 "failed to initialise mutex in child_init");
1499 }
1500}
1501
1503{
1505 "The shared object cache to store cache files"),
1506 AP_INIT_TAKE1("CacheSocacheMaxTime", set_cache_maxtime, NULL, RSRC_CONF | ACCESS_CONF,
1507 "The maximum cache expiry age to cache a document in seconds"),
1508 AP_INIT_TAKE1("CacheSocacheMinTime", set_cache_mintime, NULL, RSRC_CONF | ACCESS_CONF,
1509 "The minimum cache expiry age to cache a document in seconds"),
1510 AP_INIT_TAKE1("CacheSocacheMaxSize", set_cache_max, NULL, RSRC_CONF | ACCESS_CONF,
1511 "The maximum cache entry size (headers and body) to cache a document"),
1512 AP_INIT_TAKE1("CacheSocacheReadSize", set_cache_readsize, NULL, RSRC_CONF | ACCESS_CONF,
1513 "The maximum quantity of data to attempt to read and cache in one go"),
1514 AP_INIT_TAKE1("CacheSocacheReadTime", set_cache_readtime, NULL, RSRC_CONF | ACCESS_CONF,
1515 "The maximum time taken to attempt to read and cache in go"),
1516 { NULL }
1517};
1518
1525
1535
1537 create_dir_config, /* create per-directory config structure */
1538 merge_dir_config, /* merge per-directory config structures */
1539 create_config, /* create per-server config structure */
1540 merge_config, /* merge per-server config structures */
1541 cache_socache_cmds, /* command apr_table_t */
1542 cache_socache_register_hook /* register hooks */
1543};
Apache Provider API.
const char apr_size_t len
Definition ap_regex.h:187
#define APR_STRINGIFY(n)
Definition ap_release.h:62
Small object cache provider interface.
APR-UTIL Buckets/Bucket Brigades.
APR File I/O Handling.
APR general purpose library routines.
APR Strings library.
APR Versioning Interface.
APR-util Versioning Interface.
static sem_id lock
Definition threadpriv.c:21
Common Shared Object Cache vars/structs.
static apr_pool_t * pconf
Definition event.c:441
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
#define ap_get_module_config(v, m)
void ap_hook_post_config(ap_HOOK_post_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:105
#define AP_DECLARE_MODULE(foo)
ap_conf_vector_t * base
void ap_hook_pre_config(ap_HOOK_pre_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:91
const char server_rec server_rec ** ps
request_rec * r
void ap_hook_child_init(ap_HOOK_child_init_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:167
#define DECLINED
Definition httpd.h:457
#define OK
Definition httpd.h:456
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_INFO
Definition http_log.h:70
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define ap_log_perror
Definition http_log.h:412
#define APLOG_WARNING
Definition http_log.h:68
#define APLOG_CRIT
Definition http_log.h:66
#define APLOG_DEBUG
Definition http_log.h:71
apr_status_t ap_global_mutex_create(apr_global_mutex_t **mutex, const char **name, const char *type, const char *instance_id, server_rec *server, apr_pool_t *pool, apr_int32_t options)
Definition util_mutex.c:407
apr_status_t ap_mutex_register(apr_pool_t *pconf, const char *type, const char *default_dir, apr_lockmech_e default_mech, apr_int32_t options)
Definition util_mutex.c:254
static APR_INLINE int ap_rputs(const char *str, request_rec *r)
apr_status_t ap_register_provider(apr_pool_t *pool, const char *provider_group, const char *provider_name, const char *provider_version, const void *provider)
Definition provider.c:35
void * ap_lookup_provider(const char *provider_group, const char *provider_name, const char *provider_version)
Definition provider.c:99
ap_vhost_iterate_conn_cb void * baton
Definition http_vhost.h:87
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
#define CRLF
Definition httpd.h:724
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_EOF
Definition apr_errno.h:461
#define APR_BUCKET_IS_FLUSH(e)
#define APR_BUCKET_REMOVE(e)
#define APR_BUCKET_IS_METADATA(e)
#define APR_BRIGADE_INSERT_TAIL(b, e)
apr_bucket * e
#define APR_BRIGADE_CONCAT(a, b)
#define APR_BRIGADE_EMPTY(b)
#define APR_BUCKET_IS_EOS(e)
#define APR_BRIGADE_FIRST(b)
#define apr_bucket_read(e, str, len, block)
int apr_off_t * length
@ APR_BLOCK_READ
Definition apr_buckets.h:58
apr_pool_t const char apr_dbd_t ** handle
Definition apr_dbd.h:142
const char apr_ssize_t int flags
Definition apr_encode.h:168
const void apr_size_t int colon
Definition apr_escape.h:355
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
#define APR_OPTIONAL_HOOK(ns, name, pfn, aszPre, aszSucc, nOrder)
apr_redis_t * rc
Definition apr_redis.h:173
#define AP_SOCACHE_PROVIDER_GROUP
Definition ap_socache.h:218
#define AP_SOCACHE_FLAG_NOTMPSAFE
Definition ap_socache.h:46
#define AP_SOCACHE_PROVIDER_VERSION
Definition ap_socache.h:220
#define CACHE_SOCACHE_VARY_FORMAT_VERSION
#define CACHE_SOCACHE_DISK_FORMAT_VERSION
#define ACCESS_CONF
#define RSRC_CONF
#define HTTP_NOT_MODIFIED
Definition httpd.h:504
#define HTTP_PARTIAL_CONTENT
Definition httpd.h:496
#define CACHE_PROVIDER_GROUP
Definition mod_cache.h:97
apr_table_t * ap_cache_cacheable_headers_in(request_rec *r)
apr_table_t * ap_cache_cacheable_headers_out(request_rec *r)
#define AP_STATUS_SHORT
Definition mod_status.h:32
#define STANDARD20_MODULE_STUFF
#define ap_strchr_c(s, c)
Definition httpd.h:2353
char * ap_get_list_item(apr_pool_t *p, const char **field)
Definition util.c:1314
int ap_parse_strict_length(apr_off_t *len, const char *str)
Definition util.c:2683
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
#define apr_isspace(c)
Definition apr_lib.h:225
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
const char * format
void * data
const struct iovec apr_size_t nvec
char * buffer
const apr_hash_t * h
Definition apr_hash.h:97
apr_vformatter_buff_t const char va_list ap
Definition apr_lib.h:176
#define apr_pool_create(newpool, parent)
Definition apr_pools.h:322
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
@ APR_LOCK_DEFAULT
const char * sep
const char * s
Definition apr_strings.h:95
const apr_array_header_t * arr
Definition apr_tables.h:187
apr_int32_t apr_int32_t apr_int32_t err
apr_int32_t in
apr_cmdtype_e cmd
int int status
#define apr_time_from_msec(msec)
Definition apr_time.h:75
apr_int64_t apr_time_t
Definition apr_time.h:45
#define apr_time_sec(time)
Definition apr_time.h:63
#define apr_time_from_sec(sec)
Definition apr_time.h:78
Apache Configuration.
CORE HTTP Daemon.
Apache Logging library.
HTTP protocol handling.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
#define fail(msg)
Definition minicheck.h:87
Main include file for the Apache Transparent Cache.
static void cache_socache_register_hook(apr_pool_t *p)
static apr_status_t remove_lock(void *data)
static apr_status_t recall_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb)
static const char *const cache_socache_id
#define DEFAULT_MAX_FILE_SIZE
#define DEFAULT_READSIZE
static int remove_entity(cache_handle_t *h)
static apr_status_t store_body(cache_handle_t *h, request_rec *r, apr_bucket_brigade *in, apr_bucket_brigade *out)
static void socache_status_register(apr_pool_t *p)
static apr_status_t commit_entity(cache_handle_t *h, request_rec *r)
static int socache_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptmp, server_rec *base_server)
static void * create_dir_config(apr_pool_t *p, char *dummy)
static int create_entity(cache_handle_t *h, request_rec *r, const char *key, apr_off_t len, apr_bucket_brigade *bb)
static const char * set_cache_maxtime(cmd_parms *parms, void *in_struct_ptr, const char *arg)
static int socache_status_hook(request_rec *r, int flags)
static apr_status_t store_table(apr_table_t *table, unsigned char *buffer, apr_size_t buffer_len, apr_size_t *slider)
static apr_status_t read_array(request_rec *r, apr_array_header_t *arr, unsigned char *buffer, apr_size_t buffer_len, apr_size_t *slider)
static int array_alphasort(const void *fn1, const void *fn2)
static apr_status_t destroy_cache(void *data)
static const char * set_cache_readsize(cmd_parms *parms, void *in_struct_ptr, const char *arg)
static void * merge_dir_config(apr_pool_t *p, void *basev, void *addv)
static apr_status_t invalidate_entity(cache_handle_t *h, request_rec *r)
static const command_rec cache_socache_cmds[]
static void * merge_config(apr_pool_t *p, void *basev, void *overridesv)
static const char * set_cache_mintime(cmd_parms *parms, void *in_struct_ptr, const char *arg)
static const char * set_cache_socache(cmd_parms *cmd, void *in_struct_ptr, const char *arg)
static void socache_child_init(apr_pool_t *p, server_rec *s)
static void tokens_to_array(apr_pool_t *p, const char *data, apr_array_header_t *arr)
static const char * set_cache_max(cmd_parms *parms, void *in_struct_ptr, const char *arg)
static void * create_config(apr_pool_t *p, server_rec *s)
static int open_entity(cache_handle_t *h, request_rec *r, const char *key)
static apr_global_mutex_t * socache_mutex
static int socache_precfg(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptmp)
static apr_status_t recall_headers(cache_handle_t *h, request_rec *r)
static apr_status_t store_headers(cache_handle_t *h, request_rec *r, cache_info *info)
#define DEFAULT_MINTIME
static const cache_provider cache_socache_provider
static const char * regen_key(apr_pool_t *p, apr_table_t *headers, apr_array_header_t *varray, const char *oldkey, apr_size_t *newkeylen)
static apr_status_t store_array(apr_array_header_t *arr, unsigned char *buffer, apr_size_t buffer_len, apr_size_t *slider)
#define DEFAULT_MAXTIME
static const char * set_cache_readtime(cmd_parms *parms, void *in_struct_ptr, const char *arg)
#define DEFAULT_READTIME
static apr_status_t sobj_body_pre_cleanup(void *baton)
static int remove_url(cache_handle_t *h, request_rec *r)
static apr_status_t read_table(cache_handle_t *handle, request_rec *r, apr_table_t *table, unsigned char *buffer, apr_size_t buffer_len, apr_size_t *slider)
static apr_file_t * out
Definition mod_info.c:85
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
Status Report Extension Module to Apache.
char * name
apr_status_t(* store)(ap_socache_instance_t *instance, server_rec *s, const unsigned char *id, unsigned int idlen, apr_time_t expiry, unsigned char *data, unsigned int datalen, apr_pool_t *pool)
Definition ap_socache.h:151
const char *(* create)(ap_socache_instance_t **instance, const char *arg, apr_pool_t *tmp, apr_pool_t *p)
Definition ap_socache.h:109
unsigned int flags
Definition ap_socache.h:94
void(* status)(ap_socache_instance_t *instance, request_rec *r, int flags)
Definition ap_socache.h:198
apr_status_t(* remove)(ap_socache_instance_t *instance, server_rec *s, const unsigned char *id, unsigned int idlen, apr_pool_t *pool)
Definition ap_socache.h:185
void(* destroy)(ap_socache_instance_t *instance, server_rec *s)
Definition ap_socache.h:137
apr_status_t(* init)(ap_socache_instance_t *instance, const char *cname, const struct ap_socache_hints *hints, server_rec *s, apr_pool_t *pool)
Definition ap_socache.h:128
apr_status_t(* retrieve)(ap_socache_instance_t *instance, server_rec *s, const unsigned char *id, unsigned int idlen, unsigned char *data, unsigned int *datalen, apr_pool_t *pool)
Definition ap_socache.h:171
Definition apr_tables.h:81
char * val
Definition apr_tables.h:87
char * key
Definition apr_tables.h:83
cache_socache_provider_conf * provider
cache_socache_info_t socache_info
apr_bucket_brigade * body
ap_socache_provider_t * socache_provider
ap_socache_instance_t * socache_instance
struct apr_bucket_alloc_t * bucket_alloc
Definition httpd.h:1201
unsigned aborted
Definition httpd.h:1219
A structure that represents the current request.
Definition httpd.h:845
int status
Definition httpd.h:891
int header_only
Definition httpd.h:875
apr_pool_t * pool
Definition httpd.h:847
apr_time_t request_time
Definition httpd.h:886
conn_rec * connection
Definition httpd.h:849
int no_cache
Definition httpd.h:1082
apr_table_t * headers_in
Definition httpd.h:976
server_rec * server
Definition httpd.h:851
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
apr_table_t * headers_out
Definition httpd.h:978
A structure to store information for each virtual server.
Definition httpd.h:1322
server_rec * next
Definition httpd.h:1326
struct ap_conf_vector_t * module_config
Definition httpd.h:1341
static apr_pool_t * ptmp
charset conversion
#define str
Apache filter library.
Apache Mutex support library.
Apache script tools.
INT info