]> mj.ucw.cz Git - libucw.git/blob - lib/urlkey.c
Always define the memory allocation primitives with the `sh_' prefix,
[libucw.git] / lib / urlkey.c
1 /*
2  *      Sherlock Library -- URL Keys & URL Fingerprints
3  *
4  *      (c) 2003 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #undef LOCAL_DEBUG
11
12 #include "lib/lib.h"
13 #include "lib/conf.h"
14 #include "lib/index.h"
15 #include "lib/url.h"
16 #include "lib/fastbuf.h"
17 #include "lib/chartype.h"
18 #include "lib/hashfunc.h"
19
20 #include <string.h>
21 #include <fcntl.h>
22
23 /*** Prefix recognition table ***/
24
25 struct pxtab_rhs {
26   struct pxtab_node *node;
27   uns len;
28   byte rhs[1];
29 };
30
31 struct pxtab_node {
32   struct pxtab_node *parent;
33   struct pxtab_rhs *rhs;
34   uns len, total_len;
35   byte component[0];
36 };
37
38 #define HASH_NODE struct pxtab_node
39 #define HASH_PREFIX(p) pxtab_##p
40 #define HASH_KEY_COMPLEX(x) x parent, x component, x len
41 #define HASH_KEY_DECL struct pxtab_node *parent UNUSED, byte *component UNUSED, uns len UNUSED
42 #define HASH_WANT_FIND
43 #define HASH_WANT_LOOKUP
44 #define HASH_GIVE_HASHFN
45 #define HASH_GIVE_EQ
46 #define HASH_GIVE_EXTRA_SIZE
47 #define HASH_GIVE_INIT_KEY
48 #define HASH_USE_POOL cfpool
49
50 static inline uns
51 pxtab_hash(HASH_KEY_DECL)
52 {
53   return ((uns)parent) ^ hash_block(component, len);
54 }
55
56 static inline int
57 pxtab_eq(struct pxtab_node *p1, byte *c1, uns l1, struct pxtab_node *p2, byte *c2, uns l2)
58 {
59   return p1 == p2 && l1 == l2 && !memcmp(c1, c2, l1);
60 }
61
62 static inline int
63 pxtab_extra_size(HASH_KEY_DECL)
64 {
65   return len;
66 }
67
68 static inline void
69 pxtab_init_key(struct pxtab_node *node, HASH_KEY_DECL)
70 {
71   node->parent = parent;
72   node->len = len;
73   memcpy(node->component, component, len);
74   node->rhs = NULL;
75 }
76
77 #include "lib/hashtable.h"
78
79 static inline byte *
80 pxtab_skip_first_comp(byte *x)
81 {
82   while (*x && *x != ':')
83     x++;
84   byte *y = x;
85   while (*x != '/' || x[1] != '/')
86     {
87       if (!*x)
88         return y;
89       x++;
90     }
91   return x+2;
92 }
93
94 static inline byte *
95 pxtab_skip_next_comp(byte *x)
96 {
97   for(;;)
98     {
99       if (!*x)
100         return x;
101       if (*x == '/')
102         return x+1;
103       x++;
104     }
105 }
106
107 static struct pxtab_node *
108 pxtab_find_rule(byte *lhs)
109 {
110   byte *next;
111   struct pxtab_node *node, *parent = NULL;
112
113   next = pxtab_skip_first_comp(lhs);
114   DBG("\tfirst: %.*s", next-lhs, lhs);
115   node = pxtab_find(NULL, lhs, next-lhs);
116   while (node && *next)
117     {
118       parent = node;
119       lhs = next;
120       next = pxtab_skip_next_comp(lhs);
121       DBG("\tnext: %.*s", next-lhs, lhs);
122       node = pxtab_find(parent, lhs, next-lhs);
123     }
124   return node ? : parent;
125 }
126
127 static struct pxtab_node *
128 pxtab_add_rule(byte *lhs, struct pxtab_rhs *rhs)
129 {
130   byte *lhs_start = lhs;
131   byte *next;
132   struct pxtab_node *node, *parent;
133
134   next = pxtab_skip_first_comp(lhs);
135   DBG("\tfirst: %.*s", next-lhs, lhs);
136   node = pxtab_lookup(NULL, lhs, next-lhs);
137   for(;;)
138     {
139       if (node->rhs)
140         return NULL;
141       if (!*next)
142         break;
143       lhs = next;
144       next = pxtab_skip_next_comp(lhs);
145       parent = node;
146       DBG("\tnext: %.*s", next-lhs, lhs);
147       node = pxtab_lookup(parent, lhs, next-lhs);
148     }
149   DBG("\tsetting rhs, %d to eat", next-lhs_start);
150   node->rhs = rhs;
151   node->total_len = next - lhs_start;
152   return node;
153 }
154
155 static struct pxtab_rhs *
156 pxtab_add_rhs(byte *rhs)
157 {
158   uns len = strlen(rhs);
159   struct pxtab_rhs *r = cfg_malloc(sizeof(*r) + len);
160   r->len = len;
161   memcpy(r->rhs, rhs, len+1);
162   struct pxtab_node *node = pxtab_add_rule(rhs, r);
163   r->node = node;
164   return r;
165 }
166
167 static void
168 pxtab_load(byte *name)
169 {
170   struct fastbuf *f;
171   struct pxtab_rhs *rhs = NULL;
172   byte line[MAX_URL_SIZE], url[MAX_URL_SIZE], *c, *d;
173   int err;
174   int lino = 0;
175
176   DBG("Loading prefix table %s", name);
177   f = bopen(name, O_RDONLY, 4096);
178   while (bgets(f, line, sizeof(line)))
179     {
180       lino++;
181       c = line;
182       while (Cblank(*c))
183         c++;
184       if (!*c || *c == '#')
185         continue;
186       if (err = url_auto_canonicalize(c, url))
187         die("%s, line %d: Invalid URL (%s)", name, lino, url_error(err));
188       if (!(d = strrchr(c, '/')) || d[1])
189         die("%s, line %d: Prefix rules must end with a slash", name, lino);
190       if (c == line)
191         {
192           DBG("Creating RHS <%s>", c);
193           if (!(rhs = pxtab_add_rhs(c)))
194             die("%s, line %d: Right-hand side already mapped", name, lino);
195         }
196       else if (!rhs)
197         die("%s, line %d: Syntax error", name, lino);
198       else
199         {
200           DBG("Adding LHS <%s>", c);
201           if (!pxtab_add_rule(c, rhs))
202             die("%s, line %d: Duplicate rule", name, lino);
203         }
204     }
205   bclose(f);
206 }
207
208 /*** Configuration ***/
209
210 static uns urlkey_www_hack;
211 static byte *urlkey_pxtab_path;
212
213 static struct cfitem urlkey_config[] = {
214   { "URLKey",           CT_SECTION,     NULL },
215   { "WWWHack",          CT_INT,         &urlkey_www_hack },
216   { "PrefixTable",      CT_STRING,      &urlkey_pxtab_path },
217   { NULL,               CT_STOP,        NULL }
218 };
219
220 static void CONSTRUCTOR urlkey_conf_init(void)
221 {
222   cf_register(urlkey_config);
223 }
224
225 void
226 url_key_init(void)
227 {
228   pxtab_init();
229   if (urlkey_pxtab_path)
230     pxtab_load(urlkey_pxtab_path);
231 }
232
233 static inline byte *
234 url_key_remove_www(byte *url, byte **pbuf)
235 {
236   if (urlkey_www_hack && !strncmp(url, "http://www.", 11))
237     {
238       byte *buf = *pbuf;
239       strcpy(buf, "http://");
240       strcpy(buf+7, url+11);
241       DBG("\tWWW hack: %s -> %s", url, buf);
242       url = buf;
243       *pbuf = buf + MAX_URL_SIZE;
244     }
245   return url;
246 }
247
248 byte *
249 url_key(byte *url, byte *buf)
250 {
251   DBG("Generating URL key for %s", url);
252   url = url_key_remove_www(url, &buf);
253   struct pxtab_node *rule = pxtab_find_rule(url);
254   if (rule && rule->rhs && rule->rhs->node != rule)
255     {
256       struct pxtab_rhs *rhs = rule->rhs;
257       DBG("\tApplying rule <%s>, remove %d, add %d", rhs->rhs, rule->total_len, rhs->len);
258       memcpy(buf, rhs->rhs, rhs->len);
259       strcpy(buf + rhs->len, url + rule->total_len);
260       url = buf;
261       buf += MAX_URL_SIZE;
262     }
263   DBG("\tOutput: %s", url);
264   return url;
265 }
266
267 void
268 url_fingerprint(byte *url, struct fingerprint *fp)
269 {
270   byte buf[URL_KEY_BUF_SIZE];
271   fingerprint(url_key(url, buf), fp);
272 }
273
274 #ifdef TEST
275
276 int main(int argc, char **argv)
277 {
278   cf_read(cfdeffile);
279   url_key_init();
280   for (int i=1; i<argc; i++)
281     {
282       byte buf[URL_KEY_BUF_SIZE];
283       struct fingerprint fp;
284       byte *key = url_key(argv[i], buf);
285       fingerprint(key, &fp);
286       for (int j=0; j<12; j++)
287         printf("%02x", fp.hash[j]);
288       printf(" %s\n", key);
289     }
290   return 0;
291 }
292
293 #endif