static uns url_ignore_spaces;
static uns url_ignore_underflow;
-static byte *url_component_separators = "";
+static char *url_component_separators = "";
static uns url_min_repeat_count = 0x7fffffff;
static uns url_max_repeat_length = 0;
+static uns url_max_occurences = ~0U;
static struct cf_section url_config = {
CF_ITEMS {
CF_STRING("ComponentSeparators", &url_component_separators),
CF_UNS("MinRepeatCount", &url_min_repeat_count),
CF_UNS("MaxRepeatLength", &url_max_repeat_length),
+ CF_UNS("MaxOccurences", &url_max_occurences),
CF_END
}
};
}
int
-url_deescape(byte *s, byte *d)
+url_deescape(const byte *s, byte *d)
{
byte *dstart = d;
byte *end = d + MAX_URL_SIZE - 10;
*d++ = *s++;
else if (Cspace(*s))
{
- byte *s0 = s;
+ const byte *s0 = s;
while (Cspace(*s))
s++;
if (!url_ignore_spaces || !(!*s || d == dstart))
}
int
-url_enescape(byte *s, byte *d)
+url_enescape(const byte *s, byte *d)
{
byte *end = d + MAX_URL_SIZE - 10;
unsigned int c;
}
int
-url_enescape_friendly(byte *src, byte *dest)
+url_enescape_friendly(const byte *src, byte *dest)
{
byte *end = dest + MAX_URL_SIZE - 10;
while (*src)
static int url_proto_path_flags[URL_PROTO_MAX] = URL_PATH_FLAGS;
uns
-identify_protocol(byte *p)
+identify_protocol(const byte *p)
{
uns i;
/* Pack a broken-down URL */
static byte *
-append(byte *d, byte *s, byte *e)
+append(byte *d, const byte *s, byte *e)
{
if (d)
while (*s)
/* Standard cookbook recipes */
int
-url_canon_split_rel(byte *u, byte *buf1, byte *buf2, struct url *url, struct url *base)
+url_canon_split_rel(const byte *u, byte *buf1, byte *buf2, struct url *url, struct url *base)
{
int err;
}
int
-url_auto_canonicalize_rel(byte *src, byte *dst, struct url *base)
+url_auto_canonicalize_rel(const byte *src, byte *dst, struct url *base)
{
byte buf1[MAX_URL_SIZE], buf2[MAX_URL_SIZE], buf3[MAX_URL_SIZE];
int err;
#endif
struct component {
- byte *start;
+ const byte *start;
int length;
+ uns count;
u32 hash;
};
static inline u32
-hashf(byte *start, int length)
+hashf(const byte *start, int length)
{
u32 hf = length;
while (length-- > 0)
}
int
-url_has_repeated_component(byte *url)
+url_has_repeated_component(const byte *url)
{
struct component *comp;
- uns comps, comp_len, rep_prefix;
- byte *c;
- uns i;
+ uns comps, comp_len, rep_prefix, hash_size, *hash, *next;
+ const byte *c;
+ uns i, j, k;
for (comps=0, c=url; c; comps++)
{
if (c)
c++;
}
- if (comps < url_min_repeat_count)
+ if (comps < url_min_repeat_count && comps <= url_max_occurences)
return 0;
- comp = alloca(comps * sizeof(struct component));
+ comp = alloca(comps * sizeof(*comp));
for (i=0, c=url; c; i++)
{
comp[i].start = c;
ASSERT(i == comps);
for (i=0; i<comps; i++)
comp[i].hash = hashf(comp[i].start, comp[i].length);
+ if (comps > url_max_occurences)
+ {
+ hash_size = next_table_prime(comps);
+ hash = alloca(hash_size * sizeof(*hash));
+ next = alloca(comps * sizeof(*next));
+ memset(hash, 255, hash_size * sizeof(*hash));
+ for (i=0; i<comps; i++)
+ {
+ j = comp[i].hash % hash_size;
+ for (k = hash[j]; ~k && (comp[i].hash != comp[k].hash || comp[i].length != comp[k].length ||
+ memcmp(comp[k].start, comp[i].start, comp[i].length)); k = next[k]);
+ if (!~k)
+ {
+ next[i] = hash[j];
+ hash[j] = i;
+ comp[i].count = 1;
+ }
+ else
+ {
+ if (comp[k].count++ >= url_max_occurences)
+ return 1;
+ }
+ }
+ }
for (comp_len = 1; comp_len <= url_max_repeat_length && comp_len <= comps; comp_len++)
for (rep_prefix = 0; rep_prefix <= comps - comp_len; rep_prefix++)
if (repeat_count(comp + rep_prefix, comps - rep_prefix, comp_len) >= url_min_repeat_count)