]> granicus.if.org Git - apache/blob - modules/experimental/cache_util.c
91a8f62aeaedcbdf3ef84001af56cfac55934108
[apache] / modules / experimental / cache_util.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  *    if any, must include the following acknowledgment:
21  *       "This product includes software developed by the
22  *        Apache Software Foundation (http://www.apache.org/)."
23  *    Alternately, this acknowledgment may appear in the software itself,
24  *    if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Apache" and "Apache Software Foundation" must
27  *    not be used to endorse or promote products derived from this
28  *    software without prior written permission. For written
29  *    permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache",
32  *    nor may "Apache" appear in their name, without prior written
33  *    permission of the Apache Software Foundation.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation.  For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  *
54  * Portions of this software are based upon public domain software
55  * originally written at the National Center for Supercomputing Applications,
56  * University of Illinois, Urbana-Champaign.
57  */
58
59 #define CORE_PRIVATE
60
61 #include "mod_cache.h"
62
63
64
65 /* -------------------------------------------------------------- */
66
67 /* return true if the request is conditional */
68 CACHE_DECLARE(int) ap_cache_request_is_conditional(request_rec *r)
69 {
70     if (apr_table_get(r->headers_in, "If-Match") ||
71         apr_table_get(r->headers_in, "If-None-Match") ||
72         apr_table_get(r->headers_in, "If-Modified-Since") ||
73         apr_table_get(r->headers_in, "If-Unmodified-Since")) {
74
75         return 1;
76     }
77     return 0;
78 }
79
80
81 /* remove other filters from filter stack */
82 CACHE_DECLARE(void) ap_cache_reset_output_filters(request_rec *r)
83 {
84     ap_filter_t *f = r->output_filters;
85
86     while (f) {
87         if (!strcasecmp(f->frec->name, "CORE") ||
88             !strcasecmp(f->frec->name, "CONTENT_LENGTH") ||
89             !strcasecmp(f->frec->name, "HTTP_HEADER")) {
90             f = f->next;
91             continue;
92         }
93         else {
94             ap_remove_output_filter(f);
95             f = f->next;
96         }
97     }
98 }
99
100 CACHE_DECLARE(const char *)ap_cache_get_cachetype(request_rec *r, 
101                                                   cache_server_conf *conf, 
102                                                   const char *url)
103 {
104     const char *type = NULL;
105     int i;
106
107     /* loop through all the cacheenable entries */
108     for (i = 0; i < conf->cacheenable->nelts; i++) {
109         struct cache_enable *ent = 
110                                 (struct cache_enable *)conf->cacheenable->elts;
111         const char *thisurl = ent[i].url;
112         const char *thistype = ent[i].type;
113         if ((thisurl) && !strncasecmp(thisurl, url, strlen(thisurl))) {
114             if (!type) {
115                 type = thistype;
116             }
117             else {
118                 type = apr_pstrcat(r->pool, type, ",", thistype, NULL);
119             }
120         }
121     }
122
123     /* then loop through all the cachedisable entries */
124     for (i = 0; i < conf->cachedisable->nelts; i++) {
125         struct cache_disable *ent = 
126                                (struct cache_disable *)conf->cachedisable->elts;
127         const char *thisurl = ent[i].url;
128         if ((thisurl) && !strncasecmp(thisurl, url, strlen(thisurl))) {
129             type = NULL;
130         }
131     }
132
133     return type;
134 }
135
136 /*
137  * list is a comma-separated list of case-insensitive tokens, with
138  * optional whitespace around the tokens.
139  * The return returns 1 if the token val is found in the list, or 0
140  * otherwise.
141  */
142 CACHE_DECLARE(int) ap_cache_liststr(const char *list, const char *key, char **val)
143 {
144     int len, i;
145     char *p;
146     char valbuf[HUGE_STRING_LEN];
147     valbuf[sizeof(valbuf)-1] = 0; /* safety terminating zero */
148
149     len = strlen(key);
150
151     while (list != NULL) {
152         p = strchr((char *) list, ',');
153         if (p != NULL) {
154             i = p - list;
155             do
156             p++;
157             while (ap_isspace(*p));
158         }
159         else
160             i = strlen(list);
161
162         while (i > 0 && ap_isspace(list[i - 1]))
163             i--;
164         if (i == len && strncasecmp(list, key, len) == 0) {
165             if (val) {
166                 p = strchr((char *) list, ',');
167                 while (ap_isspace(*list)) {
168                     list++;
169                 }
170                 if ('=' == list[0])
171                     list++;
172                 while (ap_isspace(*list)) {
173                     list++;
174                 }
175                 strncpy(valbuf, list, MIN(p-list, sizeof(valbuf)-1));
176                 *val = valbuf;
177             }
178             return 1;
179         }
180         list = p;
181     }
182     return 0;
183 }
184
185 /* return each comma separated token, one at a time */
186 CACHE_DECLARE(const char *)ap_cache_tokstr(apr_pool_t *p, const char *list, const char **str)
187 {
188     apr_size_t i;
189     const char *s;
190
191     s = ap_strchr_c(list, ',');
192     if (s != NULL) {
193         i = s - list;
194         do
195             s++;
196         while (apr_isspace(*s))
197             ; /* noop */
198     }
199     else
200         i = strlen(list);
201
202     while (i > 0 && apr_isspace(list[i - 1]))
203         i--;
204
205     *str = s;
206     if (i)
207         return apr_pstrndup(p, list, i);
208     else
209         return NULL;
210 }
211
212 /*
213  * XXX TODO:
214  * These functions were lifted from mod_proxy
215  * Consider putting them in APR or some other common accessable
216  * location.
217  */
218 /*
219  * Converts apr_time_t hex digits to a time integer
220  */
221 CACHE_DECLARE(apr_time_t) ap_cache_hex2msec(const char *x)
222 {
223     int i, ch;
224     apr_time_t j;
225     for (i = 0, j = 0; i < sizeof(j) * 2; i++) {
226         ch = x[i];
227         j <<= 4;
228         if (apr_isdigit(ch))
229             j |= ch - '0';
230         else if (apr_isupper(ch))
231             j |= ch - ('A' - 10);
232         else
233             j |= ch - ('a' - 10);
234     }
235     return j;
236 }
237
238 /*
239  * Converts a time integer to apr_time_t hex digits
240  */
241 CACHE_DECLARE(void) ap_cache_msec2hex(apr_time_t j, char *y)
242 {
243     int i, ch;
244
245     for (i = (sizeof(j) * 2)-1; i >= 0; i--) {
246         ch = j & 0xF;
247         j >>= 4;
248         if (ch >= 10)
249             y[i] = ch + ('A' - 10);
250         else
251             y[i] = ch + '0';
252     }
253     y[sizeof(j) * 2] = '\0';
254 }
255
256 static void cache_hash(const char *it, char *val, int ndepth, int nlength)
257 {
258     apr_md5_ctx_t context;
259     unsigned char digest[16];
260     char tmp[22];
261     int i, k, d;
262     unsigned int x;
263     static const char enc_table[64] =
264     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@";
265
266     apr_md5_init(&context);
267     apr_md5_update(&context, (const unsigned char *) it, strlen(it));
268     apr_md5_final(digest, &context);
269
270     /* encode 128 bits as 22 characters, using a modified uuencoding 
271      * the encoding is 3 bytes -> 4 characters* i.e. 128 bits is 
272      * 5 x 3 bytes + 1 byte -> 5 * 4 characters + 2 characters
273      */
274     for (i = 0, k = 0; i < 15; i += 3) {
275         x = (digest[i] << 16) | (digest[i + 1] << 8) | digest[i + 2];
276         tmp[k++] = enc_table[x >> 18];
277         tmp[k++] = enc_table[(x >> 12) & 0x3f];
278         tmp[k++] = enc_table[(x >> 6) & 0x3f];
279         tmp[k++] = enc_table[x & 0x3f];
280     }
281
282     /* one byte left */
283     x = digest[15];
284     tmp[k++] = enc_table[x >> 2];    /* use up 6 bits */
285     tmp[k++] = enc_table[(x << 4) & 0x3f];
286
287     /* now split into directory levels */
288     for (i = k = d = 0; d < ndepth; ++d) {
289         memcpy(&val[i], &tmp[k], nlength);
290         k += nlength;
291         val[i + nlength] = '/';
292         i += nlength + 1;
293     }
294     memcpy(&val[i], &tmp[k], 22 - k);
295     val[i + 22 - k] = '\0';
296 }
297
298 CACHE_DECLARE(char *)generate_name(apr_pool_t *p, int dirlevels, int dirlength, const char *name)
299 {
300     char hashfile[66];
301     cache_hash(name, hashfile, dirlevels, dirlength);
302     return apr_pstrdup(p, hashfile);
303 }