varnish-cache/lib/libvmod_std/vmod_std_querysort.c
1
/*-
2
 * Copyright (c) 2010-2014 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Naren Venkataraman of Vimeo Inc.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 */
28
29
#include "config.h"
30
31
#include <stdlib.h>
32
#include <string.h>
33
34
#include "cache/cache.h"
35
36
#include "vcc_if.h"
37
38
static int
39 16
compa(const void *a, const void *b)
40
{
41 16
        const char * const *pa = a;
42 16
        const char * const *pb = b;
43
        const char *a1, *b1;
44
45 18
        for (a1 = pa[0], b1 = pb[0]; a1 < pa[1] && b1 < pb[1]; a1++, b1++)
46 14
                if (*a1 != *b1)
47 12
                        return (*a1 - *b1);
48 4
        return (0);
49
}
50
51
VCL_STRING v_matchproto_(td_std_querysort)
52 7
vmod_querysort(VRT_CTX, VCL_STRING url)
53
{
54
        const char *cq, *cu;
55
        char *p, *r;
56
        const char **pp;
57
        const char **pe;
58
        unsigned u;
59
        int np;
60
        int i;
61
62 7
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
63
64 7
        if (url == NULL)
65 0
                return (NULL);
66
67
        /* Split :query from :url */
68 7
        cu = strchr(url, '?');
69 7
        if (cu == NULL)
70 1
                return (url);
71
72
        /* Spot single-param queries */
73 6
        cq = strchr(cu, '&');
74 6
        if (cq == NULL)
75 0
                return (url);
76
77 6
        r = WS_Copy(ctx->ws, url, -1);
78 6
        if (r == NULL)
79 0
                return (url);
80
81 6
        u = WS_ReserveLumps(ctx->ws, sizeof(const char **));
82 6
        pp = (const char**)(void*)(ctx->ws->f);
83 6
        if (u < 4) {
84 0
                WS_Release(ctx->ws, 0);
85 0
                WS_MarkOverflow(ctx->ws);
86 0
                return (url);
87
        }
88 6
        pe = pp + u;
89
90
        /* Collect params as pointer pairs */
91 6
        np = 0;
92 6
        pp[np++] = 1 + cu;
93 54
        for (cq = 1 + cu; *cq != '\0'; cq++) {
94 49
                if (*cq == '&') {
95 13
                        if (pp + np + 3 > pe) {
96 1
                                WS_Release(ctx->ws, 0);
97 1
                                WS_MarkOverflow(ctx->ws);
98 1
                                return (url);
99
                        }
100 12
                        pp[np++] = cq;
101
                        /* Skip trivially empty params */
102 32
                        while (cq[1] == '&')
103 8
                                cq++;
104 12
                        pp[np++] = cq + 1;
105
                }
106
        }
107 5
        pp[np++] = cq;
108 5
        assert(!(np & 1));
109
110 5
        qsort(pp, np / 2, sizeof(*pp) * 2, compa);
111
112
        /* Emit sorted params */
113 5
        p = 1 + r + (cu - url);
114 5
        cq = "";
115 21
        for (i = 0; i < np; i += 2) {
116
                /* Ignore any edge-case zero length params */
117 16
                if (pp[i + 1] == pp[i])
118 5
                        continue;
119 11
                assert(pp[i + 1] > pp[i]);
120 11
                if (*cq)
121 7
                        *p++ = *cq;
122 11
                memcpy(p, pp[i], pp[i + 1] - pp[i]);
123 11
                p += pp[i + 1] - pp[i];
124 11
                cq = "&";
125
        }
126 5
        *p = '\0';
127
128 5
        WS_Release(ctx->ws, 0);
129 5
        return (r);
130
}