[4.0] 8d496cc I know it's the OCD talking here, but neither a fixed 32 param limit or an string-insertion-sort feels right for me.
Lasse Karstensen
lkarsten at varnish-software.com
Mon Sep 22 16:38:21 CEST 2014
commit 8d496cc9c1434d3daec6952bcbfef3e9cb5639fe
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Tue Jun 24 10:44:42 2014 +0000
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.
diff --git a/lib/libvmod_std/vmod_std_querysort.c b/lib/libvmod_std/vmod_std_querysort.c
index 8aac9df..8f7f93b 100644
--- a/lib/libvmod_std/vmod_std_querysort.c
+++ b/lib/libvmod_std/vmod_std_querysort.c
@@ -28,97 +28,105 @@
#include "config.h"
+#include <stdlib.h>
+
#include "vrt.h"
#include "cache/cache.h"
#include "vcc_if.h"
-#define QS_MAX_PARAM_COUNT 32
-#define QS_EQUALS(a, b) \
- ((a) == (b) || ((a) == '\0' && (b) == '&') || ((a) == '&' && (b) == '\0'))
-
-static ssize_t
-param_compare(const char *s, const char *t)
+static int
+compa(const void *a, const void *b)
{
- for (; QS_EQUALS(*s, *t); s++, t++) {
- if (*s == '&' || *s == '\0')
- return (0);
- }
- return (*s - *t);
-}
-
-static size_t
-param_copy(char *dst, const char *src)
-{
- size_t len;
- len = strcspn(src, "&");
- memcpy(dst, src, len);
- return (len);
+ const char * const *pa = a;
+ const char * const *pb = b;
+ const char *a1, *b1;
+
+ for(a1 = pa[0], b1 = pb[0]; a1 < pa[1] && b1 < pb[1]; a1++, b1++)
+ if (*a1 != *b1)
+ return (*a1 - *b1);
+ return (0);
}
VCL_STRING __match_proto__(td_std_querysort)
vmod_querysort(const struct vrt_ctx *ctx, VCL_STRING url)
{
- char *param, *params[QS_MAX_PARAM_COUNT];
+ const char *cq, *cu;
char *p, *r;
- size_t len;
- int param_count;
- int i, n;
+ const char **pp;
+ const char **pe;
+ int np;
+ int i;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
if (url == NULL)
return (NULL);
- p = strchr(url, '?');
- if (p == NULL)
+ /* Split :query from :url */
+ cu = strchr(url, '?');
+ if (cu == NULL)
return (url);
- param_count = 0;
- params[param_count++] = ++p;
- len = p - url;
-
- 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)
+ /* Spot single-param queries */
+ cq = strchr(cu, '&');
+ if (cq == NULL)
return (url);
- r = WS_Alloc(ctx->ws, strchr(param, '\0') - url + 1);
+ r = WS_Copy(ctx->ws, url, -1);
if (r == NULL)
return (url);
- p = memcpy(r, url, len);
- p += len;
+ (void)WS_Reserve(ctx->ws, 0);
+ /* 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 (params[i][0] != '\0' && params[i][0] != '&')
- break;
+ if (pp + 4 > pe) {
+ WS_Release(ctx->ws, 0);
+ WS_MarkOverflow(ctx->ws);
+ return (url);
}
- for (; i < param_count - 1; i++) {
- p += param_copy(p, params[i]);
- *p++ = '&';
+ /* Collect params as pointer pairs */
+ np = 0;
+ 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';
+ WS_Release(ctx->ws, 0);
return (r);
}
More information about the varnish-commit
mailing list