varnish-cache/bin/varnishd/cache/cache_range.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2015 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
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 "cache_varnishd.h"
33
#include "cache_filter.h"
34
35
#include "vct.h"
36
37
/*--------------------------------------------------------------------*/
38
39
struct vrg_priv {
40
        unsigned                magic;
41
#define VRG_PRIV_MAGIC          0xb886e711
42
        ssize_t                 range_low;
43
        ssize_t                 range_high;
44
        ssize_t                 range_off;
45
};
46
47
static int v_matchproto_(vdp_fini_f)
48 22
vrg_range_fini(struct req *req, void **priv)
49
{
50
        struct vrg_priv *vrg_priv;
51
52 22
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
53 22
        CAST_OBJ_NOTNULL(vrg_priv, *priv, VRG_PRIV_MAGIC);
54 22
        if (vrg_priv->range_off < vrg_priv->range_high)
55 2
                Req_Fail(req, SC_RANGE_SHORT);
56 22
        *priv = NULL;   /* struct on ws, no need to free */
57 22
        return (0);
58
}
59
60
static int v_matchproto_(vdp_bytes_f)
61 27
vrg_range_bytes(struct req *req, enum vdp_action act, void **priv,
62
    const void *ptr, ssize_t len)
63
{
64 27
        int retval = 0;
65
        ssize_t l;
66 27
        const char *p = ptr;
67
        struct vrg_priv *vrg_priv;
68
69 27
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
70 27
        CAST_OBJ_NOTNULL(vrg_priv, *priv, VRG_PRIV_MAGIC);
71
72 27
        l = vrg_priv->range_low - vrg_priv->range_off;
73 27
        if (l > 0) {
74 14
                if (l > len)
75 0
                        l = len;
76 14
                vrg_priv->range_off += l;
77 14
                p += l;
78 14
                len -= l;
79
        }
80 27
        l = vrg_priv->range_high - vrg_priv->range_off;
81 27
        if (l > len)
82 7
                l = len;
83 27
        if (l > 0)
84 27
                retval = VDP_bytes(req, act, p, l);
85 0
        else if (act > VDP_NULL)
86 0
                retval = VDP_bytes(req, act, p, 0);
87 27
        vrg_priv->range_off += len;
88
        return (retval ||
89 27
            vrg_priv->range_off >= vrg_priv->range_high ? 1 : 0);
90
}
91
92
static const struct vdp vrg_vdp = {
93
        .name =         "RNG",
94
        .bytes =        vrg_range_bytes,
95
        .fini =         vrg_range_fini,
96
};
97
98
/*--------------------------------------------------------------------*/
99
100
static const char *
101 34
vrg_dorange(struct req *req, const char *r)
102
{
103
        ssize_t low, high, has_low, has_high, t;
104
        struct vrg_priv *vrg_priv;
105
106 34
        if (strncasecmp(r, "bytes=", 6))
107 4
                return ("Not Bytes");
108 30
        r += 6;
109
110
        /* The low end of range */
111 30
        has_low = low = 0;
112 91
        while (vct_isdigit(*r)) {
113 31
                has_low = 1;
114 31
                t = low;
115 31
                low *= 10;
116 31
                low += *r++ - '0';
117 31
                if (low < t)
118 0
                        return ("Low number too big");
119
        }
120
121 30
        if (*r++ != '-')
122 0
                return ("Missing hyphen");
123
124
        /* The high end of range */
125 30
        has_high = high = 0;
126 97
        while (vct_isdigit(*r)) {
127 37
                has_high = 1;
128 37
                t = high;
129 37
                high *= 10;
130 37
                high += *r++ - '0';
131 37
                if (high < t)
132 0
                        return ("High number too big");
133
        }
134
135 30
        if (*r != '\0')
136 1
                return ("Trailing stuff");
137
138 29
        if (has_high + has_low == 0)
139 1
                return ("Neither high nor low");
140
141 28
        if (!has_low) {
142 4
                if (req->resp_len < 0)
143 0
                        return (NULL);          // Allow 200 response
144 4
                if (high == 0)
145 1
                        return ("No low, high is zero");
146 3
                low = req->resp_len - high;
147 3
                if (low < 0)
148 1
                        low = 0;
149 3
                high = req->resp_len - 1;
150 24
        } else if (req->resp_len >= 0 && (high >= req->resp_len || !has_high))
151 7
                high = req->resp_len - 1;
152 17
        else if (!has_high || req->resp_len < 0)
153 3
                return (NULL);                  // Allow 200 response
154
        /*
155
         * else (bo != NULL) {
156
         *    We assume that the client knows what it's doing and trust
157
         *    that both low and high make sense.
158
         * }
159
         */
160
161 24
        if (high < low)
162 2
                return ("high smaller than low");
163
164 22
        if (req->resp_len >= 0 && low >= req->resp_len)
165 0
                return ("low range beyond object");
166
167 22
        if (req->resp_len >= 0)
168 22
                http_PrintfHeader(req->resp, "Content-Range: bytes %jd-%jd/%jd",
169 22
                    (intmax_t)low, (intmax_t)high, (intmax_t)req->resp_len);
170
        else
171 0
                http_PrintfHeader(req->resp, "Content-Range: bytes %jd-%jd/*",
172
                    (intmax_t)low, (intmax_t)high);
173 22
        req->resp_len = (intmax_t)(1 + high - low);
174
175 22
        vrg_priv = WS_Alloc(req->ws, sizeof *vrg_priv);
176 22
        if (vrg_priv == NULL)
177 0
                return ("WS too small");
178
179 22
        XXXAN(vrg_priv);
180 22
        INIT_OBJ(vrg_priv, VRG_PRIV_MAGIC);
181 22
        vrg_priv->range_off = 0;
182 22
        vrg_priv->range_low = low;
183 22
        vrg_priv->range_high = high + 1;
184 22
        if (VDP_Push(req, &vrg_vdp, vrg_priv))
185 0
                return ("WS too small");
186 22
        http_PutResponse(req->resp, "HTTP/1.1", 206, NULL);
187 22
        return (NULL);
188
}
189
190
void
191 34
VRG_dorange(struct req *req, const char *r)
192
{
193
        const char *err;
194
195 34
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
196 34
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
197 34
        assert(http_IsStatus(req->resp, 200));
198
199
        /* We must snapshot the length if we're streaming from the backend */
200
201 34
        err = vrg_dorange(req, r);
202 34
        if (err != NULL) {
203 9
                VSLb(req->vsl, SLT_Debug, "RANGE_FAIL %s", err);
204 9
                if (req->resp_len >= 0)
205 9
                        http_PrintfHeader(req->resp,
206
                            "Content-Range: bytes */%jd",
207 9
                            (intmax_t)req->resp_len);
208 9
                http_PutResponse(req->resp, "HTTP/1.1", 416, NULL);
209
                /*
210
                 * XXX: We ought to produce a body explaining things.
211
                 * XXX: That really calls for us to hit vcl_synth{}
212
                 */
213 9
                req->resp_len = 0;
214
        }
215 34
}