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