Coverage Report

Created: 2026-07-12 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/src/cache.c
Line
Count
Source
1
/*
2
 * Cache management
3
 *
4
 * Copyright 2017 HAProxy Technologies
5
 * William Lallemand <wlallemand@haproxy.com>
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version
10
 * 2 of the License, or (at your option) any later version.
11
 */
12
13
#include <import/eb32tree.h>
14
#include <import/sha1.h>
15
16
#include <haproxy/action-t.h>
17
#include <haproxy/api.h>
18
#include <haproxy/applet.h>
19
#include <haproxy/cfgparse.h>
20
#include <haproxy/channel.h>
21
#include <haproxy/cli.h>
22
#include <haproxy/errors.h>
23
#include <haproxy/filters.h>
24
#include <haproxy/hash.h>
25
#include <haproxy/http.h>
26
#include <haproxy/http_ana.h>
27
#include <haproxy/http_htx.h>
28
#include <haproxy/http_rules.h>
29
#include <haproxy/htx.h>
30
#include <haproxy/net_helper.h>
31
#include <haproxy/proxy.h>
32
#include <haproxy/sample.h>
33
#include <haproxy/sc_strm.h>
34
#include <haproxy/shctx.h>
35
#include <haproxy/stconn.h>
36
#include <haproxy/stream.h>
37
#include <haproxy/tools.h>
38
#include <haproxy/xxhash.h>
39
40
0
#define CACHE_FLT_F_IMPLICIT_DECL  0x00000001 /* The cache filtre was implicitly declared (ie without
41
                 * the filter keyword) */
42
0
#define CACHE_FLT_INIT             0x00000002 /* Whether the cache name was freed. */
43
44
/* Flags for cached entries. */
45
0
#define CACHE_EF_COMPLETE          0x00000001 /* fully written and valid */
46
0
#define CACHE_EF_STRIPPED          0x00000002 /* entry stripped, only early hints data remains */
47
48
/* Flags for configuration. */
49
0
#define CACHE_CF_VARY_PROCESSING   0x00000001 /* manage Vary header (disabled by default) */
50
0
#define CACHE_CF_EARLY_HINTS       0x00000002 /* enable HTTP 103 Early Hints (disabled by default) */
51
0
#define CACHE_CF_EARLY_HINTS_ONLY  0x00000004 /* skip body storage; implies CACHE_CF_EARLY_HINTS */
52
53
/* Soft cap on the number of cache blocks that may be held by hints entries. */
54
0
#define CACHE_HINTS_CAP(cache)     ((cache)->maxblocks * (cache)->early_hints_ratio / 100)
55
56
static uint64_t cache_hash_seed = 0;
57
58
const char *cache_store_flt_id = "cache store filter";
59
60
extern struct applet http_cache_applet;
61
62
struct flt_ops cache_ops;
63
64
struct cache_tree {
65
  struct eb_root entries;  /* head of cache entries based on keys */
66
  __decl_thread(HA_RWLOCK_T lock);
67
68
  struct list cleanup_list;
69
  __decl_thread(HA_SPINLOCK_T cleanup_lock);
70
} ALIGNED(64);
71
72
struct cache {
73
  struct cache_tree trees[CACHE_TREE_NUM];
74
  struct list list;        /* cache linked list */
75
  struct list full_lru;    /* LRU list of full entries */
76
  struct list hints_lru;   /* LRU list of hints entries */
77
  unsigned int hints_blocks;  /* sum of block counts of hints entries */
78
  unsigned int maxage;     /* max-age */
79
  unsigned int maxblocks;
80
  unsigned int maxobjsz;   /* max-object-size (in bytes) */
81
  unsigned int max_secondary_entries;  /* maximum number of secondary entries with the same primary hash */
82
  uint8_t flags;           /* configuration flags, see CACHE_CF_* */
83
  uint8_t early_hints_ratio;           /* percentage of cache reserved for hints entries (1..99) */
84
  char id[33];             /* cache name */
85
};
86
87
/* the appctx context of a cache applet, stored in appctx->svcctx */
88
struct cache_appctx {
89
  struct cache *cache;
90
  struct cache_tree *cache_tree;
91
  struct cache_entry *entry;       /* Entry to be sent from cache. */
92
  unsigned int sent;               /* The number of bytes already sent for this cache entry. */
93
  unsigned int offset;             /* start offset of remaining data relative to beginning of the next block */
94
  unsigned int rem_data;           /* Remaining bytes for the last data block (HTX only, 0 means process next block) */
95
  unsigned int send_notmodified:1; /* In case of conditional request, we might want to send a "304 Not Modified" response instead of the stored data. */
96
  unsigned int unused:31;
97
  /* 4 bytes hole here */
98
  struct shared_block *next;       /* The next block of data to be sent for this cache entry. */
99
};
100
101
/* cache config for filters */
102
struct cache_flt_conf {
103
  union {
104
    struct cache *cache; /* cache used by the filter */
105
    char *name;          /* cache name used during conf parsing */
106
  } c;
107
  unsigned int flags;   /* CACHE_FLT_F_* */
108
};
109
110
/* CLI context used during "show cache" */
111
struct show_cache_ctx {
112
  struct cache *cache;
113
  struct cache_tree *cache_tree;
114
  uint next_key;
115
};
116
117
118
/*
119
 * Vary-related structures and functions
120
 */
121
enum vary_header_bit {
122
  VARY_ACCEPT_ENCODING = (1 << 0),
123
  VARY_REFERER =         (1 << 1),
124
  VARY_ORIGIN =          (1 << 2),
125
  VARY_LAST  /* should always be last */
126
};
127
128
/*
129
 * Encoding list extracted from
130
 * https://www.iana.org/assignments/http-parameters/http-parameters.xhtml
131
 * and RFC7231#5.3.4.
132
 */
133
enum vary_encoding {
134
  VARY_ENCODING_GZIP =    (1 << 0),
135
  VARY_ENCODING_DEFLATE =   (1 << 1),
136
  VARY_ENCODING_BR =    (1 << 2),
137
  VARY_ENCODING_COMPRESS =  (1 << 3),
138
  VARY_ENCODING_AES128GCM = (1 << 4),
139
  VARY_ENCODING_EXI =   (1 << 5),
140
  VARY_ENCODING_PACK200_GZIP =  (1 << 6),
141
  VARY_ENCODING_ZSTD =    (1 << 7),
142
  VARY_ENCODING_IDENTITY =  (1 << 8),
143
  VARY_ENCODING_STAR =    (1 << 9),
144
  VARY_ENCODING_OTHER =   (1 << 10)
145
};
146
147
struct vary_hashing_information {
148
  struct ist hdr_name;                 /* Header name */
149
  enum vary_header_bit value;          /* Bit representing the header in a vary signature */
150
  unsigned int hash_length;            /* Size of the sub hash for this header's value */
151
  int(*norm_fn)(struct htx*,struct ist hdr_name,char* buf,unsigned int* buf_len);  /* Normalization function */
152
  int(*cmp_fn)(const void *ref, const void *new, unsigned int len); /* Comparison function, should return 0 if the hashes are alike */
153
};
154
155
static int http_request_prebuild_full_secondary_key(struct stream *s);
156
static int http_request_build_secondary_key(struct stream *s, int vary_signature);
157
static int http_request_reduce_secondary_key(unsigned int vary_signature,
158
               char prebuilt_key[HTTP_CACHE_SEC_KEY_LEN]);
159
160
static int parse_encoding_value(struct ist value, unsigned int *encoding_value,
161
        unsigned int *has_null_weight);
162
163
static int accept_encoding_normalizer(struct htx *htx, struct ist hdr_name,
164
              char *buf, unsigned int *buf_len);
165
static int default_normalizer(struct htx *htx, struct ist hdr_name,
166
            char *buf, unsigned int *buf_len);
167
168
static int accept_encoding_bitmap_cmp(const void *ref, const void *new, unsigned int len);
169
170
/* Warning : do not forget to update HTTP_CACHE_SEC_KEY_LEN when new items are
171
 * added to this array. */
172
const struct vary_hashing_information vary_information[] = {
173
  { IST("accept-encoding"), VARY_ACCEPT_ENCODING, sizeof(uint32_t), &accept_encoding_normalizer, &accept_encoding_bitmap_cmp },
174
  { IST("referer"), VARY_REFERER, sizeof(uint64_t), &default_normalizer, NULL },
175
  { IST("origin"), VARY_ORIGIN, sizeof(uint64_t), &default_normalizer, NULL },
176
};
177
178
179
static inline void cache_rdlock(struct cache_tree *cache)
180
0
{
181
0
  HA_RWLOCK_RDLOCK(CACHE_LOCK, &cache->lock);
182
0
}
183
184
static inline  void cache_rdunlock(struct cache_tree *cache)
185
0
{
186
0
  HA_RWLOCK_RDUNLOCK(CACHE_LOCK, &cache->lock);
187
0
}
188
189
static inline void cache_wrlock(struct cache_tree *cache)
190
0
{
191
0
  HA_RWLOCK_WRLOCK(CACHE_LOCK, &cache->lock);
192
0
}
193
194
static inline void cache_wrunlock(struct cache_tree *cache)
195
0
{
196
0
  HA_RWLOCK_WRUNLOCK(CACHE_LOCK, &cache->lock);
197
0
}
198
199
/*
200
 * cache ctx for filters
201
 */
202
struct cache_st {
203
  struct shared_block *first_block;
204
  struct list detached_head;
205
};
206
207
0
#define DEFAULT_MAX_SECONDARY_ENTRY 10
208
209
struct cache_entry {
210
  unsigned int flags;       /* Cache entry flags. See CACHE_EF_* */
211
  unsigned int latest_validation;     /* latest validation date */
212
  unsigned int expire;      /* expiration date (wall clock time) */
213
  unsigned int age;         /* Origin server "Age" header value */
214
  unsigned int body_size;         /* Size of the body */
215
  int refcount;
216
217
  struct eb32_node eb;     /* ebtree node used to hold the cache object */
218
  char hash[20];
219
220
  struct list cleanup_list;/* List used between the cache_free_blocks and cache_reserve_finish calls */
221
  struct list lru;         /* Link in the cache's full_lru or hints_lru */
222
223
  char secondary_key[HTTP_CACHE_SEC_KEY_LEN];  /* Optional secondary key. */
224
  unsigned int secondary_key_signature;  /* Bitfield of the HTTP headers that should be used
225
                  * to build secondary keys for this cache entry. */
226
  unsigned int secondary_entries_count;  /* Should only be filled in the last entry of a list of dup entries */
227
  unsigned int last_clear_ts;          /* Timestamp of the last call to clear_expired_duplicates. */
228
229
  unsigned int etag_length; /* Length of the ETag value (if one was found in the response). */
230
  unsigned int etag_offset; /* Offset of the ETag value in the data buffer. */
231
232
  time_t last_modified; /* Origin server "Last-Modified" header value converted in
233
             * seconds since epoch. If no "Last-Modified"
234
             * header is found, use "Date" header value,
235
             * otherwise use reception time. This field will
236
             * be used in case of an "If-Modified-Since"-based
237
             * conditional request. */
238
239
  unsigned char data[0];
240
};
241
242
0
#define CACHE_BLOCKSIZE 1024
243
0
#define CACHE_ENTRY_MAX_AGE 2147483648U
244
245
/* Maximum size of a single Link header value for hint extraction. */
246
#define CACHE_MAX_HINT_LINK_VAL 1024
247
248
static struct list caches = LIST_HEAD_INIT(caches);
249
static struct list caches_config = LIST_HEAD_INIT(caches_config); /* cache config to init */
250
static struct cache *tmp_cache_config = NULL;
251
252
DECLARE_STATIC_TYPED_POOL(pool_head_cache_st, "cache_st", struct cache_st);
253
254
static struct eb32_node *insert_entry(struct cache *cache, struct cache_tree *tree, struct cache_entry *new_entry);
255
static void delete_entry(struct cache_entry *del_entry);
256
static inline void release_entry_locked(struct cache_tree *cache, struct cache_entry *entry);
257
static inline void release_entry_unlocked(struct cache_tree *cache, struct cache_entry *entry);
258
259
/*
260
 * Find a cache_entry in <cache_tree> that has the hash <hash>. If
261
 * <delete_expired> is non-zero and the entry is expired, it is removed from
262
 * the tree and NULL is returned. Otherwise the entry is returned as-is,
263
 * including expired entries when <delete_expired> is 0 - the caller is then
264
 * responsible for inspecting entry->expire.
265
 * The returned entry is not retained, it should be explicitly retained only
266
 * when necessary.
267
 *
268
 * This function must be called under a cache lock, either read if
269
 * delete_expired==0, write otherwise.
270
 */
271
struct cache_entry *get_entry(struct cache_tree *cache_tree, char *hash, int delete_expired)
272
0
{
273
0
  struct eb32_node *node;
274
0
  struct cache_entry *entry;
275
276
0
  node = eb32_lookup(&cache_tree->entries, read_u32(hash));
277
0
  if (!node)
278
0
    return NULL;
279
280
0
  entry = eb32_entry(node, struct cache_entry, eb);
281
282
  /* if that's not the right node */
283
0
  if (memcmp(entry->hash, hash, sizeof(entry->hash)))
284
0
    return NULL;
285
286
0
  if (delete_expired && entry->expire <= date.tv_sec) {
287
0
    release_entry_locked(cache_tree, entry);
288
0
    return NULL;
289
0
  }
290
0
  return entry;
291
0
}
292
293
/*
294
 * Increment a cache_entry's reference counter.
295
 */
296
static void retain_entry(struct cache_entry *entry)
297
0
{
298
0
  if (entry)
299
0
    HA_ATOMIC_INC(&entry->refcount);
300
0
}
301
302
/*
303
 * Decrement a cache_entry's reference counter and remove it from the <cache>'s
304
 * tree if the reference counter becomes 0.
305
 * If <needs_locking> is 0 then the cache lock was already taken by the caller,
306
 * otherwise it must be taken in write mode before actually deleting the entry.
307
 */
308
static void release_entry(struct cache_tree *cache, struct cache_entry *entry, int needs_locking)
309
0
{
310
0
  if (!entry)
311
0
    return;
312
313
0
  if (HA_ATOMIC_SUB_FETCH(&entry->refcount, 1) <= 0) {
314
0
    if (needs_locking) {
315
0
      cache_wrlock(cache);
316
      /* The value might have changed between the last time we
317
       * checked it and now, we need to recheck it just in
318
       * case.
319
       */
320
0
      if (HA_ATOMIC_LOAD(&entry->refcount) > 0) {
321
0
        cache_wrunlock(cache);
322
0
        return;
323
0
      }
324
0
    }
325
0
    delete_entry(entry);
326
0
    if (needs_locking) {
327
0
      cache_wrunlock(cache);
328
0
    }
329
0
  }
330
0
}
331
332
/*
333
 * Decrement a cache_entry's reference counter and remove it from the <cache>'s
334
 * tree if the reference counter becomes 0.
335
 * This function must be called under the cache lock in write mode.
336
 */
337
static inline void release_entry_locked(struct cache_tree *cache, struct cache_entry *entry)
338
0
{
339
0
  release_entry(cache, entry, 0);
340
0
}
341
342
/*
343
 * Decrement a cache_entry's reference counter and remove it from the <cache>'s
344
 * tree if the reference counter becomes 0.
345
 * This function must not be called under the cache lock or the shctx lock. The
346
 * cache lock might be taken in write mode (if the entry gets deleted).
347
 */
348
static inline void release_entry_unlocked(struct cache_tree *cache, struct cache_entry *entry)
349
0
{
350
0
  release_entry(cache, entry, 1);
351
0
}
352
353
354
/*
355
 * Compare a newly built secondary key to the one found in a cache_entry.
356
 * Every sub-part of the key is compared to the reference through the dedicated
357
 * comparison function of the sub-part (that might do more than a simple
358
 * memcmp).
359
 * Returns 0 if the keys are alike.
360
 */
361
static int secondary_key_cmp(const char *ref_key, const char *new_key)
362
0
{
363
0
  int retval = 0;
364
0
  size_t idx = 0;
365
0
  unsigned int offset = 0;
366
0
  const struct vary_hashing_information *info;
367
368
0
  for (idx = 0; idx < sizeof(vary_information)/sizeof(*vary_information) && !retval; ++idx) {
369
0
    info = &vary_information[idx];
370
371
0
    if (info->cmp_fn)
372
0
      retval = info->cmp_fn(&ref_key[offset], &new_key[offset], info->hash_length);
373
0
    else
374
0
      retval = memcmp(&ref_key[offset], &new_key[offset], info->hash_length);
375
376
0
    offset += info->hash_length;
377
0
  }
378
379
0
  return retval;
380
0
}
381
382
/*
383
 * There can be multiple entries with the same primary key in the ebtree so in
384
 * order to get the proper one out of the list, we use a secondary_key.
385
 * This function simply iterates over all the entries with the same primary_key
386
 * until it finds the right one.
387
 * If <delete_expired> is 0 then the entry is left untouched if it is found but
388
 * is already expired, and NULL is returned. Otherwise, the expired entry is
389
 * removed from the tree and NULL is returned.
390
 * Returns the cache_entry in case of success, NULL otherwise.
391
 *
392
 * This function must be called under a cache lock, either read if
393
 * delete_expired==0, write otherwise.
394
 */
395
struct cache_entry *get_secondary_entry(struct cache_tree *cache, struct cache_entry *entry,
396
                                        const char *primary_hash, const char *secondary_key, int delete_expired)
397
0
{
398
0
  struct eb32_node *node = &entry->eb;
399
400
0
  if (!entry->secondary_key_signature)
401
0
    return NULL;
402
403
0
  while (entry && secondary_key_cmp(entry->secondary_key, secondary_key) != 0) {
404
0
    node = eb32_next_dup(node);
405
406
    /* Make the best use of this iteration and clear expired entries
407
     * when we find them. Calling delete_entry would be too costly
408
     * so we simply call eb32_delete. The secondary_entry count will
409
     * be updated when we try to insert a new entry to this list. */
410
0
    if (entry->expire <= date.tv_sec && delete_expired) {
411
0
      release_entry_locked(cache, entry);
412
0
    }
413
414
0
    entry = node ? eb32_entry(node, struct cache_entry, eb) : NULL;
415
0
  }
416
417
  /* Now verify the full primary hash matches: eb32 only compares 32 bits so
418
   * we could have ended up on a different, unrelated entry.
419
   */
420
0
  if (entry && primary_hash && memcmp(entry->hash, primary_hash, sizeof(entry->hash)))
421
0
    entry = NULL;
422
423
  /* Expired entry */
424
0
  if (entry && entry->expire <= date.tv_sec) {
425
0
    if (delete_expired) {
426
0
      release_entry_locked(cache, entry);
427
0
    }
428
0
    entry = NULL;
429
0
  }
430
431
0
  return entry;
432
0
}
433
434
static inline struct cache_tree *get_cache_tree_from_hash(struct cache *cache, unsigned int hash)
435
0
{
436
0
  if (!cache)
437
0
    return NULL;
438
439
0
  return &cache->trees[hash % CACHE_TREE_NUM];
440
0
}
441
442
443
/*
444
 * Remove all expired entries from a list of duplicates.
445
 * Return the number of alive entries in the list and sets dup_tail to the
446
 * current last item of the list.
447
 *
448
 * This function must be called under a cache write lock.
449
 */
450
static unsigned int clear_expired_duplicates(struct cache_tree *cache, struct eb32_node **dup_tail)
451
0
{
452
0
  unsigned int entry_count = 0;
453
0
  struct cache_entry *entry = NULL;
454
0
  struct eb32_node *prev = *dup_tail;
455
0
  struct eb32_node *tail = NULL;
456
457
0
  while (prev) {
458
0
    entry = container_of(prev, struct cache_entry, eb);
459
0
    prev = eb32_prev_dup(prev);
460
0
    if (entry->expire <= date.tv_sec) {
461
0
      release_entry_locked(cache, entry);
462
0
    }
463
0
    else {
464
0
      if (!tail)
465
0
        tail = &entry->eb;
466
0
      ++entry_count;
467
0
    }
468
0
  }
469
470
0
  *dup_tail = tail;
471
472
0
  return entry_count;
473
0
}
474
475
476
/*
477
 * This function inserts a cache_entry in the cache's ebtree. In case of
478
 * duplicate entries (vary), it then checks that the number of entries did not
479
 * reach the max number of secondary entries. If this entry should not have been
480
 * created, remove it.
481
 * In the regular case (unique entries), this function does not do more than a
482
 * simple insert. In case of secondary entries, it will at most cost an
483
 * insertion+max_sec_entries time checks and entry deletion.
484
 * Returns the newly inserted node in case of success, NULL otherwise.
485
 *
486
 * This function must be called under a cache write lock.
487
 */
488
static struct eb32_node *insert_entry(struct cache *cache, struct cache_tree *tree, struct cache_entry *new_entry)
489
0
{
490
0
  struct eb32_node *prev = NULL;
491
0
  struct cache_entry *entry = NULL;
492
0
  unsigned int entry_count = 0;
493
0
  unsigned int last_clear_ts = date.tv_sec;
494
495
0
  struct eb32_node *node = eb32_insert(&tree->entries, &new_entry->eb);
496
497
0
  new_entry->refcount = 1;
498
499
  /* We should not have multiple entries with the same primary key unless
500
   * the entry has a non null vary signature. */
501
0
  if (!new_entry->secondary_key_signature)
502
0
    return node;
503
504
0
  prev = eb32_prev_dup(node);
505
0
  if (prev != NULL) {
506
    /* The last entry of a duplicate list should contain the current
507
     * number of entries in the list. */
508
0
    entry = container_of(prev, struct cache_entry, eb);
509
0
    entry_count = entry->secondary_entries_count;
510
0
    last_clear_ts = entry->last_clear_ts;
511
512
0
    if (entry_count >= cache->max_secondary_entries) {
513
      /* Some entries of the duplicate list might be expired so
514
       * we will iterate over all the items in order to free some
515
       * space. In order to avoid going over the same list too
516
       * often, we first check the timestamp of the last check
517
       * performed. */
518
0
      if (last_clear_ts == date.tv_sec) {
519
        /* Too many entries for this primary key, clear the
520
         * one that was inserted. */
521
0
        release_entry_locked(tree, new_entry);
522
0
        return NULL;
523
0
      }
524
525
0
      entry_count = clear_expired_duplicates(tree, &prev);
526
0
      if (entry_count >= cache->max_secondary_entries) {
527
        /* Still too many entries for this primary key, delete
528
         * the newly inserted one. */
529
0
        entry = container_of(prev, struct cache_entry, eb);
530
0
        entry->last_clear_ts = date.tv_sec;
531
0
        release_entry_locked(tree, new_entry);
532
0
        return NULL;
533
0
      }
534
0
    }
535
0
  }
536
537
0
  new_entry->secondary_entries_count = entry_count + 1;
538
0
  new_entry->last_clear_ts = last_clear_ts;
539
540
0
  return node;
541
0
}
542
543
544
/*
545
 * This function removes an entry from the ebtree. If the entry was a duplicate
546
 * (in case of Vary), it updates the secondary entry counter in another
547
 * duplicate entry (the last entry of the dup list).
548
 *
549
 * This function must be called under a cache write lock.
550
 */
551
static void delete_entry(struct cache_entry *del_entry)
552
0
{
553
0
  struct eb32_node *prev = NULL, *next = NULL;
554
0
  struct cache_entry *entry = NULL;
555
0
  struct eb32_node *last = NULL;
556
557
  /* The entry might have been removed from the cache before. In such a
558
   * case calling eb32_next_dup would crash. */
559
0
  if (del_entry->secondary_key_signature && del_entry->eb.key != 0) {
560
0
    next = &del_entry->eb;
561
562
    /* Look for last entry of the duplicates list. */
563
0
    while ((next = eb32_next_dup(next))) {
564
0
      last = next;
565
0
    }
566
567
0
    if (last) {
568
0
      entry = container_of(last, struct cache_entry, eb);
569
0
      --entry->secondary_entries_count;
570
0
    }
571
0
    else {
572
      /* The current entry is the last one, look for the
573
       * previous one to update its counter. */
574
0
      prev = eb32_prev_dup(&del_entry->eb);
575
0
      if (prev) {
576
0
        entry = container_of(prev, struct cache_entry, eb);
577
0
        entry->secondary_entries_count = del_entry->secondary_entries_count - 1;
578
0
      }
579
0
    }
580
0
  }
581
0
  eb32_delete(&del_entry->eb);
582
0
  del_entry->eb.key = 0;
583
0
}
584
585
586
static inline struct shared_context *shctx_ptr(struct cache *cache)
587
0
{
588
0
  return (struct shared_context *)((unsigned char *)cache -  offsetof(struct shared_context, data));
589
0
}
590
591
static inline struct shared_block *block_ptr(struct cache_entry *entry)
592
0
{
593
0
  return (struct shared_block *)((unsigned char *)entry - offsetof(struct shared_block, data));
594
0
}
595
596
/*
597
 * Reattach a row that the cache had detached for reading or writing, and
598
 * ensure the corresponding entry is at the tail of its appropriate LRU. If
599
 * the entry is not yet in any LRU and is complete, it is inserted; otherwise
600
 * it is moved to the tail. LRU bookkeeping is skipped when the cache has
601
 * early-hints disabled. Must be called under shctx wrlock.
602
 */
603
static inline void cache_row_reattach(struct cache *cache, struct shared_block *first)
604
0
{
605
0
  struct cache_entry *entry = (struct cache_entry *)first->data;
606
607
0
  if ((cache->flags & CACHE_CF_EARLY_HINTS) &&
608
0
      (LIST_INLIST(&entry->lru) || (entry->flags & CACHE_EF_COMPLETE))) {
609
0
    struct list *lru;
610
611
0
    if (entry->flags & CACHE_EF_STRIPPED)
612
0
      lru = &cache->hints_lru;
613
0
    else
614
0
      lru = &cache->full_lru;
615
616
0
    if (LIST_INLIST(&entry->lru))
617
0
      LIST_DELETE(&entry->lru);
618
0
    LIST_APPEND(lru, &entry->lru);
619
0
  }
620
0
  shctx_row_reattach(shctx_ptr(cache), first);
621
0
}
622
623
static int
624
cache_store_init(struct proxy *px, struct flt_conf *fconf)
625
0
{
626
0
  fconf->flags |= FLT_CFG_FL_HTX;
627
0
  return 0;
628
0
}
629
630
static void
631
cache_store_deinit(struct proxy *px, struct flt_conf *fconf)
632
0
{
633
0
  struct cache_flt_conf *cconf = fconf->conf;
634
635
0
  if (!(cconf->flags & CACHE_FLT_INIT))
636
0
    free(cconf->c.name);
637
0
  free(cconf);
638
0
}
639
640
static int
641
cache_store_check(struct proxy *px, struct flt_conf *fconf)
642
0
{
643
0
  struct cache_flt_conf *cconf = fconf->conf;
644
0
  struct flt_conf *f;
645
0
  struct cache *cache;
646
0
  int comp = 0;
647
648
  /* Find the cache corresponding to the name in the filter config.  The
649
  *  cache will not be referenced now in the filter config because it is
650
  *  not fully allocated. This step will be performed during the cache
651
  *  post_check.
652
  */
653
0
  list_for_each_entry(cache, &caches_config, list) {
654
0
    if (strcmp(cache->id, cconf->c.name) == 0)
655
0
      goto found;
656
0
  }
657
658
0
  ha_alert("config: %s '%s': unable to find the cache '%s' referenced by the filter 'cache'.\n",
659
0
     proxy_type_str(px), px->id, (char *)cconf->c.name);
660
0
  return 1;
661
662
0
  found:
663
  /* Here <cache> points on the cache the filter must use and <cconf>
664
   * points on the cache filter configuration. */
665
666
  /* Check all filters for proxy <px> to know if the compression is
667
   * enabled and if it is after the cache. When the compression is before
668
   * the cache, an error is returned. Also check if the cache filter must
669
   * be explicitly declaired or not. */
670
0
  list_for_each_entry(f, &px->filter_configs, list) {
671
0
    if (f == fconf) {
672
      /* The compression filter must be evaluated after the cache. */
673
0
      if (comp) {
674
0
        ha_alert("config: %s '%s': unable to enable the compression filter before "
675
0
           "the cache '%s'.\n", proxy_type_str(px), px->id, cache->id);
676
0
        return 1;
677
0
      }
678
0
    }
679
0
    else if (f->id == http_comp_req_flt_id || f->id == http_comp_res_flt_id)
680
0
      comp = 1;
681
0
#if defined(USE_FCGI)
682
0
    else if (f->id == fcgi_flt_id)
683
0
      continue;
684
0
#endif
685
0
    else if ((f->id != fconf->id) && (cconf->flags & CACHE_FLT_F_IMPLICIT_DECL)) {
686
      /* Implicit declaration is only allowed with the
687
       * compression and fcgi. For other filters, an implicit
688
       * declaration is required. */
689
0
      ha_alert("config: %s '%s': require an explicit filter declaration "
690
0
         "to use the cache '%s'.\n", proxy_type_str(px), px->id, cache->id);
691
0
      return 1;
692
0
    }
693
694
0
  }
695
0
  return 0;
696
0
}
697
698
static int
699
cache_store_strm_init(struct stream *s, struct filter *filter)
700
0
{
701
0
  struct cache_st *st;
702
703
0
  st = pool_alloc(pool_head_cache_st);
704
0
  if (st == NULL)
705
0
    return -1;
706
707
0
  st->first_block = NULL;
708
0
  filter->ctx     = st;
709
710
  /* Register post-analyzer on AN_RES_WAIT_HTTP */
711
0
  filter->post_analyzers |= AN_RES_WAIT_HTTP;
712
0
  return 1;
713
0
}
714
715
static void
716
cache_store_strm_deinit(struct stream *s, struct filter *filter)
717
0
{
718
0
  struct cache_st *st = filter->ctx;
719
0
  struct cache_flt_conf *cconf = FLT_CONF(filter);
720
0
  struct cache *cache = cconf->c.cache;
721
0
  struct shared_context *shctx = shctx_ptr(cache);
722
723
  /* Everything should be released in the http_end filter, but we need to do it
724
   * there too, in case of errors */
725
0
  if (st && st->first_block) {
726
0
    struct cache_entry *object = (struct cache_entry *)st->first_block->data;
727
0
    if (!(object->flags & CACHE_EF_COMPLETE)) {
728
      /* The stream was closed but the 'complete' flag was not
729
       * set which means that cache_store_http_end was not
730
       * called. The stream must have been closed before we
731
       * could store the full answer in the cache.
732
       */
733
0
      release_entry_unlocked(&cache->trees[object->eb.key % CACHE_TREE_NUM], object);
734
0
    }
735
0
    shctx_wrlock(shctx);
736
0
    cache_row_reattach(cache, st->first_block);
737
0
    shctx_wrunlock(shctx);
738
0
  }
739
0
  if (st) {
740
0
    pool_free(pool_head_cache_st, st);
741
0
    filter->ctx = NULL;
742
0
  }
743
0
}
744
745
static int
746
cache_store_post_analyze(struct stream *s, struct filter *filter, struct channel *chn,
747
       unsigned an_bit)
748
0
{
749
0
  struct http_txn *txn = s->txn.http;
750
0
  struct http_msg *msg = &txn->rsp;
751
0
  struct cache_st *st = filter->ctx;
752
753
0
  if (an_bit != AN_RES_WAIT_HTTP)
754
0
    goto end;
755
756
  /* Here we need to check if any compression filter precedes the cache
757
   * filter. This is only possible when the compression is configured in
758
   * the frontend while the cache filter is configured on the
759
   * backend. This case cannot be detected during HAProxy startup. So in
760
   * such cases, the cache is disabled.
761
   */
762
0
  if (st && (msg->flags & HTTP_MSGF_COMPRESSING)) {
763
0
    pool_free(pool_head_cache_st, st);
764
0
    filter->ctx = NULL;
765
0
  }
766
767
0
  end:
768
0
  return 1;
769
0
}
770
771
static int
772
cache_store_http_headers(struct stream *s, struct filter *filter, struct http_msg *msg)
773
0
{
774
0
  struct cache_st *st = filter->ctx;
775
776
0
  if (!(msg->chn->flags & CF_ISRESP) || !st)
777
0
    return 1;
778
779
0
  if (st->first_block)
780
0
    register_data_filter(s, msg->chn, filter);
781
0
  return 1;
782
0
}
783
784
static inline void disable_cache_entry(struct cache_st *st,
785
                                       struct filter *filter, struct shared_context *shctx)
786
0
{
787
0
  struct cache_entry *object;
788
0
  struct cache *cache = (struct cache*)shctx->data;
789
790
0
  object = (struct cache_entry *)st->first_block->data;
791
0
  filter->ctx = NULL; /* disable cache  */
792
0
  release_entry_unlocked(&cache->trees[object->eb.key % CACHE_TREE_NUM], object);
793
0
  shctx_wrlock(shctx);
794
0
  cache_row_reattach(cache, st->first_block);
795
0
  shctx_wrunlock(shctx);
796
0
  pool_free(pool_head_cache_st, st);
797
0
}
798
799
static int
800
cache_store_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
801
       unsigned int offset, unsigned int len)
802
0
{
803
0
  struct cache_flt_conf *cconf = FLT_CONF(filter);
804
0
  struct shared_context *shctx = shctx_ptr(cconf->c.cache);
805
0
  struct cache_st *st = filter->ctx;
806
0
  struct htx *htx = htxbuf(&msg->chn->buf);
807
0
  struct htx_blk *blk;
808
0
  struct shared_block *fb;
809
0
  struct htx_ret htxret;
810
0
  unsigned int orig_len, to_forward;
811
0
  int ret;
812
813
0
  if (!len)
814
0
    return len;
815
816
0
  if (!st->first_block) {
817
0
    unregister_data_filter(s, msg->chn, filter);
818
0
    return len;
819
0
  }
820
821
0
  orig_len = len;
822
0
  to_forward = 0;
823
824
0
  htxret = htx_find_offset(htx, offset);
825
0
  blk = htxret.blk;
826
0
  offset = htxret.ret;
827
0
  for (; blk && len; blk = htx_get_next_blk(htx, blk)) {
828
0
    enum htx_blk_type type = htx_get_blk_type(blk);
829
0
    uint32_t info, sz = htx_get_blksz(blk);
830
0
    struct ist v;
831
832
0
    switch (type) {
833
0
      case HTX_BLK_UNUSED:
834
0
        break;
835
836
0
      case HTX_BLK_DATA:
837
0
        v = htx_get_blk_value(htx, blk);
838
0
        v = istadv(v, offset);
839
0
        v = isttrim(v, len);
840
841
0
        info = (type << 28) + v.len;
842
0
        fb = shctx_row_reserve_hot(shctx, st->first_block, sizeof(info)+v.len);
843
0
        if (!fb)
844
0
          goto no_cache;
845
0
        ret = shctx_row_data_append(shctx, st->first_block, (unsigned char *)&info, sizeof(info));
846
0
        if (ret < 0)
847
0
          goto no_cache;
848
0
        ret = shctx_row_data_append(shctx, st->first_block, (unsigned char *)istptr(v), istlen(v));
849
0
        if (ret < 0)
850
0
          goto no_cache;
851
0
        ASSUME_NONNULL((struct cache_entry *)st->first_block->data)->body_size += v.len;
852
0
        to_forward += v.len;
853
0
        len -= v.len;
854
0
        break;
855
856
0
      default:
857
        /* Here offset must always be 0 because only
858
         * DATA blocks can be partially transferred. */
859
0
        if (offset)
860
0
          goto no_cache;
861
0
        if (sz > len)
862
0
          goto end;
863
864
0
        fb = shctx_row_reserve_hot(shctx, st->first_block, sizeof(blk->info)+sz);
865
0
        if (!fb)
866
0
          goto no_cache;
867
0
        ret = shctx_row_data_append(shctx, st->first_block, (unsigned char *)&(blk->info), sizeof(blk->info));
868
0
        if (ret < 0)
869
0
          goto no_cache;
870
0
        ret = shctx_row_data_append(shctx, st->first_block, (unsigned char *)htx_get_blk_ptr(htx, blk), sz);
871
0
        if (ret < 0)
872
0
          goto no_cache;
873
0
        to_forward += sz;
874
0
        len -= sz;
875
0
        break;
876
0
    }
877
878
0
    offset = 0;
879
0
  }
880
881
0
  end:
882
0
  return to_forward;
883
884
0
  no_cache:
885
0
  disable_cache_entry(st, filter, shctx);
886
0
  unregister_data_filter(s, msg->chn, filter);
887
0
  return orig_len;
888
0
}
889
890
static int
891
cache_store_http_end(struct stream *s, struct filter *filter,
892
                     struct http_msg *msg)
893
0
{
894
0
  struct cache_st *st = filter->ctx;
895
0
  struct cache_flt_conf *cconf = FLT_CONF(filter);
896
0
  struct cache *cache = cconf->c.cache;
897
0
  struct shared_context *shctx = shctx_ptr(cache);
898
0
  struct cache_entry *object;
899
900
0
  if (!(msg->chn->flags & CF_ISRESP))
901
0
    return 1;
902
903
0
  if (st && st->first_block) {
904
905
0
    object = (struct cache_entry *)st->first_block->data;
906
907
0
    shctx_wrlock(shctx);
908
    /* The whole payload was cached, the entry can now be used. */
909
0
    object->flags |= CACHE_EF_COMPLETE;
910
    /* remove from the hotlist */
911
0
    cache_row_reattach(cache, st->first_block);
912
0
    shctx_wrunlock(shctx);
913
914
0
  }
915
0
  if (st) {
916
0
    pool_free(pool_head_cache_st, st);
917
0
    filter->ctx = NULL;
918
0
  }
919
920
0
  return 1;
921
0
}
922
923
 /*
924
  * This intends to be used when checking HTTP headers for some
925
  * word=value directive. Return a pointer to the first character of value, if
926
  * the word was not found or if there wasn't any value assigned to it return NULL
927
  */
928
char *directive_value(const char *sample, int slen, const char *word, int wlen)
929
0
{
930
0
  int st = 0;
931
932
0
  if (slen < wlen)
933
0
    return 0;
934
935
0
  while (wlen) {
936
0
    char c = *sample ^ *word;
937
0
    if (c && c != ('A' ^ 'a'))
938
0
      return NULL;
939
0
    sample++;
940
0
    word++;
941
0
    slen--;
942
0
    wlen--;
943
0
  }
944
945
0
  while (slen) {
946
0
    if (st == 0) {
947
0
      if (*sample != '=')
948
0
        return NULL;
949
0
      sample++;
950
0
      slen--;
951
0
      st = 1;
952
0
      continue;
953
0
    } else {
954
0
      return (char *)sample;
955
0
    }
956
0
  }
957
958
0
  return NULL;
959
0
}
960
961
/*
962
 * Return the maxage in seconds of an HTTP response.
963
 * The returned value will always take the cache's configuration into account
964
 * (cache->maxage) but the actual max age of the response will be set in the
965
 * true_maxage parameter. It will be used to determine if a response is already
966
 * stale or not.
967
 * Compute the maxage using either:
968
 *  - the assigned max-age of the cache
969
 *  - the s-maxage directive
970
 *  - the max-age directive
971
 *  - (Expires - Data) headers
972
 *  - the default-max-age of the cache
973
 *
974
 */
975
int http_calc_maxage(struct stream *s, struct cache *cache, int *true_maxage)
976
0
{
977
0
  struct htx *htx = htxbuf(&s->res.buf);
978
0
  struct http_hdr_ctx ctx = { .blk = NULL };
979
0
  long smaxage = -1;
980
0
  long maxage = -1;
981
0
  int expires = -1;
982
0
  struct tm tm = {};
983
0
  time_t expires_val = 0;
984
0
  char *endptr = NULL;
985
0
  int offset = 0;
986
987
  /* The Cache-Control max-age and s-maxage directives should be followed by
988
   * a positive numerical value (see RFC 7234#5.2.1.1). According to the
989
   * specs, a sender "should not" generate a quoted-string value but we will
990
   * still accept this format since it isn't strictly forbidden. */
991
0
  while (http_find_header(htx, ist("cache-control"), &ctx, 0)) {
992
0
    char *value;
993
994
0
    value = directive_value(ctx.value.ptr, ctx.value.len, "s-maxage", 8);
995
0
    if (value) {
996
0
      struct buffer *chk = get_trash_chunk();
997
998
0
      chunk_memcat(chk, value, ctx.value.len - (8 + 1));
999
0
      *(b_tail(chk)) = '\0';
1000
0
      offset = (*chk->area == '"') ? 1 : 0;
1001
0
      smaxage = strtol(chk->area + offset, &endptr, 10);
1002
0
      if (unlikely(smaxage < 0 || endptr == chk->area + offset))
1003
0
        return -1;
1004
0
    }
1005
1006
0
    value = directive_value(ctx.value.ptr, ctx.value.len, "max-age", 7);
1007
0
    if (value) {
1008
0
      struct buffer *chk = get_trash_chunk();
1009
1010
0
      chunk_memcat(chk, value, ctx.value.len - (7 + 1));
1011
0
      *(b_tail(chk)) = '\0';
1012
0
      offset = (*chk->area == '"') ? 1 : 0;
1013
0
      maxage = strtol(chk->area + offset, &endptr, 10);
1014
0
      if (unlikely(maxage < 0 || endptr == chk->area + offset))
1015
0
        return -1;
1016
0
    }
1017
0
  }
1018
1019
  /* Look for Expires header if no s-maxage or max-age Cache-Control data
1020
   * was found. */
1021
0
  if (maxage == -1 && smaxage == -1) {
1022
0
    ctx.blk = NULL;
1023
0
    if (http_find_header(htx, ist("expires"), &ctx, 1)) {
1024
0
      if (parse_http_date(istptr(ctx.value), istlen(ctx.value), &tm)) {
1025
0
        expires_val = my_timegm(&tm);
1026
        /* A request having an expiring date earlier
1027
         * than the current date should be considered as
1028
         * stale. */
1029
0
        expires = (expires_val >= date.tv_sec) ?
1030
0
          (expires_val - date.tv_sec) : 0;
1031
0
      }
1032
0
      else {
1033
        /* Following RFC 7234#5.3, an invalid date
1034
         * format must be treated as a date in the past
1035
         * so the cache entry must be seen as already
1036
         * expired. */
1037
0
        expires = 0;
1038
0
      }
1039
0
    }
1040
0
  }
1041
1042
1043
0
  if (smaxage > 0) {
1044
0
    if (true_maxage)
1045
0
      *true_maxage = smaxage;
1046
0
    return MIN(smaxage, cache->maxage);
1047
0
  }
1048
1049
0
  if (maxage > 0) {
1050
0
    if (true_maxage)
1051
0
      *true_maxage = maxage;
1052
0
    return MIN(maxage, cache->maxage);
1053
0
  }
1054
1055
0
  if (expires >= 0) {
1056
0
    if (true_maxage)
1057
0
      *true_maxage = expires;
1058
0
    return MIN(expires, cache->maxage);
1059
0
  }
1060
1061
0
  return cache->maxage;
1062
1063
0
}
1064
1065
/* The rel values in Link headers for which sending a 103 response makes sense. */
1066
static const struct ist hint_rels[] = {
1067
  IST("preload"),
1068
  IST("preconnect"),
1069
  IST("dns-prefetch"),
1070
  IST("modulepreload"),
1071
  IST("prefetch"),
1072
};
1073
1074
static int rel_is_hint(const struct ist rel)
1075
0
{
1076
0
  int i;
1077
1078
0
  for (i = 0; i < sizeof(hint_rels) / sizeof(*hint_rels); i++) {
1079
0
    if (isteqi(rel, hint_rels[i]))
1080
0
      return 1;
1081
0
  }
1082
0
  return 0;
1083
0
}
1084
1085
/*
1086
 * Returns true if the value of the Link header contains at least one rel attribute
1087
 * worth sending in a 103 Early Hint response.
1088
 */
1089
static int link_is_hint(struct ist val)
1090
0
{
1091
0
  const char *p = istptr(val), *end = istend(val);
1092
0
  struct ist params, pname, pval;
1093
1094
  /* A link-value must start with a "<URI>" part (RFC 8288#3). */
1095
0
  if (p >= end || *p != '<')
1096
0
    return 0;
1097
1098
  /* Skip past the <URI> portion to reach the parameter list. */
1099
0
  while (p < end && *p != '>')
1100
0
    p++;
1101
0
  if (p < end)
1102
0
    p++;
1103
0
  params = ist2(p, end - p);
1104
1105
0
  while (http_get_hdr_param(&params, &pname, &pval,
1106
0
                            HTTP_PARAM_BADWS | HTTP_PARAM_NOVAL) > 0) {
1107
0
    if (!isteqi(pname, ist("rel")))
1108
0
      continue;
1109
1110
    /* Only the first rel parameter counts: per RFC 8288#3.3,
1111
     * parsers must ignore subsequent occurrences. Whatever the
1112
     * outcome below, we are done with this link-value.
1113
     *
1114
     * Per RFC 8288#3.3 the rel value carries only tokens, optionally
1115
     * separated by SP. Leading or trailing whitespace inside a quoted
1116
     * value is malformed; reject the whole rel parameter rather than
1117
     * silently tolerating it (cf. RFC 9110#5.6.3).
1118
     */
1119
0
    if (!pval.len || HTTP_IS_LWS(*istptr(pval)) ||
1120
0
        HTTP_IS_LWS(istptr(pval)[pval.len - 1]))
1121
0
      return 0;
1122
1123
0
    while (pval.len) {
1124
0
      const char *tp = istptr(pval), *tend = istend(pval);
1125
0
      const char *tok;
1126
0
      struct ist token;
1127
1128
0
      tok = tp;
1129
0
      while (tp < tend && !HTTP_IS_LWS(*tp))
1130
0
        tp++;
1131
0
      token = ist2(tok, tp - tok);
1132
1133
0
      if (rel_is_hint(token))
1134
0
        return 1;
1135
1136
0
      while (tp < tend && HTTP_IS_LWS(*tp))
1137
0
        tp++;
1138
0
      pval = ist2(tp, tend - tp);
1139
0
    }
1140
0
    return 0;
1141
0
  }
1142
1143
0
  return 0;
1144
0
}
1145
1146
static void cache_free_blocks(struct shared_block *first, void *data)
1147
0
{
1148
0
  struct cache_entry *object = (struct cache_entry *)first->data;
1149
0
  struct cache *cache = (struct cache *)data;
1150
0
  struct cache_tree *cache_tree;
1151
1152
0
  if (LIST_INLIST(&object->lru)) {
1153
0
    LIST_DEL_INIT(&object->lru);
1154
0
    if (object->flags & CACHE_EF_STRIPPED)
1155
0
      cache->hints_blocks -= first->block_count;
1156
0
  }
1157
1158
0
  if (object->eb.key) {
1159
0
    object->flags &= ~(CACHE_EF_COMPLETE | CACHE_EF_STRIPPED);
1160
0
    cache_tree = &cache->trees[object->eb.key % CACHE_TREE_NUM];
1161
0
    retain_entry(object);
1162
0
    HA_SPIN_LOCK(CACHE_LOCK, &cache_tree->cleanup_lock);
1163
0
    LIST_INSERT(&cache_tree->cleanup_list, &object->cleanup_list);
1164
0
    HA_SPIN_UNLOCK(CACHE_LOCK, &cache_tree->cleanup_lock);
1165
0
  }
1166
0
}
1167
1168
static void cache_extract_link_hints(struct ist link, struct buffer *hint_buf)
1169
0
{
1170
0
  struct ist lv;
1171
0
  size_t hdr_start = b_data(hint_buf);
1172
0
  uint16_t hdr_len = 0;
1173
1174
0
  if (b_data(hint_buf) + sizeof(hdr_len) > b_size(hint_buf))
1175
0
    return;
1176
1177
0
  hint_buf->data += sizeof(hdr_len);
1178
1179
0
  while (http_next_hdr_value(&link, &lv)) {
1180
0
    size_t needed = lv.len;
1181
1182
0
    if (!link_is_hint(lv))
1183
0
      continue;
1184
0
    if (hdr_len > 0)
1185
0
      needed += 2;
1186
0
    if (hdr_len + needed > UINT16_MAX)
1187
0
      continue;
1188
0
    if (b_data(hint_buf) + needed > b_size(hint_buf))
1189
0
      continue;
1190
1191
0
    if (hdr_len > 0) {
1192
0
      chunk_memcat(hint_buf, ", ", 2);
1193
0
      hdr_len += 2;
1194
0
    }
1195
0
    chunk_memcat(hint_buf, lv.ptr, lv.len);
1196
0
    hdr_len += lv.len;
1197
0
  }
1198
1199
  /* If we wrote anything in the hint buffer, encode the length of the
1200
   * data at the beginning, and if we didn't, reset the buffer pointer to
1201
   * its previous state (before the 2 bytes we initially reserved).
1202
   */
1203
0
  if (hdr_len == 0)
1204
0
    hint_buf->data -= sizeof(hdr_len);
1205
0
  else
1206
0
    memcpy(b_orig(hint_buf) + hdr_start, &hdr_len, sizeof(hdr_len));
1207
0
}
1208
1209
/*
1210
 * Walk the HTX header blocks and accumulate Link values relevant for early
1211
 * hints into <hint_buf>. Returns the number of bytes written to <hint_buf>.
1212
 */
1213
static int cache_extract_hints(struct shared_context *shctx,
1214
                               struct shared_block *first,
1215
                               struct buffer *hint_buf)
1216
0
{
1217
0
  unsigned int offset = sizeof(struct cache_entry);
1218
0
  char value_buf[CACHE_MAX_HINT_LINK_VAL];
1219
1220
0
  while (offset + sizeof(uint32_t) <= first->len) {
1221
0
    uint32_t info;
1222
0
    enum htx_blk_type type;
1223
0
    size_t name_len, value_len;
1224
1225
0
    if (shctx_row_data_get(shctx, first, (unsigned char *)&info,
1226
0
                           offset, sizeof(info)) != 0)
1227
0
      break;
1228
0
    type = __htx_blkinfo_type(info);
1229
0
    if (type == HTX_BLK_EOH)
1230
0
      break;
1231
0
    if (type != HTX_BLK_HDR) {
1232
0
      offset += sizeof(info) + (info & 0xfffffff);
1233
0
      continue;
1234
0
    }
1235
1236
0
    name_len  = info & 0xff;
1237
0
    value_len = (info >> 8) & 0xfffff;
1238
0
    if (offset + sizeof(info) + name_len + value_len > first->len)
1239
0
      break;
1240
    /* value_buf linearizes the value out of the row; the HTX
1241
     * extractor reads it in place and needs no such cap.
1242
     */
1243
0
    if (value_len <= sizeof(value_buf) && name_len == 4) {
1244
0
      char name[4];
1245
1246
0
      shctx_row_data_get(shctx, first, (unsigned char *)name,
1247
0
                         offset + sizeof(info), 4);
1248
0
      if (memcmp(name, "link", 4) == 0) {
1249
0
        struct ist value;
1250
1251
0
        shctx_row_data_get(shctx, first,
1252
0
                           (unsigned char *)value_buf,
1253
0
                           offset + sizeof(info) + name_len,
1254
0
                           value_len);
1255
1256
0
        value = ist2(value_buf, value_len);
1257
0
        cache_extract_link_hints(value, hint_buf);
1258
0
      }
1259
0
    }
1260
0
    offset += sizeof(info) + name_len + value_len;
1261
0
  }
1262
1263
0
  return b_data(hint_buf);
1264
0
}
1265
1266
/*
1267
 * Walk a live HTX response's headers and accumulate Link values relevant
1268
 * for early hints into <hint_buf>. Returns the number of bytes written
1269
 * to <hint_buf>. Used by the hints-only storage path, where hints have
1270
 * to be extracted before the response is committed to the cache.
1271
 */
1272
static int cache_extract_hints_from_htx(struct htx *htx, struct buffer *hint_buf)
1273
0
{
1274
0
  int32_t pos;
1275
1276
0
  for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
1277
0
    struct htx_blk *blk = htx_get_blk(htx, pos);
1278
0
    enum htx_blk_type type = htx_get_blk_type(blk);
1279
1280
0
    if (type == HTX_BLK_EOH)
1281
0
      break;
1282
0
    if (type == HTX_BLK_HDR) {
1283
0
      struct ist name = htx_get_blk_name(htx, blk);
1284
0
      if (isteq(name, ist("link"))) {
1285
0
        struct ist value = htx_get_blk_value(htx, blk);
1286
0
        cache_extract_link_hints(value, hint_buf);
1287
0
      }
1288
0
    }
1289
0
  }
1290
1291
0
  return b_data(hint_buf);
1292
0
}
1293
1294
/*
1295
 * Strip a full cache entry in place: persist <hint_buf>'s content past
1296
 * sizeof(cache_entry), truncate the row to match, mark the entry as
1297
 * CACHE_EF_STRIPPED, and move it to the hints LRU. Must be called under
1298
 * the shctx wrlock and with the row's refcount at 0.
1299
 *
1300
 * The extracted hint records may end up larger than the original entry
1301
 * (each value is re-joined with ", " and carries a length prefix), so the
1302
 * stripped layout is not guaranteed to be smaller. Only strip when it frees
1303
 * at least one block: this makes room, keeps the copy below within the row,
1304
 * and guarantees forward progress for the make_room() caller. Returns 1 if
1305
 * the entry was stripped, 0 if it was left untouched.
1306
 */
1307
static int cache_strip_entry(struct shared_context *shctx,
1308
                             struct cache_entry *entry,
1309
                             const struct buffer *hint_buf)
1310
0
{
1311
0
  struct cache *cache = (struct cache *)shctx->data;
1312
0
  struct shared_block *first = block_ptr(entry);
1313
0
  struct shared_block *block = first;
1314
0
  const char *src = b_head(hint_buf);
1315
0
  unsigned int new_len = sizeof(struct cache_entry) + b_data(hint_buf);
1316
0
  unsigned int off = sizeof(struct cache_entry);
1317
0
  unsigned int left = b_data(hint_buf);
1318
1319
0
  if ((new_len + shctx->block_size - 1) / shctx->block_size >= first->block_count)
1320
0
    return 0;
1321
1322
0
  while (off >= shctx->block_size) {
1323
0
    block = LIST_NEXT(&block->list, struct shared_block *, list);
1324
0
    off -= shctx->block_size;
1325
0
  }
1326
1327
0
  while (left > 0) {
1328
0
    unsigned int chunk = shctx->block_size - off;
1329
1330
0
    if (chunk > left)
1331
0
      chunk = left;
1332
0
    memcpy(block->data + off, src, chunk);
1333
0
    src += chunk;
1334
0
    left -= chunk;
1335
0
    off = 0;
1336
0
    block = LIST_NEXT(&block->list, struct shared_block *, list);
1337
0
  }
1338
1339
0
  shctx_row_truncate(shctx, first, new_len);
1340
0
  entry->flags |= CACHE_EF_STRIPPED;
1341
0
  LIST_DELETE(&entry->lru);
1342
0
  LIST_APPEND(&cache->hints_lru, &entry->lru);
1343
0
  cache->hints_blocks += first->block_count;
1344
0
  return 1;
1345
0
}
1346
1347
/*
1348
 * Free one entry's blocks. If the hints pool is at or above the limit
1349
 * (as defined by early_hints_ratio), first try to evict the oldest hints
1350
 * entry. Otherwise, pop the oldest full entry and try to strip it. If the
1351
 * entry doesn't contain the relevant Link headers, or if we are past the
1352
 * limit for hints blocks, evict it entirely.
1353
 * Returns 1 on success, 0 if nothing could be freed.
1354
 */
1355
static int cache_make_room(struct shared_context *shctx)
1356
0
{
1357
0
  struct cache *cache = (struct cache *)shctx->data;
1358
0
  struct cache_entry *entry, *back;
1359
0
  int can_strip = (cache->hints_blocks < CACHE_HINTS_CAP(cache));
1360
1361
0
  if (!can_strip) {
1362
0
    list_for_each_entry_safe(entry, back, &cache->hints_lru, lru) {
1363
0
      struct shared_block *first = block_ptr(entry);
1364
1365
0
      if (first->refcount == 0) {
1366
0
        shctx_row_truncate(shctx, first, 0);
1367
0
        return 1;
1368
0
      }
1369
0
    }
1370
0
  }
1371
1372
0
  list_for_each_entry_safe(entry, back, &cache->full_lru, lru) {
1373
0
    struct shared_block *first = block_ptr(entry);
1374
0
    struct buffer *hint_buf = NULL;
1375
0
    int hint_len = 0;
1376
1377
0
    if (first->refcount > 0)
1378
0
      continue;
1379
1380
    /* A key of 0 means the entry is no longer in the tree; its
1381
     * blocks are dead and can be reclaimed right away.
1382
     */
1383
0
    if (!entry->eb.key) {
1384
0
      shctx_row_truncate(shctx, first, 0);
1385
0
      return 1;
1386
0
    }
1387
1388
0
    if (can_strip) {
1389
0
      hint_buf = get_trash_chunk();
1390
0
      hint_len = cache_extract_hints(shctx, first, hint_buf);
1391
0
    }
1392
1393
    /* Strip the entry to keep its hints; fall back to evicting it
1394
     * whole if it has no hints or stripping would free no block.
1395
     */
1396
0
    if (hint_len <= 0 || !cache_strip_entry(shctx, entry, hint_buf))
1397
0
      shctx_row_truncate(shctx, first, 0);
1398
1399
0
    return 1;
1400
0
  }
1401
1402
0
  return 0;
1403
0
}
1404
1405
static void cache_reserve_finish(struct shared_context *shctx)
1406
0
{
1407
0
  struct cache_entry *object, *back;
1408
0
  struct cache *cache = (struct cache *)shctx->data;
1409
0
  struct cache_tree *cache_tree;
1410
0
  int cache_tree_idx = 0;
1411
1412
0
  for (; cache_tree_idx < CACHE_TREE_NUM; ++cache_tree_idx) {
1413
0
    cache_tree = &cache->trees[cache_tree_idx];
1414
1415
0
    cache_wrlock(cache_tree);
1416
0
    HA_SPIN_LOCK(CACHE_LOCK, &cache_tree->cleanup_lock);
1417
1418
0
    list_for_each_entry_safe(object, back, &cache_tree->cleanup_list, cleanup_list) {
1419
0
      LIST_DELETE(&object->cleanup_list);
1420
      /*
1421
       * At this point we locked the cache tree in write mode
1422
       * so no new thread could retain the current entry
1423
       * because the only two places where it can happen is in
1424
       * the cache_use case which is under cache_rdlock and
1425
       * the reserve_hot case which would require the
1426
       * corresponding block to still be in the avail list,
1427
       * which is impossible (we reserved it for a thread and
1428
       * took it out of the avail list already). The only two
1429
       * references are then the default one (upon cache_entry
1430
       * creation) and the one in this cleanup list.
1431
       */
1432
0
      BUG_ON(object->refcount > 2);
1433
0
      delete_entry(object);
1434
0
    }
1435
1436
0
    HA_SPIN_UNLOCK(CACHE_LOCK, &cache_tree->cleanup_lock);
1437
0
    cache_wrunlock(cache_tree);
1438
0
  }
1439
0
}
1440
1441
1442
/* As per RFC 7234#4.3.2, in case of "If-Modified-Since" conditional request, the
1443
 * date value should be compared to a date determined by in a previous response (for
1444
 * the same entity). This date could either be the "Last-Modified" value, or the "Date"
1445
 * value of the response's reception time (by decreasing order of priority). */
1446
static time_t get_last_modified_time(struct htx *htx)
1447
0
{
1448
0
  time_t last_modified = 0;
1449
0
  struct http_hdr_ctx ctx = { .blk = NULL };
1450
0
  struct tm tm = {};
1451
1452
0
  if (http_find_header(htx, ist("last-modified"), &ctx, 1)) {
1453
0
    if (parse_http_date(istptr(ctx.value), istlen(ctx.value), &tm)) {
1454
0
      last_modified = my_timegm(&tm);
1455
0
    }
1456
0
  }
1457
1458
0
  if (!last_modified) {
1459
0
    ctx.blk = NULL;
1460
0
    if (http_find_header(htx, ist("date"), &ctx, 1)) {
1461
0
      if (parse_http_date(istptr(ctx.value), istlen(ctx.value), &tm)) {
1462
0
        last_modified = my_timegm(&tm);
1463
0
      }
1464
0
    }
1465
0
  }
1466
1467
  /* Fallback on the current time if no "Last-Modified" or "Date" header
1468
   * was found. */
1469
0
  if (!last_modified)
1470
0
    last_modified = date.tv_sec;
1471
1472
0
  return last_modified;
1473
0
}
1474
1475
/*
1476
 * Checks the vary header's value. The headers on which vary should be applied
1477
 * must be explicitly supported in the vary_information array (see cache.c). If
1478
 * any other header is mentioned, we won't store the response.
1479
 * Returns 1 if Vary-based storage can work, 0 otherwise.
1480
 */
1481
static int http_check_vary_header(struct htx *htx, unsigned int *vary_signature)
1482
0
{
1483
0
  unsigned int vary_idx;
1484
0
  unsigned int vary_info_count;
1485
0
  const struct vary_hashing_information *vary_info;
1486
0
  struct http_hdr_ctx ctx = { .blk = NULL };
1487
1488
0
  int retval = 1;
1489
1490
0
  *vary_signature = 0;
1491
1492
0
  vary_info_count = sizeof(vary_information)/sizeof(*vary_information);
1493
0
  while (retval && http_find_header(htx, ist("Vary"), &ctx, 0)) {
1494
0
    for (vary_idx = 0; vary_idx < vary_info_count; ++vary_idx) {
1495
0
      vary_info = &vary_information[vary_idx];
1496
0
      if (isteqi(ctx.value, vary_info->hdr_name)) {
1497
0
        *vary_signature |= vary_info->value;
1498
0
        break;
1499
0
      }
1500
0
    }
1501
0
    retval = (vary_idx < vary_info_count);
1502
0
  }
1503
1504
0
  return retval;
1505
0
}
1506
1507
1508
/*
1509
 * Look for the accept-encoding part of the secondary_key and replace the
1510
 * encoding bitmap part of the hash with the actual encoding of the response,
1511
 * extracted from the content-encoding header value.
1512
 * Responses that have an unknown encoding will not be cached if they also
1513
 * "vary" on the accept-encoding value.
1514
 * Returns 0 if we found a known encoding in the response, -1 otherwise.
1515
 */
1516
static int set_secondary_key_encoding(struct htx *htx, unsigned int vary_signature, char *secondary_key)
1517
0
{
1518
0
  unsigned int resp_encoding_bitmap = 0;
1519
0
  const struct vary_hashing_information *info = vary_information;
1520
0
  unsigned int offset = 0;
1521
0
  unsigned int count = 0;
1522
0
  unsigned int hash_info_count = sizeof(vary_information)/sizeof(*vary_information);
1523
0
  unsigned int encoding_value;
1524
0
  struct http_hdr_ctx ctx = { .blk = NULL };
1525
1526
  /* We must not set the accept encoding part of the secondary signature
1527
   * if the response does not vary on 'Accept Encoding'. */
1528
0
  if (!(vary_signature & VARY_ACCEPT_ENCODING))
1529
0
    return 0;
1530
1531
  /* Look for the accept-encoding part of the secondary_key. */
1532
0
  while (count < hash_info_count && info->value != VARY_ACCEPT_ENCODING) {
1533
0
    offset += info->hash_length;
1534
0
    ++info;
1535
0
    ++count;
1536
0
  }
1537
1538
0
  if (count == hash_info_count)
1539
0
    return -1;
1540
1541
0
  while (http_find_header(htx, ist("content-encoding"), &ctx, 0)) {
1542
0
    if (parse_encoding_value(ctx.value, &encoding_value, NULL))
1543
0
      return -1; /* Do not store responses with an unknown encoding */
1544
0
    resp_encoding_bitmap |= encoding_value;
1545
0
  }
1546
1547
0
  if (!resp_encoding_bitmap)
1548
0
    resp_encoding_bitmap |= VARY_ENCODING_IDENTITY;
1549
1550
  /* Rewrite the bitmap part of the hash with the new bitmap that only
1551
   * corresponds the the response's encoding. */
1552
0
  write_u32(secondary_key + offset, resp_encoding_bitmap);
1553
1554
0
  return 0;
1555
0
}
1556
1557
1558
/*
1559
 * This function will store the headers of the response in a buffer and then
1560
 * register a filter to store the data
1561
 */
1562
enum act_return http_action_store_cache(struct act_rule *rule, struct proxy *px,
1563
          struct session *sess, struct stream *s, int flags)
1564
0
{
1565
0
  int effective_maxage = 0;
1566
0
  int true_maxage = 0;
1567
0
  struct http_txn *txn = s->txn.http;
1568
0
  struct http_msg *msg = &txn->rsp;
1569
0
  struct filter *filter;
1570
0
  struct shared_block *first = NULL;
1571
0
  struct cache_flt_conf *cconf = rule->arg.act.p[0];
1572
0
  struct cache *cache = cconf->c.cache;
1573
0
  struct shared_context *shctx = shctx_ptr(cache);
1574
0
  struct cache_st *cache_ctx = NULL;
1575
0
  struct cache_entry *object = NULL, *old;
1576
0
  unsigned int key = read_u32(txn->cache_hash);
1577
0
  struct htx *htx;
1578
0
  struct http_hdr_ctx ctx;
1579
0
  size_t hdrs_len = 0;
1580
0
  int32_t pos;
1581
0
  unsigned int vary_signature = 0;
1582
0
  struct cache_tree *cache_tree = NULL;
1583
1584
  /* Don't cache if the response came from a cache */
1585
0
  if ((obj_type(s->target) == OBJ_TYPE_APPLET) &&
1586
0
      s->target == &http_cache_applet.obj_type) {
1587
0
    goto out;
1588
0
  }
1589
1590
  /* cache only HTTP/1.1 */
1591
0
  if (!(txn->req.flags & HTTP_MSGF_VER_11))
1592
0
    goto out;
1593
1594
0
  cache_tree = get_cache_tree_from_hash(cache, read_u32(txn->cache_hash));
1595
1596
  /* cache only GET method */
1597
0
  if (txn->meth != HTTP_METH_GET) {
1598
    /* In case of successful unsafe method on a stored resource, the
1599
     * cached entry must be invalidated (see RFC7234#4.4).
1600
     * A "non-error response" is one with a 2xx (Successful) or 3xx
1601
     * (Redirection) status code. */
1602
0
    if (txn->status >= 200 && txn->status < 400) {
1603
0
      switch (txn->meth) {
1604
0
      case HTTP_METH_OPTIONS:
1605
0
      case HTTP_METH_GET:
1606
0
      case HTTP_METH_HEAD:
1607
0
      case HTTP_METH_TRACE:
1608
0
        break;
1609
1610
0
      default: /* Any unsafe method */
1611
        /* Discard any corresponding entry in case of successful
1612
         * unsafe request (such as PUT, POST or DELETE). */
1613
0
        cache_wrlock(cache_tree);
1614
1615
0
        old = get_entry(cache_tree, txn->cache_hash, 1);
1616
0
        if (old)
1617
0
          release_entry_locked(cache_tree, old);
1618
0
        cache_wrunlock(cache_tree);
1619
0
      }
1620
0
    }
1621
0
    goto out;
1622
0
  }
1623
1624
  /* cache key was not computed */
1625
0
  if (!key)
1626
0
    goto out;
1627
1628
  /* cache only 200 status code */
1629
0
  if (txn->status != 200)
1630
0
    goto out;
1631
1632
  /* Find the corresponding filter instance for the current stream */
1633
0
  list_for_each_entry(filter, &s->strm_flt.filters, list) {
1634
0
    if (FLT_ID(filter) == cache_store_flt_id  && FLT_CONF(filter) == cconf) {
1635
      /* No filter ctx, don't cache anything */
1636
0
      if (!filter->ctx)
1637
0
        goto out;
1638
0
      cache_ctx = filter->ctx;
1639
0
      break;
1640
0
    }
1641
0
  }
1642
1643
  /* from there, cache_ctx is always defined */
1644
0
  htx = htxbuf(&s->res.buf);
1645
1646
  /* Do not cache too big objects. */
1647
0
  if ((msg->flags & HTTP_MSGF_CNT_LEN) &&
1648
0
      !(cache->flags & CACHE_CF_EARLY_HINTS_ONLY) &&
1649
0
      shctx->max_obj_size > 0 && s->scb->sedesc->kip > shctx->max_obj_size)
1650
0
    goto out;
1651
1652
  /* Only a subset of headers are supported in our Vary implementation. If
1653
   * any other header is present in the Vary header value, we won't be
1654
   * able to use the cache. Likewise, if Vary header support is disabled,
1655
   * avoid caching responses that contain such a header. */
1656
0
  ctx.blk = NULL;
1657
0
  if (cache->flags & CACHE_CF_VARY_PROCESSING) {
1658
0
    if (!http_check_vary_header(htx, &vary_signature))
1659
0
      goto out;
1660
0
    if (vary_signature) {
1661
      /* If something went wrong during the secondary key
1662
       * building, do not store the response. */
1663
0
      if (!(txn->flags & TX_CACHE_HAS_SEC_KEY))
1664
0
        goto out;
1665
0
      http_request_reduce_secondary_key(vary_signature, txn->cache_secondary_hash);
1666
0
    }
1667
0
  }
1668
0
  else if (http_find_header(htx, ist("Vary"), &ctx, 0)) {
1669
0
    goto out;
1670
0
  }
1671
1672
0
  http_check_response_for_cacheability(s, &s->res);
1673
1674
0
  if (!(txn->flags & TX_CACHEABLE) || !(txn->flags & TX_CACHE_COOK))
1675
0
    goto out;
1676
1677
0
  cache_wrlock(cache_tree);
1678
0
  old = get_entry(cache_tree, txn->cache_hash, 1);
1679
0
  if (old) {
1680
0
    if (vary_signature)
1681
0
      old = get_secondary_entry(cache_tree, old,
1682
0
                                txn->cache_hash, txn->cache_secondary_hash, 1);
1683
0
    if (old) {
1684
0
      if (!(old->flags & CACHE_EF_COMPLETE)) {
1685
        /* An entry with the same primary key is already being
1686
         * created, we should not try to store the current
1687
         * response because it will waste space in the cache. */
1688
0
        cache_wrunlock(cache_tree);
1689
0
        goto out;
1690
0
      }
1691
0
      release_entry_locked(cache_tree, old);
1692
0
    }
1693
0
  }
1694
0
  cache_wrunlock(cache_tree);
1695
1696
0
  first = shctx_row_reserve_hot(shctx, NULL, sizeof(struct cache_entry));
1697
0
  if (!first) {
1698
0
    goto out;
1699
0
  }
1700
1701
  /* the received memory is not initialized, we need at least to mark
1702
   * the object as not indexed yet.
1703
   */
1704
0
  object = (struct cache_entry *)first->data;
1705
0
  memset(object, 0, sizeof(*object));
1706
0
  LIST_INIT(&object->lru);
1707
0
  object->eb.key = key;
1708
0
  object->secondary_key_signature = vary_signature;
1709
  /* We need to temporarily set a valid expiring time until the actual one
1710
   * is set by the end of this function (in case of concurrent accesses to
1711
   * the same resource). This way the second access will find an existing
1712
   * but not yet usable entry in the tree and will avoid storing its data. */
1713
0
  object->expire = date.tv_sec + 2;
1714
1715
0
  memcpy(object->hash, txn->cache_hash, sizeof(object->hash));
1716
0
  if (vary_signature)
1717
0
    memcpy(object->secondary_key, txn->cache_secondary_hash, HTTP_CACHE_SEC_KEY_LEN);
1718
1719
0
  cache_wrlock(cache_tree);
1720
  /* Insert the entry in the tree even if the payload is not cached yet. */
1721
0
  if (insert_entry(cache, cache_tree, object) != &object->eb) {
1722
0
    object->eb.key = 0;
1723
0
    cache_wrunlock(cache_tree);
1724
0
    goto out;
1725
0
  }
1726
0
  cache_wrunlock(cache_tree);
1727
1728
  /* reserve space for the cache_entry structure */
1729
0
  first->len = sizeof(struct cache_entry);
1730
0
  first->last_append = NULL;
1731
1732
  /* Determine the entry's maximum age (taking into account the cache's
1733
   * configuration) as well as the response's explicit max age (extracted
1734
   * from cache-control directives or the expires header). */
1735
0
  effective_maxage = http_calc_maxage(s, cache, &true_maxage);
1736
1737
0
  ctx.blk = NULL;
1738
0
  if (http_find_header(htx, ist("Age"), &ctx, 0)) {
1739
0
    long long hdr_age;
1740
0
    if (!strl2llrc(ctx.value.ptr, ctx.value.len, &hdr_age) && hdr_age > 0) {
1741
0
      if (unlikely(hdr_age > CACHE_ENTRY_MAX_AGE))
1742
0
        hdr_age = CACHE_ENTRY_MAX_AGE;
1743
      /* A response with an Age value greater than its
1744
       * announced max age is stale and should not be stored. */
1745
0
      object->age = hdr_age;
1746
0
      if (unlikely(object->age > true_maxage))
1747
0
        goto out;
1748
0
    }
1749
0
    else
1750
0
      goto out;
1751
    /* The cache serves its copies with a freshly computed Age, so
1752
     * the stored response's Age is stripped. In hints-only mode the
1753
     * response is only passed through, never served, so leave it.
1754
     */
1755
0
    if (!(cache->flags & CACHE_CF_EARLY_HINTS_ONLY))
1756
0
      http_remove_header(htx, &ctx);
1757
0
  }
1758
1759
  /* Build a last-modified time that will be stored in the cache_entry and
1760
   * compared to a future If-Modified-Since client header. */
1761
0
  object->last_modified = get_last_modified_time(htx);
1762
1763
0
  chunk_reset(&trash);
1764
0
  if (cache->flags & CACHE_CF_EARLY_HINTS_ONLY) {
1765
0
    cache_extract_hints_from_htx(htx, &trash);
1766
0
    if (b_data(&trash) == 0)
1767
0
      goto out;
1768
0
  } else {
1769
0
    for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
1770
0
      struct htx_blk *blk = htx_get_blk(htx, pos);
1771
0
      enum htx_blk_type type = htx_get_blk_type(blk);
1772
0
      uint32_t sz = htx_get_blksz(blk);
1773
1774
0
      hdrs_len += sizeof(*blk) + sz;
1775
0
      chunk_memcat(&trash, (char *)&blk->info, sizeof(blk->info));
1776
0
      chunk_memcat(&trash, htx_get_blk_ptr(htx, blk), sz);
1777
1778
      /* Look for optional ETag header.
1779
       * We need to store the offset of the ETag value in order for
1780
       * future conditional requests to be able to perform ETag
1781
       * comparisons. */
1782
0
      if (type == HTX_BLK_HDR) {
1783
0
        struct ist header_name = htx_get_blk_name(htx, blk);
1784
0
        if (isteq(header_name, ist("etag"))) {
1785
0
          object->etag_length = sz - istlen(header_name);
1786
0
          object->etag_offset = sizeof(struct cache_entry) +
1787
0
                                b_data(&trash) - sz +
1788
0
                                istlen(header_name);
1789
0
        }
1790
0
      }
1791
0
      if (type == HTX_BLK_EOH)
1792
0
        break;
1793
0
    }
1794
1795
    /* Do not cache objects if the headers are too big. */
1796
0
    if (hdrs_len > htx->size - global.tune.maxrewrite)
1797
0
      goto out;
1798
0
  }
1799
1800
  /* If the response has a secondary_key, fill its key part related to
1801
   * encodings with the actual encoding of the response. This way any
1802
   * subsequent request having the same primary key will have its accepted
1803
   * encodings tested upon the cached response's one.
1804
   * We will not cache a response that has an unknown encoding (not
1805
   * explicitly supported in parse_encoding_value function). */
1806
0
  if ((cache->flags & CACHE_CF_VARY_PROCESSING) && vary_signature)
1807
0
    if (set_secondary_key_encoding(htx, vary_signature, object->secondary_key))
1808
0
        goto out;
1809
1810
0
  if (!shctx_row_reserve_hot(shctx, first, trash.data)) {
1811
0
    goto out;
1812
0
  }
1813
1814
  /* cache the headers in a http action because it allows to chose what
1815
   * to cache, for example you might want to cache a response before
1816
   * modifying some HTTP headers, or on the contrary after modifying
1817
   * those headers.
1818
   */
1819
  /* does not need to be locked because it's in the "hot" list,
1820
   * copy the headers */
1821
0
  if (shctx_row_data_append(shctx, first, (unsigned char *)trash.area, trash.data) < 0)
1822
0
    goto out;
1823
1824
  /* store latest value and expiration time */
1825
0
  object->latest_validation = date.tv_sec;
1826
0
  object->expire = date.tv_sec + effective_maxage;
1827
1828
0
  if (cache->flags & CACHE_CF_EARLY_HINTS_ONLY) {
1829
    /* Finalize hints-only entry. */
1830
0
    shctx_wrlock(shctx);
1831
0
    object->flags |= CACHE_EF_COMPLETE | CACHE_EF_STRIPPED;
1832
0
    cache->hints_blocks += first->block_count;
1833
0
    cache_row_reattach(cache, first);
1834
0
    shctx_wrunlock(shctx);
1835
0
    return ACT_RET_CONT;
1836
0
  }
1837
1838
  /* register the buffer in the filter ctx for filling it with data*/
1839
0
  if (cache_ctx) {
1840
0
    cache_ctx->first_block = first;
1841
0
    LIST_INIT(&cache_ctx->detached_head);
1842
0
    return ACT_RET_CONT;
1843
0
  }
1844
1845
0
out:
1846
  /* if does not cache */
1847
0
  if (first) {
1848
0
    first->len = 0;
1849
0
    if (object->eb.key) {
1850
0
      release_entry_unlocked(cache_tree, object);
1851
0
    }
1852
0
    shctx_wrlock(shctx);
1853
0
    cache_row_reattach(cache, first);
1854
0
    shctx_wrunlock(shctx);
1855
0
  }
1856
1857
0
  return ACT_RET_CONT;
1858
0
}
1859
1860
0
#define   HTX_CACHE_INIT   0  /* Initial state. */
1861
0
#define   HTX_CACHE_HEADER 1  /* Cache entry headers forwarding */
1862
0
#define   HTX_CACHE_DATA   2  /* Cache entry data forwarding */
1863
0
#define   HTX_CACHE_EOM    3  /* Cache entry completely forwarded. Finish the HTX message */
1864
0
#define   HTX_CACHE_END    4  /* Cache entry treatment terminated */
1865
1866
static void http_cache_applet_release(struct appctx *appctx)
1867
0
{
1868
0
  struct cache_appctx *ctx = appctx->svcctx;
1869
0
  struct cache_entry *cache_ptr = ctx->entry;
1870
0
  struct shared_context *shctx = shctx_ptr(ctx->cache);
1871
0
  struct shared_block *first = block_ptr(cache_ptr);
1872
1873
0
  release_entry(ctx->cache_tree, cache_ptr, 1);
1874
1875
0
  shctx_wrlock(shctx);
1876
0
  cache_row_reattach(ctx->cache, first);
1877
0
  shctx_wrunlock(shctx);
1878
0
}
1879
1880
1881
static unsigned int htx_cache_dump_blk(struct appctx *appctx, struct htx *htx, enum htx_blk_type type,
1882
               uint32_t info, struct shared_block *shblk, unsigned int offset)
1883
0
{
1884
0
  struct cache_appctx *ctx = appctx->svcctx;
1885
0
  struct shared_context *shctx = shctx_ptr(ctx->cache);
1886
0
  struct htx_blk *blk;
1887
0
  char *ptr;
1888
0
  unsigned int max, total;
1889
0
  uint32_t blksz;
1890
1891
0
  max = htx_free_data_space(htx);
1892
0
  if (!max)
1893
0
    return 0;
1894
0
  blksz = ((type == HTX_BLK_HDR || type == HTX_BLK_TLR)
1895
0
     ? (info & 0xff) + ((info >> 8) & 0xfffff)
1896
0
     : info & 0xfffffff);
1897
0
  if (blksz > max)
1898
0
    return 0;
1899
1900
0
  blk = htx_add_blk(htx, type, blksz);
1901
0
  if (!blk)
1902
0
    return 0;
1903
1904
0
  blk->info = info;
1905
0
  total = 4;
1906
0
  ptr = htx_get_blk_ptr(htx, blk);
1907
0
  while (blksz) {
1908
0
    max = MIN(blksz, shctx->block_size - offset);
1909
0
    memcpy(ptr, (const char *)shblk->data + offset, max);
1910
0
    offset += max;
1911
0
    blksz  -= max;
1912
0
    total  += max;
1913
0
    ptr    += max;
1914
0
    if (blksz || offset == shctx->block_size) {
1915
0
      shblk = LIST_NEXT(&shblk->list, typeof(shblk), list);
1916
0
      offset = 0;
1917
0
    }
1918
0
  }
1919
0
  ctx->offset = offset;
1920
0
  ctx->next   = shblk;
1921
0
  ctx->sent  += total;
1922
0
  return total;
1923
0
}
1924
1925
static unsigned int htx_cache_dump_data_blk(struct appctx *appctx, struct htx *htx,
1926
              uint32_t info, struct shared_block *shblk, unsigned int offset)
1927
0
{
1928
0
  struct cache_appctx *ctx = appctx->svcctx;
1929
0
  struct shared_context *shctx = shctx_ptr(ctx->cache);
1930
0
  unsigned int max, total, rem_data, data_len;
1931
0
  uint32_t blksz;
1932
1933
0
  max = htx_free_data_space(htx);
1934
0
  if (!max)
1935
0
    return 0;
1936
1937
0
  data_len = 0;
1938
0
  rem_data = 0;
1939
0
  if (ctx->rem_data) {
1940
0
    blksz = ctx->rem_data;
1941
0
    total = 0;
1942
0
  }
1943
0
  else {
1944
0
    blksz = (info & 0xfffffff);
1945
0
    total = 4;
1946
0
  }
1947
0
  if (blksz > max) {
1948
0
    rem_data = blksz - max;
1949
0
    blksz = max;
1950
0
  }
1951
1952
0
  while (blksz) {
1953
0
    size_t sz;
1954
1955
0
    max = MIN(blksz, shctx->block_size - offset);
1956
0
    sz  = htx_add_data(htx, ist2(shblk->data + offset, max));
1957
0
    offset += sz;
1958
0
    blksz  -= sz;
1959
0
    total  += sz;
1960
0
    data_len += sz;
1961
0
    if (sz < max)
1962
0
      break;
1963
0
    if (blksz || offset == shctx->block_size) {
1964
0
      shblk = LIST_NEXT(&shblk->list, typeof(shblk), list);
1965
0
      offset = 0;
1966
0
    }
1967
0
  }
1968
1969
0
  ctx->offset   = offset;
1970
0
  ctx->next     = shblk;
1971
0
  ctx->sent    += total;
1972
0
  ctx->rem_data = rem_data + blksz;
1973
0
  appctx->to_forward -= data_len;
1974
0
  return total;
1975
0
}
1976
1977
static size_t htx_cache_dump_msg(struct appctx *appctx, struct htx *htx, unsigned int len,
1978
         enum htx_blk_type mark)
1979
0
{
1980
0
  struct cache_appctx *ctx = appctx->svcctx;
1981
0
  struct shared_context *shctx = shctx_ptr(ctx->cache);
1982
0
  struct shared_block   *shblk;
1983
0
  unsigned int offset, sz;
1984
0
  unsigned int ret, total = 0;
1985
1986
0
  while (len) {
1987
0
    enum htx_blk_type type;
1988
0
    uint32_t info;
1989
1990
0
    shblk  = ctx->next;
1991
0
    offset = ctx->offset;
1992
0
    if (ctx->rem_data) {
1993
0
      type = HTX_BLK_DATA;
1994
0
      info = 0;
1995
0
      goto add_data_blk;
1996
0
    }
1997
1998
    /* Get info of the next HTX block. May be split on 2 shblk */
1999
0
    sz = MIN(4, shctx->block_size - offset);
2000
0
    memcpy((char *)&info, (const char *)shblk->data + offset, sz);
2001
0
    offset += sz;
2002
0
    if (sz < 4) {
2003
0
      shblk = LIST_NEXT(&shblk->list, typeof(shblk), list);
2004
0
      memcpy(((char *)&info)+sz, (const char *)shblk->data, 4 - sz);
2005
0
      offset = (4 - sz);
2006
0
    }
2007
2008
    /* Get payload of the next HTX block and insert it. */
2009
0
    type = (info >> 28);
2010
0
    if (type != HTX_BLK_DATA)
2011
0
      ret = htx_cache_dump_blk(appctx, htx, type, info, shblk, offset);
2012
0
    else {
2013
0
      add_data_blk:
2014
0
      ret = htx_cache_dump_data_blk(appctx, htx, info, shblk, offset);
2015
0
    }
2016
2017
0
    if (!ret)
2018
0
      break;
2019
0
    total += ret;
2020
0
    len   -= ret;
2021
2022
0
    if (ctx->rem_data || type == mark)
2023
0
      break;
2024
0
  }
2025
2026
0
  return total;
2027
0
}
2028
2029
static unsigned int ff_cache_dump_data_blk(struct appctx *appctx, struct buffer *buf, unsigned int len,
2030
             uint32_t info, struct shared_block *shblk, unsigned int offset)
2031
0
{
2032
0
  struct cache_appctx *ctx = appctx->svcctx;
2033
0
  struct shared_context *shctx = shctx_ptr(ctx->cache);
2034
0
  unsigned int total, rem_data, data_len;
2035
0
  uint32_t blksz;
2036
2037
0
  total = 0;
2038
0
  data_len = 0;
2039
0
  rem_data = 0;
2040
0
  if (ctx->rem_data)
2041
0
    blksz = ctx->rem_data;
2042
0
  else {
2043
0
    blksz = (info & 0xfffffff);
2044
0
    ctx->sent += 4;
2045
0
  }
2046
0
  if (blksz > len) {
2047
0
    rem_data = blksz - len;
2048
0
    blksz = len;
2049
0
  }
2050
2051
0
  while (blksz) {
2052
0
    size_t sz;
2053
2054
0
    len = MIN(blksz, shctx->block_size - offset);
2055
0
    sz = b_putblk(buf, (char *)(shblk->data + offset), len);
2056
0
    offset += sz;
2057
0
    blksz  -= sz;
2058
0
    total  += sz;
2059
0
    data_len += sz;
2060
0
    if (sz < len)
2061
0
      break;
2062
0
    if (blksz || offset == shctx->block_size) {
2063
0
      shblk = LIST_NEXT(&shblk->list, typeof(shblk), list);
2064
0
      offset = 0;
2065
0
    }
2066
0
  }
2067
2068
0
  ctx->offset   = offset;
2069
0
  ctx->next     = shblk;
2070
0
  ctx->sent    += total;
2071
0
  ctx->rem_data = rem_data + blksz;
2072
0
  appctx->to_forward -= data_len;
2073
0
  return total;
2074
0
}
2075
2076
static size_t ff_cache_dump_msg(struct appctx *appctx, struct buffer *buf, unsigned int len)
2077
0
{
2078
0
  struct cache_appctx *ctx = appctx->svcctx;
2079
0
  struct cache_entry *cache_ptr = ctx->entry;
2080
0
  struct shared_block *first = block_ptr(cache_ptr);
2081
0
  struct shared_context *shctx = shctx_ptr(ctx->cache);
2082
0
  struct shared_block   *shblk;
2083
0
  unsigned int offset, sz;
2084
0
  unsigned int ret, total = 0;
2085
2086
0
  while (len && (ctx->sent != first->len - sizeof(*cache_ptr))) {
2087
0
    enum htx_blk_type type;
2088
0
    uint32_t info;
2089
2090
0
    shblk  = ctx->next;
2091
0
    offset = ctx->offset;
2092
0
    if (ctx->rem_data) {
2093
0
      type = HTX_BLK_DATA;
2094
0
      info = 0;
2095
0
      goto add_data_blk;
2096
0
    }
2097
2098
    /* Get info of the next HTX block. May be split on 2 shblk */
2099
0
    sz = MIN(4, shctx->block_size - offset);
2100
0
    memcpy((char *)&info, (const char *)shblk->data + offset, sz);
2101
0
    offset += sz;
2102
0
    if (sz < 4) {
2103
0
      shblk = LIST_NEXT(&shblk->list, typeof(shblk), list);
2104
0
      memcpy(((char *)&info)+sz, (const char *)shblk->data, 4 - sz);
2105
0
      offset = (4 - sz);
2106
0
    }
2107
2108
    /* Get payload of the next HTX block and insert it. */
2109
0
    type = (info >> 28);
2110
0
    if (type == HTX_BLK_DATA) {
2111
0
      add_data_blk:
2112
0
      ret = ff_cache_dump_data_blk(appctx, buf, len, info, shblk, offset);
2113
0
    }
2114
0
    else
2115
0
      ret = 0;
2116
2117
0
    if (!ret)
2118
0
      break;
2119
0
    total += ret;
2120
0
    len   -= ret;
2121
2122
0
    if (ctx->rem_data)
2123
0
      break;
2124
0
  }
2125
2126
0
  return total;
2127
0
}
2128
2129
static int htx_cache_add_age_hdr(struct appctx *appctx, struct htx *htx)
2130
0
{
2131
0
  struct cache_appctx *ctx = appctx->svcctx;
2132
0
  struct cache_entry *cache_ptr = ctx->entry;
2133
0
  unsigned int age;
2134
0
  char *end;
2135
2136
0
  chunk_reset(&trash);
2137
0
  age = MAX(0, (int)(date.tv_sec - cache_ptr->latest_validation)) + cache_ptr->age;
2138
0
  if (unlikely(age > CACHE_ENTRY_MAX_AGE))
2139
0
    age = CACHE_ENTRY_MAX_AGE;
2140
0
  end = ultoa_o(age, b_head(&trash), b_size(&trash));
2141
0
  b_set_data(&trash, end - b_head(&trash));
2142
0
  if (!http_add_header(htx, ist("Age"), ist2(b_head(&trash), b_data(&trash)), 0))
2143
0
    return 0;
2144
0
  return 1;
2145
0
}
2146
2147
static size_t http_cache_fastfwd(struct appctx *appctx, struct buffer *buf, size_t count, unsigned int flags)
2148
0
{
2149
0
  struct cache_appctx *ctx = appctx->svcctx;
2150
0
  struct cache_entry *cache_ptr = ctx->entry;
2151
0
  struct shared_block *first = block_ptr(cache_ptr);
2152
0
  size_t ret;
2153
2154
0
  BUG_ON(!appctx->to_forward || count > appctx->to_forward);
2155
2156
0
  ret = ff_cache_dump_msg(appctx, buf, count);
2157
2158
0
  if (!appctx->to_forward) {
2159
0
    se_fl_clr(appctx->sedesc, SE_FL_MAY_FASTFWD_PROD);
2160
0
    applet_fl_clr(appctx, APPCTX_FL_FASTFWD);
2161
0
    if (ctx->sent == first->len - sizeof(*cache_ptr)) {
2162
0
      applet_set_eoi(appctx);
2163
0
      applet_set_eos(appctx);
2164
0
      appctx->st0 = HTX_CACHE_END;
2165
0
    }
2166
0
  }
2167
0
  return ret;
2168
0
}
2169
2170
static void http_cache_io_handler(struct appctx *appctx)
2171
0
{
2172
0
  struct cache_appctx *ctx = appctx->svcctx;
2173
0
  struct cache_entry *cache_ptr = ctx->entry;
2174
0
  struct shared_block *first = block_ptr(cache_ptr);
2175
0
  struct htx *res_htx = NULL;
2176
0
  struct buffer *errmsg;
2177
0
  unsigned int len;
2178
0
  size_t ret;
2179
2180
0
  if (applet_fl_test(appctx, APPCTX_FL_INBLK_ALLOC|APPCTX_FL_OUTBLK_ALLOC|APPCTX_FL_OUTBLK_FULL))
2181
0
    goto exit;
2182
2183
0
  if (applet_fl_test(appctx, APPCTX_FL_FASTFWD) && se_fl_test(appctx->sedesc, SE_FL_MAY_FASTFWD_PROD))
2184
0
    goto exit;
2185
2186
0
  if (appctx->st0 == HTX_CACHE_INIT) {
2187
0
    if (!appctx_get_buf(appctx, &appctx->inbuf) || htx_is_empty(htxbuf(&appctx->inbuf)))
2188
0
      goto wait_request;
2189
2190
0
    ctx->next = block_ptr(cache_ptr);
2191
0
    ctx->offset = sizeof(*cache_ptr);
2192
0
    ctx->sent = 0;
2193
0
    ctx->rem_data = 0;
2194
0
    appctx->st0 = HTX_CACHE_HEADER;
2195
0
  }
2196
2197
0
  if (!appctx_get_buf(appctx, &appctx->outbuf)) {
2198
0
    goto exit;
2199
0
  }
2200
2201
0
  if (unlikely(applet_fl_test(appctx, APPCTX_FL_EOS|APPCTX_FL_ERROR))) {
2202
0
    goto exit;
2203
0
  }
2204
2205
0
  len = first->len - sizeof(*cache_ptr) - ctx->sent;
2206
0
  res_htx = htx_from_buf(&appctx->outbuf);
2207
2208
0
  if (appctx->st0 == HTX_CACHE_HEADER) {
2209
0
    struct ist meth;
2210
2211
0
    if (unlikely(applet_fl_test(appctx, APPCTX_FL_INBLK_ALLOC))) {
2212
0
      goto exit;
2213
0
    }
2214
2215
    /* Headers must be dump at once. Otherwise it is an error */
2216
0
    ret = htx_cache_dump_msg(appctx, res_htx, len, HTX_BLK_EOH);
2217
0
    if (!ret || (htx_get_tail_type(res_htx) != HTX_BLK_EOH) ||
2218
0
        !htx_cache_add_age_hdr(appctx, res_htx))
2219
0
      goto error;
2220
2221
    /* In case of a conditional request, we might want to send a
2222
     * "304 Not Modified" response instead of the stored data. */
2223
0
    if (ctx->send_notmodified) {
2224
0
      if (!http_replace_res_status(res_htx, ist("304"), ist("Not Modified"))) {
2225
        /* If replacing the status code fails we need to send the full response. */
2226
0
        ctx->send_notmodified = 0;
2227
0
      }
2228
0
    }
2229
2230
    /* Skip response body for HEAD requests or in case of "304 Not
2231
     * Modified" response. */
2232
0
    meth = htx_sl_req_meth(http_get_stline(htxbuf(&appctx->inbuf)));
2233
0
    if (find_http_meth(istptr(meth), istlen(meth)) == HTTP_METH_HEAD || ctx->send_notmodified)
2234
0
      appctx->st0 = HTX_CACHE_EOM;
2235
0
    else {
2236
0
      if (!(global.tune.no_zero_copy_fwd & NO_ZERO_COPY_FWD_APPLET))
2237
0
        se_fl_set(appctx->sedesc, SE_FL_MAY_FASTFWD_PROD);
2238
2239
0
      appctx->to_forward = cache_ptr->body_size;
2240
0
      len = first->len - sizeof(*cache_ptr) - ctx->sent;
2241
0
      appctx->st0 = HTX_CACHE_DATA;
2242
0
    }
2243
0
  }
2244
2245
0
  if (appctx->st0 == HTX_CACHE_DATA) {
2246
0
    if (len) {
2247
0
      ret = htx_cache_dump_msg(appctx, res_htx, len, HTX_BLK_UNUSED);
2248
0
      if (ret < len) {
2249
0
        applet_fl_set(appctx, APPCTX_FL_OUTBLK_FULL);
2250
0
        goto out;
2251
0
      }
2252
0
    }
2253
0
    BUG_ON(appctx->to_forward);
2254
0
    appctx->st0 = HTX_CACHE_EOM;
2255
0
  }
2256
2257
0
  if (appctx->st0 == HTX_CACHE_EOM) {
2258
     /* no more data are expected. */
2259
0
    res_htx->flags |= HTX_FL_EOM;
2260
0
    applet_set_eoi(appctx);
2261
0
    se_fl_clr(appctx->sedesc, SE_FL_MAY_FASTFWD_PROD);
2262
0
    applet_fl_clr(appctx, APPCTX_FL_FASTFWD);
2263
0
    appctx->st0 = HTX_CACHE_END;
2264
0
  }
2265
2266
0
  end:
2267
0
  if (appctx->st0 == HTX_CACHE_END) {
2268
0
    applet_set_eos(appctx);
2269
0
  }
2270
2271
0
  out:
2272
0
  if (res_htx)
2273
0
    htx_to_buf(res_htx, &appctx->outbuf);
2274
2275
0
  exit:
2276
  /* eat the whole request */
2277
0
  b_reset(&appctx->inbuf);
2278
0
  applet_fl_clr(appctx, APPCTX_FL_INBLK_FULL);
2279
0
  appctx->sedesc->iobuf.flags &= ~IOBUF_FL_FF_BLOCKED;
2280
0
  return;
2281
2282
0
  wait_request:
2283
  /* Wait for the request before starting to deliver the response */
2284
0
  applet_need_more_data(appctx);
2285
0
  return;
2286
2287
0
  error:
2288
  /* Sent and HTTP error 500 */
2289
0
  b_reset(&appctx->outbuf);
2290
0
  errmsg = &http_err_chunks[HTTP_ERR_500];
2291
0
  appctx->outbuf.data = b_data(errmsg);
2292
0
  memcpy(appctx->outbuf.area, b_head(errmsg), b_data(errmsg));
2293
0
  res_htx = htx_from_buf(&appctx->outbuf);
2294
2295
0
  applet_set_eos(appctx);
2296
0
  applet_set_error(appctx);
2297
0
  appctx->st0 = HTX_CACHE_END;
2298
0
  goto end;
2299
0
}
2300
2301
2302
static int parse_cache_rule(struct proxy *proxy, const char *name, struct act_rule *rule, char **err)
2303
0
{
2304
0
  struct flt_conf *fconf;
2305
0
  struct cache_flt_conf *cconf = NULL;
2306
2307
0
  if (!*name || strcmp(name, "if") == 0 || strcmp(name, "unless") == 0) {
2308
0
    memprintf(err, "expects a cache name");
2309
0
    goto err;
2310
0
  }
2311
2312
  /* check if a cache filter was already registered with this cache
2313
   * name, if that's the case, must use it. */
2314
0
  list_for_each_entry(fconf, &proxy->filter_configs, list) {
2315
0
    if (fconf->id == cache_store_flt_id) {
2316
0
      cconf = fconf->conf;
2317
0
      if (cconf && strcmp((char *)cconf->c.name, name) == 0) {
2318
0
        rule->arg.act.p[0] = cconf;
2319
0
        return 1;
2320
0
      }
2321
0
    }
2322
0
  }
2323
2324
  /* Create the filter cache config  */
2325
0
  cconf = calloc(1, sizeof(*cconf));
2326
0
  if (!cconf) {
2327
0
    memprintf(err, "out of memory\n");
2328
0
    goto err;
2329
0
  }
2330
0
  cconf->flags = CACHE_FLT_F_IMPLICIT_DECL;
2331
0
  cconf->c.name = strdup(name);
2332
0
  if (!cconf->c.name) {
2333
0
    memprintf(err, "out of memory\n");
2334
0
    goto err;
2335
0
  }
2336
2337
  /* register a filter to fill the cache buffer */
2338
0
  fconf = calloc(1, sizeof(*fconf));
2339
0
  if (!fconf) {
2340
0
    memprintf(err, "out of memory\n");
2341
0
    goto err;
2342
0
  }
2343
0
  fconf->id = cache_store_flt_id;
2344
0
  fconf->conf = cconf;
2345
0
  fconf->ops  = &cache_ops;
2346
0
  LIST_APPEND(&proxy->filter_configs, &fconf->list);
2347
2348
0
  rule->arg.act.p[0] = cconf;
2349
0
  return 1;
2350
2351
0
  err:
2352
0
  if (cconf) {
2353
0
    free(cconf->c.name);
2354
0
    free(cconf);
2355
0
  }
2356
0
  return 0;
2357
0
}
2358
2359
enum act_parse_ret parse_cache_store(const char **args, int *orig_arg, struct proxy *proxy,
2360
                                          struct act_rule *rule, char **err)
2361
0
{
2362
0
  rule->action       = ACT_CUSTOM;
2363
0
  rule->action_ptr   = http_action_store_cache;
2364
2365
0
  if (!parse_cache_rule(proxy, args[*orig_arg], rule, err))
2366
0
    return ACT_RET_PRS_ERR;
2367
2368
0
  (*orig_arg)++;
2369
0
  return ACT_RET_PRS_OK;
2370
0
}
2371
2372
/* This produces a sha1 hash of the concatenation of the HTTP method,
2373
 * the first occurrence of the Host header followed by the path component
2374
 * if it begins with a slash ('/'). */
2375
int sha1_hosturi(struct stream *s)
2376
0
{
2377
0
  struct http_txn *txn = s->txn.http;
2378
0
  struct htx *htx = htxbuf(&s->req.buf);
2379
0
  struct htx_sl *sl;
2380
0
  struct http_hdr_ctx ctx;
2381
0
  struct ist uri;
2382
0
  blk_SHA_CTX sha1_ctx;
2383
0
  struct buffer *trash;
2384
2385
0
  trash = get_trash_chunk();
2386
0
  ctx.blk = NULL;
2387
2388
0
  sl = http_get_stline(htx);
2389
0
  uri = htx_sl_req_uri(sl); // whole uri
2390
0
  if (!uri.len)
2391
0
    return 0;
2392
2393
  /* In HTTP/1, most URIs are seen in origin form ('/path/to/resource'),
2394
   * unless haproxy is deployed in front of an outbound cache. In HTTP/2,
2395
   * URIs are almost always sent in absolute form with their scheme. In
2396
   * this case, the scheme is almost always "https". In order to support
2397
   * sharing of cache objects between H1 and H2, we'll hash the absolute
2398
   * URI whenever known, or prepend "https://" + the Host header for
2399
   * relative URIs. The difference will only appear on absolute HTTP/1
2400
   * requests sent to an origin server, which practically is never met in
2401
   * the real world so we don't care about the ability to share the same
2402
   * key here.URIs are normalized from the absolute URI to an origin form as
2403
   * well.
2404
   */
2405
0
  if (!(sl->flags & HTX_SL_F_HAS_AUTHORITY)) {
2406
0
    chunk_istcat(trash, ist("https://"));
2407
0
    if (!http_find_header(htx, ist("Host"), &ctx, 0))
2408
0
      return 0;
2409
0
    chunk_istcat(trash, ctx.value);
2410
0
  }
2411
2412
0
  chunk_istcat(trash, uri);
2413
2414
  /* hash everything */
2415
0
  blk_SHA1_Init(&sha1_ctx);
2416
0
  blk_SHA1_Update(&sha1_ctx, trash->area, trash->data);
2417
0
  blk_SHA1_Final((unsigned char *)txn->cache_hash, &sha1_ctx);
2418
2419
0
  return 1;
2420
0
}
2421
2422
/* Looks for "If-None-Match" headers in the request and compares their value
2423
 * with the one that might have been stored in the cache_entry. If any of them
2424
 * matches, a "304 Not Modified" response should be sent instead of the cached
2425
 * data.
2426
 * Although unlikely in a GET/HEAD request, the "If-None-Match: *" syntax is
2427
 * valid and should receive a "304 Not Modified" response (RFC 7234#4.3.2).
2428
 *
2429
 * If no "If-None-Match" header was found, look for an "If-Modified-Since"
2430
 * header and compare its value (date) to the one stored in the cache_entry.
2431
 * If the request's date is later than the cached one, we also send a
2432
 * "304 Not Modified" response (see RFCs 7232#3.3 and 7234#4.3.2).
2433
 *
2434
 * Returns 1 if "304 Not Modified" should be sent, 0 otherwise.
2435
 */
2436
static int should_send_notmodified_response(struct cache *cache, struct htx *htx,
2437
                                            struct cache_entry *entry)
2438
0
{
2439
0
  int retval = 0;
2440
2441
0
  struct http_hdr_ctx ctx = { .blk = NULL };
2442
0
  struct ist cache_entry_etag = IST_NULL;
2443
0
  struct buffer *etag_buffer = NULL;
2444
0
  int if_none_match_found = 0;
2445
2446
0
  struct tm tm = {};
2447
0
  time_t if_modified_since = 0;
2448
2449
  /* If we find a "If-None-Match" header in the request, rebuild the
2450
   * cache_entry's ETag in order to perform comparisons.
2451
   * There could be multiple "if-none-match" header lines. */
2452
0
  while (http_find_header(htx, ist("if-none-match"), &ctx, 0)) {
2453
0
    if_none_match_found = 1;
2454
2455
    /* A '*' matches everything. */
2456
0
    if (isteq(ctx.value, ist("*")) != 0) {
2457
0
      retval = 1;
2458
0
      break;
2459
0
    }
2460
2461
    /* No need to rebuild an etag if none was stored in the cache. */
2462
0
    if (entry->etag_length == 0)
2463
0
      break;
2464
2465
    /* Rebuild the stored ETag. */
2466
0
    if (etag_buffer == NULL) {
2467
0
      etag_buffer = get_trash_chunk();
2468
2469
0
      if (shctx_row_data_get(shctx_ptr(cache), block_ptr(entry),
2470
0
                 (unsigned char*)b_orig(etag_buffer),
2471
0
                 entry->etag_offset, entry->etag_length) == 0) {
2472
0
        cache_entry_etag = ist2(b_orig(etag_buffer), entry->etag_length);
2473
0
      } else {
2474
        /* We could not rebuild the ETag in one go, we
2475
         * won't send a "304 Not Modified" response. */
2476
0
        break;
2477
0
      }
2478
0
    }
2479
2480
0
    if (http_compare_etags(cache_entry_etag, ctx.value) == 1) {
2481
0
      retval = 1;
2482
0
      break;
2483
0
    }
2484
0
  }
2485
2486
  /* If the request did not contain an "If-None-Match" header, we look for
2487
   * an "If-Modified-Since" header (see RFC 7232#3.3). */
2488
0
  if (retval == 0 && if_none_match_found == 0) {
2489
0
    ctx.blk = NULL;
2490
0
    if (http_find_header(htx, ist("if-modified-since"), &ctx, 1)) {
2491
0
      if (parse_http_date(istptr(ctx.value), istlen(ctx.value), &tm)) {
2492
0
        if_modified_since = my_timegm(&tm);
2493
2494
        /* We send a "304 Not Modified" response if the
2495
         * entry's last modified date is earlier than
2496
         * the one found in the "If-Modified-Since"
2497
         * header. */
2498
0
        retval = (entry->last_modified <= if_modified_since);
2499
0
      }
2500
0
    }
2501
0
  }
2502
2503
0
  return retval;
2504
0
}
2505
2506
/*
2507
 * Emit an HTTP 103 Early Hints response built from the cached <hint_data> of
2508
 * length <hint_data_len>. The format matches what http_action_store_cache
2509
 * writes: concatenated records of {uint16_t length, char value[length]}, each
2510
 * value being a Link header value. Skipped for HTTP/1.0 clients.
2511
 * Returns 1 if a 103 response was emitted, 0 otherwise.
2512
 */
2513
static int cache_emit_early_hints(struct stream *s, const char *hint_data,
2514
                                  unsigned int hint_data_len)
2515
0
{
2516
0
  struct htx *htx;
2517
0
  const char *p = hint_data;
2518
0
  const char *end = hint_data + hint_data_len;
2519
2520
0
  if (!(s->txn.http->req.flags & HTTP_MSGF_VER_11))
2521
0
    return 0;
2522
2523
0
  htx = http_early_hint_start(s);
2524
0
  if (!htx)
2525
0
    goto error;
2526
2527
0
  while (p + sizeof(uint16_t) <= end) {
2528
0
    uint16_t vlen = read_u16(p);
2529
2530
0
    p += sizeof(vlen);
2531
0
    if (p + vlen > end)
2532
0
      break;
2533
0
    if (!htx_add_header(htx, ist("link"), ist2(p, vlen)))
2534
0
      goto error;
2535
0
    p += vlen;
2536
0
  }
2537
2538
0
  if (!http_early_hint_end(s))
2539
0
    goto error;
2540
0
  return 1;
2541
2542
0
  error:
2543
0
  channel_htx_truncate(&s->res, htxbuf(&s->res.buf));
2544
0
  s->txn.http->status = 0;
2545
0
  return 0;
2546
0
}
2547
2548
enum act_return http_action_req_cache_use(struct act_rule *rule, struct proxy *px,
2549
                                         struct session *sess, struct stream *s, int flags)
2550
0
{
2551
2552
0
  struct http_txn *txn = s->txn.http;
2553
0
  struct cache_entry *res, *sec_entry = NULL;
2554
0
  struct cache_flt_conf *cconf = rule->arg.act.p[0];
2555
0
  struct cache *cache = cconf->c.cache;
2556
0
  struct shared_context *shctx = shctx_ptr(cache);
2557
0
  struct shared_block *entry_block;
2558
0
  struct buffer *hint_buf = NULL;
2559
2560
0
  struct cache_tree *cache_tree = NULL;
2561
2562
  /* Ignore cache for HTTP/1.0 requests and for requests other than GET
2563
   * and HEAD */
2564
0
  if (!(txn->req.flags & HTTP_MSGF_VER_11) ||
2565
0
      (txn->meth != HTTP_METH_GET && txn->meth != HTTP_METH_HEAD))
2566
0
    txn->flags |= TX_CACHE_IGNORE;
2567
2568
0
  http_check_request_for_cacheability(s, &s->req);
2569
2570
  /* The request's hash has to be calculated for all requests, even POSTs
2571
   * or PUTs for instance because RFC7234 specifies that a successful
2572
   * "unsafe" method on a stored resource must invalidate it
2573
   * (see RFC7234#4.4). */
2574
0
  if (!sha1_hosturi(s))
2575
0
    return ACT_RET_CONT;
2576
2577
0
  if (s->txn.http->flags & TX_CACHE_IGNORE)
2578
0
    return ACT_RET_CONT;
2579
2580
0
  if (px == strm_fe(s)) {
2581
0
    if (px->fe_counters.shared.tg)
2582
0
      _HA_ATOMIC_INC(&px->fe_counters.shared.tg[tgid - 1]->p.http.cache_lookups);
2583
0
  }
2584
0
  else {
2585
0
    if (px->be_counters.shared.tg)
2586
0
      _HA_ATOMIC_INC(&px->be_counters.shared.tg[tgid - 1]->p.http.cache_lookups);
2587
0
  }
2588
2589
0
  cache_tree = get_cache_tree_from_hash(cache,
2590
0
                read_u32(s->txn.http->cache_hash));
2591
2592
0
  if (!cache_tree)
2593
0
    return ACT_RET_CONT;
2594
2595
0
  cache_rdlock(cache_tree);
2596
0
  res = get_entry(cache_tree, s->txn.http->cache_hash, 0);
2597
  /* We must not use an entry that is not complete but the check will be
2598
   * performed after we look for a potential secondary entry (in case of
2599
   * Vary). */
2600
0
  if (res) {
2601
0
    struct appctx *appctx;
2602
0
    int detached = 0;
2603
2604
0
    retain_entry(res);
2605
2606
0
    entry_block = block_ptr(res);
2607
0
    shctx_wrlock(shctx);
2608
0
    if (res->expire > date.tv_sec &&
2609
0
        (res->flags & CACHE_EF_COMPLETE) && !(res->flags & CACHE_EF_STRIPPED)) {
2610
0
      shctx_row_detach(shctx, entry_block);
2611
0
      detached = 1;
2612
0
    } else {
2613
      /* p[1] holds the "no-early-hints" opt-out set by parse_cache_use(). */
2614
0
      if ((cache->flags & CACHE_CF_EARLY_HINTS) && !rule->arg.act.p[1] &&
2615
0
          (res->flags & (CACHE_EF_STRIPPED | CACHE_EF_COMPLETE))) {
2616
        /* The emitted hints are best-effort and may not exactly
2617
         * match the response finally served: with Vary they may
2618
         * come from a different variant (resolved below), and a
2619
         * stripped entry keeps emitting after expiry until it is
2620
         * re-cached or evicted. This only affects which resources
2621
         * are preloaded, never the response itself, so it is
2622
         * accepted here.
2623
         *
2624
         * The trash chunk in hint_buf is consumed only after the
2625
         * unlocks below. As get_trash_chunk() rotates between two
2626
         * buffers, reusing it more than once before then would
2627
         * cycle back onto hint_buf and clobber it.
2628
         */
2629
0
        hint_buf = get_trash_chunk();
2630
0
        if (res->flags & CACHE_EF_STRIPPED) {
2631
0
          unsigned int len =
2632
0
            entry_block->len - sizeof(struct cache_entry);
2633
2634
0
          if (len > 0 && len <= b_size(hint_buf) &&
2635
0
              shctx_row_data_get(shctx, entry_block,
2636
0
                                 (unsigned char *)b_orig(hint_buf),
2637
0
                                 sizeof(struct cache_entry),
2638
0
                                 len) == 0)
2639
0
            hint_buf->data = len;
2640
2641
          /* Refresh this entry's position in the hints LRU. */
2642
0
          LIST_DELETE(&res->lru);
2643
0
          LIST_APPEND(&cache->hints_lru, &res->lru);
2644
0
        } else {
2645
          /* CACHE_EF_COMPLETE */
2646
0
          cache_extract_hints(shctx, entry_block, hint_buf);
2647
0
          if (b_data(hint_buf) > 0 && entry_block->refcount == 0 &&
2648
0
              cache->hints_blocks < CACHE_HINTS_CAP(cache))
2649
0
            cache_strip_entry(shctx, res, hint_buf);
2650
0
        }
2651
0
      }
2652
0
      release_entry(cache_tree, res, 0);
2653
0
      res = NULL;
2654
0
    }
2655
0
    shctx_wrunlock(shctx);
2656
0
    cache_rdunlock(cache_tree);
2657
2658
0
    if (hint_buf && b_data(hint_buf) > 0 &&
2659
0
        cache_emit_early_hints(s, b_orig(hint_buf), b_data(hint_buf))) {
2660
0
      long long *ctr = NULL;
2661
2662
0
      if (px == strm_fe(s)) {
2663
0
        if (px->fe_counters.shared.tg)
2664
0
          ctr = &px->fe_counters.shared.tg[tgid - 1]->p.http.cache_hint_hits;
2665
0
      }
2666
0
      else if (px->be_counters.shared.tg)
2667
0
        ctr = &px->be_counters.shared.tg[tgid - 1]->p.http.cache_hint_hits;
2668
2669
0
      if (ctr)
2670
0
        _HA_ATOMIC_INC(ctr);
2671
0
    }
2672
2673
    /* In case of Vary, we could have multiple entries with the same
2674
     * primary hash. We need to calculate the secondary hash in order
2675
     * to find the actual entry we want (if it exists). */
2676
0
    if (res && res->secondary_key_signature) {
2677
0
      if (!http_request_build_secondary_key(s, res->secondary_key_signature)) {
2678
0
        cache_rdlock(cache_tree);
2679
0
        sec_entry = get_secondary_entry(cache_tree, res,
2680
0
                                        s->txn.http->cache_hash,
2681
0
                                        s->txn.http->cache_secondary_hash,
2682
0
                                        0);
2683
0
        if (!sec_entry) {
2684
          /* Secondary key miss: release the retained primary entry
2685
           * and reattach the detached row before returning.
2686
           */
2687
0
          release_entry(cache_tree, res, 0);
2688
0
          shctx_wrlock(shctx);
2689
0
          if (detached)
2690
0
            cache_row_reattach(cache, entry_block);
2691
0
          shctx_wrunlock(shctx);
2692
0
        }
2693
0
        else if (sec_entry != res) {
2694
          /* The wrong row was added to the hot list. */
2695
0
          release_entry(cache_tree, res, 0);
2696
0
          retain_entry(sec_entry);
2697
0
          shctx_wrlock(shctx);
2698
0
          if (detached)
2699
0
            cache_row_reattach(cache, entry_block);
2700
0
          entry_block = block_ptr(sec_entry);
2701
0
          shctx_row_detach(shctx, entry_block);
2702
0
          shctx_wrunlock(shctx);
2703
0
        }
2704
0
        res = sec_entry;
2705
0
        cache_rdunlock(cache_tree);
2706
0
      }
2707
0
      else {
2708
0
        release_entry(cache_tree, res, 1);
2709
2710
0
        res = NULL;
2711
0
        shctx_wrlock(shctx);
2712
0
        cache_row_reattach(cache, entry_block);
2713
0
        shctx_wrunlock(shctx);
2714
0
      }
2715
0
    }
2716
2717
    /* We either looked for a valid secondary entry and could not
2718
     * find one, or the entry we want to use is not complete. We
2719
     * can't use the cache's entry and must forward the request to
2720
     * the server. */
2721
0
    if (!res) {
2722
0
      return ACT_RET_CONT;
2723
0
    } else if (!(res->flags & CACHE_EF_COMPLETE) || (res->flags & CACHE_EF_STRIPPED)) {
2724
0
      release_entry(cache_tree, res, 1);
2725
0
      shctx_wrlock(shctx);
2726
0
      cache_row_reattach(cache, entry_block);
2727
0
      shctx_wrunlock(shctx);
2728
0
      return ACT_RET_CONT;
2729
0
    }
2730
2731
0
    s->target = &http_cache_applet.obj_type;
2732
0
    if ((appctx = sc_applet_create(s->scb, objt_applet(s->target)))) {
2733
0
      struct cache_appctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
2734
2735
0
      appctx->st0 = HTX_CACHE_INIT;
2736
0
      ctx->cache = cache;
2737
0
      ctx->cache_tree = cache_tree;
2738
0
      ctx->entry = res;
2739
0
      ctx->next = NULL;
2740
0
      ctx->sent = 0;
2741
0
      ctx->send_notmodified =
2742
0
                                should_send_notmodified_response(cache, htxbuf(&s->req.buf), res);
2743
2744
0
      if (px == strm_fe(s)) {
2745
0
        if (px->fe_counters.shared.tg)
2746
0
          _HA_ATOMIC_INC(&px->fe_counters.shared.tg[tgid - 1]->p.http.cache_hits);
2747
0
      }
2748
0
      else {
2749
0
        if (px->be_counters.shared.tg)
2750
0
          _HA_ATOMIC_INC(&px->be_counters.shared.tg[tgid - 1]->p.http.cache_hits);
2751
0
      }
2752
0
      return ACT_RET_CONT;
2753
0
    } else {
2754
0
      s->target = NULL;
2755
0
      release_entry(cache_tree, res, 1);
2756
0
      shctx_wrlock(shctx);
2757
0
      cache_row_reattach(cache, entry_block);
2758
0
      shctx_wrunlock(shctx);
2759
0
      return ACT_RET_CONT;
2760
0
    }
2761
0
  }
2762
0
  cache_rdunlock(cache_tree);
2763
2764
  /* Shared context does not need to be locked while we calculate the
2765
   * secondary hash. */
2766
0
  if (!res && (cache->flags & CACHE_CF_VARY_PROCESSING)) {
2767
    /* Build a complete secondary hash until the server response
2768
     * tells us which fields should be kept (if any). */
2769
0
    http_request_prebuild_full_secondary_key(s);
2770
0
  }
2771
0
  return ACT_RET_CONT;
2772
0
}
2773
2774
2775
enum act_parse_ret parse_cache_use(const char **args, int *orig_arg, struct proxy *proxy,
2776
                                          struct act_rule *rule, char **err)
2777
0
{
2778
0
  rule->action       = ACT_CUSTOM;
2779
0
  rule->action_ptr   = http_action_req_cache_use;
2780
2781
0
  if (!parse_cache_rule(proxy, args[*orig_arg], rule, err))
2782
0
    return ACT_RET_PRS_ERR;
2783
2784
0
  (*orig_arg)++;
2785
2786
  /* Stash the "no-early-hints" opt-out in p[1], read back by
2787
   * http_action_req_cache_use() to skip 103 emission. */
2788
0
  if (*args[*orig_arg] && strcmp(args[*orig_arg], "no-early-hints") == 0) {
2789
0
    rule->arg.act.p[1] = (void *)(uintptr_t)1;
2790
0
    (*orig_arg)++;
2791
0
  }
2792
2793
0
  return ACT_RET_PRS_OK;
2794
0
}
2795
2796
int cfg_parse_cache(const char *file, int linenum, char **args, int kwm)
2797
0
{
2798
0
  int err_code = 0;
2799
2800
0
  if (strcmp(args[0], "cache") == 0) { /* new cache section */
2801
2802
0
    if (!*args[1]) {
2803
0
      ha_alert("parsing [%s:%d] : '%s' expects a <name> argument\n",
2804
0
         file, linenum, args[0]);
2805
0
      err_code |= ERR_ALERT | ERR_ABORT;
2806
0
      goto out;
2807
0
    }
2808
2809
0
    if (alertif_too_many_args(1, file, linenum, args, &err_code)) {
2810
0
      err_code |= ERR_ABORT;
2811
0
      goto out;
2812
0
    }
2813
2814
0
    if (tmp_cache_config == NULL) {
2815
0
      struct cache *cache_config;
2816
2817
0
      tmp_cache_config = calloc(1, sizeof(*tmp_cache_config));
2818
0
      if (!tmp_cache_config) {
2819
0
        ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
2820
0
        err_code |= ERR_ALERT | ERR_ABORT;
2821
0
        goto out;
2822
0
      }
2823
2824
0
      strlcpy2(tmp_cache_config->id, args[1], 33);
2825
0
      if (strlen(args[1]) > 32) {
2826
0
        ha_warning("parsing [%s:%d]: cache name is limited to 32 characters, truncate to '%s'.\n",
2827
0
             file, linenum, tmp_cache_config->id);
2828
0
        err_code |= ERR_WARN;
2829
0
      }
2830
2831
0
      list_for_each_entry(cache_config, &caches_config, list) {
2832
0
        if (strcmp(tmp_cache_config->id, cache_config->id) == 0) {
2833
0
          ha_alert("parsing [%s:%d]: Duplicate cache name '%s'.\n",
2834
0
                   file, linenum, tmp_cache_config->id);
2835
0
          err_code |= ERR_ALERT | ERR_ABORT;
2836
0
          goto out;
2837
0
        }
2838
0
      }
2839
2840
0
      tmp_cache_config->maxage = 60;
2841
0
      tmp_cache_config->maxblocks = 0;
2842
0
      tmp_cache_config->maxobjsz = 0;
2843
0
      tmp_cache_config->early_hints_ratio = 25;
2844
0
      tmp_cache_config->max_secondary_entries = DEFAULT_MAX_SECONDARY_ENTRY;
2845
0
    }
2846
0
  } else if (strcmp(args[0], "total-max-size") == 0) {
2847
0
    unsigned long int maxsize;
2848
0
    char *err;
2849
2850
0
    if (alertif_too_many_args(1, file, linenum, args, &err_code)) {
2851
0
      err_code |= ERR_ABORT;
2852
0
      goto out;
2853
0
    }
2854
2855
0
    maxsize = strtoul(args[1], &err, 10);
2856
0
    if (err == args[1] || *err != '\0') {
2857
0
      ha_warning("parsing [%s:%d]: total-max-size wrong value '%s'\n",
2858
0
                 file, linenum, args[1]);
2859
0
      err_code |= ERR_ABORT;
2860
0
      goto out;
2861
0
    }
2862
2863
0
    if (maxsize > (UINT_MAX >> 20)) {
2864
0
      ha_warning("parsing [%s:%d]: \"total-max-size\" (%s) must not be greater than %u\n",
2865
0
                 file, linenum, args[1], UINT_MAX >> 20);
2866
0
      err_code |= ERR_ABORT;
2867
0
      goto out;
2868
0
    }
2869
2870
    /* size in megabytes */
2871
0
    maxsize *= 1024 * 1024 / CACHE_BLOCKSIZE;
2872
0
    tmp_cache_config->maxblocks = maxsize;
2873
0
  } else if (strcmp(args[0], "max-age") == 0) {
2874
0
    if (alertif_too_many_args(1, file, linenum, args, &err_code)) {
2875
0
      err_code |= ERR_ABORT;
2876
0
      goto out;
2877
0
    }
2878
2879
0
    if (!*args[1]) {
2880
0
      ha_warning("parsing [%s:%d]: '%s' expects an age parameter in seconds.\n",
2881
0
              file, linenum, args[0]);
2882
0
      err_code |= ERR_WARN;
2883
0
    }
2884
2885
0
    tmp_cache_config->maxage = atoi(args[1]);
2886
0
  } else if (strcmp(args[0], "max-object-size") == 0) {
2887
0
    unsigned int maxobjsz;
2888
0
    char *err;
2889
2890
0
    if (alertif_too_many_args(1, file, linenum, args, &err_code)) {
2891
0
      err_code |= ERR_ABORT;
2892
0
      goto out;
2893
0
    }
2894
2895
0
    if (!*args[1]) {
2896
0
      ha_warning("parsing [%s:%d]: '%s' expects a maximum file size parameter in bytes.\n",
2897
0
              file, linenum, args[0]);
2898
0
      err_code |= ERR_WARN;
2899
0
    }
2900
2901
0
    maxobjsz = strtoul(args[1], &err, 10);
2902
0
    if (err == args[1] || *err != '\0') {
2903
0
      ha_warning("parsing [%s:%d]: max-object-size wrong value '%s'\n",
2904
0
                 file, linenum, args[1]);
2905
0
      err_code |= ERR_ABORT;
2906
0
      goto out;
2907
0
    }
2908
0
    tmp_cache_config->maxobjsz = maxobjsz;
2909
0
  } else if (strcmp(args[0], "process-vary") == 0) {
2910
0
    if (alertif_too_many_args(1, file, linenum, args, &err_code)) {
2911
0
      err_code |= ERR_ABORT;
2912
0
      goto out;
2913
0
    }
2914
2915
0
    if (!*args[1]) {
2916
0
      ha_warning("parsing [%s:%d]: '%s' expects \"on\" or \"off\" (enable or disable vary processing).\n",
2917
0
           file, linenum, args[0]);
2918
0
      err_code |= ERR_WARN;
2919
0
    }
2920
0
    if (strcmp(args[1], "on") == 0)
2921
0
      tmp_cache_config->flags |= CACHE_CF_VARY_PROCESSING;
2922
0
    else if (strcmp(args[1], "off") == 0)
2923
0
      tmp_cache_config->flags &= ~CACHE_CF_VARY_PROCESSING;
2924
0
    else {
2925
0
      ha_warning("parsing [%s:%d]: '%s' expects \"on\" or \"off\" (enable or disable vary processing).\n",
2926
0
           file, linenum, args[0]);
2927
0
      err_code |= ERR_WARN;
2928
0
    }
2929
0
  } else if (strcmp(args[0], "early-hints") == 0) {
2930
0
    if (alertif_too_many_args(3, file, linenum, args, &err_code)) {
2931
0
      err_code |= ERR_ABORT;
2932
0
      goto out;
2933
0
    }
2934
2935
0
    if (strcmp(args[1], "on") == 0) {
2936
0
      tmp_cache_config->flags |= CACHE_CF_EARLY_HINTS;
2937
0
      tmp_cache_config->flags &= ~CACHE_CF_EARLY_HINTS_ONLY;
2938
0
    } else if (strcmp(args[1], "off") == 0) {
2939
0
      tmp_cache_config->flags &= ~(CACHE_CF_EARLY_HINTS | CACHE_CF_EARLY_HINTS_ONLY);
2940
0
    } else if (strcmp(args[1], "only") == 0) {
2941
0
      tmp_cache_config->flags |= CACHE_CF_EARLY_HINTS | CACHE_CF_EARLY_HINTS_ONLY;
2942
0
    } else {
2943
0
      ha_warning("parsing [%s:%d]: '%s' expects \"on\", \"off\" or \"only\" (enable or disable HTTP 103 Early Hints support, or store only hints).\n",
2944
0
           file, linenum, args[0]);
2945
0
      err_code |= ERR_WARN;
2946
0
    }
2947
2948
0
    if (*args[2]) {
2949
0
      char *err;
2950
0
      unsigned int ratio;
2951
2952
0
      if (strcmp(args[2], "ratio") != 0) {
2953
0
        ha_alert("parsing [%s:%d]: '%s' unexpected argument '%s', expected 'ratio'.\n",
2954
0
           file, linenum, args[0], args[2]);
2955
0
        err_code |= ERR_ALERT | ERR_FATAL;
2956
0
        goto out;
2957
0
      }
2958
0
      if (!*args[3]) {
2959
0
        ha_alert("parsing [%s:%d]: '%s ratio' expects an integer argument between 1 and 99.\n",
2960
0
           file, linenum, args[0]);
2961
0
        err_code |= ERR_ALERT | ERR_FATAL;
2962
0
        goto out;
2963
0
      }
2964
0
      ratio = strtoul(args[3], &err, 10);
2965
0
      if (err == args[3] || *err != '\0' || ratio < 1 || ratio > 99) {
2966
0
        ha_alert("parsing [%s:%d]: '%s ratio' expects an integer argument between 1 and 99, got '%s'.\n",
2967
0
           file, linenum, args[0], args[3]);
2968
0
        err_code |= ERR_ALERT | ERR_FATAL;
2969
0
        goto out;
2970
0
      }
2971
0
      tmp_cache_config->early_hints_ratio = ratio;
2972
0
    }
2973
0
  } else if (strcmp(args[0], "max-secondary-entries") == 0) {
2974
0
    unsigned int max_sec_entries;
2975
0
    char *err;
2976
2977
0
    if (alertif_too_many_args(1, file, linenum, args, &err_code)) {
2978
0
      err_code |= ERR_ABORT;
2979
0
      goto out;
2980
0
    }
2981
2982
0
    if (!*args[1]) {
2983
0
      ha_warning("parsing [%s:%d]: '%s' expects a strictly positive number.\n",
2984
0
           file, linenum, args[0]);
2985
0
      err_code |= ERR_WARN;
2986
0
    }
2987
2988
0
    max_sec_entries = strtoul(args[1], &err, 10);
2989
0
    if (err == args[1] || *err != '\0' || max_sec_entries == 0) {
2990
0
      ha_warning("parsing [%s:%d]: max-secondary-entries wrong value '%s'\n",
2991
0
                 file, linenum, args[1]);
2992
0
      err_code |= ERR_ABORT;
2993
0
      goto out;
2994
0
    }
2995
0
    tmp_cache_config->max_secondary_entries = max_sec_entries;
2996
0
  }
2997
0
  else if (*args[0] != 0) {
2998
0
    ha_alert("parsing [%s:%d] : unknown keyword '%s' in 'cache' section\n", file, linenum, args[0]);
2999
0
    err_code |= ERR_ALERT | ERR_FATAL;
3000
0
    goto out;
3001
0
  }
3002
0
out:
3003
0
  return err_code;
3004
0
}
3005
3006
/* once the cache section is parsed */
3007
3008
int cfg_post_parse_section_cache()
3009
0
{
3010
0
  int err_code = 0;
3011
3012
0
  if (tmp_cache_config) {
3013
3014
0
    if (tmp_cache_config->maxblocks <= 0) {
3015
0
      ha_alert("Size not specified for cache '%s'\n", tmp_cache_config->id);
3016
0
      err_code |= ERR_FATAL | ERR_ALERT;
3017
0
      goto out;
3018
0
    }
3019
3020
0
    if (!tmp_cache_config->maxobjsz) {
3021
      /* Default max. file size is a 256th of the cache size. */
3022
0
      tmp_cache_config->maxobjsz =
3023
0
        (tmp_cache_config->maxblocks * CACHE_BLOCKSIZE) >> 8;
3024
0
    }
3025
0
    else if (tmp_cache_config->maxobjsz > tmp_cache_config->maxblocks * CACHE_BLOCKSIZE / 2) {
3026
0
      ha_alert("\"max-object-size\" is limited to an half of \"total-max-size\" => %u\n", tmp_cache_config->maxblocks * CACHE_BLOCKSIZE / 2);
3027
0
      err_code |= ERR_FATAL | ERR_ALERT;
3028
0
      goto out;
3029
0
    }
3030
3031
    /* add to the list of cache to init and reinit tmp_cache_config
3032
     * for next cache section, if any.
3033
     */
3034
0
    LIST_APPEND(&caches_config, &tmp_cache_config->list);
3035
0
    tmp_cache_config = NULL;
3036
0
    return err_code;
3037
0
  }
3038
0
out:
3039
0
  ha_free(&tmp_cache_config);
3040
0
  return err_code;
3041
3042
0
}
3043
3044
int post_check_cache()
3045
0
{
3046
0
  struct proxy *px;
3047
0
  struct cache *back, *cache_config, *cache;
3048
0
  struct shared_context *shctx;
3049
0
  int ret_shctx;
3050
0
  int err_code = ERR_NONE;
3051
0
  int i;
3052
3053
0
  list_for_each_entry_safe(cache_config, back, &caches_config, list) {
3054
3055
0
    ret_shctx = shctx_init(&shctx, cache_config->maxblocks, CACHE_BLOCKSIZE,
3056
0
                           cache_config->maxobjsz, sizeof(struct cache), cache_config->id);
3057
3058
0
    if (ret_shctx <= 0) {
3059
0
      if (ret_shctx == SHCTX_E_INIT_LOCK)
3060
0
        ha_alert("Unable to initialize the lock for the cache.\n");
3061
0
      else
3062
0
        ha_alert("Unable to allocate cache.\n");
3063
3064
0
      err_code |= ERR_FATAL | ERR_ALERT;
3065
0
      goto out;
3066
0
    }
3067
0
    shctx->free_block = cache_free_blocks;
3068
0
    shctx->reserve_finish = cache_reserve_finish;
3069
0
    shctx->make_room = cache_make_room;
3070
0
    shctx->cb_data = (void*)shctx->data;
3071
    /* the cache structure is stored in the shctx and added to the
3072
     * caches list, we can remove the entry from the caches_config
3073
     * list */
3074
0
    memcpy(shctx->data, cache_config, sizeof(struct cache));
3075
0
    cache = (struct cache *)shctx->data;
3076
0
    LIST_APPEND(&caches, &cache->list);
3077
0
    LIST_DELETE(&cache_config->list);
3078
0
    free(cache_config);
3079
0
    LIST_INIT(&cache->full_lru);
3080
0
    LIST_INIT(&cache->hints_lru);
3081
0
    cache->hints_blocks = 0;
3082
0
    for (i = 0; i < CACHE_TREE_NUM; ++i) {
3083
0
      cache->trees[i].entries = EB_ROOT;
3084
0
      HA_RWLOCK_INIT(&cache->trees[i].lock);
3085
3086
0
      LIST_INIT(&cache->trees[i].cleanup_list);
3087
0
      HA_SPIN_INIT(&cache->trees[i].cleanup_lock);
3088
0
    }
3089
3090
    /* Find all references for this cache in the existing filters
3091
     * (over all proxies) and reference it in matching filters.
3092
     */
3093
0
    for (px = proxies_list; px; px = px->next) {
3094
0
      struct flt_conf *fconf;
3095
0
      struct cache_flt_conf *cconf;
3096
3097
0
      list_for_each_entry(fconf, &px->filter_configs, list) {
3098
0
        if (fconf->id != cache_store_flt_id)
3099
0
          continue;
3100
3101
0
        cconf = fconf->conf;
3102
0
        if (strcmp(cache->id, cconf->c.name) == 0) {
3103
0
          free(cconf->c.name);
3104
0
          cconf->flags |= CACHE_FLT_INIT;
3105
0
          cconf->c.cache = cache;
3106
0
          break;
3107
0
        }
3108
0
      }
3109
0
    }
3110
0
  }
3111
3112
0
out:
3113
0
  return err_code;
3114
3115
0
}
3116
3117
struct flt_ops cache_ops = {
3118
  .init   = cache_store_init,
3119
  .check  = cache_store_check,
3120
  .deinit = cache_store_deinit,
3121
3122
  /* Handle stream init/deinit */
3123
  .attach = cache_store_strm_init,
3124
  .detach = cache_store_strm_deinit,
3125
3126
  /* Handle channels activity */
3127
  .channel_post_analyze = cache_store_post_analyze,
3128
3129
  /* Filter HTTP requests and responses */
3130
  .http_headers        = cache_store_http_headers,
3131
  .http_payload        = cache_store_http_payload,
3132
  .http_end            = cache_store_http_end,
3133
};
3134
3135
3136
#define CHECK_ENCODING(str, encoding_name, encoding_value) \
3137
0
  ({ \
3138
0
    int retval = 0; \
3139
0
    if (istmatch(str, (struct ist){ .ptr = encoding_name+1, .len = sizeof(encoding_name) - 2 })) { \
3140
0
      retval = encoding_value; \
3141
0
      encoding = istadv(encoding, sizeof(encoding_name) - 2); \
3142
0
    } \
3143
0
    (retval); \
3144
0
  })
3145
3146
/*
3147
 * Parse the encoding <encoding> and try to match the encoding part upon an
3148
 * encoding list of explicitly supported encodings (which all have a specific
3149
 * bit in an encoding bitmap). If a weight is included in the value, find out if
3150
 * it is null or not. The bit value will be set in the <encoding_value>
3151
 * parameter and the <has_null_weight> will be set to 1 if the weight is strictly
3152
 * 0, 1 otherwise.
3153
 * The encodings list is extracted from
3154
 * https://www.iana.org/assignments/http-parameters/http-parameters.xhtml.
3155
 * Returns 0 in case of success and -1 in case of error.
3156
 */
3157
static int parse_encoding_value(struct ist encoding, unsigned int *encoding_value,
3158
        unsigned int *has_null_weight)
3159
0
{
3160
0
  int retval = 0;
3161
3162
0
  if (!encoding_value)
3163
0
    return -1;
3164
3165
0
  if (!istlen(encoding))
3166
0
    return -1; /* Invalid encoding */
3167
3168
0
  *encoding_value = 0;
3169
0
  if (has_null_weight)
3170
0
    *has_null_weight = 0;
3171
3172
0
  switch (*encoding.ptr) {
3173
0
  case 'a':
3174
0
    encoding = istnext(encoding);
3175
0
    *encoding_value = CHECK_ENCODING(encoding, "aes128gcm", VARY_ENCODING_AES128GCM);
3176
0
    break;
3177
0
  case 'b':
3178
0
    encoding = istnext(encoding);
3179
0
    *encoding_value = CHECK_ENCODING(encoding, "br", VARY_ENCODING_BR);
3180
0
    break;
3181
0
  case 'c':
3182
0
    encoding = istnext(encoding);
3183
0
    *encoding_value = CHECK_ENCODING(encoding, "compress", VARY_ENCODING_COMPRESS);
3184
0
    break;
3185
0
  case 'd':
3186
0
    encoding = istnext(encoding);
3187
0
    *encoding_value = CHECK_ENCODING(encoding, "deflate", VARY_ENCODING_DEFLATE);
3188
0
    break;
3189
0
  case 'e':
3190
0
    encoding = istnext(encoding);
3191
0
    *encoding_value = CHECK_ENCODING(encoding, "exi", VARY_ENCODING_EXI);
3192
0
    break;
3193
0
  case 'g':
3194
0
    encoding = istnext(encoding);
3195
0
    *encoding_value = CHECK_ENCODING(encoding, "gzip", VARY_ENCODING_GZIP);
3196
0
    break;
3197
0
  case 'i':
3198
0
    encoding = istnext(encoding);
3199
0
    *encoding_value = CHECK_ENCODING(encoding, "identity", VARY_ENCODING_IDENTITY);
3200
0
    break;
3201
0
  case 'p':
3202
0
    encoding = istnext(encoding);
3203
0
    *encoding_value = CHECK_ENCODING(encoding, "pack200-gzip", VARY_ENCODING_PACK200_GZIP);
3204
0
    break;
3205
0
  case 'x':
3206
0
    encoding = istnext(encoding);
3207
0
    *encoding_value = CHECK_ENCODING(encoding, "x-gzip", VARY_ENCODING_GZIP);
3208
0
    if (!*encoding_value)
3209
0
      *encoding_value = CHECK_ENCODING(encoding, "x-compress", VARY_ENCODING_COMPRESS);
3210
0
    break;
3211
0
  case 'z':
3212
0
    encoding = istnext(encoding);
3213
0
    *encoding_value = CHECK_ENCODING(encoding, "zstd", VARY_ENCODING_ZSTD);
3214
0
    break;
3215
0
  case '*':
3216
0
    encoding = istnext(encoding);
3217
0
    *encoding_value = VARY_ENCODING_STAR;
3218
0
    break;
3219
0
  default:
3220
0
    retval = -1; /* Unmanaged encoding */
3221
0
    break;
3222
0
  }
3223
3224
  /* Process the optional weight part of the encoding. */
3225
0
  if (*encoding_value) {
3226
0
    encoding = http_trim_leading_spht(encoding);
3227
0
    if (istlen(encoding)) {
3228
0
      if (*encoding.ptr != ';')
3229
0
        return -1;
3230
3231
0
      if (has_null_weight) {
3232
0
        encoding = istnext(encoding);
3233
3234
0
        encoding = http_trim_leading_spht(encoding);
3235
3236
0
        *has_null_weight = isteq(encoding, ist("q=0"));
3237
0
      }
3238
0
    }
3239
0
  }
3240
3241
0
  return retval;
3242
0
}
3243
3244
0
#define ACCEPT_ENCODING_MAX_ENTRIES 16
3245
/*
3246
 * Build a bitmap of the accept-encoding header.
3247
 *
3248
 * The bitmap is built by matching every sub-part of the accept-encoding value
3249
 * with a subset of explicitly supported encodings, which all have their own bit
3250
 * in the bitmap. This bitmap will be used to determine if a response can be
3251
 * served to a client (that is if it has an encoding that is accepted by the
3252
 * client). Any unknown encodings will be indicated by the VARY_ENCODING_OTHER
3253
 * bit.
3254
 *
3255
 * Returns 0 in case of success and -1 in case of error.
3256
 */
3257
static int accept_encoding_normalizer(struct htx *htx, struct ist hdr_name,
3258
              char *buf, unsigned int *buf_len)
3259
0
{
3260
0
  size_t count = 0;
3261
0
  uint32_t encoding_bitmap = 0;
3262
0
  unsigned int encoding_bmp_bl = -1;
3263
0
  struct http_hdr_ctx ctx = { .blk = NULL };
3264
0
  unsigned int encoding_value;
3265
0
  unsigned int rejected_encoding;
3266
3267
  /* A user agent always accepts an unencoded value unless it explicitly
3268
   * refuses it through an "identity;q=0" accept-encoding value. */
3269
0
  encoding_bitmap |= VARY_ENCODING_IDENTITY;
3270
3271
  /* Iterate over all the ACCEPT_ENCODING_MAX_ENTRIES first accept-encoding
3272
   * values that might span acrosse multiple accept-encoding headers. */
3273
0
  while (http_find_header(htx, hdr_name, &ctx, 0) && count < ACCEPT_ENCODING_MAX_ENTRIES) {
3274
0
    count++;
3275
3276
    /* As per RFC7231#5.3.4, "An Accept-Encoding header field with a
3277
     * combined field-value that is empty implies that the user agent
3278
     * does not want any content-coding in response."
3279
     *
3280
     * We must (and did) count the existence of this empty header to not
3281
     * hit the `count == 0` case below, but must ignore the value to not
3282
     * include VARY_ENCODING_OTHER into the final bitmap.
3283
     */
3284
0
    if (istlen(ctx.value) == 0)
3285
0
      continue;
3286
3287
    /* Turn accept-encoding value to lower case */
3288
0
    ist2bin_lc(istptr(ctx.value), ctx.value);
3289
3290
    /* Try to identify a known encoding and to manage null weights. */
3291
0
    if (!parse_encoding_value(ctx.value, &encoding_value, &rejected_encoding)) {
3292
0
      if (rejected_encoding)
3293
0
        encoding_bmp_bl &= ~encoding_value;
3294
0
      else
3295
0
        encoding_bitmap |= encoding_value;
3296
0
    }
3297
0
    else {
3298
      /* Unknown encoding */
3299
0
      encoding_bitmap |= VARY_ENCODING_OTHER;
3300
0
    }
3301
0
  }
3302
3303
  /* If a "*" was found in the accepted encodings (without a null weight),
3304
   * all the encoding are accepted except the ones explicitly rejected. */
3305
0
  if (encoding_bitmap & VARY_ENCODING_STAR) {
3306
0
    encoding_bitmap = ~0;
3307
0
  }
3308
3309
  /* Clear explicitly rejected encodings from the bitmap */
3310
0
  encoding_bitmap &= encoding_bmp_bl;
3311
3312
  /* As per RFC7231#5.3.4, "If no Accept-Encoding field is in the request,
3313
   * any content-coding is considered acceptable by the user agent". */
3314
0
  if (count == 0)
3315
0
    encoding_bitmap = ~0;
3316
3317
  /* A request with more than ACCEPT_ENCODING_MAX_ENTRIES accepted
3318
   * encodings might be illegitimate so we will not use it. */
3319
0
  if (count == ACCEPT_ENCODING_MAX_ENTRIES)
3320
0
    return -1;
3321
3322
0
  write_u32(buf, encoding_bitmap);
3323
0
  *buf_len = sizeof(encoding_bitmap);
3324
3325
  /* This function fills the hash buffer correctly even if no header was
3326
   * found, hence the 0 return value (success). */
3327
0
  return 0;
3328
0
}
3329
#undef ACCEPT_ENCODING_MAX_ENTRIES
3330
3331
/*
3332
 * Normalizer used by default for the Referer and Origin header. It only
3333
 * calculates a hash of the whole value using xxhash algorithm.
3334
 * Only the first occurrence of the header will be taken into account in the
3335
 * hash.
3336
 * Returns 0 in case of success, 1 if the hash buffer should be filled with 0s
3337
 * and -1 in case of error.
3338
 */
3339
static int default_normalizer(struct htx *htx, struct ist hdr_name,
3340
            char *buf, unsigned int *buf_len)
3341
0
{
3342
0
  int retval = 1;
3343
0
  struct http_hdr_ctx ctx = { .blk = NULL };
3344
3345
0
  if (http_find_header(htx, hdr_name, &ctx, 1)) {
3346
0
    retval = 0;
3347
0
    write_u64(buf, XXH3(istptr(ctx.value), istlen(ctx.value), cache_hash_seed));
3348
0
    *buf_len = sizeof(uint64_t);
3349
0
  }
3350
3351
0
  return retval;
3352
0
}
3353
3354
/*
3355
 * Accept-Encoding bitmap comparison function.
3356
 * Returns 0 if the bitmaps are compatible.
3357
 */
3358
static int accept_encoding_bitmap_cmp(const void *ref, const void *new, unsigned int len)
3359
0
{
3360
0
  uint32_t ref_bitmap = read_u32(ref);
3361
0
  uint32_t new_bitmap = read_u32(new);
3362
3363
0
  if (!(ref_bitmap & VARY_ENCODING_OTHER)) {
3364
    /* All the bits set in the reference bitmap correspond to the
3365
     * stored response' encoding and should all be set in the new
3366
     * encoding bitmap in order for the client to be able to manage
3367
     * the response.
3368
     *
3369
     * If this is the case the cached response has encodings that
3370
     * are accepted by the client. It can be served directly by
3371
     * the cache (as far as the accept-encoding part is concerned).
3372
     */
3373
3374
0
    return (ref_bitmap & new_bitmap) != ref_bitmap;
3375
0
  }
3376
0
  else {
3377
0
    return 1;
3378
0
  }
3379
0
}
3380
3381
3382
/*
3383
 * Pre-calculate the hashes of all the supported headers (in our Vary
3384
 * implementation) of a given request. We have to calculate all the hashes
3385
 * in advance because the actual Vary signature won't be known until the first
3386
 * response.
3387
 * Only the first occurrence of every header will be taken into account in the
3388
 * hash.
3389
 * If the header is not present, the hash portion of the given header will be
3390
 * filled with zeros.
3391
 * Returns 0 in case of success.
3392
 */
3393
static int http_request_prebuild_full_secondary_key(struct stream *s)
3394
0
{
3395
  /* The fake signature (second parameter) will ensure that every part of the
3396
   * secondary key is calculated. */
3397
0
  return http_request_build_secondary_key(s, ~0);
3398
0
}
3399
3400
3401
/*
3402
 * Calculate the secondary key for a request for which we already have a known
3403
 * vary signature. The key is made by aggregating hashes calculated for every
3404
 * header mentioned in the vary signature.
3405
 * Only the first occurrence of every header will be taken into account in the
3406
 * hash.
3407
 * If the header is not present, the hash portion of the given header will be
3408
 * filled with zeros.
3409
 * Returns 0 in case of success.
3410
 */
3411
static int http_request_build_secondary_key(struct stream *s, int vary_signature)
3412
0
{
3413
0
  struct http_txn *txn = s->txn.http;
3414
0
  struct htx *htx = htxbuf(&s->req.buf);
3415
3416
0
  unsigned int idx;
3417
0
  const struct vary_hashing_information *info = NULL;
3418
0
  unsigned int hash_length = 0;
3419
0
  int retval = 0;
3420
0
  int offset = 0;
3421
3422
0
  for (idx = 0; idx < sizeof(vary_information)/sizeof(*vary_information) && retval >= 0; ++idx) {
3423
0
    info = &vary_information[idx];
3424
3425
    /* The normalizing functions will be in charge of getting the
3426
     * header values from the htx. This way they can manage multiple
3427
     * occurrences of their processed header. */
3428
0
    if ((vary_signature & info->value) && info->norm_fn != NULL &&
3429
0
        !(retval = info->norm_fn(htx, info->hdr_name, &txn->cache_secondary_hash[offset], &hash_length))) {
3430
0
      offset += hash_length;
3431
0
    }
3432
0
    else {
3433
      /* Fill hash with 0s. */
3434
0
      hash_length = info->hash_length;
3435
0
      memset(&txn->cache_secondary_hash[offset], 0, hash_length);
3436
0
      offset += hash_length;
3437
0
    }
3438
0
  }
3439
3440
0
  if (retval >= 0)
3441
0
    txn->flags |= TX_CACHE_HAS_SEC_KEY;
3442
3443
0
  return (retval < 0);
3444
0
}
3445
3446
/*
3447
 * Build the actual secondary key of a given request out of the prebuilt key and
3448
 * the actual vary signature (extracted from the response).
3449
 * Returns 0 in case of success.
3450
 */
3451
static int http_request_reduce_secondary_key(unsigned int vary_signature,
3452
               char prebuilt_key[HTTP_CACHE_SEC_KEY_LEN])
3453
0
{
3454
0
  int offset = 0;
3455
0
  int global_offset = 0;
3456
0
  int vary_info_count = 0;
3457
0
  int keep = 0;
3458
0
  unsigned int vary_idx;
3459
0
  const struct vary_hashing_information *vary_info;
3460
3461
0
  vary_info_count = sizeof(vary_information)/sizeof(*vary_information);
3462
0
  for (vary_idx = 0; vary_idx < vary_info_count; ++vary_idx) {
3463
0
    vary_info = &vary_information[vary_idx];
3464
0
    keep = (vary_signature & vary_info->value) ? 0xff : 0;
3465
3466
0
    for (offset = 0; offset < vary_info->hash_length; ++offset,++global_offset) {
3467
0
      prebuilt_key[global_offset] &= keep;
3468
0
    }
3469
0
  }
3470
3471
0
  return 0;
3472
0
}
3473
3474
3475
3476
static int
3477
parse_cache_flt(char **args, int *cur_arg, struct proxy *px,
3478
    struct flt_conf *fconf, char **err, void *private)
3479
0
{
3480
0
  struct flt_conf *f, *back;
3481
0
  struct cache_flt_conf *cconf = NULL;
3482
0
  char *name = NULL;
3483
0
  int pos = *cur_arg;
3484
3485
  /* Get the cache filter name. <pos> point on "cache" keyword */
3486
0
  if (!*args[pos + 1]) {
3487
0
    memprintf(err, "%s : expects a <name> argument", args[pos]);
3488
0
    goto error;
3489
0
  }
3490
0
  name = strdup(args[pos + 1]);
3491
0
  if (!name) {
3492
0
    memprintf(err, "%s '%s' : out of memory", args[pos], args[pos + 1]);
3493
0
    goto error;
3494
0
  }
3495
0
  pos += 2;
3496
3497
  /* Check if an implicit filter with the same name already exists. If so,
3498
   * we remove the implicit filter to use the explicit one. */
3499
0
  list_for_each_entry_safe(f, back, &px->filter_configs, list) {
3500
0
    if (f->id != cache_store_flt_id)
3501
0
      continue;
3502
3503
0
    cconf = f->conf;
3504
0
    if (strcmp(name, cconf->c.name) != 0) {
3505
0
      cconf = NULL;
3506
0
      continue;
3507
0
    }
3508
3509
0
    if (!(cconf->flags & CACHE_FLT_F_IMPLICIT_DECL)) {
3510
0
      cconf = NULL;
3511
0
      memprintf(err, "%s: multiple explicit declarations of the cache filter '%s'",
3512
0
          px->id, name);
3513
0
      goto error;
3514
0
    }
3515
3516
    /* Remove the implicit filter. <cconf> is kept for the explicit one */
3517
0
    LIST_DELETE(&f->list);
3518
0
    free(f);
3519
0
    free(name);
3520
0
    break;
3521
0
  }
3522
3523
  /* No implicit cache filter found, create configuration for the explicit one */
3524
0
  if (!cconf) {
3525
0
    cconf = calloc(1, sizeof(*cconf));
3526
0
    if (!cconf) {
3527
0
      memprintf(err, "%s: out of memory", args[*cur_arg]);
3528
0
      goto error;
3529
0
    }
3530
0
    cconf->c.name = name;
3531
0
  }
3532
3533
0
  cconf->flags = 0;
3534
0
  fconf->id   = cache_store_flt_id;
3535
0
  fconf->conf = cconf;
3536
0
  fconf->ops  = &cache_ops;
3537
3538
0
  *cur_arg = pos;
3539
0
  return 0;
3540
3541
0
  error:
3542
0
  free(name);
3543
0
  free(cconf);
3544
0
  return -1;
3545
0
}
3546
3547
/* It reserves a struct show_cache_ctx for the local variables */
3548
static int cli_parse_show_cache(char **args, char *payload, struct appctx *appctx, void *private)
3549
0
{
3550
0
  struct show_cache_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
3551
3552
0
  if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
3553
0
    return 1;
3554
3555
0
  ctx->cache = LIST_ELEM((caches).n, typeof(struct cache *), list);
3556
0
  return 0;
3557
0
}
3558
3559
/* It uses a struct show_cache_ctx for the local variables */
3560
static int cli_io_handler_show_cache(struct appctx *appctx)
3561
0
{
3562
0
  struct show_cache_ctx *ctx = appctx->svcctx;
3563
0
  struct cache* cache = ctx->cache;
3564
0
  struct buffer *buf = alloc_trash_chunk();
3565
3566
0
  if (buf == NULL)
3567
0
    return 1;
3568
3569
0
  list_for_each_entry_from(cache, &caches, list) {
3570
0
    struct eb32_node *node = NULL;
3571
0
    unsigned int next_key;
3572
0
    struct cache_entry *entry;
3573
0
    unsigned int i;
3574
0
    struct shared_context *shctx = shctx_ptr(cache);
3575
0
    int cache_tree_index = 0;
3576
0
    struct cache_tree *cache_tree = NULL;
3577
3578
0
    next_key = ctx->next_key;
3579
0
    if (!next_key) {
3580
0
      shctx_rdlock(shctx);
3581
0
      chunk_printf(buf, "%p: %s (shctx:%p, available blocks:%d)\n", cache, cache->id, shctx_ptr(cache), shctx_ptr(cache)->nbav);
3582
0
      shctx_rdunlock(shctx);
3583
0
      if (applet_putchk(appctx, buf) == -1) {
3584
0
        goto yield;
3585
0
      }
3586
0
    }
3587
3588
0
    ctx->cache = cache;
3589
3590
0
    if (ctx->cache_tree)
3591
0
      cache_tree_index = (ctx->cache_tree - ctx->cache->trees);
3592
3593
0
    for (;cache_tree_index < CACHE_TREE_NUM; ++cache_tree_index) {
3594
3595
0
      ctx->cache_tree = cache_tree = &ctx->cache->trees[cache_tree_index];
3596
3597
0
      cache_rdlock(cache_tree);
3598
3599
0
      while (1) {
3600
0
        node = eb32_lookup_ge(&cache_tree->entries, next_key);
3601
0
        if (!node) {
3602
0
          ctx->next_key = 0;
3603
0
          next_key = 0;
3604
0
          break;
3605
0
        }
3606
3607
0
        entry = container_of(node, struct cache_entry, eb);
3608
0
        next_key = node->key + 1;
3609
3610
0
        if (entry->expire > date.tv_sec) {
3611
0
          chunk_printf(buf, "%p hash:%u vary:0x", entry, read_u32(entry->hash));
3612
0
          for (i = 0; i < HTTP_CACHE_SEC_KEY_LEN; ++i)
3613
0
            chunk_appendf(buf, "%02x", (unsigned char)entry->secondary_key[i]);
3614
0
          chunk_appendf(buf, " type:%s size:%u (%u blocks), refcount:%u, expire:%d\n",
3615
0
                  (entry->flags & CACHE_EF_STRIPPED) ? "hints" : "full",
3616
0
                  block_ptr(entry)->len, block_ptr(entry)->block_count,
3617
0
                  block_ptr(entry)->refcount, entry->expire - (int)date.tv_sec);
3618
0
        }
3619
3620
0
        ctx->next_key = next_key;
3621
3622
0
        if (applet_putchk(appctx, buf) == -1) {
3623
0
          cache_rdunlock(cache_tree);
3624
0
          goto yield;
3625
0
        }
3626
0
      }
3627
0
      cache_rdunlock(cache_tree);
3628
0
    }
3629
0
  }
3630
3631
0
  free_trash_chunk(buf);
3632
0
  return 1;
3633
3634
0
yield:
3635
0
  free_trash_chunk(buf);
3636
0
  return 0;
3637
0
}
3638
3639
3640
/*
3641
 * boolean, returns true if response was built out of a cache entry.
3642
 */
3643
static int
3644
smp_fetch_res_cache_hit(const struct arg *args, struct sample *smp,
3645
                        const char *kw, void *private)
3646
0
{
3647
0
  smp->data.type = SMP_T_BOOL;
3648
0
  smp->data.u.sint = (smp->strm ? (smp->strm->target == &http_cache_applet.obj_type) : 0);
3649
3650
0
  return 1;
3651
0
}
3652
3653
/*
3654
 * string, returns cache name (if response came from a cache).
3655
 */
3656
static int
3657
smp_fetch_res_cache_name(const struct arg *args, struct sample *smp,
3658
                         const char *kw, void *private)
3659
0
{
3660
0
  struct appctx *appctx = NULL;
3661
3662
0
  if (!smp->strm || smp->strm->target != &http_cache_applet.obj_type)
3663
0
    return 0;
3664
3665
  /* Get appctx from the stream connector. */
3666
0
  appctx = sc_appctx(smp->strm->scb);
3667
0
  if (appctx) {
3668
0
    struct cache_appctx *ctx = appctx->svcctx;
3669
3670
0
    smp->data.type = SMP_T_STR;
3671
0
    smp->flags = SMP_F_CONST;
3672
0
    smp->data.u.str.area = ctx->cache->id;
3673
0
    smp->data.u.str.data = strlen(ctx->cache->id);
3674
0
    return 1;
3675
0
  }
3676
3677
0
  return 0;
3678
0
}
3679
3680
3681
/* early boot initialization */
3682
static void cache_init()
3683
0
{
3684
0
  cache_hash_seed = ha_random64();
3685
0
}
3686
3687
INITCALL0(STG_PREPARE, cache_init);
3688
3689
/* Declare the filter parser for "cache" keyword */
3690
static struct flt_kw_list filter_kws = { "CACHE", { }, {
3691
    { "cache", parse_cache_flt, NULL },
3692
    { NULL, NULL, NULL },
3693
  }
3694
};
3695
3696
INITCALL1(STG_REGISTER, flt_register_keywords, &filter_kws);
3697
3698
static struct cli_kw_list cli_kws = {{},{
3699
  { { "show", "cache", NULL }, "show cache                              : show cache status", cli_parse_show_cache, cli_io_handler_show_cache, NULL, NULL },
3700
  {{},}
3701
}};
3702
3703
INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
3704
3705
static struct action_kw_list http_res_actions = {
3706
  .kw = {
3707
    { "cache-store", parse_cache_store },
3708
    { NULL, NULL }
3709
  }
3710
};
3711
3712
INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_actions);
3713
3714
static struct action_kw_list http_req_actions = {
3715
  .kw = {
3716
    { "cache-use", parse_cache_use },
3717
    { NULL, NULL }
3718
  }
3719
};
3720
3721
INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_actions);
3722
3723
struct applet http_cache_applet = {
3724
  .obj_type = OBJ_TYPE_APPLET,
3725
  .flags = APPLET_FL_NEW_API|APPLET_FL_HTX,
3726
  .name = "<CACHE>", /* used for logging */
3727
  .fct = http_cache_io_handler,
3728
  .rcv_buf = appctx_htx_rcv_buf,
3729
  .snd_buf = appctx_htx_snd_buf,
3730
  .fastfwd = http_cache_fastfwd,
3731
  .release = http_cache_applet_release,
3732
};
3733
3734
3735
/* config parsers for this section */
3736
REGISTER_CONFIG_SECTION("cache", cfg_parse_cache, cfg_post_parse_section_cache);
3737
REGISTER_POST_CHECK(post_check_cache);
3738
3739
3740
/* Note: must not be declared <const> as its list will be overwritten */
3741
static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
3742
    { "res.cache_hit",  smp_fetch_res_cache_hit,  0, NULL, SMP_T_BOOL, SMP_USE_HRSHP, SMP_VAL_RESPONSE },
3743
    { "res.cache_name", smp_fetch_res_cache_name, 0, NULL, SMP_T_STR,  SMP_USE_HRSHP, SMP_VAL_RESPONSE },
3744
    { /* END */ },
3745
  }
3746
};
3747
3748
INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);