View | Details | Raw Unified | Return to bug 39380
Collapse All | Expand All

(-)mod_disk_cache.c (-261 / +673 lines)
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
(-)mod_disk_cache.h (-4 / +24 lines)
Lines 22-28 Link Here
22
 */
22
 */
23
23
24
#define VARY_FORMAT_VERSION 3
24
#define VARY_FORMAT_VERSION 3
25
#define DISK_FORMAT_VERSION 4
25
#define DISK_FORMAT_VERSION_OLD 4
26
#define DISK_FORMAT_VERSION 5
26
27
27
#define CACHE_HEADER_SUFFIX ".header"
28
#define CACHE_HEADER_SUFFIX ".header"
28
#define CACHE_DATA_SUFFIX   ".data"
29
#define CACHE_DATA_SUFFIX   ".data"
Lines 30-35 Link Here
30
31
31
#define CACHE_BUF_SIZE 65536
32
#define CACHE_BUF_SIZE 65536
32
33
34
/* How long to sleep before retrying while looping */
35
#define CACHE_LOOP_SLEEP 200000
36
37
33
#define AP_TEMPFILE_PREFIX "/"
38
#define AP_TEMPFILE_PREFIX "/"
34
#define AP_TEMPFILE_BASE   "aptmp"
39
#define AP_TEMPFILE_BASE   "aptmp"
35
#define AP_TEMPFILE_SUFFIX "XXXXXX"
40
#define AP_TEMPFILE_SUFFIX "XXXXXX"
Lines 37-45 Link Here
37
#define AP_TEMPFILE_NAMELEN strlen(AP_TEMPFILE_BASE AP_TEMPFILE_SUFFIX)
42
#define AP_TEMPFILE_NAMELEN strlen(AP_TEMPFILE_BASE AP_TEMPFILE_SUFFIX)
38
#define AP_TEMPFILE AP_TEMPFILE_PREFIX AP_TEMPFILE_BASE AP_TEMPFILE_SUFFIX
43
#define AP_TEMPFILE AP_TEMPFILE_PREFIX AP_TEMPFILE_BASE AP_TEMPFILE_SUFFIX
39
44
45
/* Indicates the format of the header struct stored on-disk. */
46
typedef apr_uint32_t disk_cache_format_t;
47
40
typedef struct {
48
typedef struct {
41
    /* Indicates the format of the header struct stored on-disk. */
42
    apr_uint32_t format;
43
    /* The HTTP status code returned for this response.  */
49
    /* The HTTP status code returned for this response.  */
44
    int status;
50
    int status;
45
    /* The size of the entity name that follows. */
51
    /* The size of the entity name that follows. */
Lines 51-56 typedef struct { Link Here
51
    apr_time_t expire;
57
    apr_time_t expire;
52
    apr_time_t request_time;
58
    apr_time_t request_time;
53
    apr_time_t response_time;
59
    apr_time_t response_time;
60
    /* The body size forced to 64bit to not break when people go from non-LFS
61
     * to LFS builds */
62
    apr_int64_t file_size;
54
} disk_cache_info_t;
63
} disk_cache_info_t;
55
64
56
/*
65
/*
Lines 66-77 typedef struct disk_cache_object { Link Here
66
    const char *hdrsfile;    /* name of file where the hdrs will go */
75
    const char *hdrsfile;    /* name of file where the hdrs will go */
67
    const char *hashfile;    /* Computed hash key for this URI */
76
    const char *hashfile;    /* Computed hash key for this URI */
68
    const char *name;   /* Requested URI without vary bits - suitable for mortals. */
77
    const char *name;   /* Requested URI without vary bits - suitable for mortals. */
69
    const char *key;    /* On-disk prefix; URI with Vary bits (if present) */
70
    apr_file_t *fd;          /* data file */
78
    apr_file_t *fd;          /* data file */
71
    apr_file_t *hfd;         /* headers file */
79
    apr_file_t *hfd;         /* headers file */
72
    apr_file_t *tfd;         /* temporary file for data */
80
    apr_file_t *tfd;         /* temporary file for data */
73
    apr_off_t file_size;     /*  File size of the cached data file  */
81
    apr_off_t file_size;     /*  File size of the cached data file  */
82
    apr_off_t initial_size;  /*  Initial file size reported by caller */
74
    disk_cache_info_t disk_info; /* Header information. */
83
    disk_cache_info_t disk_info; /* Header information. */
84
85
    apr_interval_time_t updtimeout; /* Cache update timeout */
86
87
    int skipstore;           /* Set if we should skip storing stuff */
75
} disk_cache_object_t;
88
} disk_cache_object_t;
76
89
77
90
Lines 84-89 typedef struct disk_cache_object { Link Here
84
#define DEFAULT_DIRLENGTH 2
97
#define DEFAULT_DIRLENGTH 2
85
#define DEFAULT_MIN_FILE_SIZE 1
98
#define DEFAULT_MIN_FILE_SIZE 1
86
#define DEFAULT_MAX_FILE_SIZE 1000000
99
#define DEFAULT_MAX_FILE_SIZE 1000000
100
#define DEFAULT_UPDATE_TIMEOUT apr_time_from_sec(10)
87
101
88
typedef struct {
102
typedef struct {
89
    const char* cache_root;
103
    const char* cache_root;
Lines 92-97 typedef struct { Link Here
92
    int dirlength;               /* Length of subdirectory names */
106
    int dirlength;               /* Length of subdirectory names */
93
    apr_off_t minfs;             /* minimum file size for cached files */
107
    apr_off_t minfs;             /* minimum file size for cached files */
94
    apr_off_t maxfs;             /* maximum file size for cached files */
108
    apr_off_t maxfs;             /* maximum file size for cached files */
109
    apr_interval_time_t updtimeout;   /* Cache update timeout */
95
} disk_cache_conf;
110
} disk_cache_conf;
96
111
112
#define CACHE_ENODATA (APR_OS_START_USERERR+1)
113
#define CACHE_EDECLINED (APR_OS_START_USERERR+2)
114
#define CACHE_EEXIST (APR_OS_START_USERERR+3)
115
116
97
#endif /*MOD_DISK_CACHE_H*/
117
#endif /*MOD_DISK_CACHE_H*/

Return to bug 39380