1 /*
2  * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 20    Storage Manager Swapfile Metadata */
10 
11 #include "squid.h"
12 #include "MemObject.h"
13 #include "Store.h"
14 #include "StoreMeta.h"
15 #include "StoreMetaMD5.h"
16 #include "StoreMetaObjSize.h"
17 #include "StoreMetaSTD.h"
18 #include "StoreMetaSTDLFS.h"
19 #include "StoreMetaURL.h"
20 #include "StoreMetaVary.h"
21 
22 bool
validType(char type)23 StoreMeta::validType(char type)
24 {
25     /* VOID is reserved, and new types have to be added as classes */
26     if (type <= STORE_META_VOID || type >= STORE_META_END + 10) {
27         debugs(20, DBG_CRITICAL, "storeSwapMetaUnpack: bad type (" << type << ")!");
28         return false;
29     }
30 
31     /* Not yet implemented */
32     if (type >= STORE_META_END ||
33             type == STORE_META_STOREURL ||
34             type == STORE_META_VARY_ID) {
35         debugs(20, 3, "storeSwapMetaUnpack: Not yet implemented (" << type << ") in disk metadata");
36         return false;
37     }
38 
39     /* Unused in any current squid code */
40     if (type == STORE_META_KEY_URL ||
41             type == STORE_META_KEY_SHA ||
42             type == STORE_META_HITMETERING ||
43             type == STORE_META_VALID) {
44         debugs(20, DBG_CRITICAL, "Obsolete and unused type (" << type << ") in disk metadata");
45         return false;
46     }
47 
48     return true;
49 }
50 
51 class IntRange
52 {
53 
54 public:
IntRange(int minimum,int maximum)55     IntRange (int minimum, int maximum) : _min (minimum), _max (maximum) {
56         if (_min > _max) {
57             int temp = _min;
58             _min = _max;
59             _max = temp;
60         }
61     }
62 
includes(int anInt) const63     bool includes (int anInt) const {
64         if (anInt < _min || anInt > _max)
65             return false;
66 
67         return true;
68     }
69 
70 private:
71     int _min;
72     int _max;
73 };
74 
75 const int StoreMeta::MinimumTLVLength = 0;
76 const int StoreMeta::MaximumTLVLength = 1 << 16;
77 
78 bool
validLength(int aLength) const79 StoreMeta::validLength(int aLength) const
80 {
81     if (!IntRange (MinimumTLVLength, MaximumTLVLength).includes(aLength)) {
82         debugs(20, DBG_CRITICAL, "storeSwapMetaUnpack: insane length (" << aLength << ")!");
83         return false;
84     }
85 
86     return true;
87 }
88 
89 StoreMeta *
Factory(char type,size_t len,void const * value)90 StoreMeta::Factory (char type, size_t len, void const *value)
91 {
92     if (!validType(type))
93         return NULL;
94 
95     StoreMeta *result;
96 
97     switch (type) {
98 
99     case STORE_META_KEY:
100         result = new StoreMetaMD5;
101         break;
102 
103     case STORE_META_URL:
104         result = new StoreMetaURL;
105         break;
106 
107     case STORE_META_STD:
108         result = new StoreMetaSTD;
109         break;
110 
111     case STORE_META_STD_LFS:
112         result = new StoreMetaSTDLFS;
113         break;
114 
115     case STORE_META_OBJSIZE:
116         result = new StoreMetaObjSize;
117         break;
118 
119     case STORE_META_VARY_HEADERS:
120         result = new StoreMetaVary;
121         break;
122 
123     default:
124         debugs(20, DBG_CRITICAL, "Attempt to create unknown concrete StoreMeta");
125         return NULL;
126     }
127 
128     if (!result->validLength(len)) {
129         delete result;
130         return NULL;
131     }
132 
133     result->length = len;
134     result->value = xmalloc(len);
135     memcpy(result->value, value, len);
136     return result;
137 }
138 
139 void
FreeList(StoreMeta ** head)140 StoreMeta::FreeList(StoreMeta **head)
141 {
142     StoreMeta *node;
143 
144     while ((node = *head) != NULL) {
145         *head = node->next;
146         xfree(node->value);
147         delete node;
148     }
149 }
150 
151 StoreMeta **
Add(StoreMeta ** tail,StoreMeta * aNode)152 StoreMeta::Add(StoreMeta **tail, StoreMeta *aNode)
153 {
154     assert (*tail == NULL);
155     *tail = aNode;
156     return &aNode->next;        /* return new tail pointer */
157 }
158 
159 bool
checkConsistency(StoreEntry *) const160 StoreMeta::checkConsistency(StoreEntry *) const
161 {
162     switch (getType()) {
163 
164     case STORE_META_KEY:
165 
166     case STORE_META_URL:
167 
168     case STORE_META_VARY_HEADERS:
169         assert(0);
170         break;
171 
172     case STORE_META_STD:
173         break;
174 
175     case STORE_META_STD_LFS:
176         break;
177 
178     case STORE_META_OBJSIZE:
179         break;
180 
181     default:
182         debugs(20, DBG_IMPORTANT, "WARNING: got unused STORE_META type " << getType());
183         break;
184     }
185 
186     return true;
187 }
188 
StoreMeta(const StoreMeta & s)189 StoreMeta::StoreMeta(const StoreMeta &s) :
190     length(s.length),
191     value(s.value),
192     next(s.next)
193 {}
194 
operator =(const StoreMeta & s)195 StoreMeta& StoreMeta::operator=(const StoreMeta &s)
196 {
197     length=s.length;
198     value=s.value;
199     next=s.next;
200     return *this;
201 }
202 
203