varnish-cache/bin/varnishd/http1/cache_http1_line.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2011 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
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
 * Write data to fd
31
 * We try to use writev() if possible in order to minimize number of
32
 * syscalls made and packets sent.  It also just might allow the worker
33
 * thread to complete the request without holding stuff locked.
34
 *
35
 * XXX: chunked header (generated in Flush) and Tail (EndChunk)
36
 *      are not accounted by means of the size_t returned. Obvious ideas:
37
 *      - add size_t return value to Flush and EndChunk
38
 *      - base accounting on (struct v1l).cnt
39
 */
40
41
#include "config.h"
42
43
#include <sys/uio.h>
44
#include "cache/cache_varnishd.h"
45
#include "cache/cache_filter.h"
46
47
#include <stdio.h>
48
49
#include "cache_http1.h"
50
#include "vtim.h"
51
52
/*--------------------------------------------------------------------*/
53
54
struct v1l {
55
        unsigned                magic;
56
#define V1L_MAGIC               0x2f2142e5
57
        int                     *wfd;
58
        stream_close_t          werr;   /* valid after V1L_Flush() */
59
        struct iovec            *iov;
60
        unsigned                siov;
61
        unsigned                niov;
62
        ssize_t                 liov;
63
        ssize_t                 cliov;
64
        unsigned                ciov;   /* Chunked header marker */
65
        vtim_real               deadline;
66
        struct vsl_log          *vsl;
67
        ssize_t                 cnt;    /* Flushed byte count */
68
        struct ws               *ws;
69
        uintptr_t               ws_snap;
70
};
71
72
/*--------------------------------------------------------------------
73
 * for niov == 0, reserve the ws for max number of iovs
74
 * otherwise, up to niov
75
 */
76
77
void
78 198468
V1L_Open(struct worker *wrk, struct ws *ws, int *fd, struct vsl_log *vsl,
79
    vtim_real deadline, unsigned niov)
80
{
81
        struct v1l *v1l;
82
        unsigned u;
83
        uintptr_t ws_snap;
84
85 198468
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
86 198468
        AZ(wrk->v1l);
87
88 198468
        if (WS_Overflowed(ws))
89 0
                return;
90
91 198468
        if (niov != 0)
92 114957
                assert(niov >= 3);
93
94 198468
        ws_snap = WS_Snapshot(ws);
95
96 198468
        v1l = WS_Alloc(ws, sizeof *v1l);
97 198468
        if (v1l == NULL)
98 40
                return;
99 198428
        INIT_OBJ(v1l, V1L_MAGIC);
100
101 198428
        v1l->ws = ws;
102 198428
        v1l->ws_snap = ws_snap;
103
104 198428
        u = WS_ReserveLumps(ws, sizeof(struct iovec));
105 198428
        if (u < 3) {
106
                /* Must have at least 3 in case of chunked encoding */
107 0
                WS_Release(ws, 0);
108 0
                WS_MarkOverflow(ws);
109 0
                return;
110
        }
111 198428
        if (u > IOV_MAX)
112 0
                u = IOV_MAX;
113 198428
        if (niov != 0 && u > niov)
114 111907
                u = niov;
115 198428
        v1l->iov = WS_Reservation(ws);
116 198428
        v1l->siov = u;
117 198428
        v1l->ciov = u;
118 198428
        v1l->wfd = fd;
119 198428
        v1l->deadline = deadline;
120 198428
        v1l->vsl = vsl;
121 198428
        v1l->werr = SC_NULL;
122
123 198428
        AZ(wrk->v1l);
124 198428
        wrk->v1l = v1l;
125
126 198428
        WS_Release(ws, u * sizeof(struct iovec));
127 198468
}
128
129
stream_close_t
130 198455
V1L_Close(struct worker *wrk, uint64_t *cnt)
131
{
132
        struct v1l *v1l;
133
        struct ws *ws;
134
        uintptr_t ws_snap;
135
        stream_close_t sc;
136
137 198455
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
138 198455
        AN(cnt);
139 198455
        sc = V1L_Flush(wrk);
140 198455
        TAKE_OBJ_NOTNULL(v1l, &wrk->v1l, V1L_MAGIC);
141 198455
        *cnt = v1l->cnt;
142 198455
        ws = v1l->ws;
143 198455
        ws_snap = v1l->ws_snap;
144 198455
        ZERO_OBJ(v1l, sizeof *v1l);
145 198455
        WS_Rollback(ws, ws_snap);
146 198455
        return (sc);
147
}
148
149
static void
150 739
v1l_prune(struct v1l *v1l, size_t bytes)
151
{
152 739
        ssize_t used = 0;
153
        ssize_t j, used_here;
154
155 2729
        for (j = 0; j < v1l->niov; j++) {
156 2729
                if (used + v1l->iov[j].iov_len > bytes) {
157
                        /* Cutoff is in this iov */
158 739
                        used_here = bytes - used;
159 739
                        v1l->iov[j].iov_len -= used_here;
160 739
                        v1l->iov[j].iov_base =
161 739
                            (char*)v1l->iov[j].iov_base + used_here;
162 1478
                        memmove(v1l->iov, &v1l->iov[j],
163 739
                            (v1l->niov - j) * sizeof(struct iovec));
164 739
                        v1l->niov -= j;
165 739
                        v1l->liov -= bytes;
166 739
                        return;
167
                }
168 1990
                used += v1l->iov[j].iov_len;
169 1990
        }
170 0
        AZ(v1l->liov);
171 739
}
172
173
stream_close_t
174 400753
V1L_Flush(const struct worker *wrk)
175
{
176
        ssize_t i;
177
        int err;
178
        struct v1l *v1l;
179
        char cbuf[32];
180
181 400753
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
182 400753
        v1l = wrk->v1l;
183 400753
        CHECK_OBJ_NOTNULL(v1l, V1L_MAGIC);
184 400753
        CHECK_OBJ_NOTNULL(v1l->werr, STREAM_CLOSE_MAGIC);
185 400753
        AN(v1l->wfd);
186
187 400753
        assert(v1l->niov <= v1l->siov);
188
189 400753
        if (*v1l->wfd >= 0 && v1l->liov > 0 && v1l->werr == SC_NULL) {
190 269986
                if (v1l->ciov < v1l->siov && v1l->cliov > 0) {
191
                        /* Add chunk head & tail */
192 42082
                        bprintf(cbuf, "00%zx\r\n", v1l->cliov);
193 42082
                        i = strlen(cbuf);
194 42082
                        v1l->iov[v1l->ciov].iov_base = cbuf;
195 42082
                        v1l->iov[v1l->ciov].iov_len = i;
196 42082
                        v1l->liov += i;
197
198
                        /* This is OK, because siov was --'ed */
199 42082
                        v1l->iov[v1l->niov].iov_base = cbuf + i - 2;
200 42082
                        v1l->iov[v1l->niov++].iov_len = 2;
201 42082
                        v1l->liov += 2;
202 269986
                } else if (v1l->ciov < v1l->siov) {
203 2527
                        v1l->iov[v1l->ciov].iov_base = cbuf;
204 2527
                        v1l->iov[v1l->ciov].iov_len = 0;
205 2527
                }
206
207 269986
                i = 0;
208 269986
                err = 0;
209 269986
                do {
210 271822
                        if (VTIM_real() > v1l->deadline) {
211 320
                                VSLb(v1l->vsl, SLT_Debug,
212
                                    "Hit total send timeout, "
213
                                    "wrote = %zd/%zd; not retrying",
214 160
                                    i, v1l->liov);
215 160
                                i = -1;
216 160
                                break;
217
                        }
218
219 271662
                        i = writev(*v1l->wfd, v1l->iov, v1l->niov);
220 271662
                        if (i > 0)
221 270266
                                v1l->cnt += i;
222
223 271662
                        if (i == v1l->liov)
224 269529
                                break;
225
226
                        /* we hit a timeout, and some data may have been sent:
227
                         * Remove sent data from start of I/O vector, then retry
228
                         *
229
                         * XXX: Add a "minimum sent data per timeout counter to
230
                         * prevent slowloris attacks
231
                         */
232
233 2133
                        err = errno;
234
235 2133
                        if (err == EWOULDBLOCK) {
236 2148
                                VSLb(v1l->vsl, SLT_Debug,
237
                                    "Hit idle send timeout, "
238
                                    "wrote = %zd/%zd; retrying",
239 1074
                                    i, v1l->liov);
240 1074
                        }
241
242 2133
                        if (i > 0)
243 739
                                v1l_prune(v1l, i);
244 2133
                } while (i > 0 || err == EWOULDBLOCK);
245
246 269986
                if (i <= 0) {
247 960
                        VSLb(v1l->vsl, SLT_Debug,
248
                            "Write error, retval = %zd, len = %zd, errno = %s",
249 480
                            i, v1l->liov, VAS_errtxt(err));
250 480
                        assert(v1l->werr == SC_NULL);
251 480
                        if (err == EPIPE)
252 314
                                v1l->werr = SC_REM_CLOSE;
253
                        else
254 166
                                v1l->werr = SC_TX_ERROR;
255 480
                        errno = err;
256 480
                }
257 269986
        }
258 400769
        v1l->liov = 0;
259 400769
        v1l->cliov = 0;
260 400769
        v1l->niov = 0;
261 400769
        if (v1l->ciov < v1l->siov)
262 81690
                v1l->ciov = v1l->niov++;
263 400743
        CHECK_OBJ_NOTNULL(v1l->werr, STREAM_CLOSE_MAGIC);
264 400743
        return (v1l->werr);
265
}
266
267
size_t
268 4527154
V1L_Write(const struct worker *wrk, const void *ptr, ssize_t len)
269
{
270
        struct v1l *v1l;
271
272 4527154
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
273 4527154
        v1l = wrk->v1l;
274 4527154
        CHECK_OBJ_NOTNULL(v1l, V1L_MAGIC);
275 4527154
        AN(v1l->wfd);
276 4527154
        if (len == 0 || *v1l->wfd < 0)
277 312
                return (0);
278 4527130
        if (len == -1)
279 2297027
                len = strlen(ptr);
280 4527130
        assert(v1l->niov < v1l->siov);
281 4527130
        v1l->iov[v1l->niov].iov_base = TRUST_ME(ptr);
282 4527130
        v1l->iov[v1l->niov].iov_len = len;
283 4527130
        v1l->liov += len;
284 4527130
        v1l->niov++;
285 4527130
        v1l->cliov += len;
286 4527130
        if (v1l->niov >= v1l->siov) {
287 4400
                (void)V1L_Flush(wrk);
288 4400
                VSC_C_main->http1_iovs_flush++;
289 4400
        }
290 4527130
        return (len);
291 4527130
}
292
293
void
294 10439
V1L_Chunked(const struct worker *wrk)
295
{
296
        struct v1l *v1l;
297
298 10439
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
299 10439
        v1l = wrk->v1l;
300 10439
        CHECK_OBJ_NOTNULL(v1l, V1L_MAGIC);
301
302 10439
        assert(v1l->ciov == v1l->siov);
303 10439
        assert(v1l->siov >= 3);
304
        /*
305
         * If there is no space for chunked header, a chunk of data and
306
         * a chunk tail, we might as well flush right away.
307
         */
308 10439
        if (v1l->niov + 3 >= v1l->siov) {
309 0
                (void)V1L_Flush(wrk);
310 0
                VSC_C_main->http1_iovs_flush++;
311 0
        }
312 10439
        v1l->siov--;
313 10439
        v1l->ciov = v1l->niov++;
314 10439
        v1l->cliov = 0;
315 10439
        assert(v1l->ciov < v1l->siov);
316 10439
        assert(v1l->niov < v1l->siov);
317 10439
}
318
319
/*
320
 * XXX: It is not worth the complexity to attempt to get the
321
 * XXX: end of chunk into the V1L_Flush(), because most of the time
322
 * XXX: if not always, that is a no-op anyway, because the calling
323
 * XXX: code already called V1L_Flush() to release local storage.
324
 */
325
326
void
327 9597
V1L_EndChunk(const struct worker *wrk)
328
{
329
        struct v1l *v1l;
330
331 9597
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
332 9597
        v1l = wrk->v1l;
333 9597
        CHECK_OBJ_NOTNULL(v1l, V1L_MAGIC);
334
335 9597
        assert(v1l->ciov < v1l->siov);
336 9597
        (void)V1L_Flush(wrk);
337 9597
        v1l->siov++;
338 9597
        v1l->ciov = v1l->siov;
339 9597
        v1l->niov = 0;
340 9597
        v1l->cliov = 0;
341 9597
        (void)V1L_Write(wrk, "0\r\n\r\n", -1);
342 9597
}
343
344
/*--------------------------------------------------------------------
345
 * VDP using V1L
346
 */
347
348
static int v_matchproto_(vdp_bytes_f)
349 194146
v1l_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
350
    const void *ptr, ssize_t len)
351
{
352 194146
        ssize_t wl = 0;
353
354 194146
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
355 194146
        (void)priv;
356
357 194146
        AZ(vdc->nxt);           /* always at the bottom of the pile */
358
359 194146
        if (len > 0)
360 140530
                wl = V1L_Write(vdc->wrk, ptr, len);
361 194146
        if (act > VDP_NULL && V1L_Flush(vdc->wrk) != SC_NULL)
362 478
                return (-1);
363 193668
        if (len != wl)
364 0
                return (-1);
365 193668
        return (0);
366 194146
}
367
368
const struct vdp * const VDP_v1l = &(struct vdp){
369
        .name =         "V1B",
370
        .bytes =        v1l_bytes,
371
};