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 MD5 Cache Keys */
10 
11 #include "squid.h"
12 #include "HttpRequest.h"
13 #include "md5.h"
14 #include "store_key_md5.h"
15 
16 static cache_key null_key[SQUID_MD5_DIGEST_LENGTH];
17 
18 const char *
storeKeyText(const cache_key * key)19 storeKeyText(const cache_key *key)
20 {
21     if (!key)
22         return "[null_store_key]";
23 
24     static char buf[SQUID_MD5_DIGEST_LENGTH * 2+1];
25     int i;
26 
27     for (i = 0; i < SQUID_MD5_DIGEST_LENGTH; ++i)
28         snprintf(&buf[i*2],sizeof(buf) - i*2, "%02X", *(key + i));
29 
30     return buf;
31 }
32 
33 const cache_key *
storeKeyScan(const char * buf)34 storeKeyScan(const char *buf)
35 {
36     static unsigned char digest[SQUID_MD5_DIGEST_LENGTH];
37     int i;
38     int j = 0;
39     char t[3];
40 
41     for (i = 0; i < SQUID_MD5_DIGEST_LENGTH; ++i) {
42         t[0] = *(buf + (j++));
43         t[1] = *(buf + (j++));
44         t[2] = '\0';
45         *(digest + i) = (unsigned char) strtol(t, NULL, 16);
46     }
47 
48     return digest;
49 }
50 
51 int
storeKeyHashCmp(const void * a,const void * b)52 storeKeyHashCmp(const void *a, const void *b)
53 {
54     const unsigned char *A = (const unsigned char *)a;
55     const unsigned char *B = (const unsigned char *)b;
56     int i;
57 
58     for (i = 0; i < SQUID_MD5_DIGEST_LENGTH; ++i) {
59         if (A[i] < B[i])
60             return -1;
61 
62         if (A[i] > B[i])
63             return 1;
64     }
65 
66     return 0;
67 }
68 
69 unsigned int
storeKeyHashHash(const void * key,unsigned int n)70 storeKeyHashHash(const void *key, unsigned int n)
71 {
72     /* note, n must be a power of 2! */
73     const unsigned char *digest = (const unsigned char *)key;
74     unsigned int i = digest[0]
75                      | digest[1] << 8
76                      | digest[2] << 16
77                      | digest[3] << 24;
78     return (i & (--n));
79 }
80 
81 const cache_key *
storeKeyPrivate()82 storeKeyPrivate()
83 {
84     // only the count field is required
85     // others just simplify searching for keys in a multi-process cache.log
86     static struct {
87         uint64_t count;
88         pid_t pid;
89         int32_t kid;
90     } key = { 0, getpid(), KidIdentifier };
91     assert(sizeof(key) == SQUID_MD5_DIGEST_LENGTH);
92     ++key.count;
93     return reinterpret_cast<cache_key*>(&key);
94 }
95 
96 const cache_key *
storeKeyPublic(const char * url,const HttpRequestMethod & method,const KeyScope keyScope)97 storeKeyPublic(const char *url, const HttpRequestMethod& method, const KeyScope keyScope)
98 {
99     static cache_key digest[SQUID_MD5_DIGEST_LENGTH];
100     unsigned char m = (unsigned char) method.id();
101     SquidMD5_CTX M;
102     SquidMD5Init(&M);
103     SquidMD5Update(&M, &m, sizeof(m));
104     SquidMD5Update(&M, (unsigned char *) url, strlen(url));
105     if (keyScope)
106         SquidMD5Update(&M, &keyScope, sizeof(keyScope));
107     SquidMD5Final(digest, &M);
108     return digest;
109 }
110 
111 const cache_key *
storeKeyPublicByRequest(HttpRequest * request,const KeyScope keyScope)112 storeKeyPublicByRequest(HttpRequest * request, const KeyScope keyScope)
113 {
114     return storeKeyPublicByRequestMethod(request, request->method, keyScope);
115 }
116 
117 const cache_key *
storeKeyPublicByRequestMethod(HttpRequest * request,const HttpRequestMethod & method,const KeyScope keyScope)118 storeKeyPublicByRequestMethod(HttpRequest * request, const HttpRequestMethod& method, const KeyScope keyScope)
119 {
120     static cache_key digest[SQUID_MD5_DIGEST_LENGTH];
121     unsigned char m = (unsigned char) method.id();
122     const SBuf url = request->storeId(); /* returns the right storeID\URL for the MD5 calc */
123     SquidMD5_CTX M;
124     SquidMD5Init(&M);
125     SquidMD5Update(&M, &m, sizeof(m));
126     SquidMD5Update(&M, (unsigned char *) url.rawContent(), url.length());
127     if (keyScope)
128         SquidMD5Update(&M, &keyScope, sizeof(keyScope));
129 
130     if (!request->vary_headers.isEmpty()) {
131         SquidMD5Update(&M, request->vary_headers.rawContent(), request->vary_headers.length());
132         debugs(20, 3, "updating public key by vary headers: " << request->vary_headers << " for: " << url);
133     }
134 
135     SquidMD5Final(digest, &M);
136 
137     return digest;
138 }
139 
140 cache_key *
storeKeyDup(const cache_key * key)141 storeKeyDup(const cache_key * key)
142 {
143     cache_key *dup = (cache_key *)memAllocate(MEM_MD5_DIGEST);
144     memcpy(dup, key, SQUID_MD5_DIGEST_LENGTH);
145     return dup;
146 }
147 
148 cache_key *
storeKeyCopy(cache_key * dst,const cache_key * src)149 storeKeyCopy(cache_key * dst, const cache_key * src)
150 {
151     memcpy(dst, src, SQUID_MD5_DIGEST_LENGTH);
152     return dst;
153 }
154 
155 void
storeKeyFree(const cache_key * key)156 storeKeyFree(const cache_key * key)
157 {
158     memFree((void *) key, MEM_MD5_DIGEST);
159 }
160 
161 int
storeKeyHashBuckets(int nbuckets)162 storeKeyHashBuckets(int nbuckets)
163 {
164     int n = 0x2000;
165 
166     while (n < nbuckets)
167         n <<= 1;
168 
169     return n;
170 }
171 
172 int
storeKeyNull(const cache_key * key)173 storeKeyNull(const cache_key * key)
174 {
175     if (memcmp(key, null_key, SQUID_MD5_DIGEST_LENGTH) == 0)
176         return 1;
177     else
178         return 0;
179 }
180 
181 void
storeKeyInit(void)182 storeKeyInit(void)
183 {
184     memset(null_key, '\0', SQUID_MD5_DIGEST_LENGTH);
185 }
186 
187