Lines 37-49
Link Here
|
37 |
* re-read in <hash>.header (must be format #2) |
37 |
* re-read in <hash>.header (must be format #2) |
38 |
* read in <hash>.data |
38 |
* read in <hash>.data |
39 |
* |
39 |
* |
40 |
* Format #1: |
40 |
* Always first in the header file: |
41 |
* apr_uint32_t format; |
41 |
* disk_cache_format_t format; |
|
|
42 |
* |
43 |
* VARY_FORMAT_VERSION: |
42 |
* apr_time_t expire; |
44 |
* apr_time_t expire; |
43 |
* apr_array_t vary_headers (delimited by CRLF) |
45 |
* apr_array_t vary_headers (delimited by CRLF) |
44 |
* |
46 |
* |
45 |
* Format #2: |
47 |
* DISK_FORMAT_VERSION: |
46 |
* disk_cache_info_t (first sizeof(apr_uint32_t) bytes is the format) |
48 |
* disk_cache_info_t |
47 |
* entity name (dobj->name) [length is in disk_cache_info_t->name_len] |
49 |
* entity name (dobj->name) [length is in disk_cache_info_t->name_len] |
48 |
* r->headers_out (delimited by CRLF) |
50 |
* r->headers_out (delimited by CRLF) |
49 |
* CRLF |
51 |
* CRLF |
Lines 102-110
static char *data_file(apr_pool_t *p, di
Link Here
|
102 |
} |
104 |
} |
103 |
} |
105 |
} |
104 |
|
106 |
|
105 |
static void mkdir_structure(disk_cache_conf *conf, const char *file, apr_pool_t *pool) |
107 |
static apr_status_t mkdir_structure(disk_cache_conf *conf, const char *file, apr_pool_t *pool) |
106 |
{ |
108 |
{ |
107 |
apr_status_t rv; |
109 |
apr_status_t rv = APR_SUCCESS; |
108 |
char *p; |
110 |
char *p; |
109 |
|
111 |
|
110 |
for (p = (char*)file + conf->cache_root_len + 1;;) { |
112 |
for (p = (char*)file + conf->cache_root_len + 1;;) { |
Lines 115-126
static void mkdir_structure(disk_cache_c
Link Here
|
115 |
|
117 |
|
116 |
rv = apr_dir_make(file, |
118 |
rv = apr_dir_make(file, |
117 |
APR_UREAD|APR_UWRITE|APR_UEXECUTE, pool); |
119 |
APR_UREAD|APR_UWRITE|APR_UEXECUTE, pool); |
|
|
120 |
*p = '/'; |
118 |
if (rv != APR_SUCCESS && !APR_STATUS_IS_EEXIST(rv)) { |
121 |
if (rv != APR_SUCCESS && !APR_STATUS_IS_EEXIST(rv)) { |
119 |
/* XXX */ |
122 |
break; |
120 |
} |
123 |
} |
121 |
*p = '/'; |
|
|
122 |
++p; |
124 |
++p; |
123 |
} |
125 |
} |
|
|
126 |
if (rv != APR_SUCCESS && !APR_STATUS_IS_EEXIST(rv)) { |
127 |
return rv; |
128 |
} |
129 |
|
130 |
return APR_SUCCESS; |
124 |
} |
131 |
} |
125 |
|
132 |
|
126 |
/* htcacheclean may remove directories underneath us. |
133 |
/* htcacheclean may remove directories underneath us. |
Lines 150-190
static apr_status_t safe_file_rename(dis
Link Here
|
150 |
return rv; |
157 |
return rv; |
151 |
} |
158 |
} |
152 |
|
159 |
|
153 |
static apr_status_t file_cache_el_final(disk_cache_object_t *dobj, |
|
|
154 |
request_rec *r) |
155 |
{ |
156 |
/* move the data over */ |
157 |
if (dobj->tfd) { |
158 |
apr_status_t rv; |
159 |
|
160 |
rv = apr_file_close(dobj->tfd); |
161 |
dobj->tfd = NULL; |
162 |
|
163 |
if(rv != APR_SUCCESS) { |
164 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server, |
165 |
"disk_cache: closing tempfile failed: %s", |
166 |
dobj->tempfile); |
167 |
apr_file_remove(dobj->tempfile, r->pool); |
168 |
return rv; |
169 |
} |
170 |
|
171 |
/* This assumes that the tempfile is on the same file system |
172 |
* as the cache_root. If not, then we need a file copy/move |
173 |
* rather than a rename. |
174 |
*/ |
175 |
rv = apr_file_rename(dobj->tempfile, dobj->datafile, r->pool); |
176 |
if (rv != APR_SUCCESS) { |
177 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server, |
178 |
"disk_cache: rename tempfile to datafile failed:" |
179 |
" %s -> %s", dobj->tempfile, dobj->datafile); |
180 |
apr_file_remove(dobj->tempfile, r->pool); |
181 |
return rv; |
182 |
} |
183 |
} |
184 |
|
185 |
return APR_SUCCESS; |
186 |
} |
187 |
|
188 |
static apr_status_t file_cache_errorcleanup(disk_cache_object_t *dobj, request_rec *r) |
160 |
static apr_status_t file_cache_errorcleanup(disk_cache_object_t *dobj, request_rec *r) |
189 |
{ |
161 |
{ |
190 |
/* Remove the header file and the body file. */ |
162 |
/* Remove the header file and the body file. */ |
Lines 202-254
static apr_status_t file_cache_errorclea
Link Here
|
202 |
} |
174 |
} |
203 |
|
175 |
|
204 |
|
176 |
|
205 |
/* These two functions get and put state information into the data |
|
|
206 |
* file for an ap_cache_el, this state information will be read |
207 |
* and written transparent to clients of this module |
208 |
*/ |
209 |
static int file_cache_recall_mydata(apr_file_t *fd, cache_info *info, |
210 |
disk_cache_object_t *dobj, request_rec *r) |
211 |
{ |
212 |
apr_status_t rv; |
213 |
char *urlbuff; |
214 |
disk_cache_info_t disk_info; |
215 |
apr_size_t len; |
216 |
|
217 |
/* read the data from the cache file */ |
218 |
len = sizeof(disk_cache_info_t); |
219 |
rv = apr_file_read_full(fd, &disk_info, len, &len); |
220 |
if (rv != APR_SUCCESS) { |
221 |
return rv; |
222 |
} |
223 |
|
224 |
/* Store it away so we can get it later. */ |
225 |
dobj->disk_info = disk_info; |
226 |
|
227 |
info->status = disk_info.status; |
228 |
info->date = disk_info.date; |
229 |
info->expire = disk_info.expire; |
230 |
info->request_time = disk_info.request_time; |
231 |
info->response_time = disk_info.response_time; |
232 |
|
233 |
/* Note that we could optimize this by conditionally doing the palloc |
234 |
* depending upon the size. */ |
235 |
urlbuff = apr_palloc(r->pool, disk_info.name_len + 1); |
236 |
len = disk_info.name_len; |
237 |
rv = apr_file_read_full(fd, urlbuff, len, &len); |
238 |
if (rv != APR_SUCCESS) { |
239 |
return rv; |
240 |
} |
241 |
urlbuff[disk_info.name_len] = '\0'; |
242 |
|
243 |
/* check that we have the same URL */ |
244 |
/* Would strncmp be correct? */ |
245 |
if (strcmp(urlbuff, dobj->name) != 0) { |
246 |
return APR_EGENERAL; |
247 |
} |
248 |
|
249 |
return APR_SUCCESS; |
250 |
} |
251 |
|
252 |
static const char* regen_key(apr_pool_t *p, apr_table_t *headers, |
177 |
static const char* regen_key(apr_pool_t *p, apr_table_t *headers, |
253 |
apr_array_header_t *varray, const char *oldkey) |
178 |
apr_array_header_t *varray, const char *oldkey) |
254 |
{ |
179 |
{ |
Lines 368-437
static int create_entity(cache_handle_t
Link Here
|
368 |
dobj->datafile = data_file(r->pool, conf, dobj, key); |
293 |
dobj->datafile = data_file(r->pool, conf, dobj, key); |
369 |
dobj->hdrsfile = header_file(r->pool, conf, dobj, key); |
294 |
dobj->hdrsfile = header_file(r->pool, conf, dobj, key); |
370 |
dobj->tempfile = apr_pstrcat(r->pool, conf->cache_root, AP_TEMPFILE, NULL); |
295 |
dobj->tempfile = apr_pstrcat(r->pool, conf->cache_root, AP_TEMPFILE, NULL); |
|
|
296 |
dobj->initial_size = len; |
297 |
dobj->file_size = -1; |
298 |
dobj->updtimeout = conf->updtimeout; |
371 |
|
299 |
|
372 |
return OK; |
300 |
return OK; |
373 |
} |
301 |
} |
374 |
|
302 |
|
375 |
static int open_entity(cache_handle_t *h, request_rec *r, const char *key) |
303 |
|
|
|
304 |
static apr_status_t file_read_timeout(apr_file_t *file, char * buf, |
305 |
apr_size_t len, apr_time_t timeout) |
376 |
{ |
306 |
{ |
377 |
apr_uint32_t format; |
307 |
apr_size_t left, done; |
378 |
apr_size_t len; |
|
|
379 |
const char *nkey; |
380 |
apr_status_t rc; |
381 |
static int error_logged = 0; |
382 |
disk_cache_conf *conf = ap_get_module_config(r->server->module_config, |
383 |
&disk_cache_module); |
384 |
apr_finfo_t finfo; |
308 |
apr_finfo_t finfo; |
385 |
cache_object_t *obj; |
309 |
apr_status_t rc; |
386 |
cache_info *info; |
|
|
387 |
disk_cache_object_t *dobj; |
388 |
int flags; |
389 |
|
310 |
|
390 |
h->cache_obj = NULL; |
311 |
done = 0; |
|
|
312 |
left = len; |
391 |
|
313 |
|
392 |
/* Look up entity keyed to 'url' */ |
314 |
while(1) { |
393 |
if (conf->cache_root == NULL) { |
315 |
rc = apr_file_read_full(file, buf+done, left, &len); |
394 |
if (!error_logged) { |
316 |
if (rc == APR_SUCCESS) { |
395 |
error_logged = 1; |
317 |
break; |
396 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
|
|
397 |
"disk_cache: Cannot cache files to disk without a CacheRoot specified."); |
398 |
} |
318 |
} |
399 |
return DECLINED; |
319 |
done += len; |
400 |
} |
320 |
left -= len; |
401 |
|
321 |
|
402 |
/* Create and init the cache object */ |
322 |
if(!APR_STATUS_IS_EOF(rc)) { |
403 |
h->cache_obj = obj = apr_pcalloc(r->pool, sizeof(cache_object_t)); |
323 |
return rc; |
404 |
obj->vobj = dobj = apr_pcalloc(r->pool, sizeof(disk_cache_object_t)); |
324 |
} |
|
|
325 |
rc = apr_file_info_get(&finfo, APR_FINFO_MTIME, file); |
326 |
if(rc != APR_SUCCESS) { |
327 |
return rc; |
328 |
} |
329 |
if(finfo.mtime < (apr_time_now() - timeout) ) { |
330 |
return APR_ETIMEDOUT; |
331 |
} |
332 |
apr_sleep(CACHE_LOOP_SLEEP); |
333 |
} |
405 |
|
334 |
|
406 |
info = &(obj->info); |
335 |
return APR_SUCCESS; |
|
|
336 |
} |
407 |
|
337 |
|
408 |
/* Open the headers file */ |
|
|
409 |
dobj->prefix = NULL; |
410 |
|
338 |
|
411 |
/* Save the cache root */ |
339 |
static apr_status_t open_header(cache_handle_t *h, request_rec *r, |
412 |
dobj->root = apr_pstrndup(r->pool, conf->cache_root, conf->cache_root_len); |
340 |
const char *key, disk_cache_conf *conf) |
413 |
dobj->root_len = conf->cache_root_len; |
341 |
{ |
|
|
342 |
int flags; |
343 |
disk_cache_format_t format; |
344 |
apr_status_t rc; |
345 |
const char *nkey = key; |
346 |
disk_cache_info_t disk_info; |
347 |
cache_object_t *obj = h->cache_obj; |
348 |
disk_cache_object_t *dobj = obj->vobj; |
414 |
|
349 |
|
415 |
dobj->hdrsfile = header_file(r->pool, conf, dobj, key); |
|
|
416 |
flags = APR_READ|APR_BINARY|APR_BUFFERED; |
350 |
flags = APR_READ|APR_BINARY|APR_BUFFERED; |
|
|
351 |
|
417 |
rc = apr_file_open(&dobj->hfd, dobj->hdrsfile, flags, 0, r->pool); |
352 |
rc = apr_file_open(&dobj->hfd, dobj->hdrsfile, flags, 0, r->pool); |
418 |
if (rc != APR_SUCCESS) { |
353 |
if (rc != APR_SUCCESS) { |
419 |
return DECLINED; |
354 |
return CACHE_EDECLINED; |
420 |
} |
355 |
} |
421 |
|
356 |
|
422 |
/* read the format from the cache file */ |
357 |
/* read the format from the cache file */ |
423 |
len = sizeof(format); |
358 |
rc = apr_file_read_full(dobj->hfd, &format, sizeof(format), NULL); |
424 |
apr_file_read_full(dobj->hfd, &format, len, &len); |
359 |
if(APR_STATUS_IS_EOF(rc)) { |
|
|
360 |
return CACHE_ENODATA; |
361 |
} |
362 |
else if(rc != APR_SUCCESS) { |
363 |
return rc; |
364 |
} |
425 |
|
365 |
|
|
|
366 |
/* Vary-files are being written to tmpfile and moved in place, so |
367 |
the should always be complete */ |
426 |
if (format == VARY_FORMAT_VERSION) { |
368 |
if (format == VARY_FORMAT_VERSION) { |
427 |
apr_array_header_t* varray; |
369 |
apr_array_header_t* varray; |
428 |
apr_time_t expire; |
370 |
apr_time_t expire; |
429 |
|
371 |
|
430 |
len = sizeof(expire); |
372 |
rc = apr_file_read_full(dobj->hfd, &expire, sizeof(expire), NULL); |
431 |
apr_file_read_full(dobj->hfd, &expire, len, &len); |
373 |
if(rc != APR_SUCCESS) { |
|
|
374 |
return rc; |
375 |
} |
432 |
|
376 |
|
433 |
if (expire < r->request_time) { |
377 |
if (expire < r->request_time) { |
434 |
return DECLINED; |
378 |
return CACHE_EDECLINED; |
435 |
} |
379 |
} |
436 |
|
380 |
|
437 |
varray = apr_array_make(r->pool, 5, sizeof(char*)); |
381 |
varray = apr_array_make(r->pool, 5, sizeof(char*)); |
Lines 440-511
static int open_entity(cache_handle_t *h
Link Here
|
440 |
ap_log_error(APLOG_MARK, APLOG_ERR, rc, r->server, |
384 |
ap_log_error(APLOG_MARK, APLOG_ERR, rc, r->server, |
441 |
"disk_cache: Cannot parse vary header file: %s", |
385 |
"disk_cache: Cannot parse vary header file: %s", |
442 |
dobj->hdrsfile); |
386 |
dobj->hdrsfile); |
443 |
return DECLINED; |
387 |
return CACHE_EDECLINED; |
444 |
} |
388 |
} |
445 |
apr_file_close(dobj->hfd); |
389 |
apr_file_close(dobj->hfd); |
446 |
|
390 |
|
447 |
nkey = regen_key(r->pool, r->headers_in, varray, key); |
391 |
nkey = regen_key(r->pool, r->headers_in, varray, key); |
448 |
|
392 |
|
449 |
dobj->hashfile = NULL; |
|
|
450 |
dobj->prefix = dobj->hdrsfile; |
393 |
dobj->prefix = dobj->hdrsfile; |
451 |
dobj->hdrsfile = header_file(r->pool, conf, dobj, nkey); |
394 |
dobj->hdrsfile = data_file(r->pool, conf, dobj, nkey); |
452 |
|
395 |
|
453 |
flags = APR_READ|APR_BINARY|APR_BUFFERED; |
|
|
454 |
rc = apr_file_open(&dobj->hfd, dobj->hdrsfile, flags, 0, r->pool); |
396 |
rc = apr_file_open(&dobj->hfd, dobj->hdrsfile, flags, 0, r->pool); |
455 |
if (rc != APR_SUCCESS) { |
397 |
if (rc != APR_SUCCESS) { |
456 |
return DECLINED; |
398 |
dobj->hfd = NULL; |
|
|
399 |
return CACHE_EDECLINED; |
400 |
} |
401 |
rc = apr_file_read_full(dobj->hfd, &format, sizeof(format), NULL); |
402 |
if(APR_STATUS_IS_EOF(rc)) { |
403 |
return CACHE_ENODATA; |
404 |
} |
405 |
else if(rc != APR_SUCCESS) { |
406 |
return rc; |
457 |
} |
407 |
} |
458 |
} |
408 |
} |
459 |
else if (format != DISK_FORMAT_VERSION) { |
409 |
|
460 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
410 |
if(format != DISK_FORMAT_VERSION) { |
461 |
"disk_cache: File '%s' has a version mismatch. File had version: %d.", |
411 |
ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, |
462 |
dobj->hdrsfile, format); |
412 |
"disk_cache: File '%s' had a version mismatch. File had " |
463 |
return DECLINED; |
413 |
"version: %d (current is %d). Deleted.", dobj->hdrsfile, |
464 |
} |
414 |
format, DISK_FORMAT_VERSION); |
465 |
else { |
415 |
file_cache_errorcleanup(dobj, r); |
466 |
apr_off_t offset = 0; |
416 |
return CACHE_EDECLINED; |
467 |
/* This wasn't a Vary Format file, so we must seek to the |
|
|
468 |
* start of the file again, so that later reads work. |
469 |
*/ |
470 |
apr_file_seek(dobj->hfd, APR_SET, &offset); |
471 |
nkey = key; |
472 |
} |
417 |
} |
473 |
|
418 |
|
474 |
obj->key = nkey; |
419 |
obj->key = nkey; |
475 |
dobj->key = nkey; |
|
|
476 |
dobj->name = key; |
420 |
dobj->name = key; |
477 |
dobj->datafile = data_file(r->pool, conf, dobj, nkey); |
|
|
478 |
dobj->tempfile = apr_pstrcat(r->pool, conf->cache_root, AP_TEMPFILE, NULL); |
479 |
|
421 |
|
480 |
/* Open the data file */ |
422 |
/* read the data from the header file */ |
481 |
flags = APR_READ|APR_BINARY; |
423 |
rc = apr_file_read_full(dobj->hfd, &disk_info, sizeof(disk_info), NULL); |
482 |
#ifdef APR_SENDFILE_ENABLED |
424 |
if(APR_STATUS_IS_EOF(rc)) { |
483 |
flags |= APR_SENDFILE_ENABLED; |
425 |
return CACHE_ENODATA; |
484 |
#endif |
426 |
} |
485 |
rc = apr_file_open(&dobj->fd, dobj->datafile, flags, 0, r->pool); |
427 |
else if(rc != APR_SUCCESS) { |
486 |
if (rc != APR_SUCCESS) { |
428 |
return rc; |
487 |
/* XXX: Log message */ |
429 |
} |
|
|
430 |
|
431 |
/* Store it away so we can get it later. */ |
432 |
dobj->disk_info = disk_info; |
433 |
|
434 |
return APR_SUCCESS; |
435 |
} |
436 |
|
437 |
|
438 |
static apr_status_t open_header_timeout(cache_handle_t *h, request_rec *r, |
439 |
const char *key, disk_cache_conf *conf, |
440 |
disk_cache_object_t *dobj) |
441 |
{ |
442 |
apr_status_t rc; |
443 |
apr_finfo_t finfo; |
444 |
|
445 |
while(1) { |
446 |
if(dobj->hfd) { |
447 |
apr_file_close(dobj->hfd); |
448 |
} |
449 |
rc = open_header(h, r, key, conf); |
450 |
if(rc != APR_SUCCESS && rc != CACHE_ENODATA) { |
451 |
if(rc != CACHE_EDECLINED) { |
452 |
ap_log_error(APLOG_MARK, APLOG_ERR, rc, r->server, |
453 |
"disk_cache: Cannot load header file: %s", |
454 |
dobj->hdrsfile); |
455 |
} |
456 |
return rc; |
457 |
} |
458 |
|
459 |
/* Objects with unknown body size will have file_size == -1 until the |
460 |
entire body is written and the header updated with the actual size. |
461 |
And since we depend on knowing the body size we wait until the size |
462 |
is written */ |
463 |
if(rc == APR_SUCCESS && dobj->disk_info.file_size >= 0) { |
464 |
break; |
465 |
} |
466 |
rc = apr_file_info_get(&finfo, APR_FINFO_MTIME, dobj->hfd); |
467 |
if(rc != APR_SUCCESS) { |
468 |
return rc; |
469 |
} |
470 |
if(finfo.mtime < (apr_time_now() - dobj->updtimeout)) { |
471 |
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, |
472 |
"disk_cache: Timed out waiting for header for URL %s" |
473 |
" - caching the body failed?", key); |
474 |
return CACHE_EDECLINED; |
475 |
} |
476 |
apr_sleep(CACHE_LOOP_SLEEP); |
477 |
} |
478 |
|
479 |
return APR_SUCCESS; |
480 |
} |
481 |
|
482 |
|
483 |
static apr_status_t open_body_timeout(request_rec *r, const char *key, |
484 |
disk_cache_object_t *dobj) |
485 |
{ |
486 |
apr_off_t off; |
487 |
core_dir_config *pdconf = ap_get_module_config(r->per_dir_config, |
488 |
&core_module); |
489 |
apr_time_t starttime = apr_time_now(); |
490 |
int flags; |
491 |
apr_status_t rc; |
492 |
|
493 |
flags = APR_READ|APR_BINARY|APR_BUFFERED; |
494 |
#if APR_HAS_SENDFILE |
495 |
flags |= ((pdconf->enable_sendfile == ENABLE_SENDFILE_OFF) |
496 |
? 0 : APR_SENDFILE_ENABLED); |
497 |
#endif |
498 |
|
499 |
/* Wait here until we get a body cachefile, data in it, and do quick sanity |
500 |
* check */ |
501 |
|
502 |
while(1) { |
503 |
if(dobj->fd == NULL) { |
504 |
rc = apr_file_open(&dobj->fd, dobj->datafile, flags, 0, r->pool); |
505 |
if(rc != APR_SUCCESS) { |
506 |
if(starttime < (apr_time_now() - dobj->updtimeout) ) { |
507 |
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, |
508 |
"disk_cache: Timed out waiting for body for " |
509 |
"URL %s - caching failed?", key); |
510 |
return CACHE_EDECLINED; |
511 |
} |
512 |
apr_sleep(CACHE_LOOP_SLEEP); |
513 |
continue; |
514 |
} |
515 |
} |
516 |
|
517 |
dobj->file_size = 0; |
518 |
rc = apr_file_seek(dobj->fd, APR_END, &dobj->file_size); |
519 |
if(rc != APR_SUCCESS) { |
520 |
return rc; |
521 |
} |
522 |
|
523 |
if(dobj->initial_size < dobj->file_size) { |
524 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
525 |
"disk_cache: Bad cached body for URL %s, size %" |
526 |
APR_OFF_T_FMT " != %" APR_OFF_T_FMT, dobj->name, |
527 |
dobj->initial_size, dobj->file_size); |
528 |
file_cache_errorcleanup(dobj, r); |
529 |
return CACHE_EDECLINED; |
530 |
} |
531 |
else if(dobj->initial_size > dobj->file_size) { |
532 |
/* Still caching or failed? */ |
533 |
apr_finfo_t finfo; |
534 |
|
535 |
rc = apr_file_info_get(&finfo, APR_FINFO_MTIME, dobj->fd); |
536 |
if(rc != APR_SUCCESS || |
537 |
finfo.mtime < (apr_time_now() - dobj->updtimeout) ) |
538 |
{ |
539 |
ap_log_error(APLOG_MARK, APLOG_WARNING, rc, r->server, |
540 |
"disk_cache: Body for URL %s is too small - " |
541 |
"caching the body failed?", dobj->name); |
542 |
return CACHE_EDECLINED; |
543 |
} |
544 |
} |
545 |
if(dobj->file_size == dobj->initial_size) { |
546 |
break; |
547 |
} |
548 |
apr_sleep(CACHE_LOOP_SLEEP); |
549 |
} |
550 |
|
551 |
/* Go back to the beginning */ |
552 |
off = 0; |
553 |
rc = apr_file_seek(dobj->fd, APR_SET, &off); |
554 |
if(rc != APR_SUCCESS) { |
555 |
return rc; |
556 |
} |
557 |
|
558 |
return APR_SUCCESS; |
559 |
} |
560 |
|
561 |
|
562 |
static int open_entity(cache_handle_t *h, request_rec *r, const char *key) |
563 |
{ |
564 |
apr_status_t rc; |
565 |
disk_cache_object_t *dobj; |
566 |
cache_info *info; |
567 |
apr_size_t len; |
568 |
static int error_logged = 0; |
569 |
disk_cache_conf *conf = ap_get_module_config(r->server->module_config, |
570 |
&disk_cache_module); |
571 |
char urlbuff[MAX_STRING_LEN]; |
572 |
|
573 |
h->cache_obj = NULL; |
574 |
|
575 |
/* Look up entity keyed to 'url' */ |
576 |
if (conf->cache_root == NULL) { |
577 |
if (!error_logged) { |
578 |
error_logged = 1; |
579 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
580 |
"disk_cache: Cannot cache files to disk without a " |
581 |
"CacheRoot specified."); |
582 |
} |
488 |
return DECLINED; |
583 |
return DECLINED; |
489 |
} |
584 |
} |
490 |
|
585 |
|
491 |
rc = apr_file_info_get(&finfo, APR_FINFO_SIZE, dobj->fd); |
586 |
/* Create and init the cache object */ |
492 |
if (rc == APR_SUCCESS) { |
587 |
h->cache_obj = apr_pcalloc(r->pool, sizeof(cache_object_t)); |
493 |
dobj->file_size = finfo.size; |
588 |
h->cache_obj->vobj = dobj = apr_pcalloc(r->pool, sizeof(disk_cache_object_t)); |
|
|
589 |
info = &(h->cache_obj->info); |
590 |
|
591 |
/* Save the cache root */ |
592 |
dobj->root = apr_pstrndup(r->pool, conf->cache_root, conf->cache_root_len); |
593 |
dobj->root_len = conf->cache_root_len; |
594 |
|
595 |
dobj->hdrsfile = header_file(r->pool, conf, dobj, key); |
596 |
|
597 |
dobj->updtimeout = conf->updtimeout; |
598 |
|
599 |
/* Open header and read basic info, wait until header contains |
600 |
valid size information for the body */ |
601 |
rc = open_header_timeout(h, r, key, conf, dobj); |
602 |
if(rc != APR_SUCCESS) { |
603 |
return DECLINED; |
494 |
} |
604 |
} |
495 |
|
605 |
|
496 |
/* Read the bytes to setup the cache_info fields */ |
606 |
info->status = dobj->disk_info.status; |
497 |
rc = file_cache_recall_mydata(dobj->hfd, info, dobj, r); |
607 |
info->date = dobj->disk_info.date; |
498 |
if (rc != APR_SUCCESS) { |
608 |
info->expire = dobj->disk_info.expire; |
499 |
/* XXX log message */ |
609 |
info->request_time = dobj->disk_info.request_time; |
|
|
610 |
info->response_time = dobj->disk_info.response_time; |
611 |
|
612 |
dobj->initial_size = (apr_off_t) dobj->disk_info.file_size; |
613 |
dobj->tempfile = apr_pstrcat(r->pool, conf->cache_root, AP_TEMPFILE, NULL); |
614 |
|
615 |
len = dobj->disk_info.name_len; |
616 |
|
617 |
if(len > 0) { |
618 |
rc = file_read_timeout(dobj->hfd, urlbuff, len, dobj->updtimeout); |
619 |
if (rc == APR_ETIMEDOUT) { |
620 |
ap_log_error(APLOG_MARK, APLOG_WARNING, rc, r->server, |
621 |
"disk_cache: Timed out waiting for urlbuff for " |
622 |
"URL %s - caching failed?", key); |
623 |
return DECLINED; |
624 |
} |
625 |
else if(rc != APR_SUCCESS) { |
626 |
ap_log_error(APLOG_MARK, APLOG_WARNING, rc, r->server, |
627 |
"disk_cache: Error reading urlbuff for URL %s", |
628 |
key); |
629 |
return DECLINED; |
630 |
} |
631 |
} |
632 |
urlbuff[len] = '\0'; |
633 |
|
634 |
/* check that we have the same URL */ |
635 |
if (strcmp(urlbuff, dobj->name) != 0) { |
636 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
637 |
"disk_cache: Cached URL %s didn't match requested " |
638 |
"URL %s", urlbuff, dobj->name); |
500 |
return DECLINED; |
639 |
return DECLINED; |
501 |
} |
640 |
} |
502 |
|
641 |
|
503 |
/* Initialize the cache_handle callback functions */ |
642 |
dobj->datafile = data_file(r->pool, conf, dobj, h->cache_obj->key); |
|
|
643 |
dobj->tempfile = apr_pstrcat(r->pool, conf->cache_root, AP_TEMPFILE, NULL); |
644 |
|
645 |
/* Only need body cachefile if we have a body */ |
646 |
if(dobj->initial_size > 0) { |
647 |
rc = open_body_timeout(r, key, dobj); |
648 |
if(rc != APR_SUCCESS) { |
649 |
return DECLINED; |
650 |
} |
651 |
} |
652 |
else { |
653 |
dobj->file_size = 0; |
654 |
} |
655 |
|
504 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
656 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
505 |
"disk_cache: Recalled cached URL info header %s", dobj->name); |
657 |
"disk_cache: Recalled status for cached URL %s", dobj->name); |
506 |
return OK; |
658 |
return OK; |
507 |
} |
659 |
} |
508 |
|
660 |
|
|
|
661 |
|
509 |
static int remove_entity(cache_handle_t *h) |
662 |
static int remove_entity(cache_handle_t *h) |
510 |
{ |
663 |
{ |
511 |
/* Null out the cache object pointer so next time we start from scratch */ |
664 |
/* Null out the cache object pointer so next time we start from scratch */ |
Lines 666-672
static apr_status_t store_array(apr_file
Link Here
|
666 |
&amt); |
819 |
&amt); |
667 |
} |
820 |
} |
668 |
|
821 |
|
669 |
static apr_status_t read_table(cache_handle_t *handle, request_rec *r, |
822 |
static apr_status_t read_table(request_rec *r, |
670 |
apr_table_t *table, apr_file_t *file) |
823 |
apr_table_t *table, apr_file_t *file) |
671 |
{ |
824 |
{ |
672 |
char w[MAX_STRING_LEN]; |
825 |
char w[MAX_STRING_LEN]; |
Lines 679-686
static apr_status_t read_table(cache_han
Link Here
|
679 |
/* ### What about APR_EOF? */ |
832 |
/* ### What about APR_EOF? */ |
680 |
rv = apr_file_gets(w, MAX_STRING_LEN - 1, file); |
833 |
rv = apr_file_gets(w, MAX_STRING_LEN - 1, file); |
681 |
if (rv != APR_SUCCESS) { |
834 |
if (rv != APR_SUCCESS) { |
682 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
|
|
683 |
"Premature end of cache headers."); |
684 |
return rv; |
835 |
return rv; |
685 |
} |
836 |
} |
686 |
|
837 |
|
Lines 723-729
static apr_status_t read_table(cache_han
Link Here
|
723 |
} |
874 |
} |
724 |
if (maybeASCII > maybeEBCDIC) { |
875 |
if (maybeASCII > maybeEBCDIC) { |
725 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
876 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
726 |
"CGI Interface Error: Script headers apparently ASCII: (CGI = %s)", |
877 |
"disk_cache: CGI Interface Error: Script headers apparently ASCII: (CGI = %s)", |
727 |
r->filename); |
878 |
r->filename); |
728 |
inbytes_left = outbytes_left = cp - w; |
879 |
inbytes_left = outbytes_left = cp - w; |
729 |
apr_xlate_conv_buffer(ap_hdrs_from_ascii, |
880 |
apr_xlate_conv_buffer(ap_hdrs_from_ascii, |
Lines 748-753
static apr_status_t read_table(cache_han
Link Here
|
748 |
return APR_SUCCESS; |
899 |
return APR_SUCCESS; |
749 |
} |
900 |
} |
750 |
|
901 |
|
|
|
902 |
|
903 |
static apr_status_t read_table_timeout(cache_handle_t *handle, request_rec *r, |
904 |
apr_table_t **table, apr_file_t *file, |
905 |
apr_time_t timeout) |
906 |
{ |
907 |
apr_off_t off; |
908 |
apr_finfo_t finfo; |
909 |
apr_status_t rv; |
910 |
|
911 |
off = 0; |
912 |
rv = apr_file_seek(file, APR_CUR, &off); |
913 |
if(rv != APR_SUCCESS) { |
914 |
return rv; |
915 |
} |
916 |
|
917 |
while(1) { |
918 |
*table = apr_table_make(r->pool, 20); |
919 |
rv = read_table(r, *table, file); |
920 |
if(rv == APR_SUCCESS) { |
921 |
break; |
922 |
} |
923 |
apr_table_clear(*table); |
924 |
|
925 |
rv = apr_file_seek(file, APR_SET, &off); |
926 |
if(rv != APR_SUCCESS) { |
927 |
return rv; |
928 |
} |
929 |
|
930 |
rv = apr_file_info_get(&finfo, APR_FINFO_MTIME, file); |
931 |
if(rv != APR_SUCCESS || |
932 |
finfo.mtime < (apr_time_now() - timeout) ) |
933 |
{ |
934 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
935 |
"disk_cache: Timed out waiting for cache headers " |
936 |
"URL %s", handle->cache_obj->key); |
937 |
return APR_EGENERAL; |
938 |
} |
939 |
apr_sleep(CACHE_LOOP_SLEEP); |
940 |
} |
941 |
|
942 |
return APR_SUCCESS; |
943 |
} |
944 |
|
945 |
|
751 |
/* |
946 |
/* |
752 |
* Reads headers from a buffer and returns an array of headers. |
947 |
* Reads headers from a buffer and returns an array of headers. |
753 |
* Returns NULL on file error |
948 |
* Returns NULL on file error |
Lines 758-763
static apr_status_t read_table(cache_han
Link Here
|
758 |
static apr_status_t recall_headers(cache_handle_t *h, request_rec *r) |
953 |
static apr_status_t recall_headers(cache_handle_t *h, request_rec *r) |
759 |
{ |
954 |
{ |
760 |
disk_cache_object_t *dobj = (disk_cache_object_t *) h->cache_obj->vobj; |
955 |
disk_cache_object_t *dobj = (disk_cache_object_t *) h->cache_obj->vobj; |
|
|
956 |
apr_status_t rv; |
761 |
|
957 |
|
762 |
/* This case should not happen... */ |
958 |
/* This case should not happen... */ |
763 |
if (!dobj->hfd) { |
959 |
if (!dobj->hfd) { |
Lines 765-776
static apr_status_t recall_headers(cache
Link Here
|
765 |
return APR_NOTFOUND; |
961 |
return APR_NOTFOUND; |
766 |
} |
962 |
} |
767 |
|
963 |
|
768 |
h->req_hdrs = apr_table_make(r->pool, 20); |
964 |
rv = read_table_timeout(h, r, &(h->resp_hdrs), dobj->hfd, dobj->updtimeout); |
769 |
h->resp_hdrs = apr_table_make(r->pool, 20); |
965 |
if(rv != APR_SUCCESS) { |
|
|
966 |
ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, |
967 |
"disk_cache: Timed out waiting for response headers " |
968 |
"for URL %s - caching failed?", dobj->name); |
969 |
return rv; |
970 |
} |
770 |
|
971 |
|
771 |
/* Call routine to read the header lines/status line */ |
972 |
rv = read_table_timeout(h, r, &(h->req_hdrs), dobj->hfd, dobj->updtimeout); |
772 |
read_table(h, r, h->resp_hdrs, dobj->hfd); |
973 |
if(rv != APR_SUCCESS) { |
773 |
read_table(h, r, h->req_hdrs, dobj->hfd); |
974 |
ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, |
|
|
975 |
"disk_cache: Timed out waiting for request headers " |
976 |
"for URL %s - caching failed?", dobj->name); |
977 |
return rv; |
978 |
} |
774 |
|
979 |
|
775 |
apr_file_close(dobj->hfd); |
980 |
apr_file_close(dobj->hfd); |
776 |
|
981 |
|
Lines 826-926
static apr_status_t store_table(apr_file
Link Here
|
826 |
return rv; |
1031 |
return rv; |
827 |
} |
1032 |
} |
828 |
|
1033 |
|
829 |
static apr_status_t store_headers(cache_handle_t *h, request_rec *r, cache_info *info) |
1034 |
|
|
|
1035 |
static apr_status_t open_new_file(request_rec *r, const char *filename, |
1036 |
apr_file_t **fd, disk_cache_conf *conf) |
830 |
{ |
1037 |
{ |
831 |
disk_cache_conf *conf = ap_get_module_config(r->server->module_config, |
1038 |
int flags = APR_CREATE | APR_WRITE | APR_BINARY | APR_BUFFERED | APR_EXCL; |
832 |
&disk_cache_module); |
|
|
833 |
apr_status_t rv; |
1039 |
apr_status_t rv; |
834 |
apr_size_t amt; |
|
|
835 |
disk_cache_object_t *dobj = (disk_cache_object_t*) h->cache_obj->vobj; |
836 |
|
1040 |
|
837 |
disk_cache_info_t disk_info; |
1041 |
while(1) { |
838 |
struct iovec iov[2]; |
1042 |
rv = apr_file_open(fd, filename, flags, |
839 |
|
1043 |
APR_FPROT_UREAD | APR_FPROT_UWRITE, r->pool); |
840 |
/* This is flaky... we need to manage the cache_info differently */ |
1044 |
|
841 |
h->cache_obj->info = *info; |
1045 |
/* FIXME: Debug */ |
842 |
|
1046 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server, |
843 |
if (r->headers_out) { |
1047 |
"disk_cache: open_new_file: Opening %s", filename); |
844 |
const char *tmp; |
1048 |
|
845 |
|
1049 |
if(APR_STATUS_IS_EEXIST(rv)) { |
846 |
tmp = apr_table_get(r->headers_out, "Vary"); |
1050 |
apr_finfo_t finfo; |
|
|
1051 |
|
1052 |
rv = apr_stat(&finfo, filename, APR_FINFO_MTIME, r->pool); |
1053 |
if(APR_STATUS_IS_ENOENT(rv)) { |
1054 |
/* Someone else has already removed it, try again */ |
1055 |
continue; |
1056 |
} |
1057 |
else if(rv != APR_SUCCESS) { |
1058 |
return rv; |
1059 |
} |
847 |
|
1060 |
|
848 |
if (tmp) { |
1061 |
if(finfo.mtime < (apr_time_now() - conf->updtimeout) ) { |
849 |
apr_array_header_t* varray; |
1062 |
/* Something stale that's left around */ |
850 |
apr_uint32_t format = VARY_FORMAT_VERSION; |
|
|
851 |
|
1063 |
|
852 |
mkdir_structure(conf, dobj->hdrsfile, r->pool); |
1064 |
rv = apr_file_remove(filename, r->pool); |
|
|
1065 |
if(rv != APR_SUCCESS && !APR_STATUS_IS_ENOENT(rv)) { |
1066 |
ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, |
1067 |
"disk_cache: open_new_file: Failed to " |
1068 |
"remove old %s", filename); |
1069 |
return rv; |
1070 |
} |
1071 |
continue; |
1072 |
} |
1073 |
else { |
1074 |
/* Someone else has just created the file, return identifiable |
1075 |
status so calling function can do the right thing */ |
853 |
|
1076 |
|
854 |
rv = apr_file_mktemp(&dobj->tfd, dobj->tempfile, |
1077 |
return CACHE_EEXIST; |
855 |
APR_CREATE | APR_WRITE | APR_BINARY | APR_EXCL, |
1078 |
} |
856 |
r->pool); |
1079 |
} |
|
|
1080 |
else if(APR_STATUS_IS_ENOENT(rv)) { |
1081 |
/* The directory for the file didn't exist */ |
857 |
|
1082 |
|
858 |
if (rv != APR_SUCCESS) { |
1083 |
rv = mkdir_structure(conf, filename, r->pool); |
|
|
1084 |
if(rv != APR_SUCCESS) { |
1085 |
ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, |
1086 |
"disk_cache: open_new_file: Failed to make " |
1087 |
"directory for %s", filename); |
859 |
return rv; |
1088 |
return rv; |
860 |
} |
1089 |
} |
|
|
1090 |
continue; |
1091 |
} |
1092 |
else if(rv == APR_SUCCESS) { |
1093 |
return APR_SUCCESS; |
1094 |
} |
1095 |
else { |
1096 |
ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, |
1097 |
"disk_cache: open_new_file: Failed to open %s", |
1098 |
filename); |
1099 |
return rv; |
1100 |
} |
1101 |
} |
861 |
|
1102 |
|
862 |
amt = sizeof(format); |
1103 |
/* We should never get here, so */ |
863 |
apr_file_write(dobj->tfd, &format, &amt); |
1104 |
return APR_EGENERAL; |
|
|
1105 |
} |
864 |
|
1106 |
|
865 |
amt = sizeof(info->expire); |
|
|
866 |
apr_file_write(dobj->tfd, &info->expire, &amt); |
867 |
|
1107 |
|
868 |
varray = apr_array_make(r->pool, 6, sizeof(char*)); |
1108 |
static apr_status_t store_vary_header(cache_handle_t *h, disk_cache_conf *conf, |
869 |
tokens_to_array(r->pool, tmp, varray); |
1109 |
request_rec *r, cache_info *info, |
|
|
1110 |
const char *varyhdr) |
1111 |
{ |
1112 |
disk_cache_object_t *dobj = (disk_cache_object_t*) h->cache_obj->vobj; |
1113 |
apr_array_header_t* varray; |
1114 |
const char *vfile; |
1115 |
apr_status_t rv; |
1116 |
int flags; |
1117 |
disk_cache_format_t format = VARY_FORMAT_VERSION; |
1118 |
struct iovec iov[2]; |
1119 |
apr_size_t amt; |
870 |
|
1120 |
|
871 |
store_array(dobj->tfd, varray); |
1121 |
if(dobj->prefix != NULL) { |
|
|
1122 |
vfile = dobj->prefix; |
1123 |
} |
1124 |
else { |
1125 |
vfile = dobj->hdrsfile; |
1126 |
} |
872 |
|
1127 |
|
873 |
apr_file_close(dobj->tfd); |
1128 |
flags = APR_CREATE | APR_WRITE | APR_BINARY | APR_EXCL | APR_BUFFERED; |
|
|
1129 |
rv = apr_file_mktemp(&dobj->tfd, dobj->tempfile, flags, r->pool); |
1130 |
if (rv != APR_SUCCESS) { |
1131 |
return rv; |
1132 |
} |
874 |
|
1133 |
|
875 |
dobj->tfd = NULL; |
1134 |
iov[0].iov_base = (void*)&format; |
|
|
1135 |
iov[0].iov_len = sizeof(format); |
876 |
|
1136 |
|
877 |
rv = safe_file_rename(conf, dobj->tempfile, dobj->hdrsfile, |
1137 |
iov[1].iov_base = (void*)&info->expire; |
878 |
r->pool); |
1138 |
iov[1].iov_len = sizeof(info->expire); |
879 |
if (rv != APR_SUCCESS) { |
|
|
880 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server, |
881 |
"disk_cache: rename tempfile to varyfile failed: %s -> %s", |
882 |
dobj->tempfile, dobj->hdrsfile); |
883 |
apr_file_remove(dobj->tempfile, r->pool); |
884 |
return rv; |
885 |
} |
886 |
|
1139 |
|
887 |
dobj->tempfile = apr_pstrcat(r->pool, conf->cache_root, AP_TEMPFILE, NULL); |
1140 |
rv = apr_file_writev(dobj->tfd, (const struct iovec *) &iov, 2, &amt); |
888 |
tmp = regen_key(r->pool, r->headers_in, varray, dobj->name); |
1141 |
if (rv != APR_SUCCESS) { |
889 |
dobj->prefix = dobj->hdrsfile; |
1142 |
file_cache_errorcleanup(dobj, r); |
890 |
dobj->hashfile = NULL; |
1143 |
return rv; |
891 |
dobj->datafile = data_file(r->pool, conf, dobj, tmp); |
|
|
892 |
dobj->hdrsfile = header_file(r->pool, conf, dobj, tmp); |
893 |
} |
894 |
} |
1144 |
} |
895 |
|
1145 |
|
|
|
1146 |
varray = apr_array_make(r->pool, 6, sizeof(char*)); |
1147 |
tokens_to_array(r->pool, varyhdr, varray); |
896 |
|
1148 |
|
897 |
rv = apr_file_mktemp(&dobj->hfd, dobj->tempfile, |
1149 |
rv = store_array(dobj->tfd, varray); |
898 |
APR_CREATE | APR_WRITE | APR_BINARY | |
1150 |
if (rv != APR_SUCCESS) { |
899 |
APR_BUFFERED | APR_EXCL, r->pool); |
1151 |
file_cache_errorcleanup(dobj, r); |
|
|
1152 |
return rv; |
1153 |
} |
900 |
|
1154 |
|
|
|
1155 |
rv = apr_file_close(dobj->tfd); |
1156 |
dobj->tfd = NULL; |
901 |
if (rv != APR_SUCCESS) { |
1157 |
if (rv != APR_SUCCESS) { |
|
|
1158 |
file_cache_errorcleanup(dobj, r); |
902 |
return rv; |
1159 |
return rv; |
903 |
} |
1160 |
} |
904 |
|
1161 |
|
905 |
dobj->name = h->cache_obj->key; |
1162 |
rv = safe_file_rename(conf, dobj->tempfile, vfile, r->pool); |
|
|
1163 |
if (rv != APR_SUCCESS) { |
1164 |
ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, |
1165 |
"disk_cache: rename tempfile to varyfile failed: " |
1166 |
"%s -> %s", dobj->tempfile, vfile); |
1167 |
file_cache_errorcleanup(dobj, r); |
1168 |
return rv; |
1169 |
} |
1170 |
|
1171 |
dobj->tempfile = apr_pstrcat(r->pool, conf->cache_root, AP_TEMPFILE, NULL); |
1172 |
|
1173 |
if(dobj->prefix == NULL) { |
1174 |
const char *tmp = regen_key(r->pool, r->headers_in, varray, dobj->name); |
1175 |
|
1176 |
dobj->prefix = dobj->hdrsfile; |
1177 |
dobj->hdrsfile = header_file(r->pool, conf, dobj, tmp); |
1178 |
} |
1179 |
|
1180 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
1181 |
"disk_cache: Stored vary header for URL %s", dobj->name); |
1182 |
|
1183 |
return APR_SUCCESS; |
1184 |
} |
1185 |
|
1186 |
|
1187 |
static apr_status_t store_disk_header(disk_cache_object_t *dobj, |
1188 |
request_rec *r, cache_info *info) |
1189 |
{ |
1190 |
disk_cache_format_t format = DISK_FORMAT_VERSION; |
1191 |
struct iovec iov[3]; |
1192 |
int niov; |
1193 |
disk_cache_info_t disk_info; |
1194 |
apr_size_t amt; |
1195 |
apr_status_t rv; |
906 |
|
1196 |
|
907 |
disk_info.format = DISK_FORMAT_VERSION; |
|
|
908 |
disk_info.date = info->date; |
1197 |
disk_info.date = info->date; |
909 |
disk_info.expire = info->expire; |
1198 |
disk_info.expire = info->expire; |
910 |
disk_info.entity_version = dobj->disk_info.entity_version++; |
1199 |
disk_info.entity_version = dobj->disk_info.entity_version++; |
911 |
disk_info.request_time = info->request_time; |
1200 |
disk_info.request_time = info->request_time; |
912 |
disk_info.response_time = info->response_time; |
1201 |
disk_info.response_time = info->response_time; |
913 |
disk_info.status = info->status; |
1202 |
disk_info.status = info->status; |
|
|
1203 |
disk_info.file_size = dobj->initial_size; |
914 |
|
1204 |
|
915 |
disk_info.name_len = strlen(dobj->name); |
1205 |
niov = 0; |
|
|
1206 |
iov[niov].iov_base = (void*)&format; |
1207 |
iov[niov++].iov_len = sizeof(format); |
1208 |
iov[niov].iov_base = (void*)&disk_info; |
1209 |
iov[niov++].iov_len = sizeof(disk_cache_info_t); |
916 |
|
1210 |
|
917 |
iov[0].iov_base = (void*)&disk_info; |
1211 |
disk_info.name_len = strlen(dobj->name); |
918 |
iov[0].iov_len = sizeof(disk_cache_info_t); |
1212 |
iov[niov].iov_base = (void*)dobj->name; |
919 |
iov[1].iov_base = (void*)dobj->name; |
1213 |
iov[niov++].iov_len = disk_info.name_len; |
920 |
iov[1].iov_len = disk_info.name_len; |
|
|
921 |
|
1214 |
|
922 |
rv = apr_file_writev(dobj->hfd, (const struct iovec *) &iov, 2, &amt); |
1215 |
rv = apr_file_writev(dobj->hfd, (const struct iovec *) &iov, niov, &amt); |
923 |
if (rv != APR_SUCCESS) { |
1216 |
if (rv != APR_SUCCESS) { |
|
|
1217 |
file_cache_errorcleanup(dobj, r); |
924 |
return rv; |
1218 |
return rv; |
925 |
} |
1219 |
} |
926 |
|
1220 |
|
Lines 940-945
static apr_status_t store_headers(cache_
Link Here
|
940 |
r->err_headers_out); |
1234 |
r->err_headers_out); |
941 |
rv = store_table(dobj->hfd, headers_out); |
1235 |
rv = store_table(dobj->hfd, headers_out); |
942 |
if (rv != APR_SUCCESS) { |
1236 |
if (rv != APR_SUCCESS) { |
|
|
1237 |
file_cache_errorcleanup(dobj, r); |
943 |
return rv; |
1238 |
return rv; |
944 |
} |
1239 |
} |
945 |
} |
1240 |
} |
Lines 953-983
static apr_status_t store_headers(cache_
Link Here
|
953 |
r->server); |
1248 |
r->server); |
954 |
rv = store_table(dobj->hfd, headers_in); |
1249 |
rv = store_table(dobj->hfd, headers_in); |
955 |
if (rv != APR_SUCCESS) { |
1250 |
if (rv != APR_SUCCESS) { |
|
|
1251 |
file_cache_errorcleanup(dobj, r); |
956 |
return rv; |
1252 |
return rv; |
957 |
} |
1253 |
} |
958 |
} |
1254 |
} |
959 |
|
1255 |
|
960 |
apr_file_close(dobj->hfd); /* flush and close */ |
1256 |
return APR_SUCCESS; |
|
|
1257 |
} |
961 |
|
1258 |
|
962 |
/* Remove old file with the same name. If remove fails, then |
1259 |
|
963 |
* perhaps we need to create the directory tree where we are |
1260 |
static apr_status_t store_headers(cache_handle_t *h, request_rec *r, |
964 |
* about to write the new headers file. |
1261 |
cache_info *info) |
965 |
*/ |
1262 |
{ |
966 |
rv = apr_file_remove(dobj->hdrsfile, r->pool); |
1263 |
disk_cache_conf *conf = ap_get_module_config(r->server->module_config, |
967 |
if (rv != APR_SUCCESS) { |
1264 |
&disk_cache_module); |
968 |
mkdir_structure(conf, dobj->hdrsfile, r->pool); |
1265 |
apr_status_t rv; |
|
|
1266 |
int flags=0, rewriting; |
1267 |
disk_cache_object_t *dobj = (disk_cache_object_t*) h->cache_obj->vobj; |
1268 |
|
1269 |
|
1270 |
/* This is flaky... we need to manage the cache_info differently */ |
1271 |
h->cache_obj->info = *info; |
1272 |
|
1273 |
if(dobj->hfd) { |
1274 |
ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, |
1275 |
"disk_cache: Rewriting headers for URL %s", dobj->name); |
1276 |
|
1277 |
rewriting = TRUE; |
969 |
} |
1278 |
} |
|
|
1279 |
else { |
1280 |
ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, |
1281 |
"disk_cache: Storing new headers for URL %s", dobj->name); |
970 |
|
1282 |
|
971 |
rv = safe_file_rename(conf, dobj->tempfile, dobj->hdrsfile, r->pool); |
1283 |
rewriting = FALSE; |
972 |
if (rv != APR_SUCCESS) { |
|
|
973 |
ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, |
974 |
"disk_cache: rename tempfile to hdrsfile failed: %s -> %s", |
975 |
dobj->tempfile, dobj->hdrsfile); |
976 |
apr_file_remove(dobj->tempfile, r->pool); |
977 |
return rv; |
978 |
} |
1284 |
} |
979 |
|
1285 |
|
980 |
dobj->tempfile = apr_pstrcat(r->pool, conf->cache_root, AP_TEMPFILE, NULL); |
1286 |
if (r->headers_out) { |
|
|
1287 |
const char *tmp; |
1288 |
|
1289 |
tmp = apr_table_get(r->headers_out, "Vary"); |
1290 |
|
1291 |
if (tmp) { |
1292 |
rv = store_vary_header(h, conf, r, info, tmp); |
1293 |
if(rv != APR_SUCCESS) { |
1294 |
return rv; |
1295 |
} |
1296 |
} |
1297 |
} |
1298 |
|
1299 |
if(rewriting) { |
1300 |
/* Assume we are just rewriting the header if we have an fd. The |
1301 |
fd might be readonly though, in that case reopen it for writes. |
1302 |
Something equivalent to fdopen would have been handy. */ |
1303 |
|
1304 |
flags = apr_file_flags_get(dobj->hfd); |
1305 |
|
1306 |
if(!(flags & APR_WRITE)) { |
1307 |
apr_file_close(dobj->hfd); |
1308 |
rv = apr_file_open(&dobj->hfd, dobj->hdrsfile, |
1309 |
APR_WRITE | APR_BINARY | APR_BUFFERED, 0, r->pool); |
1310 |
if (rv != APR_SUCCESS) { |
1311 |
return rv; |
1312 |
} |
1313 |
} |
1314 |
else { |
1315 |
/* We can write here, so let's just move to the right place */ |
1316 |
apr_off_t off=0; |
1317 |
rv = apr_file_seek(dobj->hfd, APR_SET, &off); |
1318 |
if (rv != APR_SUCCESS) { |
1319 |
return rv; |
1320 |
} |
1321 |
} |
1322 |
} |
1323 |
else { |
1324 |
rv = open_new_file(r, dobj->hdrsfile, &(dobj->hfd), conf); |
1325 |
if(rv == CACHE_EEXIST) { |
1326 |
dobj->skipstore = TRUE; |
1327 |
} |
1328 |
else if(rv != APR_SUCCESS) { |
1329 |
return rv; |
1330 |
} |
1331 |
} |
1332 |
|
1333 |
if(dobj->skipstore) { |
1334 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
1335 |
"disk_cache: Skipping store for URL %s: Someone else " |
1336 |
"beat us to it", dobj->name); |
1337 |
return APR_SUCCESS; |
1338 |
} |
1339 |
|
1340 |
rv = store_disk_header(dobj, r, info); |
1341 |
if(rv != APR_SUCCESS) { |
1342 |
return rv; |
1343 |
} |
981 |
|
1344 |
|
982 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
1345 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
983 |
"disk_cache: Stored headers for URL %s", dobj->name); |
1346 |
"disk_cache: Stored headers for URL %s", dobj->name); |
Lines 1116-1129
static apr_status_t store_body(cache_han
Link Here
|
1116 |
return APR_EGENERAL; |
1479 |
return APR_EGENERAL; |
1117 |
} |
1480 |
} |
1118 |
|
1481 |
|
1119 |
/* We write to a temp file and then atomically rename the file over |
1482 |
if(dobj->initial_size == 0) { |
1120 |
* in file_cache_el_final(). |
1483 |
/* Don't waste a body cachefile on a 0 length body */ |
1121 |
*/ |
1484 |
return APR_SUCCESS; |
1122 |
if (!dobj->tfd) { |
1485 |
} |
1123 |
rv = apr_file_mktemp(&dobj->tfd, dobj->tempfile, |
1486 |
|
1124 |
APR_CREATE | APR_WRITE | APR_BINARY | |
1487 |
if(dobj->skipstore) { |
1125 |
APR_BUFFERED | APR_EXCL, r->pool); |
1488 |
/* Someone else beat us to storing this object */ |
1126 |
if (rv != APR_SUCCESS) { |
1489 |
/* FIXME: Read-while-caching here */ |
|
|
1490 |
return APR_SUCCESS; |
1491 |
} |
1492 |
|
1493 |
if(!dobj->fd) { |
1494 |
rv = open_new_file(r, dobj->datafile, &(dobj->fd), conf); |
1495 |
if(rv == CACHE_EEXIST) { |
1496 |
/* Someone else beat us to storing this */ |
1497 |
/* FIXME: Read-while-caching here later on */ |
1498 |
return APR_SUCCESS; |
1499 |
} |
1500 |
else if(rv != APR_SUCCESS) { |
1127 |
return rv; |
1501 |
return rv; |
1128 |
} |
1502 |
} |
1129 |
dobj->file_size = 0; |
1503 |
dobj->file_size = 0; |
Lines 1183-1189
static apr_status_t store_body(cache_han
Link Here
|
1183 |
e = APR_BRIGADE_FIRST(bb); |
1557 |
e = APR_BRIGADE_FIRST(bb); |
1184 |
a = e->data; |
1558 |
a = e->data; |
1185 |
|
1559 |
|
1186 |
rv = copy_body(r->pool, a->fd, e->start, dobj->tfd, 0, |
1560 |
rv = copy_body(r->pool, a->fd, e->start, dobj->fd, 0, |
1187 |
dobj->file_size); |
1561 |
dobj->file_size); |
1188 |
if(rv != APR_SUCCESS) { |
1562 |
if(rv != APR_SUCCESS) { |
1189 |
ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, |
1563 |
ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, |
Lines 1269-1279
static apr_status_t store_body(cache_han
Link Here
|
1269 |
file_cache_errorcleanup(dobj, r); |
1643 |
file_cache_errorcleanup(dobj, r); |
1270 |
return APR_EGENERAL; |
1644 |
return APR_EGENERAL; |
1271 |
} |
1645 |
} |
|
|
1646 |
if(dobj->initial_size < 0) { |
1647 |
/* Update header information now that we know the size */ |
1648 |
dobj->initial_size = dobj->file_size; |
1649 |
rv = store_headers(h, r, &(h->cache_obj->info)); |
1650 |
if(rv != APR_SUCCESS) { |
1651 |
file_cache_errorcleanup(dobj, r); |
1652 |
return rv; |
1653 |
} |
1654 |
} |
1655 |
else if(dobj->initial_size != dobj->file_size) { |
1656 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
1657 |
"disk_cache: URL %s - body size mismatch: suggested %" |
1658 |
APR_OFF_T_FMT " bodysize %" APR_OFF_T_FMT ")", |
1659 |
dobj->name, dobj->initial_size, dobj->file_size); |
1660 |
file_cache_errorcleanup(dobj, r); |
1661 |
return APR_EGENERAL; |
1662 |
} |
1272 |
} |
1663 |
} |
1273 |
|
1664 |
|
1274 |
/* All checks were fine. Move tempfile to final destination */ |
1665 |
/* All checks were fine, close output file */ |
1275 |
/* Link to the perm file, and close the descriptor */ |
1666 |
rv = apr_file_close(dobj->fd); |
1276 |
rv = file_cache_el_final(dobj, r); |
|
|
1277 |
if(rv != APR_SUCCESS) { |
1667 |
if(rv != APR_SUCCESS) { |
1278 |
file_cache_errorcleanup(dobj, r); |
1668 |
file_cache_errorcleanup(dobj, r); |
1279 |
return rv; |
1669 |
return rv; |
Lines 1303-1308
static void *create_config(apr_pool_t *p
Link Here
|
1303 |
conf->dirlength = DEFAULT_DIRLENGTH; |
1693 |
conf->dirlength = DEFAULT_DIRLENGTH; |
1304 |
conf->maxfs = DEFAULT_MAX_FILE_SIZE; |
1694 |
conf->maxfs = DEFAULT_MAX_FILE_SIZE; |
1305 |
conf->minfs = DEFAULT_MIN_FILE_SIZE; |
1695 |
conf->minfs = DEFAULT_MIN_FILE_SIZE; |
|
|
1696 |
conf->updtimeout = DEFAULT_UPDATE_TIMEOUT; |
1306 |
|
1697 |
|
1307 |
conf->cache_root = NULL; |
1698 |
conf->cache_root = NULL; |
1308 |
conf->cache_root_len = 0; |
1699 |
conf->cache_root_len = 0; |
Lines 1386-1391
static const char
Link Here
|
1386 |
return NULL; |
1777 |
return NULL; |
1387 |
} |
1778 |
} |
1388 |
|
1779 |
|
|
|
1780 |
|
1781 |
static const char |
1782 |
*set_cache_updtimeout(cmd_parms *parms, void *in_struct_ptr, const char *arg) |
1783 |
{ |
1784 |
apr_int64_t val; |
1785 |
disk_cache_conf *conf = ap_get_module_config(parms->server->module_config, |
1786 |
&disk_cache_module); |
1787 |
|
1788 |
if (apr_strtoff(&val, arg, NULL, 0) != APR_SUCCESS || val < 0) |
1789 |
{ |
1790 |
return "CacheUpdateTimeout argument must be a non-negative integer representing the timeout in milliseconds for cache update operations"; |
1791 |
} |
1792 |
|
1793 |
conf->updtimeout = val * 1000; |
1794 |
|
1795 |
return NULL; |
1796 |
} |
1797 |
|
1798 |
|
1389 |
static const command_rec disk_cache_cmds[] = |
1799 |
static const command_rec disk_cache_cmds[] = |
1390 |
{ |
1800 |
{ |
1391 |
AP_INIT_TAKE1("CacheRoot", set_cache_root, NULL, RSRC_CONF, |
1801 |
AP_INIT_TAKE1("CacheRoot", set_cache_root, NULL, RSRC_CONF, |
Lines 1398-1403
static const command_rec disk_cache_cmds
Link Here
|
1398 |
"The minimum file size to cache a document"), |
1808 |
"The minimum file size to cache a document"), |
1399 |
AP_INIT_TAKE1("CacheMaxFileSize", set_cache_maxfs, NULL, RSRC_CONF, |
1809 |
AP_INIT_TAKE1("CacheMaxFileSize", set_cache_maxfs, NULL, RSRC_CONF, |
1400 |
"The maximum file size to cache a document"), |
1810 |
"The maximum file size to cache a document"), |
|
|
1811 |
AP_INIT_TAKE1("CacheUpdateTimeout", set_cache_updtimeout, NULL, RSRC_CONF, |
1812 |
"Timeout in ms for cache updates"), |
1401 |
{NULL} |
1813 |
{NULL} |
1402 |
}; |
1814 |
}; |
1403 |
|
1815 |
|