Lines 115-120
Link Here
|
115 |
* ExpiresByType text/html "access plus 1 month 15 days 2 hours" |
115 |
* ExpiresByType text/html "access plus 1 month 15 days 2 hours" |
116 |
* ExpiresByType image/gif "modification plus 5 hours 3 minutes" |
116 |
* ExpiresByType image/gif "modification plus 5 hours 3 minutes" |
117 |
* |
117 |
* |
|
|
118 |
* Finally, there is a special form for differing expiration times based |
119 |
* on the age of the file, as in this example: |
120 |
* |
121 |
* ExpiresByType image/jpg "aged 2 days then 10 years else 1 hour" |
122 |
* |
123 |
* This means that JPG image files who last modification time was two days |
124 |
* ago or more, are served with an expires time 10 years from the current |
125 |
* access time, while those image files that are less than 2 days old are |
126 |
* served with an expire time 1 hour from the current access time. |
127 |
* |
128 |
* The form is "aged <timespan> then <timespan> [else <timespan>]" |
129 |
* |
130 |
* The "else...." clause can be omitted, which means that files newer than |
131 |
* the threshold time are not given an expires header. |
132 |
* |
133 |
* This form may also be used for ExpiresDefault. |
134 |
* |
118 |
* --- |
135 |
* --- |
119 |
* |
136 |
* |
120 |
* Change-log: |
137 |
* Change-log: |
Lines 139-144
Link Here
|
139 |
* the table_get check and then looking for an ExpiresDefault. |
156 |
* the table_get check and then looking for an ExpiresDefault. |
140 |
* [Rob Hartill] |
157 |
* [Rob Hartill] |
141 |
* 04.Nov.96 'const' definitions added. |
158 |
* 04.Nov.96 'const' definitions added. |
|
|
159 |
* 27.Mar.07 added the 'aged' form |
142 |
* |
160 |
* |
143 |
* TODO |
161 |
* TODO |
144 |
* add support for Cache-Control: max-age=20 from the HTTP/1.1 |
162 |
* add support for Cache-Control: max-age=20 from the HTTP/1.1 |
Lines 194-199
Link Here
|
194 |
return NULL; |
212 |
return NULL; |
195 |
} |
213 |
} |
196 |
|
214 |
|
|
|
215 |
static const char *parse_timespan(pool *p, char *word, const char **code, unsigned int *timespan, const char *end_at); |
216 |
|
217 |
|
197 |
/* check_code() parse 'code' and return NULL or an error response |
218 |
/* check_code() parse 'code' and return NULL or an error response |
198 |
* string. If we return NULL then real_code contains code converted |
219 |
* string. If we return NULL then real_code contains code converted |
199 |
* to the cnnnn format. |
220 |
* to the cnnnn format. |
Lines 203-210
Link Here
|
203 |
char *word; |
224 |
char *word; |
204 |
char base = 'X'; |
225 |
char base = 'X'; |
205 |
int modifier = 0; |
226 |
int modifier = 0; |
206 |
int num = 0; |
227 |
const char *error; |
207 |
int factor = 0; |
228 |
unsigned age; |
|
|
229 |
unsigned num1; |
230 |
unsigned num2; |
208 |
|
231 |
|
209 |
/* 0.0.4 compatibility? |
232 |
/* 0.0.4 compatibility? |
210 |
*/ |
233 |
*/ |
Lines 213-224
Link Here
|
213 |
return NULL; |
236 |
return NULL; |
214 |
}; |
237 |
}; |
215 |
|
238 |
|
216 |
/* <base> [plus] {<num> <type>}* |
239 |
word = ap_getword_conf(p, &code); |
217 |
*/ |
|
|
218 |
|
240 |
|
219 |
/* <base> |
241 |
/* aged {<num> <type>}+ then {<num> <type>}+ [else {<num> <type>}+ ] */ |
|
|
242 |
if (!strncasecmp(word, "aged", 4)) { |
243 |
error = parse_timespan(p, NULL, &code, &age, "then"); |
244 |
if (error) |
245 |
return error; |
246 |
|
247 |
error = parse_timespan(p, NULL, &code, &num1, "else"); |
248 |
if (error) |
249 |
return error; |
250 |
|
251 |
num2 = 0; |
252 |
if (*code) { |
253 |
error = parse_timespan(p, NULL, &code, &num2, NULL); |
254 |
if (error) |
255 |
return error; |
256 |
} |
257 |
*real_code = ap_psprintf(p, ">%010d %010d %010d", age, num1, num2); |
258 |
|
259 |
/* ap_log_error(APLOG_MARK, APLOG_NOERRNO, NULL, "result[%s]", *real_code); */ |
260 |
return NULL; |
261 |
} |
262 |
|
263 |
|
264 |
/* <base> [plus] {<num> <type>}* |
220 |
*/ |
265 |
*/ |
221 |
word = ap_getword_conf(p, &code); |
|
|
222 |
if (!strncasecmp(word, "now", 1) || |
266 |
if (!strncasecmp(word, "now", 1) || |
223 |
!strncasecmp(word, "access", 1)) { |
267 |
!strncasecmp(word, "access", 1)) { |
224 |
base = 'A'; |
268 |
base = 'A'; |
Lines 238-245
Link Here
|
238 |
word = ap_getword_conf(p, &code); |
282 |
word = ap_getword_conf(p, &code); |
239 |
}; |
283 |
}; |
240 |
|
284 |
|
241 |
/* {<num> <type>}* |
285 |
error = parse_timespan(p, word, &code, &modifier, NULL); |
242 |
*/ |
286 |
if (error) |
|
|
287 |
return error; |
288 |
|
289 |
*real_code = ap_psprintf(p, "%c%d", base, modifier); |
290 |
|
291 |
return NULL; |
292 |
} |
293 |
|
294 |
static const char *parse_timespan(pool *p, char *word, const char **code, unsigned int *timespan, const char *end_at) |
295 |
{ |
296 |
int num = 0; |
297 |
int factor = 0; |
298 |
|
299 |
*timespan = 0; |
300 |
|
301 |
if (!word) |
302 |
word = ap_getword_conf(p, code); |
303 |
|
243 |
while (word[0]) { |
304 |
while (word[0]) { |
244 |
/* <num> |
305 |
/* <num> |
245 |
*/ |
306 |
*/ |
Lines 247-265
Link Here
|
247 |
num = atoi(word); |
308 |
num = atoi(word); |
248 |
} |
309 |
} |
249 |
else { |
310 |
else { |
250 |
return ap_pstrcat(p, "bad expires code, numeric value expected <num> '", |
311 |
return ap_pstrcat(p, "bad expires code, numeric value expected <num>, got '", |
251 |
word, "'", NULL); |
312 |
word, "'", NULL); |
252 |
}; |
313 |
}; |
253 |
|
314 |
|
254 |
/* <type> |
315 |
/* <type> |
255 |
*/ |
316 |
*/ |
256 |
word = ap_getword_conf(p, &code); |
317 |
word = ap_getword_conf(p, code); |
257 |
if (word[0]) { |
318 |
if (!word[0]) |
258 |
/* do nothing */ |
|
|
259 |
} |
260 |
else { |
261 |
return ap_pstrcat(p, "bad expires code, missing <type>", NULL); |
319 |
return ap_pstrcat(p, "bad expires code, missing <type>", NULL); |
262 |
}; |
|
|
263 |
|
320 |
|
264 |
factor = 0; |
321 |
factor = 0; |
265 |
if (!strncasecmp(word, "years", 1)) { |
322 |
if (!strncasecmp(word, "years", 1)) { |
Lines 288-305
Link Here
|
288 |
"'", word, "'", NULL); |
345 |
"'", word, "'", NULL); |
289 |
}; |
346 |
}; |
290 |
|
347 |
|
291 |
modifier = modifier + factor * num; |
348 |
*timespan += factor * num; |
292 |
|
349 |
|
293 |
/* next <num> |
350 |
/* next <num> |
294 |
*/ |
351 |
*/ |
295 |
word = ap_getword_conf(p, &code); |
352 |
word = ap_getword_conf(p, code); |
296 |
}; |
|
|
297 |
|
353 |
|
298 |
*real_code = ap_psprintf(p, "%c%d", base, modifier); |
354 |
if (end_at && !strncasecmp(word, end_at, strlen(end_at))) |
299 |
|
355 |
return(NULL); |
300 |
return NULL; |
356 |
}; |
|
|
357 |
return(NULL); |
301 |
} |
358 |
} |
302 |
|
359 |
|
|
|
360 |
|
303 |
static const char *set_expiresbytype(cmd_parms *cmd, expires_dir_config * dir_config, char *mime, char *code) |
361 |
static const char *set_expiresbytype(cmd_parms *cmd, expires_dir_config * dir_config, char *mime, char *code) |
304 |
{ |
362 |
{ |
305 |
char *response, *real_code; |
363 |
char *response, *real_code; |
Lines 427-432
Link Here
|
427 |
base = r->request_time; |
485 |
base = r->request_time; |
428 |
additional = atoi(&code[1]); |
486 |
additional = atoi(&code[1]); |
429 |
break; |
487 |
break; |
|
|
488 |
case '>': |
489 |
if (r->finfo.st_mode == 0) { |
490 |
/* file doesn't exist on disk, so we can't do anything based on |
491 |
* modification time. Note that this does _not_ log an error. |
492 |
*/ |
493 |
return DECLINED; |
494 |
} |
495 |
|
496 |
/* code is of the form ">0031536000 0031536000 0000003600", where |
497 |
* all numbers are 10 digits long, the first number (starting at |
498 |
* code[1]) is the age threashold. If the file is at least that |
499 |
* many seconds old, the second number (starting at code[12]) is |
500 |
* used as "additional", while if the file is newer than that |
501 |
* threshold, the third number (starting at code[23]) is used as |
502 |
* "additional". */ |
503 |
|
504 |
if (r->request_time - r->finfo.st_mtime >= atoi(&code[1])) |
505 |
additional = atoi(&code[12]); |
506 |
else |
507 |
additional = atoi(&code[23]); |
508 |
|
509 |
/* ap_log_rerror(APLOG_MARK, APLOG_NOERRNO, r, "additional = %d", additional); */ |
510 |
|
511 |
if (additional == 0) |
512 |
return DECLINED; |
513 |
else |
514 |
base = r->request_time; |
515 |
break; |
516 |
|
430 |
default: |
517 |
default: |
431 |
/* expecting the add_* routines to be case-hardened this |
518 |
/* expecting the add_* routines to be case-hardened this |
432 |
* is just a reminder that module is beta |
519 |
* is just a reminder that module is beta |