Commit 6547a456 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

I know it's the OCD talking here, but neither a fixed 32 param limit

or an string-insertion-sort feels right for me.

Using reserved workspace to tracking the params and qsort(3) to sort them
solves both problems.
parent c2c3156e
...@@ -28,97 +28,105 @@ ...@@ -28,97 +28,105 @@
#include "config.h" #include "config.h"
#include <stdlib.h>
#include "vrt.h" #include "vrt.h"
#include "cache/cache.h" #include "cache/cache.h"
#include "vcc_if.h" #include "vcc_if.h"
#define QS_MAX_PARAM_COUNT 32 static int
#define QS_EQUALS(a, b) \ compa(const void *a, const void *b)
((a) == (b) || ((a) == '\0' && (b) == '&') || ((a) == '&' && (b) == '\0'))
static ssize_t
param_compare(const char *s, const char *t)
{ {
for (; QS_EQUALS(*s, *t); s++, t++) { const char * const *pa = a;
if (*s == '&' || *s == '\0') const char * const *pb = b;
return (0); const char *a1, *b1;
}
return (*s - *t); for(a1 = pa[0], b1 = pb[0]; a1 < pa[1] && b1 < pb[1]; a1++, b1++)
} if (*a1 != *b1)
return (*a1 - *b1);
static size_t return (0);
param_copy(char *dst, const char *src)
{
size_t len;
len = strcspn(src, "&");
memcpy(dst, src, len);
return (len);
} }
VCL_STRING __match_proto__(td_std_querysort) VCL_STRING __match_proto__(td_std_querysort)
vmod_querysort(const struct vrt_ctx *ctx, VCL_STRING url) vmod_querysort(const struct vrt_ctx *ctx, VCL_STRING url)
{ {
char *param, *params[QS_MAX_PARAM_COUNT]; const char *cq, *cu;
char *p, *r; char *p, *r;
size_t len; const char **pp;
int param_count; const char **pe;
int i, n; int np;
int i;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
if (url == NULL) if (url == NULL)
return (NULL); return (NULL);
p = strchr(url, '?'); /* Split :query from :url */
if (p == NULL) cu = strchr(url, '?');
if (cu == NULL)
return (url); return (url);
param_count = 0; /* Spot single-param queries */
params[param_count++] = ++p; cq = strchr(cu, '&');
len = p - url; if (cq == NULL)
while ((p = strchr(p, '&')) != NULL) {
param = ++p;
for (i = 0; i < param_count; i++) {
if (param[0] < params[i][0] ||
param_compare(param, params[i]) < 0) {
for (n = param_count; n > i; n--)
params[n] = params[n - 1];
break;
}
}
params[i] = param;
param_count++;
if (param_count == QS_MAX_PARAM_COUNT)
return (url);
}
if (param_count == 1)
return (url); return (url);
r = WS_Alloc(ctx->ws, strchr(param, '\0') - url + 1); r = WS_Copy(ctx->ws, url, -1);
if (r == NULL) if (r == NULL)
return (url); return (url);
p = memcpy(r, url, len); (void)WS_Reserve(ctx->ws, 0);
p += len; /* We trust cache_ws.c to align sensibly */
pp = (const char**)(void*)(ctx->ws->f);
pe = (const char**)(void*)(ctx->ws->e);
for (i = 0; i < param_count - 1; i++) { if (pp + 4 > pe) {
if (params[i][0] != '\0' && params[i][0] != '&') WS_Release(ctx->ws, 0);
break; WS_MarkOverflow(ctx->ws);
return (url);
} }
for (; i < param_count - 1; i++) { /* Collect params as pointer pairs */
p += param_copy(p, params[i]); np = 0;
*p++ = '&'; pp[np++] = 1 + cu;
for (cq = 1 + cu; *cq != '\0'; cq++) {
if (*cq == '&') {
if (pp + 3 > pe) {
WS_Release(ctx->ws, 0);
WS_MarkOverflow(ctx->ws);
return (url);
}
pp[np++] = cq;
/* Skip trivially empty params */
while(cq[1] == '&')
cq++;
pp[np++] = cq + 1;
}
}
pp[np++] = cq;
assert(!(np & 1));
qsort(pp, np / 2, sizeof(*pp) * 2, compa);
/* Emit sorted params */
p = 1 + r + (cu - url);
cq = "";
for (i = 0; i < np; i += 2) {
/* Ignore any edge-case zero length params */
if (pp[i + 1] == pp[i])
continue;
assert(pp[i + 1] > pp[i]);
if (*cq)
*p++ = *cq;
memcpy(p, pp[i], pp[i + 1] - pp[i]);
p += pp[i + 1] - pp[i];
cq = "&";
} }
p += param_copy(p, params[i]);
*p = '\0'; *p = '\0';
WS_Release(ctx->ws, 0);
return (r); return (r);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment