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